diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 4e4a6cde..7db5687f 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -16,6 +16,8 @@ release, and a summary of the changes in that release. Upgrade to OpenSSL 3. Using non-deprecated APIs in OpenSSL 3, but already present in OpenSSL 1.1.1. Patch by David Bürgin (PR #162) + Extend KeyTable to specify signing algorithm. + Patch from Yasuhito Futatsuki. Fix dkimf_db_nextpunct() so it doesn't incorrectly identify an encoded hex digit as a value delimiter. Fix issue #8: The password file critical section isn't big enough. diff --git a/opendkim/opendkim-testkey.c b/opendkim/opendkim-testkey.c index fc1df4af..dc9667d8 100644 --- a/opendkim/opendkim-testkey.c +++ b/opendkim/opendkim-testkey.c @@ -236,6 +236,8 @@ main(int argc, char **argv) char domain[BUFRSZ]; char selector[BUFRSZ]; char keypath[MAXBUFRSZ]; + char signalgstr[BUFRSZ]; + dkim_alg_t signalg; progname = (p = strrchr(argv[0], '/')) == NULL ? argv[0] : p + 1; @@ -464,7 +466,7 @@ main(int argc, char **argv) size_t keylen; DKIMF_DB db; char keyname[BUFRSZ + 1]; - struct dkimf_db_data dbd[3]; + struct dkimf_db_data dbd[4]; memset(dbd, '\0', sizeof dbd); @@ -491,6 +493,7 @@ main(int argc, char **argv) memset(domain, '\0', sizeof domain); memset(selector, '\0', sizeof selector); memset(keypath, '\0', sizeof keypath); + memset(signalgstr, '\0', sizeof signalgstr); dbd[0].dbdata_buffer = domain; dbd[0].dbdata_buflen = sizeof domain; @@ -498,11 +501,14 @@ main(int argc, char **argv) dbd[1].dbdata_buflen = sizeof selector; dbd[2].dbdata_buffer = keypath; dbd[2].dbdata_buflen = sizeof keypath; + dbd[3].dbdata_buffer = signalgstr; + dbd[3].dbdata_buflen = sizeof signalgstr; + dbd[3].dbdata_flags = DKIMF_DB_DATA_OPTIONAL; keylen = sizeof keyname; status = dkimf_db_walk(db, c == 0, keyname, &keylen, - dbd, 3); + dbd, 4); if (status == -1) { fprintf(stderr, @@ -524,6 +530,27 @@ main(int argc, char **argv) progname, c, keyname); } + if (signalgstr[0] != '\0') + { + signalg = (dkim_alg_t)dkim_name_to_code(dkim_table_algorithms, + signalgstr); + if (signalg == -1) + { + fprintf(stderr, + "%s: unknown sign algorithm " + "'%s' for key '%s'\n", + progname, signalgstr, keyname); + return 1; + } + + if (verbose > 1) + { + fprintf(stderr, + "%s: key '%s': sign algorithm is '%s'\n", + progname, keyname, signalgstr); + } + } + if (keypath[0] == '/' || strncmp(keypath, "./", 2) == 0 || strncmp(keypath, "../", 3) == 0) @@ -572,6 +599,9 @@ main(int argc, char **argv) progname, keyname); } + /* To do: check consistency of the key and algorithm. + It is needed to extend dkim_test_key() for it */ + dnssec = DKIM_DNSSEC_UNKNOWN; status = dkim_test_key(lib, selector, domain, diff --git a/opendkim/opendkim.c b/opendkim/opendkim.c index 5fd732a1..fb3a270b 100644 --- a/opendkim/opendkim.c +++ b/opendkim/opendkim.c @@ -4919,10 +4919,12 @@ dkimf_add_signrequest(struct msgctx *dfc, DKIMF_DB keytable, char *keyname, _Bool found = FALSE; size_t keydatasz = 0; struct signreq *new; - struct dkimf_db_data dbd[3]; + struct dkimf_db_data dbd[4]; char keydata[MAXBUFRSZ + 1]; char domain[DKIM_MAXHOSTNAMELEN + 1]; char selector[BUFRSZ + 1]; + char signalgstr[BUFRSZ + 1]; + dkim_alg_t signalg = DKIM_SIGN_DEFAULT; char err[BUFRSZ + 1]; assert(dfc != NULL); @@ -4948,6 +4950,7 @@ dkimf_add_signrequest(struct msgctx *dfc, DKIMF_DB keytable, char *keyname, memset(domain, '\0', sizeof domain); memset(selector, '\0', sizeof selector); memset(keydata, '\0', sizeof keydata); + memset(signalgstr, '\0', sizeof signalgstr); dbd[0].dbdata_buffer = domain; dbd[0].dbdata_buflen = sizeof domain - 1; @@ -4958,9 +4961,12 @@ dkimf_add_signrequest(struct msgctx *dfc, DKIMF_DB keytable, char *keyname, dbd[2].dbdata_buffer = keydata; dbd[2].dbdata_buflen = sizeof keydata - 1; dbd[2].dbdata_flags = DKIMF_DB_DATA_OPTIONAL; + dbd[3].dbdata_buffer = signalgstr; + dbd[3].dbdata_buflen = sizeof signalgstr - 1; + dbd[3].dbdata_flags = DKIMF_DB_DATA_OPTIONAL; if (dkimf_db_get(keytable, keyname, strlen(keyname), - dbd, 3, &found) != 0) + dbd, 4, &found) != 0) { memset(err, '\0', sizeof err); (void) dkimf_db_strerror(keytable, err, sizeof err); @@ -5064,6 +5070,24 @@ dkimf_add_signrequest(struct msgctx *dfc, DKIMF_DB keytable, char *keyname, if (curconf->conf_safekeys) return 2; } + + if (dbd[3].dbdata_buflen > 0 && signalgstr[0] != '\0') + { + signalg = (dkim_alg_t)dkim_name_to_code(dkim_table_algorithms, + signalgstr); + if (signalg == -1) + { + if (dolog) + { + syslog(LOG_ERR, + "KeyTable entry for '%s' corrupt:" + " invalid sign algorithm %s", + keyname, signalgstr); + } + + return 2; + } + } } new = malloc(sizeof *new); @@ -5076,6 +5100,7 @@ dkimf_add_signrequest(struct msgctx *dfc, DKIMF_DB keytable, char *keyname, new->srq_selector = NULL; new->srq_keydata = NULL; new->srq_signlen = signlen; + new->srq_signalg = signalg; if (signer != NULL && signer[0] != '\0') new->srq_signer = (u_char *) strdup(signer); else @@ -8312,11 +8337,12 @@ dkimf_config_load(struct config *data, struct dkimf_config *conf, { _Bool first = TRUE; _Bool found; - struct dkimf_db_data dbd[3]; + struct dkimf_db_data dbd[4]; char keyname[BUFRSZ + 1]; char domain[BUFRSZ + 1]; char selector[BUFRSZ + 1]; char keydata[BUFRSZ + 1]; + char signalgstr[BUFRSZ + 1]; char signer[BUFRSZ + 1]; dbd[0].dbdata_flags = 0; @@ -8344,10 +8370,13 @@ dkimf_config_load(struct config *data, struct dkimf_config *conf, dbd[2].dbdata_buffer = keydata; dbd[2].dbdata_buflen = sizeof keydata - 1; dbd[2].dbdata_flags = DKIMF_DB_DATA_BINARY; + dbd[3].dbdata_buffer = signalgstr; + dbd[3].dbdata_buflen = sizeof signalgstr - 1; + dbd[3].dbdata_flags = DKIMF_DB_DATA_OPTIONAL; if (dkimf_db_get(conf->conf_keytabledb, keyname, strlen(keyname), - dbd, 3, &found) != 0 || + dbd, 4, &found) != 0 || !found || dbd[0].dbdata_buflen == 0 || dbd[1].dbdata_buflen == 0 || @@ -12604,6 +12633,7 @@ mlfi_eoh(SMFICTX *ctx) for (sr = dfc->mctx_srhead; sr != NULL; sr = sr->srq_next) { + dkim_alg_t signalg; #ifdef _FFR_CONDITIONAL if (sr->srq_dkim != NULL) continue; @@ -12630,13 +12660,15 @@ mlfi_eoh(SMFICTX *ctx) selector = conf->conf_selector; } + signalg = (sr->srq_signalg == DKIM_SIGN_DEFAULT)? + dfc->mctx_signalg:sr->srq_signalg; sr->srq_dkim = dkim_sign(conf->conf_libopendkim, dfc->mctx_jobid, NULL, keydata, selector, sdomain, dfc->mctx_hdrcanon, dfc->mctx_bodycanon, - dfc->mctx_signalg, + signalg, signlen, &status); if (sr->srq_dkim == NULL || status != DKIM_STAT_OK) diff --git a/opendkim/opendkim.conf.5.in b/opendkim/opendkim.conf.5.in index 21da18f5..0bd6f0f1 100644 --- a/opendkim/opendkim.conf.5.in +++ b/opendkim/opendkim.conf.5.in @@ -349,7 +349,8 @@ If present, overrides any setting in the configuration file. The data set named here maps each key name to three values: (a) the name of the domain to use in the signature's "d=" value; (b) the name of the selector to use in the signature's "s=" value; -and (c) either a private key or a path to a file containing a private key. +and (c) either a private key or a path to a file containing a private key; +(d) (optional) signing algorithm to use with this key. If the first value consists solely of a percent sign ("%") character, it will be replaced by the apparent domain of the sender when generating a signature. @@ -357,7 +358,13 @@ If the third value starts with a slash ("/") character, or "./" or "../", then it is presumed to refer to a file from which the private key should be read, otherwise it is itself a PEM-encoded private key or a base64-encoded DER private key; a "%" in the third value in this case will be replaced by -the apparent domain name of the sender. The +the apparent domain name of the sender. The fourth field should be one +of supported siginig algorithms (see +.I SignatureAlgorithm +below). +If it is omited, the algorithm specified in +.I SignatureAlgorithm +is used for the key. .I SigningTable (see below) is used to select records from this table to be used to add signatures based on the message sender. diff --git a/opendkim/opendkim.h b/opendkim/opendkim.h index e3637b10..437ec946 100644 --- a/opendkim/opendkim.h +++ b/opendkim/opendkim.h @@ -120,6 +120,7 @@ struct signreq u_char * srq_domain; u_char * srq_selector; u_char * srq_signer; + dkim_alg_t srq_signalg; DKIM * srq_dkim; struct signreq * srq_next; };