Add GCM support for EVP_CTRL_GCM_IV_GEN and EVP_CTRL_GCM_SET_IV_INV to providers
authorShane Lontis <shane.lontis@oracle.com>
Mon, 14 Oct 2019 10:59:31 +0000 (20:59 +1000)
committerShane Lontis <shane.lontis@oracle.com>
Fri, 10 Jan 2020 01:58:27 +0000 (11:58 +1000)
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/10173)

crypto/evp/evp_enc.c
doc/man7/provider-cipher.pod
include/openssl/core_names.h
providers/implementations/ciphers/ciphercommon.c
providers/implementations/ciphers/ciphercommon_gcm.c

index c650addbd1a4e5aca1f64d3480f5cf1a25391d94..35feec17f6ffa26d7f7cd0bb0a816b357b76c786 100644 (file)
@@ -1135,10 +1135,22 @@ int EVP_CIPHER_CTX_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr)
             return 0;
         params[0] = OSSL_PARAM_construct_size_t(OSSL_CIPHER_PARAM_IVLEN, &sz);
         break;
-    case EVP_CTRL_GCM_SET_IV_FIXED:
-        params[0] =
-            OSSL_PARAM_construct_octet_string(OSSL_CIPHER_PARAM_AEAD_TLS1_IV_FIXED,
-                                              ptr, sz);
+    case EVP_CTRL_AEAD_SET_IV_FIXED:
+        params[0] = OSSL_PARAM_construct_octet_string(
+                        OSSL_CIPHER_PARAM_AEAD_TLS1_IV_FIXED, ptr, sz);
+        break;
+    case EVP_CTRL_GCM_IV_GEN:
+        set_params = 0;
+        if (arg < 0)
+            sz = 0; /* special case that uses the iv length */
+        params[0] = OSSL_PARAM_construct_octet_string(
+                        OSSL_CIPHER_PARAM_AEAD_TLS1_GET_IV_GEN, ptr, sz);
+        break;
+    case EVP_CTRL_GCM_SET_IV_INV:
+        if (arg < 0)
+            return 0;
+        params[0] = OSSL_PARAM_construct_octet_string(
+                        OSSL_CIPHER_PARAM_AEAD_TLS1_SET_IV_INV, ptr, sz);
         break;
     case EVP_CTRL_GET_RC5_ROUNDS:
         set_params = 0; /* Fall thru */
index 7ad239bcb63ff8af99f6f655570bf424470b360a..80bba1f9781c67bdb4879062415158ce77033257 100644 (file)
@@ -349,6 +349,18 @@ by AES SIV ciphers which disallow multiple operations by default.
 Setting "speed" to 1 allows another encrypt or decrypt operation to be
 performed. This is used for performance testing.
 
+=item "tlsivgen" (B<OSSL_CIPHER_PARAM_AEAD_TLS1_GET_IV_GEN>) <octet string>
+
+Gets the invocation field generated for encryption.
+Can only be called after "tlsivfixed" is set.
+This is only used for GCM mode.
+
+=item "tlsivinv" (B<OSSL_CIPHER_PARAM_AEAD_TLS1_SET_IV_INV>) <octet string>
+
+Sets the invocation field used for decryption.
+Can only be called after "tlsivfixed" is set.
+This is only used for GCM mode.
+
 =item "tls1multi_enc" (B<OSSL_CIPHER_PARAM_TLS1_MULTIBLOCK_ENC>) <octet string>
 
 Triggers a multiblock tls1 encrypt operation for a tls1 aware cipher that supports
