Skip to content

Commit

Permalink
Add GCM support for EVP_CTRL_GCM_IV_GEN and EVP_CTRL_GCM_SET_IV_INV t…
Browse files Browse the repository at this point in the history
…o providers

Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from #10173)
  • Loading branch information
slontis committed Jan 10, 2020
1 parent 1e88796 commit 11b4435
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 55 deletions.
20 changes: 16 additions & 4 deletions crypto/evp/evp_enc.c
Expand Up @@ -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 */
Expand Down
12 changes: 12 additions & 0 deletions doc/man7/provider-cipher.pod
Expand Up @@ -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
Expand Down
42 changes: 22 additions & 20 deletions include/openssl/core_names.h
Expand Up @@ -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 */
Expand Down
2 changes: 2 additions & 0 deletions providers/implementations/ciphers/ciphercommon.c
Expand Up @@ -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)
Expand All @@ -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)
Expand Down
97 changes: 66 additions & 31 deletions providers/implementations/ciphers/ciphercommon_gcm.c
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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;
Expand All @@ -493,3 +527,4 @@ static int gcm_tls_cipher(PROV_GCM_CTX *ctx, unsigned char *out, size_t *padlen,
*padlen = plen;
return rv;
}

0 comments on commit 11b4435

Please sign in to comment.