EVP: Adapt KEYEXCH, SIGNATURE and ASYM_CIPHER to handle key types better
authorRichard Levitte <levitte@openssl.org>
Wed, 18 Dec 2019 12:24:27 +0000 (13:24 +0100)
committerRichard Levitte <levitte@openssl.org>
Thu, 9 Jan 2020 14:01:28 +0000 (15:01 +0100)
The adaptation is to handle the case when key types and operations
that use these keys have different names.  For example, EC keys can be
used for ECDSA and ECDH.

Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/10647)

crypto/evp/exchange.c
crypto/evp/m_sigver.c
crypto/evp/pmeth_fn.c
crypto/evp/pmeth_gn.c
crypto/evp/pmeth_lib.c
doc/man3/EVP_PKEY_CTX_new.pod
include/crypto/evp.h

index 3e7c00103c7a358ae688b037ae1d8257f6ac96b8..ade1dc373dca3021aad9dbf97ffdc28c53fbbfe2 100644 (file)
@@ -173,20 +173,32 @@ int EVP_PKEY_derive_init(EVP_PKEY_CTX *ctx)
     evp_pkey_ctx_free_old_ops(ctx);
     ctx->operation = EVP_PKEY_OP_DERIVE;
 
-    if (ctx->engine != NULL || ctx->algorithm == NULL)
+    if (ctx->engine != NULL || ctx->keytype == NULL)
         goto legacy;
 
