s390x assembly pack: accelerate X25519, X448, Ed25519 and Ed448
[openssl.git] / crypto / evp / pkey_mac.c
index 858ca28..9853e09 100644 (file)
@@ -7,9 +7,14 @@
  * https://www.openssl.org/source/license.html
  */
 
+#include <string.h>
 #include <openssl/err.h>
 #include <openssl/evp.h>
+#include <openssl/engine.h>
+#include <openssl/params.h>
+#include <openssl/core_names.h>
 #include "internal/evp_int.h"
+#include "evp_locl.h"
 
 /* MAC PKEY context structure */
 
@@ -39,18 +44,21 @@ typedef struct {
     } raw_data;
 } MAC_PKEY_CTX;
 
+static void pkey_mac_cleanup(EVP_PKEY_CTX *ctx);
+
 static int pkey_mac_init(EVP_PKEY_CTX *ctx)
 {
     MAC_PKEY_CTX *hctx;
+    /* We're being smart and using the same base NIDs for PKEY and for MAC */
     int nid = ctx->pmeth->pkey_id;
+    EVP_MAC *mac = EVP_MAC_fetch(NULL, OBJ_nid2sn(nid), NULL);
 
     if ((hctx = OPENSSL_zalloc(sizeof(*hctx))) == NULL) {
         EVPerr(EVP_F_PKEY_MAC_INIT, ERR_R_MALLOC_FAILURE);
         return 0;
     }
 
-    /* We're being smart and using the same base NIDs for PKEY and for MAC */
-    hctx->ctx = EVP_MAC_CTX_new_id(nid);
+    hctx->ctx = EVP_MAC_CTX_new(mac);
     if (hctx->ctx == NULL) {
         OPENSSL_free(hctx);
         return 0;
@@ -63,27 +71,47 @@ static int pkey_mac_init(EVP_PKEY_CTX *ctx)
         hctx->raw_data.ktmp.type = V_ASN1_OCTET_STRING;
     }
 
+    pkey_mac_cleanup(ctx);
     EVP_PKEY_CTX_set_data(ctx, hctx);
     ctx->keygen_info_count = 0;
 
     return 1;
 }
 