index 446af5fa8e6821acb66bd3b80c1ff60c20b27c0f..db9cb9ab2d4491e805bac9122822cd34ed01df39 100644 (file)
@@ -51,27 +51,29 @@ extern "C" {
 #define OSSL_ALG_PARAM_PROPERTIES   "properties"/* utf8_string */
 
 /* cipher parameters */
-#define OSSL_CIPHER_PARAM_PADDING   "padding"    /* uint */
-#define OSSL_CIPHER_PARAM_MODE      "mode"       /* uint */
-#define OSSL_CIPHER_PARAM_BLOCK_SIZE "blocksize" /* size_t */
-#define OSSL_CIPHER_PARAM_FLAGS     "flags"      /* ulong */
-#define OSSL_CIPHER_PARAM_KEYLEN    "keylen"     /* size_t */
-#define OSSL_CIPHER_PARAM_IVLEN     "ivlen"      /* size_t */
-#define OSSL_CIPHER_PARAM_IV        "iv"         /* octet_string OR octet_ptr */
-#define OSSL_CIPHER_PARAM_NUM       "num"        /* uint */
-#define OSSL_CIPHER_PARAM_ROUNDS    "rounds"     /* uint */
-#define OSSL_CIPHER_PARAM_AEAD_TAG           "tag"        /* octet_string */
-#define OSSL_CIPHER_PARAM_AEAD_TLS1_AAD      "tlsaad"     /* octet_string */
-#define OSSL_CIPHER_PARAM_AEAD_TLS1_AAD_PAD  "tlsaadpad"  /* size_t */
-#define OSSL_CIPHER_PARAM_AEAD_TLS1_IV_FIXED "tlsivfixed" /* octet_string */
-#define OSSL_CIPHER_PARAM_AEAD_IVLEN         OSSL_CIPHER_PARAM_IVLEN
-#define OSSL_CIPHER_PARAM_AEAD_TAGLEN        "taglen"     /* size_t */
-#define OSSL_CIPHER_PARAM_AEAD_MAC_KEY       "mackey"     /* octet_string */
-#define OSSL_CIPHER_PARAM_RANDOM_KEY         "randkey"    /* octet_string */
-#define OSSL_CIPHER_PARAM_RC2_KEYBITS        "keybits"    /* size_t */
-#define OSSL_CIPHER_PARAM_SPEED              "speed"      /* uint */
+#define OSSL_CIPHER_PARAM_PADDING              "padding"    /* uint */
+#define OSSL_CIPHER_PARAM_MODE                 "mode"       /* uint */
+#define OSSL_CIPHER_PARAM_BLOCK_SIZE           "blocksize" /* size_t */
+#define OSSL_CIPHER_PARAM_FLAGS                "flags"      /* ulong */
+#define OSSL_CIPHER_PARAM_KEYLEN               "keylen"     /* size_t */
+#define OSSL_CIPHER_PARAM_IVLEN                "ivlen"      /* size_t */
+#define OSSL_CIPHER_PARAM_IV                   "iv"         /* octet_string OR octet_ptr */
+#define OSSL_CIPHER_PARAM_NUM                  "num"        /* uint */
+#define OSSL_CIPHER_PARAM_ROUNDS               "rounds"     /* uint */
+#define OSSL_CIPHER_PARAM_AEAD_TAG             "tag"        /* octet_string */
+#define OSSL_CIPHER_PARAM_AEAD_TLS1_AAD        "tlsaad"     /* octet_string */
+#define OSSL_CIPHER_PARAM_AEAD_TLS1_AAD_PAD    "tlsaadpad"  /* size_t */
+#define OSSL_CIPHER_PARAM_AEAD_TLS1_IV_FIXED   "tlsivfixed" /* octet_string */
+#define OSSL_CIPHER_PARAM_AEAD_TLS1_GET_IV_GEN "tlsivgen" /* octet_string */
+#define OSSL_CIPHER_PARAM_AEAD_TLS1_SET_IV_INV "tlsivinv" /* octet_string */
+#define OSSL_CIPHER_PARAM_AEAD_IVLEN           OSSL_CIPHER_PARAM_IVLEN
+#define OSSL_CIPHER_PARAM_AEAD_TAGLEN          "taglen"     /* size_t */
+#define OSSL_CIPHER_PARAM_AEAD_MAC_KEY         "mackey"     /* octet_string */
+#define OSSL_CIPHER_PARAM_RANDOM_KEY           "randkey"    /* octet_string */
+#define OSSL_CIPHER_PARAM_RC2_KEYBITS          "keybits"    /* size_t */
+#define OSSL_CIPHER_PARAM_SPEED                "speed"      /* uint */
 /* For passing the AlgorithmIdentifier parameter in DER form */
-#define OSSL_CIPHER_PARAM_ALG_ID             "alg_id_param" /* octet_string */
+#define OSSL_CIPHER_PARAM_ALG_ID               "alg_id_param" /* octet_string */
 
 #define OSSL_CIPHER_PARAM_TLS1_MULTIBLOCK_MAX_SEND_FRAGMENT                    \
     "tls1multi_maxsndfrag" /* uint */
index a6b890704e1ea73abbd41dbd036387ccc4fb1867..967622cf64e196321eebfaec9807412deba281c5 100644 (file)
@@ -109,6 +109,7 @@ static const OSSL_PARAM cipher_aead_known_gettable_ctx_params[] = {
     OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_IV, NULL, 0),
     OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_AEAD_TAG, NULL, 0),
     OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_AEAD_TLS1_AAD_PAD, NULL),
+    OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_AEAD_TLS1_GET_IV_GEN, NULL, 0),
     OSSL_PARAM_END
 };
 const OSSL_PARAM *cipher_aead_gettable_ctx_params(void)
@@ -121,6 +122,7 @@ static const OSSL_PARAM cipher_aead_known_settable_ctx_params[] = {
     OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_AEAD_TAG, NULL, 0),
     OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_AEAD_TLS1_AAD, NULL, 0),
     OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_AEAD_TLS1_IV_FIXED, NULL, 0),
+    OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_AEAD_TLS1_SET_IV_INV, NULL, 0),
     OSSL_PARAM_END
 };
 const OSSL_PARAM *cipher_aead_settable_ctx_params(void)
index 803f810a30088c1ee58d8aff3b3430f7c7d734a8..a6928e1ba36f7802aed5af08b4c3fe02c82b2cfa 100644 (file)
@@ -77,6 +77,54 @@ int gcm_dinit(void *vctx, const unsigned char *key, size_t keylen,
     return gcm_init(vctx, key, keylen, iv, ivlen, 0);
 }
 
