]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
merge rt19294
authorFrancis Dupont <fdupont@isc.org>
Mon, 7 Sep 2009 12:58:33 +0000 (12:58 +0000)
committerFrancis Dupont <fdupont@isc.org>
Mon, 7 Sep 2009 12:58:33 +0000 (12:58 +0000)
CHANGES
bin/dnssec/dnssec-keyfromlabel.c
bin/dnssec/dnssec-keyfromlabel.docbook
bin/dnssec/dnssec-keygen.c
lib/dns/opensslrsa_link.c

diff --git a/CHANGES b/CHANGES
index a02274925a83c7098d9384bd9a306f4ae38bf668..f6a22810e1b43bf980a9509530188233d307b8b4 100644 (file)
--- 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]
 
index 56165fd60f41bb9e172601ed95a3eef21d4d0715..4f93adccf73f0d9fc6a1e1fa24d704a8e22d1c9c 100644 (file)
  * 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 <config.h>
 
+#include <ctype.h>
 #include <stdlib.h>
 
 #include <isc/buffer.h>
@@ -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 <class> (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 <protocol>: default: 3 [dnssec]\n");
        fprintf(stderr, "    -t <type>: "
                "AUTHCONF | NOAUTHCONF | NOAUTH | NOCONF "
                "(default: AUTHCONF)\n");
-       fprintf(stderr, "    -p <protocol>: "
-              "default: 3 [dnssec]\n");
        fprintf(stderr, "    -v <verbose level>\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<name>+<alg>+<id>.key, "
-               "K<name>+<alg>+<id>.private\n");
+                       "K<name>+<alg>+<id>.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);
 
index 1e478d93a372f670f50900ccc7d627aef31c8fe8..4beb25b9fe594ad013156d5973e14bfa7c3ec1ea 100644 (file)
@@ -17,7 +17,7 @@
  - PERFORMANCE OF THIS SOFTWARE.
 -->
 
-<!-- $Id: dnssec-keyfromlabel.docbook,v 1.8 2009/07/19 23:47:55 tbox Exp $ -->
+<!-- $Id: dnssec-keyfromlabel.docbook,v 1.9 2009/09/07 12:54:59 fdupont Exp $ -->
 <refentry id="man.dnssec-keyfromlabel">
   <refentryinfo>
     <date>February 8, 2008</date>
       <command>dnssec-keyfromlabel</command>
       <arg choice="req">-a <replaceable class="parameter">algorithm</replaceable></arg>
       <arg choice="req">-l <replaceable class="parameter">label</replaceable></arg>
+      <arg><option>-A <replaceable class="parameter">date/offset</replaceable></option></arg>
       <arg><option>-c <replaceable class="parameter">class</replaceable></option></arg>
+      <arg><option>-D <replaceable class="parameter">date/offset</replaceable></option></arg>
       <arg><option>-f <replaceable class="parameter">flag</replaceable></option></arg>
       <arg><option>-k</option></arg>
       <arg><option>-K <replaceable class="parameter">directory</replaceable></option></arg>
       <arg><option>-n <replaceable class="parameter">nametype</replaceable></option></arg>
+      <arg><option>-P <replaceable class="parameter">date/offset</replaceable></option></arg>
       <arg><option>-p <replaceable class="parameter">protocol</replaceable></option></arg>
+      <arg><option>-R <replaceable class="parameter">date/offset</replaceable></option></arg>
       <arg><option>-t <replaceable class="parameter">type</replaceable></option></arg>
+      <arg><option>-U <replaceable class="parameter">date/offset</replaceable></option></arg>
       <arg><option>-v <replaceable class="parameter">level</replaceable></option></arg>
       <arg choice="req">name</arg>
     </cmdsynopsis>
       key files for DNSSEC (Secure DNS), as defined in RFC 2535
       and RFC 4034.  
     </para>
+    <para>
+      The <option>name</option> of the key is specified on the command
+      line.  This must match the name of the zone for which the key is
+      being generated.
+    </para>
   </refsect1>
 
   <refsect1>
@@ -77,8 +87,8 @@
         <listitem>
          <para>
            Selects the cryptographic algorithm.  The value of
-           <option>algorithm</option> must be one of RSAMD5 (RSA)
-           or RSASHA1, DSA, NSEC3RSASHA1, NSEC3DSA or DH (Diffie Hellman).
+           <option>algorithm</option> must be one of RSAMD5 (RSA),
+           RSASHA1, DSA, NSEC3RSASHA1, NSEC3DSA or DH (Diffie Hellman).
            These values are case insensitive.
          </para>
           <para>
             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.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>-C</term>
+        <listitem>
+          <para>
+           Compatibility mode:  generates an old-style key, without
+           any metadata.  By default, <command>dnssec-keyfromlabel</command>
+           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>-C</option> option suppresses them.
           </para>
         </listitem>
       </varlistentry>
         <listitem>
           <para>
             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.
           </para>
         </listitem>
       </varlistentry>
         <listitem>
           <para>
             Prints a short summary of the options and arguments to
-            <command>dnssec-keygen</command>.
+            <command>dnssec-keyfromlabel</command>.
           </para>
         </listitem>
       </varlistentry>
         <term>-p <replaceable class="parameter">protocol</replaceable></term>
         <listitem>
           <para>
-            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.
     </variablelist>
   </refsect1>
 
+  <refsect1>
+    <title>TIMING OPTIONS</title>
+
+    <para>
+      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.
+    </para>
+
+    <variablelist>
+      <varlistentry>
+        <term>-P <replaceable class="parameter">date/offset</replaceable></term>
+        <listitem>
+          <para>
+            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.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>-A <replaceable class="parameter">date/offset</replaceable></term>
+        <listitem>
+          <para>
+            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.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>-R <replaceable class="parameter">date/offset</replaceable></term>
+        <listitem>
+          <para>
+            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.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>-U <replaceable class="parameter">date/offset</replaceable></term>
+        <listitem>
+          <para>
+            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.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>-D <replaceable class="parameter">date/offset</replaceable></term>
+        <listitem>
+          <para>
+            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.
+          </para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
   <refsect1>
     <title>GENERATED KEY FILES</title>
     <para>
       </listitem>
       <listitem>
         <para><filename>aaa</filename> is the numeric representation
-          of the
-          algorithm.
+          of the algorithm.
         </para>
       </listitem>
       <listitem>
       on the printed string.  <filename>Knnnn.+aaa+iiiii.key</filename>
       contains the public key, and
       <filename>Knnnn.+aaa+iiiii.private</filename> contains the
-      private
-      key.
+      private key.
     </para>
     <para>
       The <filename>.key</filename> file contains a DNS KEY record
       statement).
     </para>
     <para>
-      The <filename>.private</filename> file contains algorithm
-      specific
+      The <filename>.private</filename> file contains
+      algorithm-specific
       fields.  For obvious security reasons, this file does not have
       general read permission.
     </para>
index affb064f4982433ce48ac2331baeac00a3d895a6..c5e696eca3e64a8990510aeee10e7b68237b025e 100644 (file)
@@ -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,
index 395dfdfc7f91e30808077e71215a91c01302353f..828ca3bd6f54c42175461e0fbfd04725395d79a4 100644 (file)
@@ -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);