summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xsrc/scripts/MakeLinks2
-rw-r--r--src/src/dkim.c5
-rw-r--r--src/src/hash.c4
-rw-r--r--src/src/pdkim/Makefile4
-rw-r--r--src/src/pdkim/pdkim.c33
-rw-r--r--src/src/pdkim/signing.c (renamed from src/src/pdkim/rsa.c)82
-rw-r--r--src/src/pdkim/signing.h (renamed from src/src/pdkim/rsa.h)12
7 files changed, 98 insertions, 44 deletions
diff --git a/src/scripts/MakeLinks b/src/scripts/MakeLinks
index 44e3a4ebc..22e5a4bd7 100755
--- a/src/scripts/MakeLinks
+++ b/src/scripts/MakeLinks
@@ -85,7 +85,7 @@ cd ..
mkdir pdkim
cd pdkim
for f in README Makefile crypt_ver.h pdkim.c \
- pdkim.h hash.c hash.h rsa.c rsa.h blob.h
+ pdkim.h hash.c hash.h signing.c signing.h blob.h
do
ln -s ../../src/pdkim/$f $f
done
diff --git a/src/src/dkim.c b/src/src/dkim.c
index 2857e6398..f7b9ee0d1 100644
--- a/src/src/dkim.c
+++ b/src/src/dkim.c
@@ -608,6 +608,11 @@ while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep, NULL, 0)))
dkim_private_key_expanded = big_buffer;
}
+/*XXX so we currently nail signing to RSA + SHA256. Need to extract algo
+from privkey, and provide means for selecting hash-method.
+Check for disallowed combos.
+Will need new dkim_ transport option for hash. */
+
if (!(ctx = pdkim_init_sign(CS dkim_signing_domain,
CS dkim_signing_selector,
CS dkim_private_key_expanded,
diff --git a/src/src/hash.c b/src/src/hash.c
index f49add29c..e239516e1 100644
--- a/src/src/hash.c
+++ b/src/src/hash.c
@@ -33,6 +33,7 @@ sha1;
BOOL
exim_sha_init(hctx * h, hashmethod m)
{
+/*XXX extend for sha512 */
switch (h->method = m)
{
case HASH_SHA1: h->hashlen = 20; SHA1_Init (&h->u.sha1); break;
@@ -77,6 +78,7 @@ switch (h->method)
BOOL
exim_sha_init(hctx * h, hashmethod m)
{
+/*XXX extend for sha512 */
switch (h->method = m)
{
case HASH_SHA1: h->hashlen = 20; gnutls_hash_init(&h->sha, GNUTLS_DIG_SHA1); break;
@@ -112,6 +114,7 @@ gnutls_hash_output(h->sha, b->data);
BOOL
exim_sha_init(hctx * h, hashmethod m)
{
+/*XXX extend for sha512 */
switch (h->method = m)
{
case HASH_SHA1: h->hashlen = 20; gcry_md_open(&h->sha, GCRY_MD_SHA1, 0); break;
@@ -145,6 +148,7 @@ memcpy(b->data, gcry_md_read(h->sha, 0), h->hashlen);
BOOL
exim_sha_init(hctx * h, hashmethod m)
{
+/*XXX extend for sha512 */
switch (h->method = m)
{
case HASH_SHA1: h->hashlen = 20; sha1_starts(&h->u.sha1); break;
diff --git a/src/src/pdkim/Makefile b/src/src/pdkim/Makefile
index c298568ea..10631ceaa 100644
--- a/src/src/pdkim/Makefile
+++ b/src/src/pdkim/Makefile
@@ -1,6 +1,6 @@
# Make file for building the pdkim library.
-OBJ = pdkim.o rsa.o
+OBJ = pdkim.o signing.o
pdkim.a: $(OBJ)
@$(RM_COMMAND) -f pdkim.a
@@ -13,6 +13,6 @@ pdkim.a: $(OBJ)
$(FE)$(CC) -c $(CFLAGS) $(INCLUDE) -I. $*.c
pdkim.o: $(HDRS) crypt_ver.h pdkim.h pdkim.c
-rsa.o: $(HDRS) crypt_ver.h rsa.h rsa.c
+signing.o: $(HDRS) crypt_ver.h signing.h signing.c
# End
diff --git a/src/src/pdkim/pdkim.c b/src/src/pdkim/pdkim.c
index 2ce0ff6c9..441f96cb5 100644
--- a/src/src/pdkim/pdkim.c
+++ b/src/src/pdkim/pdkim.c
@@ -42,7 +42,7 @@
#endif
#include "pdkim.h"
-#include "rsa.h"
+#include "signing.h"
#define PDKIM_SIGNATURE_VERSION "1"
#define PDKIM_PUB_RECORD_VERSION US "DKIM1"
@@ -83,11 +83,13 @@ const uschar * pdkim_canons[] = {
US"relaxed",
NULL
};
+/*XXX currently unused */
const uschar * pdkim_hashes[] = {
US"sha256",
US"sha1",
NULL
};
+/*XXX currently unused */
const uschar * pdkim_keytypes[] = {
US"rsa",
NULL
@@ -505,6 +507,7 @@ for (p = raw_hdr; ; p++)
Ustrcmp(cur_val, PDKIM_SIGNATURE_VERSION) == 0 ? 1 : -1;
break;
case 'a':
+/*XXX this searches a list of combined (algo + hash-method)s */
for (i = 0; pdkim_algos[i]; i++)
if (Ustrcmp(cur_val, pdkim_algos[i]) == 0)
{
@@ -583,6 +586,7 @@ DEBUG(D_acl)
"PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
}
+/*XXX hash method: extend for sha512 */
if (!exim_sha_init(&sig->body_hash_ctx,
sig->algo == PDKIM_ALGO_RSA_SHA1 ? HASH_SHA1 : HASH_SHA256))
{
@@ -1185,6 +1189,7 @@ col = hdr_len;
/* Required and static bits */
hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"a=",
+/*XXX this is a combo of algo and hash-method */
pdkim_algos[sig->algo]);
hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"q=",
pdkim_querymethods[sig->querymethod]);
@@ -1332,7 +1337,7 @@ DEBUG(D_acl) debug_printf(
"PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
/* Import public key */
-if ((*errstr = exim_rsa_verify_init(&p->key, vctx)))
+if ((*errstr = exim_dkim_verify_init(&p->key, vctx)))
{
DEBUG(D_acl) debug_printf("verify_init: %s\n", *errstr);
sig->verify_status = PDKIM_VERIFY_INVALID;
@@ -1370,6 +1375,7 @@ pdkim_finish_bodyhash(ctx);
while (sig)
{
+/*XXX bool probably not enough */
BOOL is_sha1 = sig->algo == PDKIM_ALGO_RSA_SHA1;
hctx hhash_ctx;
uschar * sig_hdr = US"";
@@ -1422,7 +1428,7 @@ while (sig)
exim_sha_update(&hhash_ctx, CUS rh, Ustrlen(rh));
/* Remember headers block for signing (when the library cannot do incremental) */
- (void) exim_rsa_data_append(&hdata, &hdata_alloc, rh);
+ (void) exim_dkim_data_append(&hdata, &hdata_alloc, rh);
DEBUG(D_acl) pdkim_quoteprint(rh, Ustrlen(rh));
}
@@ -1522,8 +1528,9 @@ while (sig)
}
/* Remember headers block for signing (when the library cannot do incremental) */
+/*XXX is this assuing algo == RSA? */
if (ctx->flags & PDKIM_MODE_SIGN)
- (void) exim_rsa_data_append(&hdata, &hdata_alloc, US sig_hdr);
+ (void) exim_dkim_data_append(&hdata, &hdata_alloc, US sig_hdr);
/* SIGNING ---------------------------------------------------------------- */
if (ctx->flags & PDKIM_MODE_SIGN)
@@ -1531,7 +1538,8 @@ while (sig)
es_ctx sctx;
/* Import private key */
- if ((*err = exim_rsa_signing_init(US sig->rsa_privkey, &sctx)))
+/*XXX extend for non-RSA algos */
+ if ((*err = exim_dkim_signing_init(US sig->rsa_privkey, &sctx)))
{
DEBUG(D_acl) debug_printf("signing_init: %s\n", *err);
return PDKIM_ERR_RSA_PRIVKEY;
@@ -1545,7 +1553,11 @@ while (sig)
hdata = hhash;
#endif
- if ((*err = exim_rsa_sign(&sctx, is_sha1, &hdata, &sig->sighash)))
+/*XXX extend for non-RSA algos */
+/*XXX oddly the dkim rfc does _not_ say what variant (sha1 or sha256) of
+RSA signing should be done. We use the same variant as the hash-method. */
+
+ if ((*err = exim_dkim_sign(&sctx, is_sha1, &hdata, &sig->sighash)))
{
DEBUG(D_acl) debug_printf("signing: %s\n", *err);
return PDKIM_ERR_RSA_SIGNING;
@@ -1619,7 +1631,8 @@ while (sig)
}
/* Check the signature */
- if ((*err = exim_rsa_verify(&vctx, is_sha1, &hhash, &sig->sighash)))
+/*XXX needs extension for non-RSA */
+ if ((*err = exim_dkim_verify(&vctx, is_sha1, &hhash, &sig->sighash)))
{
DEBUG(D_acl) debug_printf("headers verify: %s\n", *err);
sig->verify_status = PDKIM_VERIFY_FAIL;
@@ -1677,6 +1690,9 @@ return ctx;
/* -------------------------------------------------------------------------- */
+/*XXX ? needs extension to cover non-RSA algo? Currently the "algo" is actually
+the combo of algo and hash-method */
+
DLLEXPORT pdkim_ctx *
pdkim_init_sign(char * domain, char * selector, char * rsa_privkey, int algo,
BOOL dot_stuffed, int(*dns_txt_callback)(char *, char *),
@@ -1707,6 +1723,7 @@ sig->selector = string_copy(US selector);
sig->rsa_privkey = string_copy(US rsa_privkey);
sig->algo = algo;
+/*XXX extend for sha512 */
if (!exim_sha_init(&sig->body_hash_ctx,
algo == PDKIM_ALGO_RSA_SHA1 ? HASH_SHA1 : HASH_SHA256))
{
@@ -1761,7 +1778,7 @@ return PDKIM_OK;
void
pdkim_init(void)
{
-exim_rsa_init();
+exim_dkim_init();
}
diff --git a/src/src/pdkim/rsa.c b/src/src/pdkim/signing.c
index 950c617c7..bcd64fdc4 100644
--- a/src/src/pdkim/rsa.c
+++ b/src/src/pdkim/signing.c
@@ -4,6 +4,10 @@
* Copyright (C) 2016 Exim maintainers
*
* RSA signing/verification interface
+XXX rename interfaces to cover all signature methods.
+the method (algo) needs to be extracted from the supplied private-key
+and not only stashed as needed in the sign- or verify- context, but
+indicated to caller for protocol tag construction.
*/
#include "../exim.h"
@@ -15,21 +19,21 @@
#endif
#include "crypt_ver.h"
-#include "rsa.h"
+#include "signing.h"
/******************************************************************************/
#ifdef RSA_GNUTLS
void
-exim_rsa_init(void)
+exim_dkim_init(void)
{
}
/* accumulate data (gnutls-only). String to be appended must be nul-terminated. */
blob *
-exim_rsa_data_append(blob * b, int * alloc, uschar * s)
+exim_dkim_data_append(blob * b, int * alloc, uschar * s)
{
int len = b->len;
b->data = string_append(b->data, alloc, &len, 1, s);
@@ -43,7 +47,7 @@ return b;
Return: NULL for success, or an error string */
const uschar *
-exim_rsa_signing_init(uschar * privkey_pem, es_ctx * sign_ctx)
+exim_dkim_signing_init(uschar * privkey_pem, es_ctx * sign_ctx)
{
gnutls_datum_t k;
int rc;
@@ -52,13 +56,7 @@ k.data = privkey_pem;
k.size = strlen(privkey_pem);
if ( (rc = gnutls_x509_privkey_init(&sign_ctx->rsa)) != GNUTLS_E_SUCCESS
- /*|| (rc = gnutls_x509_privkey_import(sign_ctx->rsa, &k,
- GNUTLS_X509_FMT_PEM)) != GNUTLS_E_SUCCESS */
- )
- return gnutls_strerror(rc);
-
-if ( /* (rc = gnutls_x509_privkey_init(&sign_ctx->rsa)) != GNUTLS_E_SUCCESS
- ||*/ (rc = gnutls_x509_privkey_import(sign_ctx->rsa, &k,
+ || (rc = gnutls_x509_privkey_import(sign_ctx->rsa, &k,
GNUTLS_X509_FMT_PEM)) != GNUTLS_E_SUCCESS
)
return gnutls_strerror(rc);
@@ -76,7 +74,7 @@ sign hash.
Return: NULL for success, or an error string */
const uschar *
-exim_rsa_sign(es_ctx * sign_ctx, BOOL is_sha1, blob * data, blob * sig)
+exim_dkim_sign(es_ctx * sign_ctx, BOOL is_sha1, blob * data, blob * sig)
{
gnutls_datum_t k;
size_t sigsize = 0;
@@ -94,6 +92,8 @@ sig->data = store_get(sigsize);
sig->len = sigsize;
/* Do signing */
+/*XXX will need extension for hash type; looks ok for non-RSA algos
+so long as the privkey_import stage got them. */
if ((rc = gnutls_x509_privkey_sign_data(sign_ctx->rsa,
is_sha1 ? GNUTLS_DIG_SHA1 : GNUTLS_DIG_SHA256,
0, &k, sig->data, &sigsize)) != GNUTLS_E_SUCCESS
@@ -110,7 +110,7 @@ return ret;
Return: NULL for success, or an error string */
const uschar *
-exim_rsa_verify_init(blob * pubkey_der, ev_ctx * verify_ctx)
+exim_dkim_verify_init(blob * pubkey_der, ev_ctx * verify_ctx)
{
gnutls_datum_t k;
int rc;
@@ -132,7 +132,7 @@ return ret;
Return: NULL for success, or an error string */
const uschar *
-exim_rsa_verify(ev_ctx * verify_ctx, BOOL is_sha1, blob * data_hash, blob * sig)
+exim_dkim_verify(ev_ctx * verify_ctx, BOOL is_sha1, blob * data_hash, blob * sig)
{
gnutls_datum_t k, s;
int rc;
@@ -143,6 +143,7 @@ k.size = data_hash->len;
s.data = sig->data;
s.size = sig->len;
if ((rc = gnutls_pubkey_verify_hash2(verify_ctx->rsa,
+/*XXX needs extension for SHA512 */
is_sha1 ? GNUTLS_SIGN_RSA_SHA1 : GNUTLS_SIGN_RSA_SHA256,
0, &k, &s)) < 0)
ret = gnutls_strerror(rc);
@@ -217,7 +218,7 @@ return NULL;
void
-exim_rsa_init(void)
+exim_dkim_init(void)
{
/* Version check should be the very first call because it
makes sure that important subsystems are initialized. */
@@ -259,7 +260,7 @@ return;
String to be appended must be nul-terminated. */
blob *
-exim_rsa_data_append(blob * b, int * alloc, uschar * s)
+exim_dkim_data_append(blob * b, int * alloc, uschar * s)
{
return b; /*dummy*/
}
@@ -270,13 +271,16 @@ return b; /*dummy*/
Return: NULL for success, or an error string */
const uschar *
-exim_rsa_signing_init(uschar * privkey_pem, es_ctx * sign_ctx)
+exim_dkim_signing_init(uschar * privkey_pem, es_ctx * sign_ctx)
{
uschar * s1, * s2;
blob der;
long alen;
int rc;
+/*XXX will need extension to _spot_ as well as handle a
+non-RSA key? I think... */
+
/*
* RSAPrivateKey ::= SEQUENCE
* version Version,
@@ -360,13 +364,20 @@ sign hash.
Return: NULL for success, or an error string */
const uschar *
-exim_rsa_sign(es_ctx * sign_ctx, BOOL is_sha1, blob * data, blob * sig)
+exim_dkim_sign(es_ctx * sign_ctx, BOOL is_sha1, blob * data, blob * sig)
{
gcry_sexp_t s_hash = NULL, s_key = NULL, s_sig = NULL;
gcry_mpi_t m_sig;
uschar * errstr;
gcry_error_t gerr;
+/*XXX will need extension for hash types (though, possibly, should
+be re-specced to not rehash but take an already-hashed value? Actually
+current impl looks WRONG - it _is_ given a has so should not be
+re-hashing. Has this been tested?
+
+Will need extension for non-RSA sugning algos. */
+
#define SIGSPACE 128
sig->data = store_get(SIGSPACE);
@@ -421,7 +432,7 @@ return NULL;
Return: NULL for success, or an error string */
const uschar *
-exim_rsa_verify_init(blob * pubkey_der, ev_ctx * verify_ctx)
+exim_dkim_verify_init(blob * pubkey_der, ev_ctx * verify_ctx)
{
/*
in code sequence per b81207d2bfa92 rsa_parse_public_key() and asn1_get_mpi()
@@ -501,7 +512,7 @@ DEBUG(D_acl) return string_sprintf("%s: %s", stage, asn1_strerror(rc));
Return: NULL for success, or an error string */
const uschar *
-exim_rsa_verify(ev_ctx * verify_ctx, BOOL is_sha1, blob * data_hash, blob * sig)
+exim_dkim_verify(ev_ctx * verify_ctx, BOOL is_sha1, blob * data_hash, blob * sig)
{
/*
cf. libgnutls 2.8.5 _wrap_gcry_pk_verify()
@@ -516,6 +527,7 @@ if ( (stage = US"pkey sexp build",
verify_ctx->n, verify_ctx->e))
|| (stage = US"data sexp build",
gerr = gcry_sexp_build (&s_hash, NULL,
+/*XXX needs extension for SHA512 */
is_sha1
? "(data(flags pkcs1)(hash sha1 %b))"
: "(data(flags pkcs1)(hash sha256 %b))",
@@ -549,14 +561,14 @@ return NULL;
/******************************************************************************/
void
-exim_rsa_init(void)
+exim_dkim_init(void)
{
}
/* accumulate data (gnutls-only) */
blob *
-exim_rsa_data_append(blob * b, int * alloc, uschar * s)
+exim_dkim_data_append(blob * b, int * alloc, uschar * s)
{
return b; /*dummy*/
}
@@ -566,11 +578,14 @@ return b; /*dummy*/
Return: NULL for success, or an error string */
const uschar *
-exim_rsa_signing_init(uschar * privkey_pem, es_ctx * sign_ctx)
+exim_dkim_signing_init(uschar * privkey_pem, es_ctx * sign_ctx)
{
uschar * p, * q;
int len;
+/*XXX maybe use PEM_read_bio_PrivateKey() ???
+The sign_ctx would need to have an EVP_PKEY* */
+
/* Convert PEM to DER */
if ( !(p = Ustrstr(privkey_pem, "-----BEGIN RSA PRIVATE KEY-----"))
|| !(q = Ustrstr(p+=31, "-----END RSA PRIVATE KEY-----"))
@@ -602,11 +617,14 @@ sign hash.
Return: NULL for success, or an error string */
const uschar *
-exim_rsa_sign(es_ctx * sign_ctx, BOOL is_sha1, blob * data, blob * sig)
+exim_dkim_sign(es_ctx * sign_ctx, BOOL is_sha1, blob * data, blob * sig)
{
uint len;
const uschar * ret = NULL;
+/*XXX will need extension for non-RSA signing algo. Maybe use
+https://www.openssl.org/docs/man1.0.2/crypto/EVP_PKEY_sign.html ??? */
+
/* Allocate mem for signature */
len = RSA_size(sign_ctx->rsa);
sig->data = store_get(len);
@@ -630,14 +648,16 @@ return ret;;
/* import public key (from DER in memory)
-Return: nULL for success, or an error string */
+Return: NULL for success, or an error string */
const uschar *
-exim_rsa_verify_init(blob * pubkey_der, ev_ctx * verify_ctx)
+exim_dkim_verify_init(blob * pubkey_der, ev_ctx * verify_ctx)
{
const uschar * p = CUS pubkey_der->data;
const uschar * ret = NULL;
+/*XXX d2i_X509_PUBKEY, X509_get_pubkey(), and an EVP_PKEY* in verify_ctx. */
+
if (!(verify_ctx->rsa = d2i_RSA_PUBKEY(NULL, &p, (long) pubkey_der->len)))
{
char ssl_errstring[256];
@@ -655,10 +675,18 @@ return ret;
Return: NULL for success, or an error string */
const uschar *
-exim_rsa_verify(ev_ctx * verify_ctx, BOOL is_sha1, blob * data_hash, blob * sig)
+exim_dkim_verify(ev_ctx * verify_ctx, BOOL is_sha1, blob * data_hash, blob * sig)
{
const uschar * ret = NULL;
+/*XXX needs extension for SHA512, Possibly EVP_PKEY_verify() is all we need??? */
+/* with EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING)
+- see example code at https://www.openssl.org/docs/man1.0.2/crypto/EVP_PKEY_verify.html
+and maybe also EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha256()) though unclear
+if that only sets a pad/type field byte value, or sets up for an actual hash operation...
+Same on the signing side.
+https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_CTX_set_rsa_padding.html says it does what we want. */
+
if (RSA_verify(is_sha1 ? NID_sha1 : NID_sha256,
CUS data_hash->data, data_hash->len,
US sig->data, (uint) sig->len, verify_ctx->rsa) != 1)
diff --git a/src/src/pdkim/rsa.h b/src/src/pdkim/signing.h
index 6018eba64..4e8580859 100644
--- a/src/src/pdkim/rsa.h
+++ b/src/src/pdkim/signing.h
@@ -69,13 +69,13 @@ typedef struct {
#endif
-extern void exim_rsa_init(void);
-extern blob * exim_rsa_data_append(blob *, int *, uschar *);
+extern void exim_dkim_init(void);
+extern blob * exim_dkim_data_append(blob *, int *, uschar *);
-extern const uschar * exim_rsa_signing_init(uschar *, es_ctx *);
-extern const uschar * exim_rsa_sign(es_ctx *, BOOL, blob *, blob *);
-extern const uschar * exim_rsa_verify_init(blob *, ev_ctx *);
-extern const uschar * exim_rsa_verify(ev_ctx *, BOOL, blob *, blob *);
+extern const uschar * exim_dkim_signing_init(uschar *, es_ctx *);
+extern const uschar * exim_dkim_sign(es_ctx *, BOOL, blob *, blob *);
+extern const uschar * exim_dkim_verify_init(blob *, ev_ctx *);
+extern const uschar * exim_dkim_verify(ev_ctx *, BOOL, blob *, blob *);
#endif /*DISABLE_DKIM*/
/* End of File */