+/* increment counter (64-bit int) by 1 */
+static void ctr64_inc(unsigned char *counter)
+{
+    int n = 8;
+    unsigned char c;
+
+    do {
+        --n;
+        c = counter[n];
+        ++c;
+        counter[n] = c;
+        if (c > 0)
+            return;
+    } while (n > 0);
+}
+
+static int getivgen(PROV_GCM_CTX *ctx, unsigned char *out, size_t olen)
+{
+    if (!ctx->iv_gen
+        || !ctx->key_set
+        || !ctx->hw->setiv(ctx, ctx->iv, ctx->ivlen))
+        return 0;
+    if (olen == 0 || olen > ctx->ivlen)
+        olen = ctx->ivlen;
+    memcpy(out, ctx->iv + ctx->ivlen - olen, olen);
+    /*
+     * Invocation field will be at least 8 bytes in size and so no need
+     * to check wrap around or increment more than last 8 bytes.
+     */
+    ctr64_inc(ctx->iv + ctx->ivlen - 8);
+    ctx->iv_state = IV_STATE_COPIED;
+    return 1;
+}
+
+static int setivinv(PROV_GCM_CTX *ctx, unsigned char *in, size_t inl)
+{
+    if (!ctx->iv_gen
+        || !ctx->key_set
+        || ctx->enc)
+        return 0;
+
+    memcpy(ctx->iv + ctx->ivlen - inl, in, inl);
+    if (!ctx->hw->setiv(ctx, ctx->iv, ctx->ivlen))
+        return 0;
+    ctx->iv_state = IV_STATE_COPIED;
+    return 1;
+}
+
 int gcm_get_ctx_params(void *vctx, OSSL_PARAM params[])
 {
     PROV_GCM_CTX *ctx = (PROV_GCM_CTX *)vctx;
@@ -138,7 +186,13 @@ int gcm_get_ctx_params(void *vctx, OSSL_PARAM params[])
             return 0;
         }
     }
-
+    p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TLS1_GET_IV_GEN);
+    if (p != NULL) {
+        if (p->data == NULL
+            || p->data_type != OSSL_PARAM_OCTET_STRING
+            || !getivgen(ctx, p->data, p->data_size))
+            return 0;
+    }
     return 1;
 }
 
@@ -201,6 +255,14 @@ int gcm_set_ctx_params(void *vctx, const OSSL_PARAM params[])
             return 0;
         }
     }
+    p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TLS1_SET_IV_INV);
+    if (p != NULL) {
+        if (p->data == NULL
+            || p->data_type != OSSL_PARAM_OCTET_STRING
+            || !setivinv(ctx, p->data, p->data_size))
+            return 0;
+    }
+
 
     return 1;
 }
@@ -397,22 +459,6 @@ static int gcm_tls_iv_set_fixed(PROV_GCM_CTX *ctx, unsigned char *iv,
     return 1;
 }
 
-/* increment counter (64-bit int) by 1 */
-static void ctr64_inc(unsigned char *counter)
-{
-    int n = 8;
-    unsigned char c;
-
-    do {
-        --n;
-        c = counter[n];
-        ++c;
-        counter[n] = c;
-        if (c > 0)
-            return;
-    } while (n > 0);
-}
-
 /*
  * Handle TLS GCM packet format. This consists of the last portion of the IV
  * followed by the payload and finally the tag. On encrypt generate IV,
@@ -445,29 +491,17 @@ static int gcm_tls_cipher(PROV_GCM_CTX *ctx, unsigned char *out, size_t *padlen,
         goto err;
     }
 
-    if (ctx->iv_gen == 0)
-        goto err;
     /*
      * Set IV from start of buffer or generate IV and write to start of
      * buffer.
      */
     if (ctx->enc) {
-        if (!ctx->hw->setiv(ctx, ctx->iv, ctx->ivlen))
+        if (!getivgen(ctx, out, arg))
             goto err;
-        if (arg > ctx->ivlen)
-            arg = ctx->ivlen;
-        memcpy(out, ctx->iv + ctx->ivlen - arg, arg);
-        /*
-         * Invocation field will be at least 8 bytes in size and so no need
-         * to check wrap around or increment more than last 8 bytes.
-         */
-        ctr64_inc(ctx->iv + ctx->ivlen - 8);
     } else {
-        memcpy(ctx->iv + ctx->ivlen - arg, out, arg);
-        if (!ctx->hw->setiv(ctx, ctx->iv, ctx->ivlen))
+        if (!setivinv(ctx, out, arg))
             goto err;
     }
-    ctx->iv_state = IV_STATE_COPIED;
 
     /* Fix buffer and length to point to payload */
     in += EVP_GCM_TLS_EXPLICIT_IV_LEN;
@@ -493,3 +527,4 @@ err:
     *padlen = plen;
     return rv;
 }
+