From ff1865774db251d772847ef9e5033c214ed8fc49 Mon Sep 17 00:00:00 2001 From: GimmeHardware <23285878+jcastle-gh@users.noreply.github.com> Date: Mon, 17 Mar 2025 01:31:12 -0400 Subject: [PATCH 1/3] Merge PR162 --- libopendkim/base32.c | 7 +- libopendkim/dkim-atps.c | 16 +-- libopendkim/dkim-canon.c | 212 +++++++++------------------------ libopendkim/dkim-test.c | 19 +-- libopendkim/dkim-types.h | 31 ++--- libopendkim/dkim.c | 222 ++++++++++++++++++++--------------- opendkim/opendkim-atpszone.c | 22 ++-- opendkim/opendkim-genzone.c | 13 +- 8 files changed, 216 insertions(+), 326 deletions(-) diff --git a/libopendkim/base32.c b/libopendkim/base32.c index d807c605..f0ca9cd8 100644 --- a/libopendkim/base32.c +++ b/libopendkim/base32.c @@ -158,22 +158,21 @@ dkim_base32_encode(char *buf, size_t *buflen, const void *data, size_t size) #ifdef TEST #include +#include int main(int argc, char **argv) { int x; size_t buflen; - SHA_CTX sha; char buf[128]; unsigned char shaout[SHA_DIGEST_LENGTH]; memset(buf, '\0', sizeof buf); buflen = sizeof buf; - SHA1_Init(&sha); - SHA1_Update(&sha, argv[1], strlen(argv[1])); - SHA1_Final(shaout, &sha); + (void) EVP_Digest(argv[1], strlen(argv[1]), shaout, NULL, EVP_sha1(), + NULL); x = dkim_base32_encode(buf, &buflen, shaout, SHA_DIGEST_LENGTH); diff --git a/libopendkim/dkim-atps.c b/libopendkim/dkim-atps.c index 889f1d47..fe332087 100644 --- a/libopendkim/dkim-atps.c +++ b/libopendkim/dkim-atps.c @@ -37,6 +37,7 @@ #else /* USE_GNUTLS */ /* openssl includes */ # include +# include #endif /* USE_GNUTLS */ /* prototypes */ @@ -113,11 +114,6 @@ dkim_atps_check(DKIM *dkim, DKIM_SIGINFO *sig, struct timeval *timeout, u_char *eom; #ifdef USE_GNUTLS gnutls_hash_hd_t ctx; -#else /* USE_GNUTLS */ - SHA_CTX ctx; -# ifdef HAVE_SHA256 - SHA256_CTX ctx2; -# endif /* HAVE_SHA256 */ #endif /* USE_GNUTLS */ struct timeval to; HEADER hdr; @@ -198,16 +194,14 @@ dkim_atps_check(DKIM *dkim, DKIM_SIGINFO *sig, struct timeval *timeout, switch (hash) { case DKIM_HASHTYPE_SHA1: - SHA1_Init(&ctx); - SHA1_Update(&ctx, sdomain, strlen(sdomain)); - SHA1_Final(digest, &ctx); + (void) EVP_Digest(sdomain, strlen(sdomain), digest, + NULL, EVP_sha1(), NULL); break; # ifdef HAVE_SHA256 case DKIM_HASHTYPE_SHA256: - SHA256_Init(&ctx2); - SHA256_Update(&ctx2, sdomain, strlen(sdomain)); - SHA256_Final(digest, &ctx2); + (void) EVP_Digest(sdomain, strlen(sdomain), digest, + NULL, EVP_sha256(), NULL); break; # endif /* HAVE_SHA256 */ diff --git a/libopendkim/dkim-canon.c b/libopendkim/dkim-canon.c index da98a23c..8e78978b 100644 --- a/libopendkim/dkim-canon.c +++ b/libopendkim/dkim-canon.c @@ -116,38 +116,27 @@ dkim_canon_free(DKIM *dkim, DKIM_CANON *canon) #else /* USE_GNUTLS */ case DKIM_HASHTYPE_SHA1: + case DKIM_HASHTYPE_SHA256: { - struct dkim_sha1 *sha1; + struct dkim_sha *sha; - sha1 = (struct dkim_sha1 *) canon->canon_hash; + sha = (struct dkim_sha *) canon->canon_hash; - if (sha1->sha1_tmpbio != NULL) + if (sha->sha_tmpbio != NULL) { - BIO_free(sha1->sha1_tmpbio); - sha1->sha1_tmpfd = -1; - sha1->sha1_tmpbio = NULL; + BIO_free(sha->sha_tmpbio); + sha->sha_tmpfd = -1; + sha->sha_tmpbio = NULL; } - break; - } - -# ifdef HAVE_SHA256 - case DKIM_HASHTYPE_SHA256: - { - struct dkim_sha256 *sha256; - - sha256 = (struct dkim_sha256 *) canon->canon_hash; - - if (sha256->sha256_tmpbio != NULL) + if (sha->sha_ctx != NULL) { - BIO_free(sha256->sha256_tmpbio); - sha256->sha256_tmpfd = -1; - sha256->sha256_tmpbio = NULL; + EVP_MD_CTX_free(sha->sha_ctx); + sha->sha_ctx = NULL; } break; } -# endif /* HAVE_SHA256 */ #endif /* USE_GNUTLS */ default: @@ -217,32 +206,18 @@ dkim_canon_write(DKIM_CANON *canon, u_char *buf, size_t buflen) } #else /* USE_GNUTLS */ case DKIM_HASHTYPE_SHA1: - { - struct dkim_sha1 *sha1; - - sha1 = (struct dkim_sha1 *) canon->canon_hash; - SHA1_Update(&sha1->sha1_ctx, buf, buflen); - - if (sha1->sha1_tmpbio != NULL) - BIO_write(sha1->sha1_tmpbio, buf, buflen); - - break; - } - -# ifdef HAVE_SHA256 case DKIM_HASHTYPE_SHA256: { - struct dkim_sha256 *sha256; + struct dkim_sha *sha; - sha256 = (struct dkim_sha256 *) canon->canon_hash; - SHA256_Update(&sha256->sha256_ctx, buf, buflen); + sha = (struct dkim_sha *) canon->canon_hash; + EVP_DigestUpdate(sha->sha_ctx, buf, buflen); - if (sha256->sha256_tmpbio != NULL) - BIO_write(sha256->sha256_tmpbio, buf, buflen); + if (sha->sha_tmpbio != NULL) + BIO_write(sha->sha_tmpbio, buf, buflen); break; } -# endif /* HAVE_SHA256 */ #endif /* USE_GNUTLS */ } @@ -700,76 +675,51 @@ dkim_canon_init(DKIM *dkim, _Bool tmp, _Bool keep) } #else /* USE_GNUTLS */ case DKIM_HASHTYPE_SHA1: + case DKIM_HASHTYPE_SHA256: { - struct dkim_sha1 *sha1; + struct dkim_sha *sha; - sha1 = (struct dkim_sha1 *) DKIM_MALLOC(dkim, - sizeof(struct dkim_sha1)); - if (sha1 == NULL) + sha = (struct dkim_sha *) DKIM_MALLOC(dkim, + sizeof(struct dkim_sha)); + if (sha == NULL) { dkim_error(dkim, "unable to allocate %d byte(s)", - sizeof(struct dkim_sha1)); + sizeof(struct dkim_sha)); return DKIM_STAT_NORESOURCE; } - memset(sha1, '\0', sizeof(struct dkim_sha1)); - SHA1_Init(&sha1->sha1_ctx); + memset(sha, '\0', sizeof(struct dkim_sha)); - if (tmp) + sha->sha_ctx = EVP_MD_CTX_new(); + if (cur->canon_hashtype == DKIM_HASHTYPE_SHA1) { - status = dkim_tmpfile(dkim, &fd, keep); - if (status != DKIM_STAT_OK) - { - DKIM_FREE(dkim, sha1); - return status; - } - - sha1->sha1_tmpfd = fd; - sha1->sha1_tmpbio = BIO_new_fd(fd, 1); + (void) EVP_DigestInit_ex(sha->sha_ctx, + EVP_sha1(), NULL); } - - cur->canon_hash = sha1; - - break; - } - -# ifdef HAVE_SHA256 - case DKIM_HASHTYPE_SHA256: - { - struct dkim_sha256 *sha256; - - sha256 = (struct dkim_sha256 *) DKIM_MALLOC(dkim, - sizeof(struct dkim_sha256)); - if (sha256 == NULL) + else { - dkim_error(dkim, - "unable to allocate %d byte(s)", - sizeof(struct dkim_sha256)); - return DKIM_STAT_NORESOURCE; + (void) EVP_DigestInit_ex(sha->sha_ctx, + EVP_sha256(), NULL); } - memset(sha256, '\0', sizeof(struct dkim_sha256)); - SHA256_Init(&sha256->sha256_ctx); - if (tmp) { status = dkim_tmpfile(dkim, &fd, keep); if (status != DKIM_STAT_OK) { - DKIM_FREE(dkim, sha256); + DKIM_FREE(dkim, sha); return status; } - sha256->sha256_tmpfd = fd; - sha256->sha256_tmpbio = BIO_new_fd(fd, 1); + sha->sha_tmpfd = fd; + sha->sha_tmpbio = BIO_new_fd(fd, 1); } - cur->canon_hash = sha256; + cur->canon_hash = sha; break; } -# endif /* HAVE_SHA256 */ #endif /* USE_GNUTLS */ default: @@ -1420,32 +1370,19 @@ dkim_canon_runheaders(DKIM *dkim) #else /* USE_GNUTLS */ case DKIM_HASHTYPE_SHA1: - { - struct dkim_sha1 *sha1; - - sha1 = (struct dkim_sha1 *) cur->canon_hash; - SHA1_Final(sha1->sha1_out, &sha1->sha1_ctx); - - if (sha1->sha1_tmpbio != NULL) - (void) BIO_flush(sha1->sha1_tmpbio); - - break; - } - -# ifdef HAVE_SHA256 case DKIM_HASHTYPE_SHA256: { - struct dkim_sha256 *sha256; + struct dkim_sha *sha; - sha256 = (struct dkim_sha256 *) cur->canon_hash; - SHA256_Final(sha256->sha256_out, &sha256->sha256_ctx); + sha = (struct dkim_sha *) cur->canon_hash; + EVP_DigestFinal_ex(sha->sha_ctx, sha->sha_out, + &sha->sha_outlen); - if (sha256->sha256_tmpbio != NULL) - (void) BIO_flush(sha256->sha256_tmpbio); + if (sha->sha_tmpbio != NULL) + (void) BIO_flush(sha->sha_tmpbio); break; } -# endif /* HAVE_SHA256 */ #endif /* USE_GNUTLS */ default: @@ -1556,34 +1493,22 @@ dkim_canon_signature(DKIM *dkim, struct dkim_header *hdr) break; } + #else /* USE_GNUTLS */ case DKIM_HASHTYPE_SHA1: - { - struct dkim_sha1 *sha1; - - sha1 = (struct dkim_sha1 *) cur->canon_hash; - SHA1_Final(sha1->sha1_out, &sha1->sha1_ctx); - - if (sha1->sha1_tmpbio != NULL) - (void) BIO_flush(sha1->sha1_tmpbio); - - break; - } - -# ifdef HAVE_SHA256 case DKIM_HASHTYPE_SHA256: { - struct dkim_sha256 *sha256; + struct dkim_sha *sha; - sha256 = (struct dkim_sha256 *) cur->canon_hash; - SHA256_Final(sha256->sha256_out, &sha256->sha256_ctx); + sha = (struct dkim_sha *) cur->canon_hash; + EVP_DigestFinal_ex(sha->sha_ctx, sha->sha_out, + &sha->sha_outlen); - if (sha256->sha256_tmpbio != NULL) - (void) BIO_flush(sha256->sha256_tmpbio); + if (sha->sha_tmpbio != NULL) + (void) BIO_flush(sha->sha_tmpbio); break; } -# endif /* HAVE_SHA256 */ #endif /* USE_GNUTLS */ default: @@ -1993,32 +1918,19 @@ dkim_canon_closebody(DKIM *dkim) } #else /* USE_GNUTLS */ case DKIM_HASHTYPE_SHA1: - { - struct dkim_sha1 *sha1; - - sha1 = (struct dkim_sha1 *) cur->canon_hash; - SHA1_Final(sha1->sha1_out, &sha1->sha1_ctx); - - if (sha1->sha1_tmpbio != NULL) - (void) BIO_flush(sha1->sha1_tmpbio); - - break; - } - -# ifdef HAVE_SHA256 case DKIM_HASHTYPE_SHA256: { - struct dkim_sha256 *sha256; + struct dkim_sha *sha; - sha256 = (struct dkim_sha256 *) cur->canon_hash; - SHA256_Final(sha256->sha256_out, &sha256->sha256_ctx); + sha = (struct dkim_sha *) cur->canon_hash; + EVP_DigestFinal_ex(sha->sha_ctx, sha->sha_out, + &sha->sha_outlen); - if (sha256->sha256_tmpbio != NULL) - (void) BIO_flush(sha256->sha256_tmpbio); + if (sha->sha_tmpbio != NULL) + (void) BIO_flush(sha->sha_tmpbio); break; } -# endif /* HAVE_SHA256 */ #endif /* USE_GNUTLS */ default: @@ -2070,28 +1982,16 @@ dkim_canon_getfinal(DKIM_CANON *canon, u_char **digest, size_t *dlen) } #else /* USE_GNUTLS */ case DKIM_HASHTYPE_SHA1: - { - struct dkim_sha1 *sha1; - - sha1 = (struct dkim_sha1 *) canon->canon_hash; - *digest = sha1->sha1_out; - *dlen = sizeof sha1->sha1_out; - - return DKIM_STAT_OK; - } - -# ifdef HAVE_SHA256 case DKIM_HASHTYPE_SHA256: { - struct dkim_sha256 *sha256; + struct dkim_sha *sha; - sha256 = (struct dkim_sha256 *) canon->canon_hash; - *digest = sha256->sha256_out; - *dlen = sizeof sha256->sha256_out; + sha = (struct dkim_sha *) canon->canon_hash; + *digest = sha->sha_out; + *dlen = sha->sha_outlen; return DKIM_STAT_OK; } -# endif /* HAVE_SHA256 */ #endif /* USE_GNUTLS */ default: diff --git a/libopendkim/dkim-test.c b/libopendkim/dkim-test.c index 3985db83..62c2a044 100644 --- a/libopendkim/dkim-test.c +++ b/libopendkim/dkim-test.c @@ -27,6 +27,7 @@ # include # include # include +# include #endif /* USE_GNUTLS */ /* libopendkim includes */ @@ -431,21 +432,7 @@ dkim_test_key(DKIM_LIB *lib, char *selector, char *domain, return -1; } - crypto->crypto_key = EVP_PKEY_get1_RSA(crypto->crypto_pkey); - if (crypto->crypto_key == NULL) - { - BIO_free(keybuf); - (void) dkim_free(dkim); - if (err != NULL) - { - strlcpy(err, "EVP_PKEY_get1_RSA() failed", - errlen); - } - return -1; - } - - crypto->crypto_keysize = RSA_size(crypto->crypto_key); - crypto->crypto_pad = RSA_PKCS1_PADDING; + crypto->crypto_keysize = EVP_PKEY_size(crypto->crypto_pkey); outkey = BIO_new(BIO_s_mem()); if (outkey == NULL) @@ -457,7 +444,7 @@ dkim_test_key(DKIM_LIB *lib, char *selector, char *domain, return -1; } - status = i2d_RSA_PUBKEY_bio(outkey, crypto->crypto_key); + status = i2d_PUBKEY_bio(outkey, crypto->crypto_pkey); if (status == 0) { BIO_free(keybuf); diff --git a/libopendkim/dkim-types.h b/libopendkim/dkim-types.h index f54800a1..18ee7cae 100644 --- a/libopendkim/dkim-types.h +++ b/libopendkim/dkim-types.h @@ -37,6 +37,7 @@ # include # include # include +# include #endif /* USE_GNUTLS */ #ifdef QUERY_CACHE @@ -151,36 +152,22 @@ struct dkim_siginfo struct dkim_dstring * sig_sslerrbuf; }; -#ifdef USE_GNUTLS /* struct dkim_sha -- stuff needed to do a sha hash */ struct dkim_sha { +#ifdef USE_GNUTLS int sha_tmpfd; u_int sha_outlen; gnutls_hash_hd_t sha_hd; u_char * sha_out; -}; #else /* USE_GNUTLS */ -/* struct dkim_sha1 -- stuff needed to do a sha1 hash */ -struct dkim_sha1 -{ - int sha1_tmpfd; - BIO * sha1_tmpbio; - SHA_CTX sha1_ctx; - u_char sha1_out[SHA_DIGEST_LENGTH]; -}; - -# ifdef HAVE_SHA256 -/* struct dkim_sha256 -- stuff needed to do a sha256 hash */ -struct dkim_sha256 -{ - int sha256_tmpfd; - BIO * sha256_tmpbio; - SHA256_CTX sha256_ctx; - u_char sha256_out[SHA256_DIGEST_LENGTH]; -}; -# endif /* HAVE_SHA256 */ + int sha_tmpfd; + BIO * sha_tmpbio; + EVP_MD_CTX * sha_ctx; + u_char sha_out[EVP_MAX_MD_SIZE]; + u_int sha_outlen; #endif /* USE_GNUTLS */ +}; /* struct dkim_canon -- a canonicalization status handle */ struct dkim_canon @@ -220,12 +207,10 @@ struct dkim_crypto gnutls_datum_t crypto_rsaout; gnutls_datum_t crypto_keydata; #else /* USE_GNUTLS */ - u_char crypto_pad; int crypto_keysize; size_t crypto_inlen; size_t crypto_outlen; EVP_PKEY * crypto_pkey; - void * crypto_key; BIO * crypto_keydata; u_char * crypto_in; u_char * crypto_out; diff --git a/libopendkim/dkim.c b/libopendkim/dkim.c index e429a6fc..9eda1dc5 100644 --- a/libopendkim/dkim.c +++ b/libopendkim/dkim.c @@ -75,6 +75,7 @@ # include # include # include +# include #endif /* USE_GNUTLS */ /* libopendkim includes */ @@ -203,12 +204,6 @@ void dkim_error __P((DKIM *, const char *, ...)); (x) = NULL; \ } -# define RSA_CLOBBER(x) if ((x) != NULL) \ - { \ - RSA_free((x)); \ - (x) = NULL; \ - } - # define EVP_CLOBBER(x) if ((x) != NULL) \ { \ EVP_PKEY_free((x)); \ @@ -1270,32 +1265,14 @@ dkim_privkey_load(DKIM *dkim) } } - if (dkim->dkim_signalg == DKIM_SIGN_ED25519SHA256) - { - crypto->crypto_keysize = EVP_PKEY_size(crypto->crypto_pkey) * 8; - } - else - { - crypto->crypto_key = EVP_PKEY_get1_RSA(crypto->crypto_pkey); - if (crypto->crypto_key == NULL) - { - dkim_load_ssl_errors(dkim, 0); - dkim_error(dkim, "EVP_PKEY_get1_RSA() failed"); - BIO_CLOBBER(crypto->crypto_keydata); - return DKIM_STAT_NORESOURCE; - } + crypto->crypto_outlen = EVP_PKEY_size(crypto->crypto_pkey); + crypto->crypto_keysize = crypto->crypto_outlen * 8; - crypto->crypto_keysize = RSA_size(crypto->crypto_key) * 8; - crypto->crypto_pad = RSA_PKCS1_PADDING; - } - - crypto->crypto_outlen = crypto->crypto_keysize / 8; crypto->crypto_out = DKIM_MALLOC(dkim, crypto->crypto_outlen); if (crypto->crypto_out == NULL) { dkim_error(dkim, "unable to allocate %d byte(s)", - crypto->crypto_keysize / 8); - RSA_free(crypto->crypto_key); + crypto->crypto_outlen); BIO_CLOBBER(crypto->crypto_keydata); return DKIM_STAT_NORESOURCE; } @@ -3675,7 +3652,6 @@ static DKIM_STAT dkim_eom_sign(DKIM *dkim) { int status; - size_t l = 0; size_t diglen; size_t siglen = 0; size_t len; @@ -3811,9 +3787,7 @@ dkim_eom_sign(DKIM *dkim) #ifdef USE_GNUTLS if (crypto->crypto_privkey == NULL) #else /* USE_GNUTLS */ - if (!(crypto->crypto_key != NULL || - (sig->sig_signalg == DKIM_SIGN_ED25519SHA256 && - crypto->crypto_pkey != NULL))) + if (crypto->crypto_pkey == NULL) #endif /* USE_GNUTLS */ { dkim_error(dkim, "private key load failed"); @@ -3949,39 +3923,83 @@ dkim_eom_sign(DKIM *dkim) case DKIM_SIGN_RSASHA1: case DKIM_SIGN_RSASHA256: { - int nid; struct dkim_crypto *crypto; + EVP_PKEY_CTX *pkey_ctx; + const EVP_MD *md; crypto = (struct dkim_crypto *) sig->sig_signature; - nid = NID_sha1; + pkey_ctx = EVP_PKEY_CTX_new(crypto->crypto_pkey, NULL); + + if (pkey_ctx == NULL) + { + dkim_error(dkim, "failed to allocate EVP_PKEY context"); + BIO_CLOBBER(crypto->crypto_keydata); + return DKIM_STAT_NORESOURCE; + } + + if (EVP_PKEY_sign_init(pkey_ctx) <= 0) + { + dkim_load_ssl_errors(dkim, 0); + dkim_error(dkim, + "failed to initialize EVP_PKEY context"); + + EVP_PKEY_CTX_free(pkey_ctx); + BIO_CLOBBER(crypto->crypto_keydata); + + return DKIM_STAT_INTERNAL; + } + + if (EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PADDING) <= 0) + { + dkim_load_ssl_errors(dkim, 0); + dkim_error(dkim, "failed to set RSA padding mode"); + + EVP_PKEY_CTX_free(pkey_ctx); + BIO_CLOBBER(crypto->crypto_keydata); + + return DKIM_STAT_INTERNAL; + } + + md = EVP_sha1(); if (dkim_libfeature(dkim->dkim_libhandle, DKIM_FEATURE_SHA256) && sig->sig_hashtype == DKIM_HASHTYPE_SHA256) - nid = NID_sha256; + md = EVP_sha256(); + + if (EVP_PKEY_CTX_set_signature_md(pkey_ctx, md) <= 0) + { + dkim_load_ssl_errors(dkim, 0); + dkim_error(dkim, "failed to set message digest type"); + + EVP_PKEY_CTX_free(pkey_ctx); + BIO_CLOBBER(crypto->crypto_keydata); + + return DKIM_STAT_INTERNAL; + } + + status = EVP_PKEY_sign(pkey_ctx, crypto->crypto_out, + &crypto->crypto_outlen, digest, diglen); - status = RSA_sign(nid, digest, diglen, - crypto->crypto_out, (int *) &l, - crypto->crypto_key); - if (status != 1 || l == 0) + if (status != 1 || crypto->crypto_outlen == 0) { dkim_load_ssl_errors(dkim, 0); dkim_error(dkim, "signature generation failed (status %d, length %d)", - status, l); + status, crypto->crypto_outlen); - RSA_free(crypto->crypto_key); + EVP_PKEY_CTX_free(pkey_ctx); BIO_CLOBBER(crypto->crypto_keydata); return DKIM_STAT_INTERNAL; } - crypto->crypto_outlen = l; - signature = crypto->crypto_out; siglen = crypto->crypto_outlen; + EVP_PKEY_CTX_free(pkey_ctx); + break; } @@ -4000,7 +4018,6 @@ dkim_eom_sign(DKIM *dkim) dkim_error(dkim, "failed to initialize digest context"); - RSA_free(crypto->crypto_key); BIO_CLOBBER(crypto->crypto_keydata); return DKIM_STAT_INTERNAL; @@ -4010,9 +4027,9 @@ dkim_eom_sign(DKIM *dkim) NULL, NULL, crypto->crypto_pkey); if (status == 1) { - l = crypto->crypto_outlen; - status = EVP_DigestSign(md_ctx, crypto->crypto_out, &l, - digest, diglen); + status = EVP_DigestSign(md_ctx, crypto->crypto_out, + &crypto->crypto_outlen, digest, + diglen); } if (status != 1) @@ -4020,16 +4037,14 @@ dkim_eom_sign(DKIM *dkim) /* dkim_load_ssl_errors(dkim, 0); */ dkim_error(dkim, "signature generation failed (status %d, length %d, %s)", - status, l, ERR_error_string(ERR_get_error(), NULL)); + status, crypto->crypto_outlen, + ERR_error_string(ERR_get_error(), NULL)); - RSA_free(crypto->crypto_key); BIO_CLOBBER(crypto->crypto_keydata); return DKIM_STAT_INTERNAL; } - crypto->crypto_outlen = l; - signature = crypto->crypto_out; siglen = crypto->crypto_outlen; @@ -5146,7 +5161,6 @@ dkim_free(DKIM *dkim) #else /* USE_GNUTLS */ BIO_CLOBBER(crypto->crypto_keydata); EVP_CLOBBER(crypto->crypto_pkey); - RSA_CLOBBER(crypto->crypto_key); CLOBBER(crypto->crypto_out); #endif /* USE_GNUTLS */ } @@ -5558,6 +5572,8 @@ dkim_sig_process(DKIM *dkim, DKIM_SIGINFO *sig) # endif /* GNUTLS_VERSION_MAJOR == 3 */ #else /* USE_GNUTLS */ BIO *key; + EVP_PKEY_CTX *pkey_ctx; + const EVP_MD *md; #endif /* USE_GNUTLS */ u_char *digest = NULL; struct dkim_crypto *crypto; @@ -5836,12 +5852,10 @@ dkim_sig_process(DKIM *dkim, DKIM_SIGINFO *sig) else # endif /* HAVE_ED25519 */ { - crypto->crypto_key = EVP_PKEY_get1_RSA(crypto->crypto_pkey); - if (crypto->crypto_key == NULL) + if (EVP_PKEY_base_id(crypto->crypto_pkey) != EVP_PKEY_RSA) { - dkim_sig_load_ssl_errors(dkim, sig, 0); dkim_error(dkim, - "s=%s d=%s: EVP_PKEY_get1_RSA() failed", + "s=%s d=%s: not an RSA key", dkim_sig_getselector(sig), dkim_sig_getdomain(sig)); @@ -5852,23 +5866,69 @@ dkim_sig_process(DKIM *dkim, DKIM_SIGINFO *sig) return DKIM_STAT_OK; } - crypto->crypto_keysize = RSA_size(crypto->crypto_key); - crypto->crypto_pad = RSA_PKCS1_PADDING; + crypto->crypto_keysize = EVP_PKEY_size(crypto->crypto_pkey); crypto->crypto_in = sig->sig_sig; crypto->crypto_inlen = sig->sig_siglen; - nid = NID_sha1; + pkey_ctx = EVP_PKEY_CTX_new(crypto->crypto_pkey, NULL); + + if (pkey_ctx == NULL) + { + dkim_error(dkim, + "failed to allocate EVP_PKEY context"); + BIO_CLOBBER(key); + return DKIM_STAT_NORESOURCE; + } + + if (EVP_PKEY_verify_init(pkey_ctx) <= 0) + { + dkim_sig_load_ssl_errors(dkim, sig, 0); + dkim_error(dkim, + "failed to initialize EVP_PKEY context"); + + EVP_PKEY_CTX_free(pkey_ctx); + BIO_CLOBBER(key); + + return DKIM_STAT_INTERNAL; + } + + if (EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PADDING) <= 0) + { + dkim_sig_load_ssl_errors(dkim, sig, 0); + dkim_error(dkim, + "failed to set RSA padding mode"); + + EVP_PKEY_CTX_free(pkey_ctx); + BIO_CLOBBER(key); + + return DKIM_STAT_INTERNAL; + } + + md = EVP_sha1(); if (dkim_libfeature(dkim->dkim_libhandle, DKIM_FEATURE_SHA256) && sig->sig_hashtype == DKIM_HASHTYPE_SHA256) - nid = NID_sha256; + md = EVP_sha256(); + + if (EVP_PKEY_CTX_set_signature_md(pkey_ctx, md) <= 0) + { + dkim_sig_load_ssl_errors(dkim, sig, 0); + dkim_error(dkim, + "failed to set message digest type"); + + EVP_PKEY_CTX_free(pkey_ctx); + BIO_CLOBBER(key); + + return DKIM_STAT_INTERNAL; + } - vstat = RSA_verify(nid, digest, diglen, - crypto->crypto_in, - crypto->crypto_inlen, - crypto->crypto_key); + vstat = EVP_PKEY_verify(pkey_ctx, crypto->crypto_in, + crypto->crypto_inlen, digest, + diglen); + + EVP_PKEY_CTX_free(pkey_ctx); } dkim_sig_load_ssl_errors(dkim, sig, 0); @@ -5876,13 +5936,7 @@ dkim_sig_process(DKIM *dkim, DKIM_SIGINFO *sig) sig->sig_keybits = 8 * crypto->crypto_keysize; BIO_CLOBBER(key); - EVP_PKEY_free(crypto->crypto_pkey); - crypto->crypto_pkey = NULL; - if (crypto->crypto_key != NULL) - { - RSA_free(crypto->crypto_key); - crypto->crypto_key = NULL; - } + EVP_CLOBBER(crypto->crypto_pkey); #endif /* USE_GNUTLS */ if (vstat == 1) @@ -7598,40 +7652,22 @@ dkim_sig_getreportinfo(DKIM *dkim, DKIM_SIGINFO *sig, } #else /* USE_GNUTLS */ case DKIM_HASHTYPE_SHA1: - { - struct dkim_sha1 *sha1; - - sha1 = (struct dkim_sha1 *) sig->sig_hdrcanon->canon_hash; - if (hfd != NULL) - *hfd = sha1->sha1_tmpfd; - - if (bfd != NULL) - { - sha1 = (struct dkim_sha1 *) sig->sig_bodycanon->canon_hash; - *bfd = sha1->sha1_tmpfd; - } - - break; - } - -# ifdef HAVE_SHA256 case DKIM_HASHTYPE_SHA256: { - struct dkim_sha256 *sha256; + struct dkim_sha *sha; - sha256 = (struct dkim_sha256 *) sig->sig_hdrcanon->canon_hash; + sha = (struct dkim_sha *) sig->sig_hdrcanon->canon_hash; if (hfd != NULL) - *hfd = sha256->sha256_tmpfd; + *hfd = sha->sha_tmpfd; if (bfd != NULL) { - sha256 = (struct dkim_sha256 *) sig->sig_bodycanon->canon_hash; - *bfd = sha256->sha256_tmpfd; + sha = (struct dkim_sha *) sig->sig_bodycanon->canon_hash; + *bfd = sha->sha_tmpfd; } break; } -# endif /* HAVE_SHA256 */ #endif /* USE_GNUTLS */ default: diff --git a/opendkim/opendkim-atpszone.c b/opendkim/opendkim-atpszone.c index 02276ed0..e29555a3 100644 --- a/opendkim/opendkim-atpszone.c +++ b/opendkim/opendkim-atpszone.c @@ -144,11 +144,6 @@ main(int argc, char **argv) DKIMF_DB db; #ifdef USE_GNUTLS gnutls_hash_hd_t sha; -#else /* USE_GNUTLS */ - SHA_CTX sha; -# ifdef HAVE_SHA256 - SHA256_CTX sha256; -# endif /* HAVE_SHA256 */ #endif /* USE_GNUTLS */ char domain[DKIM_MAXHOSTNAMELEN + 1]; char hostname[DKIM_MAXHOSTNAMELEN + 1]; @@ -443,20 +438,19 @@ main(int argc, char **argv) # ifdef HAVE_SHA256 if (hash == NULL || strcasecmp(hash, "sha256") == 0) { - SHA256_Init(&sha256); - SHA256_Update(&sha256, domain, strlen(domain)); - SHA256_Final(shaout, &sha256); + (void) EVP_Digest(domain, strlen(domain), + shaout, NULL, EVP_sha256(), + NULL); } else { - SHA1_Init(&sha); - SHA1_Update(&sha, domain, strlen(domain)); - SHA1_Final(shaout, &sha); + (void) EVP_Digest(domain, strlen(domain), + shaout, NULL, EVP_sha1(), + NULL); } # else /* HAVE_SHA256 */ - SHA1_Init(&sha); - SHA1_Update(&sha, domain, strlen(domain)); - SHA1_Final(shaout, &sha); + (void) EVP_Digest(domain, strlen(domain), shaout, NULL, + EVP_sha1(), NULL); # endif /* HAVE_SHA256 */ #endif /* USE_GNUTLS */ diff --git a/opendkim/opendkim-genzone.c b/opendkim/opendkim-genzone.c index e1c53d53..48c9523b 100644 --- a/opendkim/opendkim-genzone.c +++ b/opendkim/opendkim-genzone.c @@ -26,7 +26,6 @@ # include # include #else /* USE_GNUTLS */ -# include # include # include # include @@ -264,7 +263,6 @@ main(int argc, char **argv) BIO *private; BIO *outbio = NULL; EVP_PKEY *pkey; - RSA *rsa; #endif /* USE_GNUTLS */ DKIMF_DB db; char keyname[BUFRSZ + 1]; @@ -837,12 +835,9 @@ main(int argc, char **argv) } } - rsa = EVP_PKEY_get1_RSA(pkey); - if (rsa == NULL) + if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA) { - fprintf(stderr, - "%s: EVP_PKEY_get1_RSA() failed\n", - progname); + fprintf(stderr, "%s: not an RSA key\n", progname); (void) dkimf_db_close(db); (void) BIO_free(private); (void) EVP_PKEY_free(pkey); @@ -851,11 +846,11 @@ main(int argc, char **argv) } /* convert private to public */ - status = PEM_write_bio_RSA_PUBKEY(outbio, rsa); + status = PEM_write_bio_PUBKEY(outbio, pkey); if (status == 0) { fprintf(stderr, - "%s: PEM_write_bio_RSA_PUBKEY() failed\n", + "%s: PEM_write_bio_PUBKEY() failed\n", progname); (void) dkimf_db_close(db); (void) BIO_free(private); From 52e28cfba8cc5a2b31027386b42c0124a3e635a9 Mon Sep 17 00:00:00 2001 From: GimmeHardware <23285878+jcastle-gh@users.noreply.github.com> Date: Mon, 17 Mar 2025 01:35:11 -0400 Subject: [PATCH 2/3] Support ed25519 in opendkim tools, fix orphaned opendkim-genzone bug Depends on https://github.com/trusteddomainproject/OpenDKIM/pull/162 This should be merged after PR #162, Upgrade to OpenSSL 3". 1. opendkim-genkey: require openssl >= 1.1.1 for ed25519 instead of == 1.1.1. 2. opendkim-testkey: Add options 1, 2, and e to create an rsa-sha1, rsa-sha256, or ed25519 signature, respectively. Rsa-sha256 is the default. Previously the tool could only create rsa-sha1 signatures. 3. opendkim-genzone: Debian's opendkim includes nsupdate_output.patch which was added long ago for Debian bug 849540: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=849540 The patch originally came from a bug reported against 2.10.3 in the opendkim sourceforge bug database: https://sourceforge.net/p/opendkim/feature-requests/200 Somehow that sourceforge bug and fix didn't make it to opendkim github. That patch fixes nsupdate output formatting and adds a key usage option. This patch does that and also adds support for ed25519 keys. --- opendkim/opendkim-genkey.8.in | 1 + opendkim/opendkim-genkey.in | 6 ++-- opendkim/opendkim-genzone.c | 64 +++++++++++++++++++++++++++++----- opendkim/opendkim-testmsg.8.in | 9 +++++ opendkim/opendkim-testmsg.c | 19 ++++++++-- 5 files changed, 85 insertions(+), 14 deletions(-) diff --git a/opendkim/opendkim-genkey.8.in b/opendkim/opendkim-genkey.8.in index 8d9fb0d0..4e32adcd 100644 --- a/opendkim/opendkim-genkey.8.in +++ b/opendkim/opendkim-genkey.8.in @@ -50,6 +50,7 @@ Instructs the tool to change to the named prior to creating files. By default the current directory is used. .TP +.I \-e .I \-\-ed25519 generate a ed25519 key. diff --git a/opendkim/opendkim-genkey.in b/opendkim/opendkim-genkey.in index 090d1f32..a4aba7d3 100644 --- a/opendkim/opendkim-genkey.in +++ b/opendkim/opendkim-genkey.in @@ -91,7 +91,7 @@ my $opt_retval = &Getopt::Long::GetOptions('a|append-domain!' => \$append, 'b|bits=i' => \$bits, 'D|directory=s' => \$outdir, 'd|domain=s' => \$domain, - 'ed25519' => \$ed25519, + 'e|ed25519' => \$ed25519, 'h|hash-algorithms=s' => \$hashalgs, 'help!' => \$helponly, 'n|note=s' => \$note, @@ -130,10 +130,10 @@ umask(077); if ($ed25519) { - $status = system("openssl version 2>/dev/null | grep --silent --ignore-case '^openssl 1.1.1'"); + $status = system("openssl genpkey -algorithm ed25519 > /dev/null 2>&1"); if ($status != 0) { - print STDERR "$progname: OpenSSL 1.1.1 is required for ED25519 support\n"; + print STDERR "$progname: At least OpenSSL 1.1.1 is required for ED25519 support\n"; exit(1); } } diff --git a/opendkim/opendkim-genzone.c b/opendkim/opendkim-genzone.c index 48c9523b..742a531d 100644 --- a/opendkim/opendkim-genzone.c +++ b/opendkim/opendkim-genzone.c @@ -51,7 +51,7 @@ /* definitions */ #define BUFRSZ 1024 -#define CMDLINEOPTS "C:d:DE:Fo:N:r:R:sSt:T:uvx:" +#define CMDLINEOPTS "C:d:DME:Fo:N:r:R:sSt:T:uvx:" #define DEFCONFFILE CONFIG_BASE "/opendkim.conf" #define DEFEXPIRE 604800 #define DEFREFRESH 10800 @@ -194,6 +194,7 @@ usage(void) "\t-D \tinclude '._domainkey' suffix\n" "\t-E secs \tuse specified expiration time in SOA\n" "\t-F \tinclude '._domainkey' suffix and domainname\n" + "\t-M \trestricts the keys for use in e-mail signing only\n" "\t-o file \toutput file\n" "\t-N ns[,...] \tlist NS records\n" "\t-r secs \tuse specified refresh time in SOA\n" @@ -229,6 +230,7 @@ main(int argc, char **argv) _Bool fqdnsuffix = FALSE; _Bool subdomains = FALSE; _Bool writesoa = FALSE; + _Bool mailrestrict = FALSE; int c; int status; int verbose = 0; @@ -273,6 +275,8 @@ main(int argc, char **argv) char keydata[LARGEBUFRSZ]; char derdata[LARGEBUFRSZ]; struct dkimf_db_data dbd[3]; + _Bool key_is_ed25519 = FALSE; + int ed25519_keyskip; progname = (p = strrchr(argv[0], '/')) == NULL ? argv[0] : p + 1; @@ -307,6 +311,10 @@ main(int argc, char **argv) fqdnsuffix = TRUE; break; + case 'M': + mailrestrict = TRUE; + break; + case 'N': nameservers = strdup(optarg); break; @@ -729,6 +737,21 @@ main(int argc, char **argv) return -1; } + switch (gnutls_x509_privkey_get_pk_algorithm(xprivkey)) + { + case GNUTLS_PK_RSA: + key_is_ed25519 = FALSE; + break; + case GNUTLS_PK_EDDSA_ED25519: + key_is_ed25519 = TRUE; + break; + default: + fprintf(stderr, "%s: key for '%s' invalid algorithm\n", + progname, keyname); + (void) gnutls_x509_privkey_deinit(xprivkey); + return -1; + } + status = gnutls_privkey_init(&privkey); if (status != GNUTLS_E_SUCCESS) { @@ -835,9 +858,17 @@ main(int argc, char **argv) } } - if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA) + switch (EVP_PKEY_base_id(pkey)) { - fprintf(stderr, "%s: not an RSA key\n", progname); + case EVP_PKEY_RSA: + key_is_ed25519 = FALSE; + break; + case EVP_PKEY_ED25519: + key_is_ed25519 = TRUE; + break; + default: + fprintf(stderr, "%s: key for '%s' invalid algorithm\n", + progname, keyname); (void) dkimf_db_close(db); (void) BIO_free(private); (void) EVP_PKEY_free(pkey); @@ -866,33 +897,39 @@ main(int argc, char **argv) fprintf(out, "zone %s\n", domain); snprintf(tmpbuf, sizeof tmpbuf, - "update add %s%s%s%s%s %d TXT \"", + "update add %s%s%s%s%s %d TXT \"v=DKIM1\\;k=%s\\;%sp=", selector, suffix ? DKIMZONE : "", fqdnsuffix ? "." : "", fqdnsuffix ? domain : "", fqdnsuffix ? "." : "", - ttl == -1 ? defttl : ttl); + ttl == -1 ? defttl : ttl, + key_is_ed25519 ? "ed25519" : "rsa", + mailrestrict ? "s=email\\;" : ""); } else { if (ttl == -1) { snprintf(tmpbuf, sizeof tmpbuf, - "%s%s%s%s%s\tIN\tTXT\t( \"v=DKIM1; k=rsa; p=", + "%s%s%s%s%s\tIN\tTXT\t( \"v=DKIM1\\;k=%s\\;%sp=", selector, suffix ? DKIMZONE : "", fqdnsuffix ? "." : "", fqdnsuffix ? domain : "", - fqdnsuffix ? "." : ""); + fqdnsuffix ? "." : "", + key_is_ed25519 ? "ed25519" : "rsa", + mailrestrict ? "s=email\\;" : ""); } else { snprintf(tmpbuf, sizeof tmpbuf, - "%s%s%s%s%s\t%d\tIN\tTXT\t( \"v=DKIM1; k=rsa; p=", + "%s%s%s%s%s\t%d\tIN\tTXT\t( \"v=DKIM1\\;k=%s\\;%sp=", selector, suffix ? DKIMZONE : "", fqdnsuffix ? "." : "", fqdnsuffix ? domain : "", fqdnsuffix ? "." : "", - ttl); + ttl, + key_is_ed25519 ? "ed25519" : "rsa", + mailrestrict ? "s=email\\;" : ""); } } @@ -905,6 +942,11 @@ main(int argc, char **argv) seenlf = FALSE; + /* Per RFC8463 the ed25519 key in the DNS TXT record doesn't have the ASN */ + /* prefix that RSA keys have. The base64-encoded 12-byte ASN prefix is the */ + /* first 16 characters in the PEM "PRIVATE KEY" key value. Skip over it. */ + ed25519_keyskip = 16; + #ifdef USE_GNUTLS if (gnutls_pubkey_init(&pubkey) != GNUTLS_E_SUCCESS) { @@ -957,6 +999,10 @@ main(int argc, char **argv) { continue; } + else if (key_is_ed25519 && ed25519_keyskip > 0) + { + ed25519_keyskip--; + } else if (isascii(*p) && !isspace(*p)) { if (olen >= MARGIN && !nsupdate) diff --git a/opendkim/opendkim-testmsg.8.in b/opendkim/opendkim-testmsg.8.in index 2dd36184..209cc95c 100644 --- a/opendkim/opendkim-testmsg.8.in +++ b/opendkim/opendkim-testmsg.8.in @@ -23,6 +23,15 @@ verified. If some but not all are present, an error is returned. .SH OPTIONS .TP +.I -1 +In signing mode, generate an RSA-SHA1 signature. The key must be an RSA key. +.TP +.I -2 +In signing mode, generate an RSA-SHA256 signature. The key must be an RSA key. (default) +.TP +.I -e +In signing mode, generate an ED25519-SHA256 signature. The key must be an ED25519 key. +.TP .I -C If specified, the signature header field generated in signing mode will be line-terminated with carriage-return line-feed, instead of just line-feed. diff --git a/opendkim/opendkim-testmsg.c b/opendkim/opendkim-testmsg.c index beba12a9..d0802b3d 100644 --- a/opendkim/opendkim-testmsg.c +++ b/opendkim/opendkim-testmsg.c @@ -32,7 +32,7 @@ #define BUFRSZ 1024 #define DEFTMPDIR "/tmp" -#define CMDLINEOPTS "Cd:Kk:s:t:" +#define CMDLINEOPTS "12eCd:Kk:s:t:" #define STRORNULL(x) ((x) == NULL ? "(null)" : (x)) #define TMPTEMPLATE "dkimXXXXXX" @@ -57,6 +57,9 @@ usage(void) { fprintf(stderr, "%s: usage: %s [options]\nValid options:\n" + "\t-1 \tsign with RSA-SHA1\n" + "\t-2 \tsign with RSA-SHA256 (default)\n" + "\t-e \tsign with Ed25519-SHA256\n" "\t-C \tpreserve CRLFs\n" "\t-d domain \tset signing domain\n" "\t-K \tkeep temporary files\n" @@ -120,7 +123,7 @@ main(int argc, char **argv) ssize_t rlen; ssize_t wlen; ssize_t l = (ssize_t) -1; - dkim_alg_t sa = DKIM_SIGN_RSASHA1; + dkim_alg_t sa = DKIM_SIGN_RSASHA256; dkim_canon_t bc = DKIM_CANON_SIMPLE; dkim_canon_t hc = DKIM_CANON_RELAXED; DKIM_LIB *lib; @@ -140,6 +143,18 @@ main(int argc, char **argv) { switch (c) { + case '1': + sa = DKIM_SIGN_RSASHA1; + break; + + case '2': + sa = DKIM_SIGN_RSASHA256; + break; + + case 'e': + sa = DKIM_SIGN_ED25519SHA256; + break; + case 'C': keepcrlf = TRUE; break; From e085464e65a2c639a909f18c4cff73b411d8a751 Mon Sep 17 00:00:00 2001 From: GimmeHardware <23285878+jcastle-gh@users.noreply.github.com> Date: Mon, 24 Mar 2025 17:31:27 -0400 Subject: [PATCH 3/3] Fix formatting in the opendkim-genkey.8.in man page change. --- opendkim/opendkim-genkey.8.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/opendkim/opendkim-genkey.8.in b/opendkim/opendkim-genkey.8.in index 4e32adcd..96e773cd 100644 --- a/opendkim/opendkim-genkey.8.in +++ b/opendkim/opendkim-genkey.8.in @@ -51,8 +51,8 @@ prior to creating files. By default the current directory is used. .TP .I \-e -.I \-\-ed25519 -generate a ed25519 key. +(\-\-ed25519) +Generate an ed25519 key. .TP .I \-h algorithms