Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add GCM support for EVP_CTRL_GCM_IV_GEN/EVP_CTRL_GCM_SET_IV_INV to providers #10173

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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);
slontis marked this conversation as resolved.
Show resolved Hide resolved
break;
slontis marked this conversation as resolved.
Show resolved Hide resolved
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.

slontis marked this conversation as resolved.
Show resolved Hide resolved
=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;
}