-/* $Cambridge: exim/src/src/pdkim/pdkim.h,v 1.1.2.3 2009/02/26 16:07:36 tom Exp $ */
-/* pdkim.h */
+/* $Cambridge: exim/src/src/pdkim/pdkim.h,v 1.1.2.6 2009/03/17 14:56:55 tom Exp $ */
+/* pdkim-api.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 */
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=) Decoded raw signature data, along with its length in bytes */
+ char *sigdata;
+ int sigdata_len;
+
+ /* (bh=) Decoded raw body hash data, along with its length in bytes */
+ char *bodyhash;
+ int bodyhash_len;
+
+ /* The main verification status. One of:
+
+ 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.
- /* Per-signature helper variables -------------- */
- sha1_context sha1_body;
- sha2_context sha2_body;
- unsigned long signed_body_bytes;
- pdkim_stringlist *headers;
+ PDKIM_VERIFY_FAIL Verification failed because either the body
+ hash did not match, or the signature verification
+ failed. This probably means the message was
+ modified. Check verify_ext_status for the
+ exact reason.
+
+ PDKIM_VERIFY_PASS Verification succeeded.
+ */
+ int verify_status;
+
+ /* Extended verification status. 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: 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;
+
+ /* 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 */
-
#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 */
/* 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
} 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 *, char **);
+void pdkim_free_ctx (pdkim_ctx *);
#ifdef PDKIM_DEBUG
void pdkim_set_debug_stream (pdkim_ctx *, FILE *);