Adapt diverse EVP_CIPHER functions to use get_params and set_params interfaces
authorRichard Levitte <levitte@openssl.org>
Tue, 9 Jul 2019 05:32:16 +0000 (07:32 +0200)
committerRichard Levitte <levitte@openssl.org>
Thu, 11 Jul 2019 05:27:02 +0000 (07:27 +0200)
Reviewed-by: Paul Dale <paul.dale@oracle.com>
Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/9328)

crypto/evp/build.info
crypto/evp/evp_enc.c
crypto/evp/evp_lib.c
crypto/evp/evp_locl.h
crypto/evp/evp_utils.c [new file with mode: 0644]
include/openssl/evp.h

index 26be4d9..fa49f2e 100644 (file)
@@ -1,5 +1,5 @@
 LIBS=../../libcrypto
-$COMMON=digest.c evp_enc.c evp_lib.c evp_fetch.c cmeth_lib.c
+$COMMON=digest.c evp_enc.c evp_lib.c evp_fetch.c cmeth_lib.c evp_utils.c
 SOURCE[../../libcrypto]=$COMMON\
         encode.c evp_key.c evp_cnf.c \
         e_des.c e_bf.c e_idea.c e_des3.c e_camellia.c\
index ebe7fa8..3b83d11 100644 (file)
@@ -920,6 +920,14 @@ int EVP_DecryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl)
 
 int EVP_CIPHER_CTX_set_key_length(EVP_CIPHER_CTX *c, int keylen)
 {
+    int ok = evp_do_param(c->cipher, &keylen, sizeof(keylen),
+                          OSSL_CIPHER_PARAM_KEYLEN, OSSL_PARAM_INTEGER,
+                          evp_do_ciph_ctx_setparams, c->provctx);
+
+    if (ok != -2)
+        return ok;
+
+    /* TODO(3.0) legacy code follows */
     if (c->cipher->flags & EVP_CIPH_CUSTOM_KEY_LENGTH)
         return EVP_CIPHER_CTX_ctrl(c, EVP_CTRL_SET_KEY_LENGTH, keylen, NULL);
     if (EVP_CIPHER_CTX_key_length(c) == keylen)
@@ -934,40 +942,51 @@ int EVP_CIPHER_CTX_set_key_length(EVP_CIPHER_CTX *c, int keylen)
 
 int EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *ctx, int pad)
 {
+    int ok;
+
     if (pad)
         ctx->flags &= ~EVP_CIPH_NO_PADDING;
     else
         ctx->flags |= EVP_CIPH_NO_PADDING;
 
-    if (ctx->cipher != NULL && ctx->cipher->prov != NULL) {
-        OSSL_PARAM params[] = {
-            OSSL_PARAM_int(OSSL_CIPHER_PARAM_PADDING, NULL),
-            OSSL_PARAM_END
-        };
-
-        params[0].data = &pad;
-
-        if (ctx->cipher->ctx_set_params == NULL) {
-            EVPerr(EVP_F_EVP_CIPHER_CTX_SET_PADDING, EVP_R_CTRL_NOT_IMPLEMENTED);
-            return 0;
-        }
-
-        if (!ctx->cipher->ctx_set_params(ctx->provctx, params))
-            return 0;
-    }
-
-    return 1;
+    ok = evp_do_param(ctx->cipher, &pad, sizeof(pad),
+                      OSSL_CIPHER_PARAM_PADDING, OSSL_PARAM_INTEGER,
+                      evp_do_ciph_ctx_setparams, ctx->provctx);
+    return ok != 0;
 }
 
 int EVP_CIPHER_CTX_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr)
 {
-    int ret;
+    int ret = -2;                /* Unsupported */
 
     if (!ctx->cipher) {
         EVPerr(EVP_F_EVP_CIPHER_CTX_CTRL, EVP_R_NO_CIPHER_SET);
         return 0;
     }
 
+    if (ctx->cipher->prov == NULL)
+        goto legacy;
+
+    switch (type) {
+    case EVP_CTRL_SET_KEY_LENGTH:
+        ret = evp_do_param(ctx->cipher, &arg, sizeof(arg),
+                           OSSL_CIPHER_PARAM_KEYLEN, OSSL_PARAM_INTEGER,
+                           evp_do_ciph_ctx_setparams, ctx->provctx);
+        break;
+    case EVP_CTRL_GET_IV:
+        ret = evp_do_param(ctx->cipher, ptr, arg,
+                           OSSL_CIPHER_PARAM_IV, OSSL_PARAM_OCTET_STRING,
+                           evp_do_ciph_ctx_getparams, ctx->provctx);
+        break;
+    case EVP_CTRL_RAND_KEY:      /* Used by DES */
+    case EVP_CTRL_SET_PIPELINE_OUTPUT_BUFS: /* Used by DASYNC */
+    case EVP_CTRL_INIT: /* TODO(3.0) Purely legacy, no provider counterpart */
+        ret = -2;                /* Unsupported */
+        break;
+    }
+    return ret;
+
+ legacy:
     if (!ctx->cipher->ctrl) {
         EVPerr(EVP_F_EVP_CIPHER_CTX_CTRL, EVP_R_CTRL_NOT_IMPLEMENTED);
         return 0;
@@ -1123,21 +1142,6 @@ static void *evp_cipher_from_dispatch(const OSSL_DISPATCH *fns,
                 break;
             cipher->dupctx = OSSL_get_OP_cipher_dupctx(fns);
             break;
-        case OSSL_FUNC_CIPHER_KEY_LENGTH:
-            if (cipher->key_length != NULL)
-                break;
-            cipher->key_length = OSSL_get_OP_cipher_key_length(fns);
-            break;
-        case OSSL_FUNC_CIPHER_IV_LENGTH:
-            if (cipher->iv_length != NULL)
-                break;
-            cipher->iv_length = OSSL_get_OP_cipher_iv_length(fns);
-            break;
-        case OSSL_FUNC_CIPHER_BLOCK_SIZE:
-            if (cipher->blocksize != NULL)
-                break;
-            cipher->blocksize = OSSL_get_OP_cipher_block_size(fns);
-            break;
         case OSSL_FUNC_CIPHER_GET_PARAMS:
             if (cipher->get_params != NULL)
                 break;
@@ -1157,10 +1161,7 @@ static void *evp_cipher_from_dispatch(const OSSL_DISPATCH *fns,
     }
     if ((fnciphcnt != 0 && fnciphcnt != 3 && fnciphcnt != 4)
             || (fnciphcnt == 0 && cipher->ccipher == NULL)
-            || fnctxcnt != 2
-            || cipher->blocksize == NULL
-            || cipher->iv_length == NULL
-            || cipher->key_length == NULL) {
+            || fnctxcnt != 2) {
         /*
          * In order to be a consistent set of functions we must have at least
          * a complete set of "encrypt" functions, or a complete set of "decrypt"
index 8ed39cb..9d1d197 100644 (file)
@@ -217,13 +217,12 @@ int EVP_CIPHER_type(const EVP_CIPHER *ctx)
 
 int EVP_CIPHER_block_size(const EVP_CIPHER *cipher)
 {
-    if (cipher->prov != NULL) {
-        if (cipher->blocksize != NULL)
-            return cipher->blocksize();
-        /* We default to a block size of 1 */
-        return 1;
-    }
-    return cipher->block_size;
+    int v = cipher->block_size;
+    int ok = evp_do_param(cipher, &v, sizeof(v),
+                          OSSL_CIPHER_PARAM_BLOCK_SIZE, OSSL_PARAM_INTEGER,
+                          evp_do_ciph_getparams, NULL);
+
+    return ok != 0 ? v : -1;
 }
 
 int EVP_CIPHER_CTX_block_size(const EVP_CIPHER_CTX *ctx)
@@ -266,7 +265,12 @@ int EVP_CIPHER_CTX_encrypting(const EVP_CIPHER_CTX *ctx)
 
 unsigned long EVP_CIPHER_flags(const EVP_CIPHER *cipher)
 {
-    return cipher->flags;
+    unsigned long v = cipher->flags;
+    int ok = evp_do_param(cipher, &v, sizeof(v),
+                          OSSL_CIPHER_PARAM_FLAGS, OSSL_PARAM_UNSIGNED_INTEGER,
+                          evp_do_ciph_getparams, NULL);
+
+    return ok != 0 ? v : 0;
 }
 
 void *EVP_CIPHER_CTX_get_app_data(const EVP_CIPHER_CTX *ctx)
@@ -296,13 +300,12 @@ void *EVP_CIPHER_CTX_set_cipher_data(EVP_CIPHER_CTX *ctx, void *cipher_data)
 
 int EVP_CIPHER_iv_length(const EVP_CIPHER *cipher)
 {
-    if (cipher->prov != NULL) {
-        if (cipher->iv_length != NULL)
-            return (int)cipher->iv_length();
-        return 0;
-    }
+    int v = cipher->iv_len;
+    int ok = evp_do_param(cipher, &v, sizeof(v),
+                          OSSL_CIPHER_PARAM_IVLEN, OSSL_PARAM_UNSIGNED_INTEGER,
+                          evp_do_ciph_getparams, NULL);
 
-    return cipher->iv_len;
+    return ok != 0 ? v: -1;
 }
 
 int EVP_CIPHER_CTX_iv_length(const EVP_CIPHER_CTX *ctx)
@@ -315,14 +318,27 @@ const unsigned char *EVP_CIPHER_CTX_original_iv(const EVP_CIPHER_CTX *ctx)
     return ctx->oiv;
 }
 
+/*
+ * OSSL_PARAM_OCTET_PTR gets us the pointer to the running IV in the provider
+ */
 const unsigned char *EVP_CIPHER_CTX_iv(const EVP_CIPHER_CTX *ctx)
 {
-    return ctx->iv;
+    const unsigned char *v = ctx->iv;
+    int ok = evp_do_param(ctx->cipher, &v, sizeof(ctx->iv),
+                          OSSL_CIPHER_PARAM_IV, OSSL_PARAM_OCTET_PTR,
+                          evp_do_ciph_ctx_getparams, ctx->provctx);
+
+    return ok != 0 ? v: NULL;
 }
 
 unsigned char *EVP_CIPHER_CTX_iv_noconst(EVP_CIPHER_CTX *ctx)
 {
-    return ctx->iv;
+    unsigned char *v = ctx->iv;
+    int ok = evp_do_param(ctx->cipher, &v, sizeof(ctx->iv),
+                          OSSL_CIPHER_PARAM_IV, OSSL_PARAM_OCTET_PTR,
+                          evp_do_ciph_ctx_getparams, ctx->provctx);
+
+    return ok != 0 ? v: NULL;
 }
 
 unsigned char *EVP_CIPHER_CTX_buf_noconst(EVP_CIPHER_CTX *ctx)
@@ -332,34 +348,42 @@ unsigned char *EVP_CIPHER_CTX_buf_noconst(EVP_CIPHER_CTX *ctx)
 
 int EVP_CIPHER_CTX_num(const EVP_CIPHER_CTX *ctx)
 {
-    return ctx->num;
+    int v = ctx->num;
+    int ok = evp_do_param(ctx->cipher, &v, sizeof(v),
+                          OSSL_CIPHER_PARAM_NUM, OSSL_PARAM_INTEGER,
+                          evp_do_ciph_ctx_getparams, ctx->provctx);
+
+    return ok != 0 ? v: -1;
 }
 
-void EVP_CIPHER_CTX_set_num(EVP_CIPHER_CTX *ctx, int num)
+int EVP_CIPHER_CTX_set_num(EVP_CIPHER_CTX *ctx, int num)
 {
+    int ok = evp_do_param(ctx->cipher, &num, sizeof(num),
+                          OSSL_CIPHER_PARAM_NUM, OSSL_PARAM_INTEGER,
+                          evp_do_ciph_ctx_setparams, ctx->provctx);
+
     ctx->num = num;
+    return ok != 0;
 }
 
 int EVP_CIPHER_key_length(const EVP_CIPHER *cipher)
 {
-    if (cipher->prov != NULL) {
-        if (cipher->key_length != NULL)
-            return (int)cipher->key_length();
-        return -1;
-    }
+    int v = cipher->key_len;
+    int ok = evp_do_param(cipher, &v, sizeof(v),
+                          OSSL_CIPHER_PARAM_KEYLEN, OSSL_PARAM_INTEGER,
+                          evp_do_ciph_getparams, NULL);
 
-    return cipher->key_len;
+    return ok != 0 ? v: -1;
 }
 
 int EVP_CIPHER_CTX_key_length(const EVP_CIPHER_CTX *ctx)
 {
-    /*
-     * TODO(3.0): This may need to change if/when we introduce variable length
-     * key ciphers into the providers.
-     */
-    if (ctx->cipher != NULL && ctx->cipher->prov != NULL)
-        return EVP_CIPHER_key_length(ctx->cipher);
-    return ctx->key_len;
+    int v = ctx->key_len;
+    int ok = evp_do_param(ctx->cipher, &v, sizeof(v),
+                          OSSL_CIPHER_PARAM_KEYLEN, OSSL_PARAM_INTEGER,
+                          evp_do_ciph_ctx_getparams, ctx->provctx);
+
+    return ok != 0 ? v: -1;
 }
 
 int EVP_CIPHER_nid(const EVP_CIPHER *cipher)
@@ -374,28 +398,12 @@ int EVP_CIPHER_CTX_nid(const EVP_CIPHER_CTX *ctx)
 
 int EVP_CIPHER_mode(const EVP_CIPHER *cipher)
 {
-    if (cipher->prov != NULL) {
-        int mode;
+    int v = EVP_CIPHER_flags(cipher) & EVP_CIPH_MODE;
+    int ok = evp_do_param(cipher, &v, sizeof(v),
+                          OSSL_CIPHER_PARAM_MODE, OSSL_PARAM_INTEGER,
+                          evp_do_ciph_getparams, NULL);
 
-        /* Cipher comes from a provider - so ask the provider for the mode */
-        OSSL_PARAM params[] = {
-            OSSL_PARAM_int(OSSL_CIPHER_PARAM_MODE, NULL),
-            OSSL_PARAM_END
-        };
-
-        params[0].data = &mode;
-
-        if (cipher->get_params == NULL) {
-            EVPerr(EVP_F_EVP_CIPHER_MODE, EVP_R_CTRL_NOT_IMPLEMENTED);
-            return 0;
-        }
-
-        if (!cipher->get_params(params))
-            return 0;
-
-        return mode;
-    }
-    return EVP_CIPHER_flags(cipher) & EVP_CIPH_MODE;
+    return ok != 0 ? v: 0;
 }
 
 
index fdafe4f..54f9e08 100644 (file)
@@ -95,3 +95,40 @@ void *evp_generic_fetch(OPENSSL_CTX *ctx, int operation_id,
                                             OSSL_PROVIDER *prov),
                         int (*up_ref_method)(void *),
                         void (*free_method)(void *));