-static void pkey_mac_cleanup(EVP_PKEY_CTX *ctx);
-
 static int pkey_mac_copy(EVP_PKEY_CTX *dst, const EVP_PKEY_CTX *src)
 {
     MAC_PKEY_CTX *sctx, *dctx;
 
-    if (!pkey_mac_init(dst))
+    sctx = EVP_PKEY_CTX_get_data(src);
+    if (sctx->ctx->data == NULL)
         return 0;
 
-    sctx = EVP_PKEY_CTX_get_data(src);
-    dctx = EVP_PKEY_CTX_get_data(dst);
+    dctx = OPENSSL_zalloc(sizeof(*dctx));
+    if (dctx == NULL) {
+        EVPerr(EVP_F_PKEY_MAC_COPY, ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+
+    EVP_PKEY_CTX_set_data(dst, dctx);
+    dst->keygen_info_count = 0;
+
+    dctx->ctx = EVP_MAC_CTX_dup(sctx->ctx);
+    if (dctx->ctx == NULL)
+        goto err;
 
-    if (!EVP_MAC_CTX_copy(dctx->ctx, sctx->ctx))
+    /*
+     * Normally, nothing special would be done with the MAC method.  In
+     * this particular case, though, the MAC method was fetched internally
+     * by pkey_mac_init() above or by EVP_PKEY_new_CMAC_key() and passed
+     * via the EVP_MAC_CTX, so it is effectively like every new EVP_MAC_CTX
+     * fetches the MAC method anew in this case.  Therefore, its reference
+     * count must be adjusted here.
+     */
+    if (!EVP_MAC_up_ref(EVP_MAC_CTX_mac(dctx->ctx)))
         goto err;
 
+    dctx->type = sctx->type;
+
     switch (dctx->type) {
     case MAC_TYPE_RAW:
         dctx->raw_data.md = sctx->raw_data.md;
@@ -100,15 +128,22 @@ static int pkey_mac_copy(EVP_PKEY_CTX *dst, const EVP_PKEY_CTX *src)
     }
     return 1;
  err:
-    pkey_mac_cleanup (dst);
+    pkey_mac_cleanup(dst);
     return 0;
 }
 
 static void pkey_mac_cleanup(EVP_PKEY_CTX *ctx)
 {
-    MAC_PKEY_CTX *hctx = EVP_PKEY_CTX_get_data(ctx);
+    /*
+     * For the exact same reasons the MAC reference count is incremented
+     * in pkey_mac_copy() above, it must be explicitly freed here.
+     */
+
+    MAC_PKEY_CTX *hctx = ctx == NULL ? NULL : EVP_PKEY_CTX_get_data(ctx);
 
     if (hctx != NULL) {
+        EVP_MAC *mac = EVP_MAC_CTX_mac(hctx->ctx);
+
         switch (hctx->type) {
         case MAC_TYPE_RAW:
             OPENSSL_clear_free(hctx->raw_data.ktmp.data,
@@ -116,6 +151,7 @@ static void pkey_mac_cleanup(EVP_PKEY_CTX *ctx)
             break;
         }
         EVP_MAC_CTX_free(hctx->ctx);
+        EVP_MAC_free(mac);
         OPENSSL_free(hctx);
         EVP_PKEY_CTX_set_data(ctx, NULL);
     }
@@ -141,14 +177,12 @@ static int pkey_mac_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
         break;
     case MAC_TYPE_MAC:
         {
-            EVP_MAC_CTX *cmkey = EVP_MAC_CTX_new_id(nid);
+            EVP_MAC_CTX *cmkey = EVP_MAC_CTX_dup(hctx->ctx);
 
             if (cmkey == NULL)
                 return 0;
-            if (!EVP_MAC_CTX_copy(cmkey, hctx->ctx)) {
-                EVP_MAC_CTX_free(cmkey);
+            if (!EVP_MAC_up_ref(EVP_MAC_CTX_mac(hctx->ctx)))
                 return 0;
-            }
             EVP_PKEY_assign(pkey, nid, cmkey);
         }
         break;
@@ -187,25 +221,34 @@ static int pkey_mac_signctx_init(EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx)
         && (ctx->pmeth->flags & EVP_PKEY_FLAG_SIGCTX_CUSTOM) != 0;
 
     if (set_key) {
-        if (EVP_PKEY_id(EVP_PKEY_CTX_get0_pkey(ctx))
-            != EVP_MAC_nid(EVP_MAC_CTX_mac(hctx->ctx)))
+        if (!EVP_MAC_is_a(EVP_MAC_CTX_mac(hctx->ctx),
+                          OBJ_nid2sn(EVP_PKEY_id(EVP_PKEY_CTX_get0_pkey(ctx)))))
             return 0;
         key = EVP_PKEY_get0(EVP_PKEY_CTX_get0_pkey(ctx));
         if (key == NULL)
             return 0;
     }
 
-    /* Some MACs don't support this control...  that's fine */
-    EVP_MAC_ctrl(hctx->ctx, EVP_MAC_CTRL_SET_FLAGS,
-                 EVP_MD_CTX_test_flags(mctx, ~EVP_MD_CTX_FLAG_NO_INIT));
-
     EVP_MD_CTX_set_flags(mctx, EVP_MD_CTX_FLAG_NO_INIT);
     EVP_MD_CTX_set_update_fn(mctx, int_update);
 
-    if (set_key)
-        rv = EVP_MAC_ctrl(hctx->ctx, EVP_MAC_CTRL_SET_KEY, key->data,
-                          key->length);
-    return rv > 0;
+    /* Some MACs don't support this control...  that's fine */
+    {
+        OSSL_PARAM params[3];
+        size_t params_n = 0;
+        int flags = EVP_MD_CTX_test_flags(mctx, ~EVP_MD_CTX_FLAG_NO_INIT);
+
+        /* TODO(3.0) "flags" isn't quite right, i.e. a quick hack for now */
+        params[params_n++] =
+            OSSL_PARAM_construct_int(OSSL_MAC_PARAM_FLAGS, &flags);
+        if (set_key)
+            params[params_n++] =
+                OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_KEY,
+                                                  key->data, key->length);
+        params[params_n++] = OSSL_PARAM_construct_end();
+        rv = EVP_MAC_CTX_set_params(hctx->ctx, params);
+    }
+    return rv;
 }
 
 static int pkey_mac_signctx(EVP_PKEY_CTX *ctx, unsigned char *sig,
@@ -213,7 +256,7 @@ static int pkey_mac_signctx(EVP_PKEY_CTX *ctx, unsigned char *sig,
 {
     MAC_PKEY_CTX *hctx = EVP_PKEY_CTX_get_data(ctx);
 
-    return EVP_MAC_final(hctx->ctx, sig, siglen);
+    return EVP_MAC_final(hctx->ctx, sig, siglen, EVP_MAC_size(hctx->ctx));
 }
 
 static int pkey_mac_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
@@ -228,14 +271,23 @@ static int pkey_mac_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
             return -2;       /* The raw types don't support ciphers */
         case MAC_TYPE_MAC:
             {
-                int rv;
-
-                if ((rv = EVP_MAC_ctrl(hctx->ctx, EVP_MAC_CTRL_SET_ENGINE,
-                                       ctx->engine)) < 0
-                    || (rv = EVP_MAC_ctrl(hctx->ctx, EVP_MAC_CTRL_SET_CIPHER,
-                                          p2)) < 0
-                    || !(rv = EVP_MAC_init(hctx->ctx)))
-                    return rv;
+                OSSL_PARAM params[3];
+                size_t params_n = 0;
+                char *ciphname = (char *)OBJ_nid2sn(EVP_CIPHER_nid(p2));
+#ifndef OPENSSL_NO_ENGINE
+                char *engineid = (char *)ENGINE_get_id(ctx->engine);
+
+                params[params_n++] =
+                    OSSL_PARAM_construct_utf8_string("engine", engineid, 0);
+#endif
+                params[params_n++] =
+                    OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_CIPHER,
+                                                     ciphname, 0);
+                params[params_n] = OSSL_PARAM_construct_end();
+
+                if (!EVP_MAC_CTX_set_params(hctx->ctx, params)
+                    || !EVP_MAC_init(hctx->ctx))
+                    return 0;
             }
             break;
         default:
@@ -249,13 +301,18 @@ static int pkey_mac_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
         case MAC_TYPE_RAW:
             hctx->raw_data.md = p2;
             break;
-        case MAC_TYPE_MAC:
-            if (ctx->pkey != NULL
-                && !EVP_MAC_CTX_copy(hctx->ctx,
-                                     (EVP_MAC_CTX *)ctx->pkey->pkey.ptr))
-                return 0;
-            if (!EVP_MAC_init(hctx->ctx))
-                return 0;
+        case MAC_TYPE_MAC: {
+                EVP_MAC_CTX *new_mac_ctx;
+
+                if (ctx->pkey == NULL)
+                    return 0;
+                new_mac_ctx = EVP_MAC_CTX_dup((EVP_MAC_CTX *)ctx->pkey
+                                              ->pkey.ptr);
+                if (new_mac_ctx == NULL)
+                    return 0;
+                EVP_MAC_CTX_free(hctx->ctx);
+                hctx->ctx = new_mac_ctx;
+            }
             break;
         default:
             /* This should be dead code */
@@ -264,8 +321,40 @@ static int pkey_mac_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
         break;
 
     case EVP_PKEY_CTRL_SET_DIGEST_SIZE:
-        return EVP_MAC_ctrl(hctx->ctx, EVP_MAC_CTRL_SET_SIZE, (size_t)p1);
+        {
+            OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END };
+            size_t size = (size_t)p1;
+            size_t verify = 0;
+
+            /*
+             * We verify that the length is actually set by getting back
+             * the same parameter and checking that it matches what we
+             * tried to set.
+             * TODO(3.0) when we have a more direct mechanism to check if
+             * a parameter was used, we must refactor this to use that.
+             */
+
+            params[0] =
+                OSSL_PARAM_construct_size_t(OSSL_MAC_PARAM_SIZE, &size);
+
+            if (!EVP_MAC_CTX_set_params(hctx->ctx, params))
+                return 0;
+
+            params[0] =
+                OSSL_PARAM_construct_size_t(OSSL_MAC_PARAM_SIZE, &verify);
+
+            if (!EVP_MAC_CTX_get_params(hctx->ctx, params))
+                return 0;
 
+            /*
+             * Since EVP_MAC_CTX_{get,set}_params() returned successfully,
+             * we can only assume that the size was ignored, i.e. this
+             * control is unsupported.
+             */
+            if (verify != size)
+                return -2;
+        }
+        break;
     case EVP_PKEY_CTRL_SET_MAC_KEY:
         switch (hctx->type) {
         case MAC_TYPE_RAW:
@@ -275,8 +364,17 @@ static int pkey_mac_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
                 return 0;
             break;
         case MAC_TYPE_MAC:
-            if (!EVP_MAC_ctrl(hctx->ctx, EVP_MAC_CTRL_SET_KEY, p2, p1))
-                return 0;
+            {
+                OSSL_PARAM params[2];
+                size_t params_n = 0;
+
+                params[params_n++] =
+                    OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_KEY,
+                                                      p2, p1);
+                params[params_n] = OSSL_PARAM_construct_end();
+
+                return EVP_MAC_CTX_set_params(hctx->ctx, params);
+            }
             break;
         default:
             /* This should be dead code */
@@ -291,17 +389,29 @@ static int pkey_mac_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
             if (!EVP_MAC_init(hctx->ctx))
                 return 0;
             {
-                int rv;
                 ASN1_OCTET_STRING *key =
                     (ASN1_OCTET_STRING *)ctx->pkey->pkey.ptr;
-
-                if ((rv = EVP_MAC_ctrl(hctx->ctx, EVP_MAC_CTRL_SET_ENGINE,
-                                       ctx->engine)) < 0
-                    || (rv = EVP_MAC_ctrl(hctx->ctx, EVP_MAC_CTRL_SET_MD,
-                                          hctx->raw_data.md)) < 0
-                    || (rv = EVP_MAC_ctrl(hctx->ctx, EVP_MAC_CTRL_SET_KEY,
-                                          key->data, key->length)) < 0)
-                    return rv;
+                OSSL_PARAM params[4];
+                size_t params_n = 0;
+                char *mdname =
+                    (char *)OBJ_nid2sn(EVP_MD_nid(hctx->raw_data.md));
+#ifndef OPENSSL_NO_ENGINE
+                char *engineid = ctx->engine == NULL
+                    ? NULL : (char *)ENGINE_get_id(ctx->engine);
+
+                if (engineid != NULL)
+                    params[params_n++] =
+                        OSSL_PARAM_construct_utf8_string("engine", engineid, 0);
+#endif
+                params[params_n++] =
+                    OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST,
+                                                     mdname, 0);
+                params[params_n++] =
+                    OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_KEY,
+                                                      key->data, key->length);
+                params[params_n] = OSSL_PARAM_construct_end();
+
+                return EVP_MAC_CTX_set_params(hctx->ctx, params);
             }
             break;
         case MAC_TYPE_MAC:
