more pdkim wip
[users/jgh/exim.git] / src / src / pdkim / pdkim.h
index 57b6c6a66617b8410193654e139e0aa8cae1653c..3f7a2dfb495a6045fc2eaf7e62b4eb0f05b1c91b 100644 (file)
@@ -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 *);