From: Tom Kistner Date: Tue, 17 Mar 2009 14:56:55 +0000 (+0000) Subject: pdkim API cleanup X-Git-Url: https://git.exim.org/users/jgh/exim.git/commitdiff_plain/48c3e117aed5b2e97b11a64b3bcc92f8e98a7963 pdkim API cleanup --- diff --git a/src/scripts/MakeLinks b/src/scripts/MakeLinks index c99e97ef6..ee8c8dca6 100755 --- a/src/scripts/MakeLinks +++ b/src/scripts/MakeLinks @@ -1,5 +1,5 @@ #!/bin/sh -# $Cambridge: exim/src/scripts/MakeLinks,v 1.14.2.2 2009/02/24 15:57:55 tom Exp $ +# $Cambridge: exim/src/scripts/MakeLinks,v 1.14.2.3 2009/03/17 14:56:55 tom Exp $ # Script to build links for all the exim source files from the system- # specific build directory. It should be run from within that directory. @@ -201,6 +201,7 @@ ln -s ../../src/pdkim/bignum.h bignum.h ln -s ../../src/pdkim/bn_mul.h bn_mul.h ln -s ../../src/pdkim/pdkim.c pdkim.c ln -s ../../src/pdkim/pdkim.h pdkim.h +ln -s ../../src/pdkim/pdkim-api.h pdkim-api.h ln -s ../../src/pdkim/rsa.c rsa.c ln -s ../../src/pdkim/rsa.h rsa.h ln -s ../../src/pdkim/sha1.c sha1.c diff --git a/src/src/dkim.c b/src/src/dkim.c index fb846beb4..62f3814d7 100644 --- a/src/src/dkim.c +++ b/src/src/dkim.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/dkim.c,v 1.1.2.2 2009/02/24 18:43:59 tom Exp $ */ +/* $Cambridge: exim/src/src/dkim.c,v 1.1.2.3 2009/03/17 14:56:55 tom Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -119,15 +119,15 @@ uschar *dkim_exim_sign(int dkim_fd, dkim_private_key = big_buffer; } - ctx = pdkim_init_sign((char *)dkim_signing_domain, + ctx = pdkim_init_sign(PDKIM_INPUT_SMTP, + (char *)dkim_signing_domain, (char *)dkim_signing_selector, - dkim_private_key + (char *)dkim_private_key ); pdkim_set_debug_stream(ctx,debug_file); pdkim_set_optional(ctx, - PDKIM_INPUT_SMTP, (char *)dkim_sign_headers, NULL, pdkim_canon, diff --git a/src/src/pdkim/pdkim.c b/src/src/pdkim/pdkim.c index 0fefd9ace..82bfe1ed4 100644 --- a/src/src/pdkim/pdkim.c +++ b/src/src/pdkim/pdkim.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/pdkim/pdkim.c,v 1.1.2.6 2009/03/17 12:57:37 tom Exp $ */ +/* $Cambridge: exim/src/src/pdkim/pdkim.c,v 1.1.2.7 2009/03/17 14:56:55 tom Exp $ */ /* pdkim.c */ #include @@ -7,8 +7,45 @@ #include #include #include + #include "pdkim.h" +#include "sha1.h" +#include "sha2.h" +#include "rsa.h" +#include "base64.h" + +#define PDKIM_SIGNATURE_VERSION "1" +#define PDKIM_PUB_RECORD_VERSION "DKIM1" + +#define PDKIM_MAX_HEADER_LEN 65536 +#define PDKIM_MAX_HEADERS 512 +#define PDKIM_MAX_BODY_LINE_LEN 1024 +#define PDKIM_DNS_TXT_MAX_NAMELEN 1024 +#define PDKIM_DNS_TXT_MAX_RECLEN 4096 +#define PDKIM_DEFAULT_SIGN_HEADERS "From:Sender:Reply-To:Subject:Date:"\ + "Message-ID:To:Cc:MIME-Version:Content-Type:"\ + "Content-Transfer-Encoding:Content-ID:"\ + "Content-Description:Resent-Date:Resent-From:"\ + "Resent-Sender:Resent-To:Resent-Cc:"\ + "Resent-Message-ID:In-Reply-To:References:"\ + "List-Id:List-Help:List-Unsubscribe:"\ + "List-Subscribe:List-Post:List-Owner:List-Archive" + + +struct pdkim_stringlist { + char *value; + void *next; +}; + +#define PDKIM_STR_ALLOC_FRAG 256 +struct pdkim_str { + char *str; + unsigned int len; + unsigned int allocated; +}; + + /* -------------------------------------------------------------------------- */ /* A bunch of list constants */ @@ -53,7 +90,7 @@ pdkim_combined_canon_entry pdkim_combined_canons[] = { /* -------------------------------------------------------------------------- */ -/* Various debugging functions */ +/* Print debugging functions */ #ifdef PDKIM_DEBUG void pdkim_quoteprint(FILE *stream, char *data, int len, int lf) { int i; @@ -129,9 +166,6 @@ pdkim_str *pdkim_strnew (char *cstr) { if (cstr) strcpy(p->str,cstr); return p; }; -char *pdkim_strcat(pdkim_str *str, char *cstr) { - return pdkim_strncat(str, cstr, strlen(cstr)); -}; char *pdkim_strncat(pdkim_str *str, char *data, int len) { if ((str->allocated - str->len) < (len+1)) { /* Extend the buffer */ @@ -147,6 +181,9 @@ char *pdkim_strncat(pdkim_str *str, char *data, int len) { str->str[str->len] = '\0'; return str->str; }; +char *pdkim_strcat(pdkim_str *str, char *cstr) { + return pdkim_strncat(str, cstr, strlen(cstr)); +}; char *pdkim_numcat(pdkim_str *str, unsigned long num) { char minibuf[20]; snprintf(minibuf,20,"%lu",num); @@ -177,6 +214,63 @@ void pdkim_strfree(pdkim_str *str) { }; + +/* -------------------------------------------------------------------------- */ +void pdkim_free_pubkey(pdkim_pubkey *pub) { + if (pub) { + if (pub->version != NULL) free(pub->version); + if (pub->granularity != NULL) free(pub->granularity); + if (pub->hashes != NULL) free(pub->hashes); + if (pub->keytype != NULL) free(pub->keytype); + if (pub->srvtype != NULL) free(pub->srvtype); + if (pub->notes != NULL) free(pub->notes); + if (pub->key != NULL) free(pub->key); + free(pub); + } +} + + +/* -------------------------------------------------------------------------- */ +void pdkim_free_sig(pdkim_signature *sig) { + if (sig) { + pdkim_signature *next = (pdkim_signature *)sig->next; + + pdkim_stringlist *e = sig->headers; + while(e != NULL) { + pdkim_stringlist *c = e; + if (e->value != NULL) free(e->value); + e = e->next; + free(c); + } + + if (sig->sigdata != NULL) free(sig->sigdata); + if (sig->bodyhash != NULL) free(sig->bodyhash); + if (sig->selector != NULL) free(sig->selector); + if (sig->domain != NULL) free(sig->domain); + if (sig->identity != NULL) free(sig->identity); + if (sig->headernames != NULL) free(sig->headernames); + if (sig->copiedheaders != NULL) free(sig->copiedheaders); + if (sig->rsa_privkey != NULL) free(sig->rsa_privkey); + if (sig->sign_headers != NULL) free(sig->sign_headers); + + if (sig->pubkey != NULL) pdkim_free_pubkey(sig->pubkey); + + free(sig); + if (next != NULL) pdkim_free_sig(next); + } +}; + + +/* -------------------------------------------------------------------------- */ +void pdkim_free_ctx(pdkim_ctx *ctx) { + if (ctx) { + pdkim_free_sig(ctx->sig); + pdkim_strfree(ctx->cur_header); + free(ctx); + } +}; + + /* -------------------------------------------------------------------------- */ /* Matches the name of the passed raw "header" against the passed colon-separated "list", starting at entry @@ -560,8 +654,19 @@ pdkim_signature *pdkim_parse_sig_header(pdkim_ctx *ctx, char *raw_hdr) { } #endif - sha1_starts(&(sig->sha1_body)); - sha2_starts(&(sig->sha2_body),0); + sig->sha1_body = malloc(sizeof(sha1_context)); + if (sig->sha1_body == NULL) { + pdkim_free_sig(sig); + return NULL; + } + sig->sha2_body = malloc(sizeof(sha2_context)); + if (sig->sha2_body == NULL) { + pdkim_free_sig(sig); + return NULL; + } + + sha1_starts(sig->sha1_body); + sha2_starts(sig->sha2_body,0); return sig; } @@ -736,9 +841,9 @@ int pdkim_update_bodyhash(pdkim_ctx *ctx, char *data, int len) { if (canon_len > 0) { if (sig->algo == PDKIM_ALGO_RSA_SHA1) - sha1_update(&(sig->sha1_body),(unsigned char *)canon_data,canon_len); + sha1_update(sig->sha1_body,(unsigned char *)canon_data,canon_len); else - sha2_update(&(sig->sha2_body),(unsigned char *)canon_data,canon_len); + sha2_update(sig->sha2_body,(unsigned char *)canon_data,canon_len); sig->signed_body_bytes += canon_len; #ifdef PDKIM_DEBUG if (ctx->debug_stream!=NULL) @@ -764,9 +869,9 @@ int pdkim_finish_bodyhash(pdkim_ctx *ctx) { /* Finish hashes */ unsigned char bh[32]; /* SHA-256 = 32 Bytes, SHA-1 = 20 Bytes */ if (sig->algo == PDKIM_ALGO_RSA_SHA1) - sha1_finish(&(sig->sha1_body),bh); + sha1_finish(sig->sha1_body,bh); else - sha2_finish(&(sig->sha2_body),bh); + sha2_finish(sig->sha2_body,bh); #ifdef PDKIM_DEBUG if (ctx->debug_stream) { @@ -1406,6 +1511,13 @@ pdkim_ctx *pdkim_init_verify(int input_mode, pdkim_ctx *ctx = malloc(sizeof(pdkim_ctx)); if (ctx == NULL) return NULL; memset(ctx,0,sizeof(pdkim_ctx)); + + ctx->linebuf = malloc(PDKIM_MAX_BODY_LINE_LEN); + if (ctx->linebuf == NULL) { + free(ctx); + return NULL; + } + ctx->mode = PDKIM_MODE_VERIFY; ctx->input_mode = input_mode; ctx->dns_txt_callback = dns_txt_callback; @@ -1426,8 +1538,16 @@ pdkim_ctx *pdkim_init_sign(int input_mode, ctx = malloc(sizeof(pdkim_ctx)); if (ctx == NULL) return NULL; memset(ctx,0,sizeof(pdkim_ctx)); + + ctx->linebuf = malloc(PDKIM_MAX_BODY_LINE_LEN); + if (ctx->linebuf == NULL) { + free(ctx); + return NULL; + } + pdkim_signature *sig = malloc(sizeof(pdkim_signature)); if (sig == NULL) { + free(ctx->linebuf); free(ctx); return NULL; } @@ -1450,8 +1570,8 @@ pdkim_ctx *pdkim_init_sign(int input_mode, strcpy(ctx->sig->selector, selector); strcpy(ctx->sig->rsa_privkey, rsa_privkey); - sha1_starts(&(ctx->sig->sha1_body)); - sha2_starts(&(ctx->sig->sha2_body),0); + sha1_starts(ctx->sig->sha1_body); + sha2_starts(ctx->sig->sha2_body,0); return ctx; }; @@ -1500,59 +1620,3 @@ int pdkim_set_optional(pdkim_ctx *ctx, return PDKIM_OK; }; - - -/* -------------------------------------------------------------------------- */ -void pdkim_free_pubkey(pdkim_pubkey *pub) { - if (pub) { - if (pub->version != NULL) free(pub->version); - if (pub->granularity != NULL) free(pub->granularity); - if (pub->hashes != NULL) free(pub->hashes); - if (pub->keytype != NULL) free(pub->keytype); - if (pub->srvtype != NULL) free(pub->srvtype); - if (pub->notes != NULL) free(pub->notes); - if (pub->key != NULL) free(pub->key); - free(pub); - } -} - - -/* -------------------------------------------------------------------------- */ -void pdkim_free_sig(pdkim_signature *sig) { - if (sig) { - pdkim_signature *next = (pdkim_signature *)sig->next; - - pdkim_stringlist *e = sig->headers; - while(e != NULL) { - pdkim_stringlist *c = e; - if (e->value != NULL) free(e->value); - e = e->next; - free(c); - } - - if (sig->sigdata != NULL) free(sig->sigdata); - if (sig->bodyhash != NULL) free(sig->bodyhash); - if (sig->selector != NULL) free(sig->selector); - if (sig->domain != NULL) free(sig->domain); - if (sig->identity != NULL) free(sig->identity); - if (sig->headernames != NULL) free(sig->headernames); - if (sig->copiedheaders != NULL) free(sig->copiedheaders); - if (sig->rsa_privkey != NULL) free(sig->rsa_privkey); - if (sig->sign_headers != NULL) free(sig->sign_headers); - - if (sig->pubkey != NULL) pdkim_free_pubkey(sig->pubkey); - - free(sig); - if (next != NULL) pdkim_free_sig(next); - } -}; - - -/* -------------------------------------------------------------------------- */ -void pdkim_free_ctx(pdkim_ctx *ctx) { - if (ctx) { - pdkim_free_sig(ctx->sig); - pdkim_strfree(ctx->cur_header); - free(ctx); - } -}; diff --git a/src/src/pdkim/pdkim.h b/src/src/pdkim/pdkim.h index 8463312b6..d90010136 100644 --- a/src/src/pdkim/pdkim.h +++ b/src/src/pdkim/pdkim.h @@ -1,30 +1,12 @@ -/* $Cambridge: exim/src/src/pdkim/pdkim.h,v 1.1.2.5 2009/03/17 12:57:37 tom Exp $ */ -/* pdkim.h */ - -#include "sha1.h" -#include "sha2.h" -#include "rsa.h" -#include "base64.h" - -#define PDKIM_SIGNATURE_VERSION "1" -#define PDKIM_PUB_RECORD_VERSION "DKIM1" - -#define PDKIM_MAX_HEADER_LEN 65536 -#define PDKIM_MAX_HEADERS 512 -#define PDKIM_MAX_BODY_LINE_LEN 1024 -#define PDKIM_DNS_TXT_MAX_NAMELEN 1024 -#define PDKIM_DNS_TXT_MAX_RECLEN 4096 -#define PDKIM_DEBUG -#define PDKIM_DEFAULT_SIGN_HEADERS "From:Sender:Reply-To:Subject:Date:"\ - "Message-ID:To:Cc:MIME-Version:Content-Type:"\ - "Content-Transfer-Encoding:Content-ID:"\ - "Content-Description:Resent-Date:Resent-From:"\ - "Resent-Sender:Resent-To:Resent-Cc:"\ - "Resent-Message-ID:In-Reply-To:References:"\ - "List-Id:List-Help:List-Unsubscribe:"\ - "List-Subscribe:List-Post:List-Owner:List-Archive" +/* $Cambridge: exim/src/src/pdkim/pdkim.h,v 1.1.2.6 2009/03/17 14:56:55 tom Exp $ */ +/* pdkim-api.h */ +/* -------------------------------------------------------------------------- */ +/* Debugging. This can also be enabled/disabled at run-time. I recommend to + leave it defined. */ +#define PDKIM_DEBUG +/* -------------------------------------------------------------------------- */ /* Function success / error codes */ #define PDKIM_OK 0 #define PDKIM_FAIL -1 @@ -34,43 +16,21 @@ #define PDKIM_ERR_LONG_LINE -103 #define PDKIM_ERR_BUFFER_TOO_SMALL -104 -/* Main verification status */ +/* -------------------------------------------------------------------------- */ +/* Main/Extended verification status */ #define PDKIM_VERIFY_NONE 0 #define PDKIM_VERIFY_INVALID 1 #define PDKIM_VERIFY_FAIL 2 #define PDKIM_VERIFY_PASS 3 -/* Extended verification status */ -#define PDKIM_VERIFY_FAIL_BODY 1 -#define PDKIM_VERIFY_FAIL_MESSAGE 2 - +#define PDKIM_VERIFY_FAIL_BODY 1 +#define PDKIM_VERIFY_FAIL_MESSAGE 2 #define PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE 3 #define PDKIM_VERIFY_INVALID_BUFFER_SIZE 4 #define PDKIM_VERIFY_INVALID_PUBKEY_PARSING 5 - -#ifdef PDKIM_DEBUG -void pdkim_quoteprint(FILE *, char *, int, int); -#endif - -typedef struct pdkim_stringlist { - char *value; - void *next; -} pdkim_stringlist; -pdkim_stringlist *pdkim_append_stringlist(pdkim_stringlist *, char *); - - -#define PDKIM_STR_ALLOC_FRAG 256 -typedef struct pdkim_str { - char *str; - unsigned int len; - unsigned int allocated; -} pdkim_str; -pdkim_str *pdkim_strnew (char *); -char *pdkim_strcat (pdkim_str *, char *); -char *pdkim_strncat(pdkim_str *, char *, int); -void pdkim_strfree(pdkim_str *); - +/* -------------------------------------------------------------------------- */ +/* Some parameter values */ #define PDKIM_QUERYMETHOD_DNS_TXT 0 #define PDKIM_ALGO_RSA_SHA256 0 @@ -84,6 +44,14 @@ void pdkim_strfree(pdkim_str *); #define PDKIM_KEYTYPE_RSA 0 +/* -------------------------------------------------------------------------- */ +/* Some required forward declarations, please ignore */ +typedef struct pdkim_stringlist pdkim_stringlist; +typedef struct pdkim_str pdkim_str; +typedef struct sha1_context sha1_context; +typedef struct sha2_context sha2_context; +#define HAVE_SHA1_CONTEXT +#define HAVE_SHA2_CONTEXT /* -------------------------------------------------------------------------- */ /* Public key as (usually) fetched from DNS */ @@ -180,7 +148,6 @@ typedef struct pdkim_signature { */ int verify_status; - /* Extended verification status. Depending on the value of verify_status, it can contain: @@ -201,22 +168,30 @@ typedef struct pdkim_signature { For verify_status == PDKIM_VERIFY_FAIL: PDKIM_VERIFY_FAIL_BODY - PDKIM_VERIFY_FAIL_MESSAGE - + The calculated body hash does not match the advertised body hash + from the bh= tag of the signature. + PDKIM_VERIFY_FAIL_MESSAGE + RSA verification of the signature (b= tag) failed. */ int verify_ext_status; + /* Pointer to a public key record that was used to verify the signature. + See pdkim_pubkey declaration above for more information. + Caution: can be NULL if no record was retrieved. */ + pdkim_pubkey *pubkey; + /* Pointer to the next pdkim_signature signature. NULL if this is the + last signature. */ + void *next; - pdkim_pubkey *pubkey; /* Public key used to verify this signature. */ - void *next; /* Pointer to next signature in list. */ + /* Properties below this point are used internally only ------------- */ /* Per-signature helper variables ----------------------------------- */ - sha1_context sha1_body; - sha2_context sha2_body; - unsigned long signed_body_bytes; - pdkim_stringlist *headers; + sha1_context *sha1_body; /* SHA1 block */ + sha2_context *sha2_body; /* SHA256 block */ + unsigned long signed_body_bytes; /* How many body bytes we hashed */ + pdkim_stringlist *headers; /* Raw headers included in the sig */ /* Signing specific ------------------------------------------------- */ char *rsa_privkey; /* Private RSA key */ char *sign_headers; /* To-be-signed header names */ @@ -228,12 +203,10 @@ typedef struct pdkim_signature { /* -------------------------------------------------------------------------- */ /* Context to keep state between all operations */ - #define PDKIM_MODE_SIGN 0 #define PDKIM_MODE_VERIFY 1 #define PDKIM_INPUT_NORMAL 0 #define PDKIM_INPUT_SMTP 1 - typedef struct pdkim_ctx { /* PDKIM_MODE_VERIFY or PDKIM_MODE_SIGN */ @@ -250,7 +223,7 @@ typedef struct pdkim_ctx { /* Coder's little helpers */ pdkim_str *cur_header; - char linebuf[PDKIM_MAX_BODY_LINE_LEN]; + char *linebuf; int linebuf_offset; int seen_lf; int seen_eod; @@ -267,25 +240,14 @@ typedef struct pdkim_ctx { } pdkim_ctx; -int header_name_match (char *, char *, int); -char *pdkim_relax_header (char *, int); - -int pdkim_update_bodyhash (pdkim_ctx *, char *, int); -int pdkim_finish_bodyhash (pdkim_ctx *); - -int pdkim_bodyline_complete (pdkim_ctx *); -int pdkim_header_complete (pdkim_ctx *); - -int pdkim_feed (pdkim_ctx *, char *, int); -int pdkim_feed_finish (pdkim_ctx *, char **); - -char *pdkim_create_header (pdkim_signature *, int); +/* -------------------------------------------------------------------------- */ +/* API functions. Please see pdkim-api.txt for documentation / example code. */ pdkim_ctx *pdkim_init_sign (int, char *, char *, char *); pdkim_ctx - *pdkim_init_verify (int, int(*dns_txt_callback)(char *, char *)); + *pdkim_init_verify (int, int(*)(char *, char *)); int pdkim_set_optional (pdkim_ctx *, char *, char *, @@ -294,10 +256,10 @@ int pdkim_set_optional (pdkim_ctx *, unsigned long, unsigned long); -void pdkim_free_pubkey (pdkim_pubkey *); -void pdkim_free_sig (pdkim_signature *); -void pdkim_free_ctx (pdkim_ctx *); +int pdkim_feed (pdkim_ctx *, char *, int); +int pdkim_feed_finish (pdkim_ctx *, char **); +void pdkim_free_ctx (pdkim_ctx *); #ifdef PDKIM_DEBUG void pdkim_set_debug_stream (pdkim_ctx *, FILE *); diff --git a/src/src/pdkim/sha1.h b/src/src/pdkim/sha1.h index 620fc3dc2..748093cee 100644 --- a/src/src/pdkim/sha1.h +++ b/src/src/pdkim/sha1.h @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/pdkim/sha1.h,v 1.1.2.2 2009/02/24 18:43:59 tom Exp $ */ +/* $Cambridge: exim/src/src/pdkim/sha1.h,v 1.1.2.3 2009/03/17 14:56:55 tom Exp $ */ /** * \file sha1.h * @@ -26,7 +26,12 @@ /** * \brief SHA-1 context structure */ -typedef struct +#ifndef HAVE_SHA1_CONTEXT +#define HAVE_SHA1_CONTEXT +typedef struct sha1_context sha1_context; +#endif + +struct sha1_context { unsigned long total[2]; /*!< number of bytes processed */ unsigned long state[5]; /*!< intermediate digest state */ @@ -34,8 +39,7 @@ typedef struct unsigned char ipad[64]; /*!< HMAC: inner padding */ unsigned char opad[64]; /*!< HMAC: outer padding */ -} -sha1_context; +}; #ifdef __cplusplus extern "C" { diff --git a/src/src/pdkim/sha2.h b/src/src/pdkim/sha2.h index 06676d5a0..0be2d271f 100644 --- a/src/src/pdkim/sha2.h +++ b/src/src/pdkim/sha2.h @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/pdkim/sha2.h,v 1.1.2.1 2009/02/24 13:13:47 tom Exp $ */ +/* $Cambridge: exim/src/src/pdkim/sha2.h,v 1.1.2.2 2009/03/17 14:56:55 tom Exp $ */ /** * \file sha2.h * @@ -26,7 +26,12 @@ /** * \brief SHA-256 context structure */ -typedef struct +#ifndef HAVE_SHA2_CONTEXT +#define HAVE_SHA2_CONTEXT +typedef struct sha2_context sha2_context; +#endif + +struct sha2_context { unsigned long total[2]; /*!< number of bytes processed */ unsigned long state[8]; /*!< intermediate digest state */ @@ -35,8 +40,7 @@ typedef struct unsigned char ipad[64]; /*!< HMAC: inner padding */ unsigned char opad[64]; /*!< HMAC: outer padding */ int is224; /*!< 0 => SHA-256, else SHA-224 */ -} -sha2_context; +}; #ifdef __cplusplus extern "C" {