diff --git a/CHANGES b/CHANGES index a02274925a..f6a22810e1 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,8 @@ +2671. [bug] Add support for PKCS#11 providers not returning + the public exponent in RSA private keys + (OpenCryptoki for instance) in + dnssec-keyfromlabel. [RT #19294] + 2670. [bug] Unexpected connect failures failed to log enough information to be useful. [RT #20205] diff --git a/bin/dnssec/dnssec-keyfromlabel.c b/bin/dnssec/dnssec-keyfromlabel.c index 56165fd60f..4f93adccf7 100644 --- a/bin/dnssec/dnssec-keyfromlabel.c +++ b/bin/dnssec/dnssec-keyfromlabel.c @@ -14,12 +14,13 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dnssec-keyfromlabel.c,v 1.11 2009/09/03 13:43:52 fdupont Exp $ */ +/* $Id: dnssec-keyfromlabel.c,v 1.12 2009/09/07 12:54:59 fdupont Exp $ */ /*! \file */ #include +#include #include #include @@ -58,25 +59,32 @@ usage(void) { fprintf(stderr, "Version: %s\n", VERSION); fprintf(stderr, "Required options:\n"); fprintf(stderr, " -a algorithm: %s\n", algs); - fprintf(stderr, " -l label: label of the key\n"); + fprintf(stderr, " -l label: label of the keys\n"); fprintf(stderr, " name: owner of the key\n"); fprintf(stderr, "Other options:\n"); - fprintf(stderr, " -n nametype: ZONE | HOST | ENTITY | USER | OTHER\n"); - fprintf(stderr, " (DNSKEY generation defaults to ZONE\n"); fprintf(stderr, " -c (default: IN)\n"); - fprintf(stderr, " -f keyflag (KSK or REVOKE)\n"); + fprintf(stderr, " -f keyflag: KSK | REVOKE\n"); fprintf(stderr, " -K directory: directory in which to place " "key files\n"); + fprintf(stderr, " -k : generate a TYPE=KEY key\n"); + fprintf(stderr, " -n nametype: ZONE | HOST | ENTITY | USER | OTHER\n"); + fprintf(stderr, " (DNSKEY generation defaults to ZONE\n"); + fprintf(stderr, " -p : default: 3 [dnssec]\n"); fprintf(stderr, " -t : " "AUTHCONF | NOAUTHCONF | NOAUTH | NOCONF " "(default: AUTHCONF)\n"); - fprintf(stderr, " -p : " - "default: 3 [dnssec]\n"); fprintf(stderr, " -v \n"); - fprintf(stderr, " -k : generate a TYPE=KEY key\n"); + fprintf(stderr, "Date options:\n"); + fprintf(stderr, " -P date/[+-]offset: set key publication date\n"); + fprintf(stderr, " -A date/[+-]offset: set key activation date\n"); + fprintf(stderr, " -R date/[+-]offset: set key revocation date\n"); + fprintf(stderr, " -U date/[+-]offset: set key unpublication date\n"); + fprintf(stderr, " -D date/[+-]offset: set key deletion date\n"); + fprintf(stderr, " -C: generate a backward-compatible key, omitting" + " dates\n"); fprintf(stderr, "Output:\n"); fprintf(stderr, " K++.key, " - "K++.private\n"); + "K++.private\n"); exit (-1); } @@ -84,15 +92,15 @@ usage(void) { int main(int argc, char **argv) { char *algname = NULL, *nametype = NULL, *type = NULL; - char *directory = NULL; + const char *directory = NULL; char *classname = NULL; char *endp; dst_key_t *key = NULL, *oldkey = NULL; dns_fixedname_t fname; dns_name_t *name; - isc_uint16_t flags = 0, ksk = 0, revoke = 0; + isc_uint16_t flags = 0, kskflag = 0, revflag = 0; dns_secalg_t alg; - isc_boolean_t null_key = ISC_FALSE; + isc_boolean_t oldstyle = ISC_FALSE; isc_mem_t *mctx = NULL; int ch; int protocol = -1, signatory = 0; @@ -104,7 +112,16 @@ main(int argc, char **argv) { isc_entropy_t *ectx = NULL; dns_rdataclass_t rdclass; int options = DST_TYPE_PRIVATE | DST_TYPE_PUBLIC; - char *label = NULL; + char *label = NULL, *engine = NULL; + isc_stdtime_t publish = 0, activate = 0, revoke = 0; + isc_stdtime_t unpublish = 0, delete = 0; + isc_stdtime_t now; + isc_boolean_t setpub = ISC_FALSE, setact = ISC_FALSE; + isc_boolean_t setrev = ISC_FALSE, setunpub = ISC_FALSE; + isc_boolean_t setdel = ISC_FALSE; + isc_boolean_t unsetpub = ISC_FALSE, unsetact = ISC_FALSE; + isc_boolean_t unsetrev = ISC_FALSE, unsetunpub = ISC_FALSE; + isc_boolean_t unsetdel = ISC_FALSE; if (argc == 1) usage(); @@ -115,22 +132,26 @@ main(int argc, char **argv) { isc_commandline_errprint = ISC_FALSE; + isc_stdtime_get(&now); + while ((ch = isc_commandline_parse(argc, argv, - "a:c:f:K:kl:n:p:t:v:Fh")) != -1) + "a:Cc:f:K:kl:n:p:t:v:FhP:A:R:U:D:")) != -1) { switch (ch) { case 'a': algname = isc_commandline_argument; break; + case 'C': + oldstyle = ISC_TRUE; + break; case 'c': classname = isc_commandline_argument; break; case 'f': - if (strcasecmp(isc_commandline_argument, "KSK") == 0) - ksk = DNS_KEYFLAG_KSK; - else if (strcasecmp(isc_commandline_argument, - "REVOKE") == 0) - revoke = DNS_KEYFLAG_REVOKE; + if (toupper(isc_commandline_argument[0]) == 'K') + kskflag = DNS_KEYFLAG_KSK; + else if (toupper(isc_commandline_argument[0]) == 'R') + revflag = DNS_KEYFLAG_REVOKE; else fatal("unknown flag '%s'", isc_commandline_argument); @@ -161,6 +182,66 @@ main(int argc, char **argv) { if (*endp != '\0') fatal("-v must be followed by a number"); break; + case 'P': + if (setpub || unsetpub) + fatal("-P specified more than once"); + + if (strcasecmp(isc_commandline_argument, "none")) { + setpub = ISC_TRUE; + publish = strtotime(isc_commandline_argument, + now, now); + } else { + unsetpub = ISC_TRUE; + } + break; + case 'A': + if (setact || unsetact) + fatal("-A specified more than once"); + + if (strcasecmp(isc_commandline_argument, "none")) { + setact = ISC_TRUE; + activate = strtotime(isc_commandline_argument, + now, now); + } else { + unsetact = ISC_TRUE; + } + break; + case 'R': + if (setrev || unsetrev) + fatal("-R specified more than once"); + + if (strcasecmp(isc_commandline_argument, "none")) { + setrev = ISC_TRUE; + revoke = strtotime(isc_commandline_argument, + now, now); + } else { + unsetrev = ISC_TRUE; + } + break; + case 'U': + if (setunpub || unsetunpub) + fatal("-U specified more than once"); + + if (strcasecmp(isc_commandline_argument, "none")) { + setunpub = ISC_TRUE; + unpublish = strtotime(isc_commandline_argument, + now, now); + } else { + unsetunpub = ISC_TRUE; + } + break; + case 'D': + if (setdel || unsetdel) + fatal("-D specified more than once"); + + if (strcasecmp(isc_commandline_argument, "none")) { + setdel = ISC_TRUE; + delete = strtotime(isc_commandline_argument, + now, now); + } else { + unsetdel = ISC_TRUE; + } + break; case 'F': /* Reserved for FIPS mode */ /* FALLTHROUGH */ @@ -245,11 +326,14 @@ main(int argc, char **argv) { rdclass = strtoclass(classname); + if (directory == NULL) + directory = "."; + if ((options & DST_TYPE_KEY) != 0) /* KEY */ flags |= signatory; else if ((flags & DNS_KEYOWNER_ZONE) != 0) { /* DNSKEY */ - flags |= ksk; - flags |= revoke; + flags |= kskflag; + flags |= revflag; } if (protocol == -1) @@ -278,14 +362,11 @@ main(int argc, char **argv) { fatal("invalid key name %s: %s", argv[isc_commandline_index], isc_result_totext(ret)); - if ((flags & DNS_KEYFLAG_TYPEMASK) == DNS_KEYTYPE_NOKEY) - null_key = ISC_TRUE; - isc_buffer_init(&buf, filename, sizeof(filename) - 1); /* associate the key */ ret = dst_key_fromlabel(name, alg, flags, protocol, - rdclass, "", label, NULL, mctx, &key); + rdclass, engine, label, NULL, mctx, &key); isc_entropy_stopcallbacksources(ectx); if (ret != ISC_R_SUCCESS) { @@ -293,16 +374,43 @@ main(int argc, char **argv) { char algstr[ALG_FORMATSIZE]; dns_name_format(name, namestr, sizeof(namestr)); alg_format(alg, algstr, sizeof(algstr)); - fatal("failed to generate key %s/%s: %s\n", + fatal("failed to get key %s/%s: %s\n", namestr, algstr, isc_result_totext(ret)); exit(-1); } + /* + * Set key timing metadata (unless using -C) + */ + if (!oldstyle) { + dst_key_settime(key, DST_TIME_CREATED, now); + + if (setpub) + dst_key_settime(key, DST_TIME_PUBLISH, publish); + if (setact) + dst_key_settime(key, DST_TIME_ACTIVATE, activate); + if (setrev) + dst_key_settime(key, DST_TIME_REVOKE, revoke); + if (setunpub) + dst_key_settime(key, DST_TIME_UNPUBLISH, unpublish); + if (setdel) + dst_key_settime(key, DST_TIME_DELETE, delete); + } else { + if (setpub || setact || setrev || setunpub || + setdel || unsetpub || unsetact || + unsetrev || unsetunpub || unsetdel) + fatal("cannot use -C together with " + "-P, -A, -R, -U, or -D options"); + /* + * Compatibility mode: Private-key-format + * should be set to 1.2. + */ + dst_key_setprivateformat(key, 1, 2); + } + /* * Try to read a key with the same name, alg and id from disk. - * If there is one we must continue generating a new one - * unless we were asked to generate a null key, in which - * case we return failure. + * If there is one we must return failure. */ ret = dst_key_fromfile(name, dst_key_id(key), alg, DST_TYPE_PRIVATE, directory, mctx, &oldkey); @@ -310,10 +418,7 @@ main(int argc, char **argv) { if (ret == ISC_R_SUCCESS) { isc_buffer_clear(&buf); ret = dst_key_buildfilename(key, 0, directory, &buf); - fprintf(stderr, "%s: %s already exists\n", - program, filename); - dst_key_free(&key); - exit (1); + fatal("%s: %s already exists\n", program, filename); } ret = dst_key_tofile(key, options, directory); @@ -325,7 +430,7 @@ main(int argc, char **argv) { } isc_buffer_clear(&buf); - ret = dst_key_buildfilename(key, 0, directory, &buf); + ret = dst_key_buildfilename(key, 0, NULL, &buf); printf("%s\n", filename); dst_key_free(&key); diff --git a/bin/dnssec/dnssec-keyfromlabel.docbook b/bin/dnssec/dnssec-keyfromlabel.docbook index 1e478d93a3..4beb25b9fe 100644 --- a/bin/dnssec/dnssec-keyfromlabel.docbook +++ b/bin/dnssec/dnssec-keyfromlabel.docbook @@ -17,7 +17,7 @@ - PERFORMANCE OF THIS SOFTWARE. --> - + February 8, 2008 @@ -47,13 +47,18 @@ dnssec-keyfromlabel -a algorithm -l label + + + + + name @@ -66,6 +71,11 @@ key files for DNSSEC (Secure DNS), as defined in RFC 2535 and RFC 4034. + + The of the key is specified on the command + line. This must match the name of the zone for which the key is + being generated. + @@ -77,8 +87,8 @@ Selects the cryptographic algorithm. The value of - must be one of RSAMD5 (RSA) - or RSASHA1, DSA, NSEC3RSASHA1, NSEC3DSA or DH (Diffie Hellman). + must be one of RSAMD5 (RSA), + RSASHA1, DSA, NSEC3RSASHA1, NSEC3DSA or DH (Diffie Hellman). These values are case insensitive. @@ -110,8 +120,22 @@ zone key (KEY/DNSKEY)), HOST or ENTITY (for a key associated with a host (KEY)), USER (for a key associated with a user(KEY)) or OTHER (DNSKEY). - These values are - case insensitive. + These values are case insensitive. + + + + + + -C + + + Compatibility mode: generates an old-style key, without + any metadata. By default, dnssec-keyfromlabel + will include the key's creation date in the metadata stored + with the private key, and other dates may be set there as well + (publication date, activation date, etc). Keys that include + this data may be incompatible with older versions of BIND; the + option suppresses them. @@ -131,7 +155,7 @@ Set the specified flag in the flag field of the KEY/DNSKEY record. - The only recognized flag is KSK (Key Signing Key) DNSKEY. + The only recognized flags are KSK (Key Signing Key) and REVOKE. @@ -141,7 +165,7 @@ Prints a short summary of the options and arguments to - dnssec-keygen. + dnssec-keyfromlabel. @@ -168,7 +192,7 @@ -p protocol - Sets the protocol value for the generated key. The protocol + Sets the protocol value for the key. The protocol is a number between 0 and 255. The default is 3 (DNSSEC). Other possible values for this argument are listed in RFC 2535 and its successors. @@ -200,6 +224,80 @@ + + TIMING OPTIONS + + + Dates can be expressed in the format YYYYMMDD or YYYYMMDDHHMMSS. + If the argument begins with a '+' or '-', it is interpreted as + an offset from the present time. For convenience, if such an offset + is followed by one of the suffixes 'y', 'mo', 'w', 'd', 'h', or 'mi', + then the offset is computed in years (defined as 365 24-hour days, + ignoring leap years), months (defined as 30 24-hour days), weeks, + days, hours, or minutes, respectively. Without a suffix, the offset + is computed in seconds. + + + + + -P date/offset + + + Sets the date on which a key is to be published to the zone. + After that date, the key will be included in the zone but will + not be used to sign it. + + + + + + -A date/offset + + + Sets the date on which the key is to be activated. After that + date, the key will be included and the zone and used to sign + it. + + + + + + -R date/offset + + + Sets the date on which the key is to be revoked. After that + date, the key will be flagged as revoked. It will be included + in the zone and will be used to sign it. + + + + + + -U date/offset + + + Sets the date on which the key is to be unpublished. After that + date, the key will no longer be included in the zone, but it + may remain in the key repository. + + + + + + -D date/offset + + + Sets the date on which the key is to be deleted. After that + date, the key can be removed from the key repository. + NOTE: Keys are not currently deleted automatically; this field + is included for informational purposes and for future + development. + + + + + + GENERATED KEY FILES @@ -216,8 +314,7 @@ aaa is the numeric representation - of the - algorithm. + of the algorithm. @@ -231,8 +328,7 @@ on the printed string. Knnnn.+aaa+iiiii.key contains the public key, and Knnnn.+aaa+iiiii.private contains the - private - key. + private key. The .key file contains a DNS KEY record @@ -241,8 +337,8 @@ statement). - The .private file contains algorithm - specific + The .private file contains + algorithm-specific fields. For obvious security reasons, this file does not have general read permission. diff --git a/bin/dnssec/dnssec-keygen.c b/bin/dnssec/dnssec-keygen.c index affb064f49..c5e696eca3 100644 --- a/bin/dnssec/dnssec-keygen.c +++ b/bin/dnssec/dnssec-keygen.c @@ -29,7 +29,7 @@ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dnssec-keygen.c,v 1.93 2009/09/04 16:57:22 each Exp $ */ +/* $Id: dnssec-keygen.c,v 1.94 2009/09/07 12:54:59 fdupont Exp $ */ /*! \file */ @@ -699,8 +699,8 @@ main(int argc, char **argv) { /* * Try to read a key with the same name, alg and id from disk. - * If there is one we must continue generating a new one - * unless we were asked to generate a null key, in which + * If there is one we must continue generating a different + * key unless we were asked to generate a null key, in which * case we return failure. */ ret = dst_key_fromfile(name, dst_key_id(key), alg, diff --git a/lib/dns/opensslrsa_link.c b/lib/dns/opensslrsa_link.c index 395dfdfc7f..828ca3bd6f 100644 --- a/lib/dns/opensslrsa_link.c +++ b/lib/dns/opensslrsa_link.c @@ -17,7 +17,7 @@ /* * Principal Author: Brian Wellington - * $Id: opensslrsa_link.c,v 1.26 2009/09/03 04:09:58 marka Exp $ + * $Id: opensslrsa_link.c,v 1.27 2009/09/07 12:54:59 fdupont Exp $ */ #ifdef OPENSSL #ifndef USE_EVP @@ -800,7 +800,7 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { RSA *rsa = NULL, *pubrsa = NULL; ENGINE *e = NULL; isc_mem_t *mctx = key->mctx; - const char *name = NULL, *label = NULL; + const char *engine = NULL, *label = NULL; EVP_PKEY *pkey = NULL; #if USE_EVP @@ -821,7 +821,7 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { for (i = 0; i < priv.nelements; i++) { switch (priv.elements[i].tag) { case TAG_RSA_ENGINE: - name = (char *)priv.elements[i].data; + engine = (char *)priv.elements[i].data; break; case TAG_RSA_LABEL: label = (char *)priv.elements[i].data; @@ -834,10 +834,10 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { * Is this key is stored in a HSM? * See if we can fetch it. */ - if (name != NULL || label != NULL) { - INSIST(name != NULL); - INSIST(label != NULL); - e = dst__openssl_getengine(name); + if (label != NULL) { + if (engine == NULL) + DST_RET(DST_R_NOENGINE); + e = dst__openssl_getengine(engine); if (e == NULL) DST_RET(DST_R_NOENGINE); pkey = ENGINE_load_private_key(e, label, NULL, NULL); @@ -845,7 +845,7 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { /* ERR_print_errors_fp(stderr); */ DST_RET(ISC_R_NOTFOUND); } - key->engine = isc_mem_strdup(key->mctx, name); + key->engine = isc_mem_strdup(key->mctx, engine); if (key->engine == NULL) DST_RET(ISC_R_NOMEMORY); key->label = isc_mem_strdup(key->mctx, label); @@ -856,9 +856,12 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { DST_RET(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); if (rsa_check(rsa, pubrsa) != ISC_R_SUCCESS) DST_RET(DST_R_INVALIDPRIVATEKEY); + if (pubrsa != NULL) + RSA_free(pubrsa); key->key_size = EVP_PKEY_bits(pkey); #if USE_EVP key->keydata.pkey = pkey; + RSA_free(rsa); #else key->keydata.rsa = rsa; EVP_PKEY_free(pkey); @@ -877,9 +880,8 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { pkey = EVP_PKEY_new(); if (pkey == NULL) DST_RET(ISC_R_NOMEMORY); - if (!EVP_PKEY_set1_RSA(pkey, rsa)) { + if (!EVP_PKEY_set1_RSA(pkey, rsa)) DST_RET(ISC_R_FAILURE); - } key->keydata.pkey = pkey; #else key->keydata.rsa = rsa; @@ -964,33 +966,61 @@ opensslrsa_fromlabel(dst_key_t *key, const char *engine, const char *label, ENGINE *e = NULL; isc_result_t ret; EVP_PKEY *pkey = NULL; + RSA *rsa = NULL, *pubrsa = NULL; + char *colon; UNUSED(pin); e = dst__openssl_getengine(engine); if (e == NULL) DST_RET(DST_R_NOENGINE); + pkey = ENGINE_load_public_key(e, label, NULL, NULL); + if (pkey != NULL) { + pubrsa = EVP_PKEY_get1_RSA(pkey); + EVP_PKEY_free(pkey); + if (pubrsa == NULL) + DST_RET(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); + } pkey = ENGINE_load_private_key(e, label, NULL, NULL); if (pkey == NULL) DST_RET(ISC_R_NOTFOUND); - key->engine = isc_mem_strdup(key->mctx, label); - if (key->engine == NULL) - DST_RET(ISC_R_NOMEMORY); + if (engine != NULL) { + key->engine = isc_mem_strdup(key->mctx, engine); + if (key->engine == NULL) + DST_RET(ISC_R_NOMEMORY); + } else { + key->engine = isc_mem_strdup(key->mctx, label); + if (key->engine == NULL) + DST_RET(ISC_R_NOMEMORY); + colon = strchr(key->engine, ':'); + if (colon != NULL) + *colon = '\0'; + } key->label = isc_mem_strdup(key->mctx, label); if (key->label == NULL) DST_RET(ISC_R_NOMEMORY); + rsa = EVP_PKEY_get1_RSA(pkey); + if (rsa == NULL) + DST_RET(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); + if (rsa_check(rsa, pubrsa) != ISC_R_SUCCESS) + DST_RET(DST_R_INVALIDPRIVATEKEY); + if (pubrsa != NULL) + RSA_free(pubrsa); key->key_size = EVP_PKEY_bits(pkey); #if USE_EVP key->keydata.pkey = pkey; + RSA_free(rsa); #else - key->keydata.rsa = EVP_PKEY_get1_RSA(pkey); + key->keydata.rsa = rsa; EVP_PKEY_free(pkey); - if (key->keydata.rsa == NULL) - return (dst__openssl_toresult(DST_R_OPENSSLFAILURE)); #endif return (ISC_R_SUCCESS); err: + if (rsa != NULL) + RSA_free(rsa); + if (pubrsa != NULL) + RSA_free(pubrsa); if (pkey != NULL) EVP_PKEY_free(pkey); return (ret);