+
+/* Helper functions to avoid duplicating code */
+
+/*
+ * The callbacks implement different ways to pass a params array to the
+ * provider.  They will return one of these values:
+ *
+ * -2 if the method doesn't come from a provider
+ *    (evp_do_param will return this to the called)
+ * -1 if the provider doesn't offer the desired function
+ *    (evp_do_param will raise an error and return 0)
+ * or the return value from the desired function
+ *    (evp_do_param will return it to the caller)
+ */
+int evp_do_ciph_getparams(const void *vciph, void *ignored,
+                          OSSL_PARAM params[]);
+int evp_do_ciph_ctx_getparams(const void *vciph, void *provctx,
+                              OSSL_PARAM params[]);
+int evp_do_ciph_ctx_setparams(const void *vciph, void *provctx,
+                              OSSL_PARAM params[]);
+
+/*-
+ * prepares a singular parameter, then calls the callback to execute.
+ *
+ * |method|   points to the method used by the callback.
+ *            EVP_CIPHER, EVP_MD, ...
+ * |ptr|      points at the data to transfer.
+ * |sz|       is the size of the data to transfer.
+ * |key|      is the name of the parameter to pass.
+ * |datatype| is the data type of the parameter to pass.
+ * |cb|       is the callback that actually performs the parameter passing
+ * |cb_ctx|   is the cipher context
+ */
+int evp_do_param(const void *method, void *ptr, size_t sz, const char *key,
+                 int datatype,
+                 int (*cb)(const void *method, void *ctx, OSSL_PARAM params[]),
+                 void *cb_ctx);
diff --git a/crypto/evp/evp_utils.c b/crypto/evp/evp_utils.c
new file mode 100644 (file)
index 0000000..48f548c
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+/* Internal EVP utility functions */
+
+#include <openssl/core.h>
+#include <openssl/evp.h>
+#include <openssl/err.h>
+#include <openssl/asn1.h>        /* evp_locl.h needs it */
+#include <openssl/safestack.h>   /* evp_locl.h needs it */
+#include "internal/evp_int.h"    /* evp_locl.h needs it */
+#include "evp_locl.h"
+
+int evp_do_ciph_getparams(const void *vciph, void *ignored,
+                          OSSL_PARAM params[])
+{
+    const EVP_CIPHER *ciph = vciph;
+
+    if (ciph->prov == NULL)
+        return -2;
+    if (ciph->get_params == NULL)
+        return -1;
+    return ciph->get_params(params);
+}
+
+int evp_do_ciph_ctx_getparams(const void *vciph, void *provctx,
+                              OSSL_PARAM params[])
+{
+    const EVP_CIPHER *ciph = vciph;
+
+    if (ciph->prov == NULL)
+        return -2;
+    if (ciph->ctx_get_params == NULL)
+        return -1;
+    return ciph->ctx_get_params(provctx, params);
+}
+
+int evp_do_ciph_ctx_setparams(const void *vciph, void *provctx,
+                              OSSL_PARAM params[])
+{
+    const EVP_CIPHER *ciph = vciph;
+
+    if (ciph->prov == NULL)
+        return -2;
+    if (ciph->ctx_set_params == NULL)
+        return -1;
+    return ciph->ctx_set_params(provctx, params);
+}
+
+int evp_do_param(const void *method, void *ptr, size_t sz, const char *key,
+                 int datatype,
+                 int (*cb)(const void *method, void *ctx, OSSL_PARAM params[]),
+                 void *cb_ctx)
+{
+    OSSL_PARAM params[2] = {
+        OSSL_PARAM_END,
+        OSSL_PARAM_END
+    };
+    int ret;
+
+    params[0].key = key;
+    params[0].data_type = datatype;
+    params[0].data = ptr;
+    params[0].data_size = sz;
+
+    ret = cb(method, cb_ctx, params);
+    if (ret == -1) {
+        EVPerr(0, EVP_R_CTRL_NOT_IMPLEMENTED);
+        ret = 0;
+    }
+    return ret;
+}
index 2fb5fe2..e781ebe 100644 (file)
@@ -490,7 +490,7 @@ const unsigned char *EVP_CIPHER_CTX_original_iv(const EVP_CIPHER_CTX *ctx);
 unsigned char *EVP_CIPHER_CTX_iv_noconst(EVP_CIPHER_CTX *ctx);
 unsigned char *EVP_CIPHER_CTX_buf_noconst(EVP_CIPHER_CTX *ctx);
 int EVP_CIPHER_CTX_num(const EVP_CIPHER_CTX *ctx);
-void EVP_CIPHER_CTX_set_num(EVP_CIPHER_CTX *ctx, int num);
+int EVP_CIPHER_CTX_set_num(EVP_CIPHER_CTX *ctx, int num);
 int EVP_CIPHER_CTX_copy(EVP_CIPHER_CTX *out, const EVP_CIPHER_CTX *in);
 void *EVP_CIPHER_CTX_get_app_data(const EVP_CIPHER_CTX *ctx);
 void EVP_CIPHER_CTX_set_app_data(EVP_CIPHER_CTX *ctx, void *data);