#!/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.
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
-/* $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 *
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,
-/* $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 <stdlib.h>
#include <strings.h>
#include <ctype.h>
#include <unistd.h>
+
#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 */
/* -------------------------------------------------------------------------- */
-/* Various debugging functions */
+/* Print debugging functions */
#ifdef PDKIM_DEBUG
void pdkim_quoteprint(FILE *stream, char *data, int len, int lf) {
int i;
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 */
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);
};
+
+/* -------------------------------------------------------------------------- */
+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
}
#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;
}
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)
/* 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) {
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;
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;
}
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;
};
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);
- }
-};
-/* $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
#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
#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 */
*/
int verify_status;
-
/* Extended verification status. Depending on the value of verify_status,
it can contain:
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 */
/* -------------------------------------------------------------------------- */
/* 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 */
/* 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;
} 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 *,
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 *);
-/* $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
*
/**
* \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 */
unsigned char ipad[64]; /*!< HMAC: inner padding */
unsigned char opad[64]; /*!< HMAC: outer padding */
-}
-sha1_context;
+};
#ifdef __cplusplus
extern "C" {
-/* $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
*
/**
* \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 */
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" {