@@ -323,11 +433,35 @@ static int pkey_mac_ctrl_str(EVP_PKEY_CTX *ctx,
                               const char *type, const char *value)
 {
     MAC_PKEY_CTX *hctx = EVP_PKEY_CTX_get_data(ctx);
+    const EVP_MAC *mac = EVP_MAC_CTX_mac(hctx->ctx);
+    OSSL_PARAM params[2];
+    int ok = 0;
 
-    return EVP_MAC_ctrl_str(hctx->ctx, type, value);
+    /*
+     * Translation of some control names that are equivalent to a single
+     * parameter name.
+     *
+     * "md" and "digest" are the same thing, we use the single "digest"
+     *
+     * "digestsize" was a setting control in siphash, but naming wise,
+     * it's really the same as "size".
+     */
+    if (strcmp(type, "md") == 0)
+        type = OSSL_MAC_PARAM_DIGEST;
+    else if (strcmp(type, "digestsize") == 0)
+        type = OSSL_MAC_PARAM_SIZE;
+
+    if (!OSSL_PARAM_allocate_from_text(&params[0],
+                                       EVP_MAC_CTX_settable_params(mac),
+                                       type, value, strlen(value) + 1))
+        return 0;
+    params[1] = OSSL_PARAM_construct_end();
+    ok = EVP_MAC_CTX_set_params(hctx->ctx, params);
+    OPENSSL_free(params[0].data);
+    return ok;
 }
 
