X-Git-Url: https://git.exim.org/users/jgh/exim.git/blobdiff_plain/05ee2d2a64657850445805d4587258ddaa76fe53..a6885fb494fd12134b6dd434de1ceddbf1815be9:/src/src/pdkim/pdkim.h diff --git a/src/src/pdkim/pdkim.h b/src/src/pdkim/pdkim.h index 57b6c6a66..3f7a2dfb4 100644 --- a/src/src/pdkim/pdkim.h +++ b/src/src/pdkim/pdkim.h @@ -1,67 +1,57 @@ -/* $Cambridge: exim/src/src/pdkim/pdkim.h,v 1.1.2.3 2009/02/26 16:07:36 tom Exp $ */ +/* $Cambridge: exim/src/src/pdkim/pdkim.h,v 1.1.2.8 2009/03/17 21:11:56 tom Exp $ */ /* pdkim.h */ -#include "sha1.h" -#include "sha2.h" -#include "rsa.h" -#include "base64.h" - -#define PDKIM_SIGNATURE_VERSION "1" -#define PDKIM_MAX_BODY_LINE_LEN 1024 +/* -------------------------------------------------------------------------- */ +/* Debugging. This can also be enabled/disabled at run-time. I recommend to + leave it defined. */ #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" - - -/* Success / Error codes */ -#define PDKIM_OK 0 -#define PDKIM_FAIL 1 -#define PDKIM_ERR_OOM 100 -#define PDKIM_ERR_RSA_PRIVKEY 101 -#define PDKIM_ERR_RSA_SIGNING 102 -#define PDKIM_ERR_LONG_LINE 103 - - -#ifdef PDKIM_DEBUG -void pdkim_quoteprint(FILE *, char *, int, int); -#endif +/* -------------------------------------------------------------------------- */ +/* Function success / error codes */ +#define PDKIM_OK 0 +#define PDKIM_FAIL -1 +#define PDKIM_ERR_OOM -100 +#define PDKIM_ERR_RSA_PRIVKEY -101 +#define PDKIM_ERR_RSA_SIGNING -102 +#define PDKIM_ERR_LONG_LINE -103 +#define PDKIM_ERR_BUFFER_TOO_SMALL -104 -typedef struct pdkim_stringlist { - char *value; - void *next; -} pdkim_stringlist; -pdkim_stringlist *pdkim_append_stringlist(pdkim_stringlist *, char *); +/* -------------------------------------------------------------------------- */ +/* Main/Extended verification status */ +#define PDKIM_VERIFY_NONE 0 +#define PDKIM_VERIFY_INVALID 1 +#define PDKIM_VERIFY_FAIL 2 +#define PDKIM_VERIFY_PASS 3 + +#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 +/* -------------------------------------------------------------------------- */ +/* Some parameter values */ +#define PDKIM_QUERYMETHOD_DNS_TXT 0 -#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 *); +#define PDKIM_ALGO_RSA_SHA256 0 +#define PDKIM_ALGO_RSA_SHA1 1 -#define PDKIM_QUERYMETHOD_DNS_TXT 0 -/* extern char *pdkim_querymethods[]; */ +#define PDKIM_CANON_SIMPLE 0 +#define PDKIM_CANON_RELAXED 1 -#define PDKIM_ALGO_RSA_SHA256 0 -#define PDKIM_ALGO_RSA_SHA1 1 -/* extern char *pdkim_algos[]; */ +#define PDKIM_HASH_SHA256 0 +#define PDKIM_HASH_SHA1 1 -#define PDKIM_CANON_SIMPLE 0 -#define PDKIM_CANON_RELAXED 1 -/* extern char *pdkim_canons[]; */ +#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 */ @@ -69,71 +59,159 @@ typedef struct pdkim_pubkey { char *version; /* v= */ char *granularity; /* g= */ - int num_hash_algos; - int **hash_algos; /* h= */ - - int keytype; /* k= */ - int srvtype; /* s= */ - + char *hashes; /* h= */ + char *keytype; /* k= */ + char *srvtype; /* s= */ char *notes; /* n= */ + char *key; /* p= */ + int key_len; - int testing; /* t=y */ - int no_subdomaining; /* t=s */ + int testing; /* t=y */ + int no_subdomaining; /* t=s */ } pdkim_pubkey; /* -------------------------------------------------------------------------- */ /* Signature as it appears in a DKIM-Signature header */ typedef struct pdkim_signature { - /* Bits stored in a DKIM signature header ------ */ - int version; /* v= */ - int algo; /* a= */ - int canon_headers; /* c=x/ */ - int canon_body; /* c=/x */ - int querymethod; /* q= */ + /* Bits stored in a DKIM signature header --------------------------- */ - char *sigdata; /* b= */ - char *bodyhash; /* bh= */ + /* (v=) The version, as an integer. Currently, always "1" */ + int version; - char *selector; /* s= */ - char *domain; /* d= */ - char *identity; /* i= */ + /* (a=) The signature algorithm. Either PDKIM_ALGO_RSA_SHA256 + or PDKIM_ALGO_RSA_SHA1 */ + int algo; - unsigned long created; /* t= */ - unsigned long expires; /* x= */ - unsigned long bodylength; /* l= */ + /* (c=x/) Header canonicalization method. Either PDKIM_CANON_SIMPLE + or PDKIM_CANON_RELAXED */ + int canon_headers; - char *headernames; /* h= */ - char *copiedheaders; /* z= */ + /* (c=/x) Body canonicalization method. Either PDKIM_CANON_SIMPLE + or PDKIM_CANON_RELAXED */ + int canon_body; + /* (q=) Query Method. Currently, only PDKIM_QUERYMETHOD_DNS_TXT + is specified */ + int querymethod; - /* Signing specific ---------------------------- */ - char *rsa_privkey; /* Private RSA key */ - char *sign_headers; /* To-be-signed header names */ + /* (s=) The selector string as given in the signature */ + char *selector; - /* Verification specific ----------------------- */ - pdkim_pubkey pubkey; /* Public key used to verify this signature. */ - int verify_result; /* Verification result */ - char *rawsig_no_b_val; /* Original signature header w/o b= tag value. */ - void *next; /* Pointer to next signature in list. */ + /* (d=) The domain as given in the signature */ + char *domain; + + /* (i=) The identity as given in the signature */ + char *identity; + + /* (t=) Timestamp of signature creation */ + unsigned long created; + + /* (x=) Timestamp of expiry of signature */ + unsigned long expires; + + /* (l=) Amount of hashed body bytes (after canonicalization) */ + unsigned long bodylength; + + /* (h=) Colon-separated list of header names that are included in the + signature */ + char *headernames; + + /* (z=) */ + char *copiedheaders; + + /* (b=) Raw signature data, along with its length in bytes */ + char *sigdata; + int sigdata_len; + + /* (bh=) Raw body hash data, along with its length in bytes */ + char *bodyhash; + int bodyhash_len; + + /* Folded DKIM-Signature: header. Singing only, NULL for verifying. + Ready for insertion into the message. Note: Folded using CRLFTB, + but final line terminator is NOT included. Note2: This buffer is + free()d when you call pdkim_free_ctx(). */ + char *signature_header; + + /* The main verification status. Verification only. One of: - /* Per-signature helper variables -------------- */ - sha1_context sha1_body; - sha2_context sha2_body; - unsigned long signed_body_bytes; - pdkim_stringlist *headers; + PDKIM_VERIFY_NONE Verification was not attempted. This status + should not appear. + + PDKIM_VERIFY_INVALID There was an error while trying to verify + the signature. A more precise description + is available in verify_ext_status. + + PDKIM_VERIFY_FAIL Verification failed because either the body + hash did not match, or the signature verification + failed. This means the message was modified. + Check verify_ext_status for the exact reason. + + PDKIM_VERIFY_PASS Verification succeeded. + */ + int verify_status; + + /* Extended verification status. Verification only. Depending on the value + of verify_status, it can contain: + + For verify_status == PDKIM_VERIFY_INVALID: + + PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE + Unable to retrieve a public key container. + + PDKIM_VERIFY_INVALID_BUFFER_SIZE + Either the DNS name constructed to retrieve the public key record + does not fit into PDKIM_DNS_TXT_MAX_NAMELEN bytes, or the retrieved + record is longer than PDKIM_DNS_TXT_MAX_RECLEN bytes. + + PDKIM_VERIFY_INVALID_PUBKEY_PARSING + (Syntax) error while parsing the retrieved public key record. + + + For verify_status == PDKIM_VERIFY_FAIL: + + PDKIM_VERIFY_FAIL_BODY + 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: is NULL if signing or if no record was retrieved. */ + pdkim_pubkey *pubkey; + + /* Pointer to the next pdkim_signature signature. NULL if signing or if + this is the last signature. */ + void *next; + + /* Properties below this point are used internally only ------------- */ + + /* Per-signature helper variables ----------------------------------- */ + 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 */ + /* Verification specific -------------------------------------------- */ + int headernames_pos; /* Current position in header name list */ + char *rawsig_no_b_val; /* Original signature header w/o b= tag value. */ } pdkim_signature; /* -------------------------------------------------------------------------- */ -/* Context to keep state between all operations */ - +/* 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 */ @@ -145,14 +223,18 @@ typedef struct pdkim_ctx { /* One (signing) or several chained (verification) signatures */ pdkim_signature *sig; + /* Callback for dns/txt query method (verification only) */ + int(*dns_txt_callback)(char *, char *); + /* 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; int past_headers; int num_buffered_crlf; + int num_headers; #ifdef PDKIM_DEBUG /* A FILE pointer. When not NULL, debug output will be generated @@ -163,38 +245,26 @@ typedef struct pdkim_ctx { } pdkim_ctx; -int header_name_match (char *, char *); -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 **); - -pdkim_str - *pdkim_create_header (pdkim_signature *, int); +/* -------------------------------------------------------------------------- */ +/* API functions. Please see pdkim-api.txt for documentation / example code. */ pdkim_ctx - *pdkim_init_sign (char *, char *, char *); + *pdkim_init_sign (int, char *, char *, char *); pdkim_ctx - *pdkim_init_verify (void); + *pdkim_init_verify (int, int(*)(char *, char *)); int pdkim_set_optional (pdkim_ctx *, - int, char *, char *, int, int, unsigned long, int, unsigned long, unsigned long); -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 *, pdkim_signature **); +void pdkim_free_ctx (pdkim_ctx *); #ifdef PDKIM_DEBUG void pdkim_set_debug_stream (pdkim_ctx *, FILE *);