-    /*
-     * Because we cleared out old ops, we shouldn't need to worry about
-     * checking if exchange is already there.  Keymgmt is a different
-     * matter, as it isn't tied to a specific EVP_PKEY op.
-     */
-    exchange = EVP_KEYEXCH_fetch(ctx->libctx, ctx->algorithm, ctx->propquery);
-    if (exchange != NULL && ctx->keymgmt == NULL) {
-        int name_id = EVP_KEYEXCH_number(exchange);
-
+    if (ctx->keymgmt == NULL)
         ctx->keymgmt =
-            evp_keymgmt_fetch_by_number(ctx->libctx, name_id, ctx->propquery);
+            EVP_KEYMGMT_fetch(ctx->libctx, ctx->keytype, ctx->propquery);
+    if (ctx->keymgmt != NULL) {
+        const char *supported_exch = NULL;
+
+        if (ctx->keymgmt->query_operation_name != NULL)
+            supported_exch =
+                ctx->keymgmt->query_operation_name(OSSL_OP_KEYEXCH);
+
+        /*
+         * If we didn't get a supported exch, assume there is one with the
+         * same name as the key type.
+         */
+        if (supported_exch == NULL)
+            supported_exch = ctx->keytype;
+
+        /*
+         * Because we cleared out old ops, we shouldn't need to worry about
+         * checking if exchange is already there.
+         */
+        exchange =
+            EVP_KEYEXCH_fetch(ctx->libctx, supported_exch, ctx->propquery);
     }
 
     if (ctx->keymgmt == NULL
index 9d12e9b96adecdc370e349ff5963604607225866..ff9406318182103f1c1ddd024a0215a7199fbd40 100644 (file)
@@ -52,7 +52,7 @@ static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
     locpctx = ctx->pctx;
     evp_pkey_ctx_free_old_ops(locpctx);
 
-    if (locpctx->algorithm == NULL)
+    if (locpctx->keytype == NULL)
         goto legacy;
 
     if (mdname == NULL) {
@@ -71,18 +71,28 @@ static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
         }
     }
 
-    /*
-     * Because we cleared out old ops, we shouldn't need to worry about
-     * checking if signature is already there.  Keymgmt is a different
-     * matter, as it isn't tied to a specific EVP_PKEY op.
-     */
-    signature = EVP_SIGNATURE_fetch(locpctx->libctx, locpctx->algorithm,
-                                    locpctx->propquery);
-    if (signature != NULL && locpctx->keymgmt == NULL) {
-        int name_id = EVP_SIGNATURE_number(signature);
+    if (locpctx->keymgmt == NULL)
+        locpctx->keymgmt = EVP_KEYMGMT_fetch(locpctx->libctx, locpctx->keytype,
+                                             locpctx->propquery);
+    if (locpctx->keymgmt != NULL) {
+        const char *supported_sig = NULL;
+
+        if (locpctx->keymgmt->query_operation_name != NULL)
+            supported_sig =
+                locpctx->keymgmt->query_operation_name(OSSL_OP_SIGNATURE);
+
+        /*
+         * If we didn't get a supported sig, assume there is one with the
+         * same name as the key type.
+         */
+        if (supported_sig == NULL)
+            supported_sig = locpctx->keytype;
 
-        locpctx->keymgmt =
-            evp_keymgmt_fetch_by_number(locpctx->libctx, name_id,
+        /*
+         * Because we cleared out old ops, we shouldn't need to worry about
+         * checking if signature is already there.
+         */
+        signature = EVP_SIGNATURE_fetch(locpctx->libctx, supported_sig,
                                         locpctx->propquery);
     }
 
index 0ce4ff95221cd7538768c4caf4adff617f979189..3d0ee2e6466754756f3d269b2e5777503ae08320 100644 (file)
@@ -331,21 +331,32 @@ static int evp_pkey_signature_init(EVP_PKEY_CTX *ctx, int operation)
     evp_pkey_ctx_free_old_ops(ctx);
     ctx->operation = operation;
 
-    if (ctx->algorithm == NULL)
+    if (ctx->keytype == NULL)
         goto legacy;
 
-    /*
-     * Because we cleared out old ops, we shouldn't need to worry about
-     * checking if signature is already there.  Keymgmt is a different
-     * matter, as it isn't tied to a specific EVP_PKEY op.
-     */
-    signature = EVP_SIGNATURE_fetch(ctx->libctx, ctx->algorithm,
-                                    ctx->propquery);
-    if (signature != NULL && ctx->keymgmt == NULL) {
-        int name_id = EVP_SIGNATURE_number(signature);
+    if (ctx->keymgmt == NULL)
+        ctx->keymgmt =
+            EVP_KEYMGMT_fetch(ctx->libctx, ctx->keytype, ctx->propquery);
+    if (ctx->keymgmt != NULL) {
+        const char *supported_sig = NULL;
+
+        if (ctx->keymgmt->query_operation_name != NULL)
+            supported_sig =
+                ctx->keymgmt->query_operation_name(OSSL_OP_SIGNATURE);
+
+        /*
+         * If we didn't get a supported sig, assume there is one with the
+         * same name as the key type.
+         */
+        if (supported_sig == NULL)
+            supported_sig = ctx->keytype;
 
-        ctx->keymgmt = evp_keymgmt_fetch_by_number(ctx->libctx, name_id,
-                                                   ctx->propquery);
+        /*
+         * Because we cleared out old ops, we shouldn't need to worry about
+         * checking if signature is already there.
+         */
+        signature =
+            EVP_SIGNATURE_fetch(ctx->libctx, supported_sig, ctx->propquery);
     }
 
     if (ctx->keymgmt == NULL
@@ -582,20 +593,32 @@ static int evp_pkey_asym_cipher_init(EVP_PKEY_CTX *ctx, int operation)
     evp_pkey_ctx_free_old_ops(ctx);
     ctx->operation = operation;
 
-    if (ctx->algorithm == NULL || ctx->engine != NULL)
+    if (ctx->keytype == NULL || ctx->engine != NULL)
         goto legacy;
 
-    /*
-     * Because we cleared out old ops, we shouldn't need to worry about
-     * checking if exchange is already there.  Keymgmt is a different
-     * matter, as it isn't tied to a specific EVP_PKEY op.
-     */
-    cipher = EVP_ASYM_CIPHER_fetch(ctx->libctx, ctx->algorithm, ctx->propquery);
-    if (cipher != NULL && ctx->keymgmt == NULL) {
-        int name_id = EVP_ASYM_CIPHER_number(cipher);
-
+    if (ctx->keymgmt == NULL)
         ctx->keymgmt =
-            evp_keymgmt_fetch_by_number(ctx->libctx, name_id, ctx->propquery);
+            EVP_KEYMGMT_fetch(ctx->libctx, ctx->keytype, ctx->propquery);
+    if (ctx->keymgmt != NULL) {
+        const char *supported_ciph = NULL;
+
+        if (ctx->keymgmt->query_operation_name != NULL)
+            supported_ciph =
+                ctx->keymgmt->query_operation_name(OSSL_OP_ASYM_CIPHER);
+
+        /*
+         * If we didn't get a supported ciph, assume there is one with the
+         * same name as the key type.
+         */
+        if (supported_ciph == NULL)
+            supported_ciph = ctx->keytype;
+
+        /*
+         * Because we cleared out old ops, we shouldn't need to worry about
+         * checking if cipher is already there.
+         */
+        cipher =
+            EVP_ASYM_CIPHER_fetch(ctx->libctx, supported_ciph, ctx->propquery);
     }
 
     if (ctx->keymgmt == NULL
index a5f7dbaf53b2893479cf859a6fb63b82c6f0033f..100931cda7f111cbc434e3a04b96f97aace39643 100644 (file)
 
 static int fromdata_init(EVP_PKEY_CTX *ctx, int operation)
 {
-    if (ctx == NULL || ctx->algorithm == NULL)
+    if (ctx == NULL || ctx->keytype == NULL)
         goto not_supported;
 
     evp_pkey_ctx_free_old_ops(ctx);
     ctx->operation = operation;
     if (ctx->keymgmt == NULL)
-        ctx->keymgmt = EVP_KEYMGMT_fetch(NULL, ctx->algorithm, ctx->propquery);
+        ctx->keymgmt = EVP_KEYMGMT_fetch(NULL, ctx->keytype, ctx->propquery);
     if (ctx->keymgmt == NULL)
         goto not_supported;
 
index 8b49baf6abdba93e2e0eb56ccaf7a728b797dc2c..2ecc17734e71308671d414f00edff1d5348f4b27 100644 (file)
@@ -221,7 +221,7 @@ static EVP_PKEY_CTX *int_ctx_new(OPENSSL_CTX *libctx,
         return NULL;
     }
     ret->libctx = libctx;
-    ret->algorithm = name;
+    ret->keytype = name;
     ret->propquery = propquery;
     ret->engine = e;
     ret->pmeth = pmeth;
@@ -382,7 +382,7 @@ EVP_PKEY_CTX *EVP_PKEY_CTX_dup(const EVP_PKEY_CTX *pctx)
     rctx->pkey = pctx->pkey;
     rctx->operation = pctx->operation;
     rctx->libctx = pctx->libctx;
-    rctx->algorithm = pctx->algorithm;
+    rctx->keytype = pctx->keytype;
     rctx->propquery = pctx->propquery;
 
     if (EVP_PKEY_CTX_IS_DERIVE_OP(pctx)) {
index 5d18a043444243dc936fa47b0b8682545538bb09..90486ae0dcbcf83a2261a3ba70c4107c549b67cb 100644 (file)
@@ -21,14 +21,14 @@ EVP_PKEY_CTX_dup, EVP_PKEY_CTX_free
 =head1 DESCRIPTION
 
 The EVP_PKEY_CTX_new() function allocates public key algorithm context using
-the algorithm specified in I<pkey> and ENGINE I<e>.
+the I<pkey> key type and ENGINE I<e>.
 
 The EVP_PKEY_CTX_new_id() function allocates public key algorithm context
-using the algorithm specified by I<id> and ENGINE I<e>.
+using the key type specified by I<id> and ENGINE I<e>.
 
 The EVP_PKEY_CTX_new_provided() function allocates a public key algorithm
 context using the library context I<libctx> (see L<OPENSSL_CTX(3)>), the
-algorithm specified by I<name> and the property query I<propquery>.  None
+key type specified by I<name> and the property query I<propquery>.  None
 of the arguments are duplicated, so they  must remain unchanged for the
 lifetime of the returned B<EVP_PKEY_CTX> or of any of its duplicates.
 
@@ -44,11 +44,25 @@ If I<ctx> is NULL, nothing is done.
 
 =head1 NOTES
 
+=over 4
+
+=item 1.
+
 The B<EVP_PKEY_CTX> structure is an opaque public key algorithm context used
 by the OpenSSL high level public key API. Contexts B<MUST NOT> be shared between
 threads: that is it is not permissible to use the same context simultaneously
 in two threads.
 
+=item 2.
+
+We mention "key type" in this manual, which is the same
+as "algorithm" in most cases, allowing either term to be used
+interchangeably.  There are algorithms where the I<key type> and the
+I<algorithm> of the operations that use the keys are not the same,
+such as EC keys being used for ECDSA and ECDH operations.
+
+=back
+
 =head1 RETURN VALUES
 
 EVP_PKEY_CTX_new(), EVP_PKEY_CTX_new_id(), EVP_PKEY_CTX_dup() returns either
index 592cbdd536363088b58435af9f06b41527552573..973ef203ba854d013f5dd6796ce796089e597c3d 100644 (file)
@@ -22,11 +22,11 @@ struct evp_pkey_ctx_st {
     int operation;
 
     /*
-     * Library context, Algorithm name and properties associated
+     * Library context, Key type name and properties associated
      * with this context
      */
     OPENSSL_CTX *libctx;
-    const char *algorithm;
+    const char *keytype;
     const char *propquery;
 
     /* cached key manager */