-const EVP_PKEY_METHOD cmac_pkey_meth = {
+static const EVP_PKEY_METHOD cmac_pkey_meth = {
     EVP_PKEY_CMAC,
     EVP_PKEY_FLAG_SIGCTX_CUSTOM,
     pkey_mac_init,
@@ -360,7 +494,12 @@ const EVP_PKEY_METHOD cmac_pkey_meth = {
     pkey_mac_ctrl_str
 };
 
-const EVP_PKEY_METHOD hmac_pkey_meth = {
+const EVP_PKEY_METHOD *cmac_pkey_method(void)
+{
+    return &cmac_pkey_meth;
+}
+
+static const EVP_PKEY_METHOD hmac_pkey_meth = {
     EVP_PKEY_HMAC,
     0,
     pkey_mac_init,
@@ -393,7 +532,12 @@ const EVP_PKEY_METHOD hmac_pkey_meth = {
     pkey_mac_ctrl_str
 };
 
-const EVP_PKEY_METHOD siphash_pkey_meth = {
+const EVP_PKEY_METHOD *hmac_pkey_method(void)
+{
+    return &hmac_pkey_meth;
+}
+
+static const EVP_PKEY_METHOD siphash_pkey_meth = {
     EVP_PKEY_SIPHASH,
     EVP_PKEY_FLAG_SIGCTX_CUSTOM,
     pkey_mac_init,
@@ -426,7 +570,12 @@ const EVP_PKEY_METHOD siphash_pkey_meth = {
     pkey_mac_ctrl_str
 };
 
-const EVP_PKEY_METHOD poly1305_pkey_meth = {
+const EVP_PKEY_METHOD *siphash_pkey_method(void)
+{
+    return &siphash_pkey_meth;
+}
+
+static const EVP_PKEY_METHOD poly1305_pkey_meth = {
     EVP_PKEY_POLY1305,
     EVP_PKEY_FLAG_SIGCTX_CUSTOM,
     pkey_mac_init,
@@ -458,3 +607,8 @@ const EVP_PKEY_METHOD poly1305_pkey_meth = {
     pkey_mac_ctrl,
     pkey_mac_ctrl_str
 };
+
+const EVP_PKEY_METHOD *poly1305_pkey_method(void)
+{
+    return &poly1305_pkey_meth;
+}