#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
+#include <stdbool.h>
#include <openssl/evp.h>
#include <openssl/kdf.h>
#include <openssl/bn.h>
static OSSL_FUNC_kdf_get_ctx_params_fn kdf_srtpkdf_get_ctx_params;
static int SRTPKDF(OSSL_LIB_CTX *provctx, const EVP_CIPHER *cipher,
- const unsigned char *mkey, const unsigned char *msalt, const unsigned char *index,
+ const uint8_t *mkey, const uint8_t *msalt,
+ const uint8_t *index, size_t index_len,
const uint32_t kdr, const uint32_t kdr_n,
- const uint32_t label, unsigned char *obuffer, const size_t keylen);
+ const uint32_t label, uint8_t *obuffer, const size_t keylen);
typedef struct {
/* Warning: Any changes to this structure may require you to update kdf_srtpkdf_dup */
return 1;
}
+static int kdf_srtpkdf_check_key(KDF_SRTPKDF *ctx)
+{
+ const EVP_CIPHER *cipher = cipher = ossl_prov_cipher_cipher(&ctx->cipher);
+
+ if (cipher != NULL) {
+ if (ctx->key == NULL) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY);
+ return 0;
+ }
+ if (ctx->key_len != (size_t)EVP_CIPHER_get_key_length(cipher)) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH);
+ return 0;
+ }
+ }
+ return 1;
+}
+
static int kdf_srtpkdf_derive(void *vctx, unsigned char *key, size_t keylen,
const OSSL_PARAM params[])
{
ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_CIPHER);
return 0;
}
- if (ctx->key == NULL) {
- ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY);
+ if (!kdf_srtpkdf_check_key(ctx))
return 0;
- }
if (ctx->salt == NULL) {
ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_SALT);
return 0;
}
- if (ctx->kdr > 0) {
- uint32_t n = 0;
- if (!is_power_of_two(ctx->kdr, &n)
- || n > KDF_SRTP_MAX_KDR) {
- ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KDR);
- return 0;
- }
- ctx->kdr_n = n;
- }
- if (ctx->label > KDF_SRTP_MAX_LABEL) {
- ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_LABEL);
- return 0;
- }
-
- return SRTPKDF(libctx, cipher, ctx->key, ctx->salt, ctx->index,
- ctx->kdr, ctx->kdr_n, ctx->label, key, keylen);
+ return SRTPKDF(libctx, cipher, ctx->key, ctx->salt,
+ ctx->index, ctx->index_len, ctx->kdr, ctx->kdr_n, ctx->label,
+ key, keylen);
}
static int kdf_srtpkdf_set_ctx_params(void *vctx, const OSSL_PARAM params[])
struct srtp_set_ctx_params_st p;
KDF_SRTPKDF *ctx = vctx;
OSSL_LIB_CTX *libctx;
- const EVP_CIPHER *cipher;
- int key_len;
if (params == NULL)
return 1;
libctx = PROV_LIBCTX_OF(ctx->provctx);
- if ((p.cipher != NULL)
- && !ossl_prov_cipher_load(&ctx->cipher, p.cipher, p.propq, libctx))
- return 0;
-
- cipher = ossl_prov_cipher_cipher(&ctx->cipher);
- if (cipher == NULL)
- return 0;
-
- if (!EVP_CIPHER_is_a(cipher, "AES-128-CTR") && !EVP_CIPHER_is_a(cipher, "AES-192-CTR")
- && !EVP_CIPHER_is_a(cipher, "AES-256-CTR"))
- return 0;
+ if (p.cipher != NULL) {
+ const EVP_CIPHER *cipher = NULL;
+ if (!ossl_prov_cipher_load(&ctx->cipher, p.cipher, p.propq, libctx))
+ return 0;
+ cipher = ossl_prov_cipher_cipher(&ctx->cipher);
+ if (cipher == NULL)
+ return 0;
+ if (!EVP_CIPHER_is_a(cipher, "AES-128-CTR")
+ && !EVP_CIPHER_is_a(cipher, "AES-192-CTR")
+ && !EVP_CIPHER_is_a(cipher, "AES-256-CTR")) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_CIPHER);
+ return 0;
+ }
+ }
if (p.key != NULL) {
- key_len = EVP_CIPHER_get_key_length(cipher);
if (!srtpkdf_set_membuf(&ctx->key, &ctx->key_len, p.key))
return 0;
- if (ctx->key_len != (size_t)key_len)
+ if (!kdf_srtpkdf_check_key(ctx))
return 0;
}
-
if (p.salt != NULL) {
if (!srtpkdf_set_membuf(&ctx->salt, &ctx->salt_len, p.salt))
return 0;
- if (ctx->salt_len < KDF_SRTP_SALT_LEN)
+ if (ctx->salt_len < KDF_SRTP_SALT_LEN) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_SALT_LENGTH);
return 0;
+ }
}
-
- if ((p.index != NULL)
- && !srtpkdf_set_membuf(&ctx->index, &ctx->index_len, p.index))
- return 0;
-
if (p.kdr != NULL) {
if (!OSSL_PARAM_get_uint32(p.kdr, &ctx->kdr))
return 0;
+ if (ctx->kdr > 0) {
+ uint32_t n = 0;
+
+ if (!is_power_of_two(ctx->kdr, &n)
+ || n > KDF_SRTP_MAX_KDR) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KDR);
+ return 0;
+ }
+ ctx->kdr_n = n;
+ }
}
if (p.label != NULL) {
if (!OSSL_PARAM_get_uint32(p.label, &ctx->label))
return 0;
+ if (ctx->label > KDF_SRTP_MAX_LABEL) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_LABEL);
+ return 0;
+ }
+ }
+ if (p.index != NULL) {
+ if (!srtpkdf_set_membuf(&ctx->index, &ctx->index_len, p.index))
+ return 0;
+ /*
+ * Defer checking the index until the derive() since it is dependant
+ * on values of kdr and label.
+ */
}
return 1;
{ 0, NULL }
};
+static bool is_srtp(uint32_t label)
+{
+ static const bool strp_table[] = {
+ true, /* 0 */
+ true, /* 1 */
+ true, /* 2 */
+ false, /* 3 */
+ false, /* 4 */
+ false, /* 5 */
+ true, /* 6 */
+ true, /* 7 */
+ };
+ return strp_table[label];
+}
+
/*
* SRTPKDF - In compliance with SP800-135 and RFC3711, calculate
* various keys defined by label using a master key,
* cipher - AES cipher
* mkey - pointer to master key
* msalt - pointer to master salt
- * idx - pointer to index
+ * index - pointer to index
+ * idxlen - size of the index buffer
* kdr - key derivation rate
* kdr_n - power of kdr (2**kdr_n = kdr)
* label - 8-bit label
- * obuffer - buffer for output
- * keylen - length of output buffer
+ * keylen - size of obuffer
* Output:
* obuffer - filled with derived key
* return - 1 on pass, 0 fail
*/
int SRTPKDF(OSSL_LIB_CTX *provctx, const EVP_CIPHER *cipher,
- const unsigned char *mkey, const unsigned char *msalt, const unsigned char *index,
+ const uint8_t *mkey, const uint8_t *msalt,
+ const uint8_t *index, size_t idxlen,
const uint32_t kdr, const uint32_t kdr_n,
- const uint32_t label, unsigned char *obuffer, const size_t keylen)
+ const uint32_t label, uint8_t *obuffer, const size_t keylen)
{
EVP_CIPHER_CTX *ctx = NULL;
int outl, i, index_len = 0, o_len = 0, salt_len = 0;
- unsigned char buf[EVP_MAX_KEY_LENGTH];
- unsigned char iv[KDF_SRTP_IV_LEN];
- unsigned char local_salt[KDF_SRTP_MAX_SALT_LEN];
- unsigned char master_salt[KDF_SRTP_MAX_SALT_LEN];
+ uint8_t buf[EVP_MAX_KEY_LENGTH];
+ uint8_t iv[KDF_SRTP_IV_LEN];
+ uint8_t local_salt[KDF_SRTP_MAX_SALT_LEN];
+ uint8_t master_salt[KDF_SRTP_MAX_SALT_LEN];
BIGNUM *bn_index = NULL, *bn_salt = NULL;
int ret, iv_len = KDF_SRTP_IV_LEN, rv = 0;
- salt_len = KDF_SRTP_SALT_LEN;
-
+ if (obuffer == NULL || keylen > INT_MAX)
+ return rv;
/* get label-specific lengths */
switch (label) {
case 0:
- index_len = KDF_SRTP_IDX_LEN;
+ case 3:
+ case 6:
o_len = EVP_CIPHER_key_length(cipher);
break;
case 1:
- index_len = KDF_SRTP_IDX_LEN;
o_len = KDF_SRTP_AUTH_KEY_LEN;
break;
- case 2:
- index_len = KDF_SRTP_IDX_LEN;
- o_len = KDF_SRTP_SALT_KEY_LEN;
- break;
- case 3:
- index_len = KDF_SRTCP_IDX_LEN;
- o_len = EVP_CIPHER_key_length(cipher);
- break;
case 4:
- index_len = KDF_SRTCP_IDX_LEN;
o_len = KDF_SRTCP_AUTH_KEY_LEN;
break;
- case 5:
- index_len = KDF_SRTCP_IDX_LEN;
- o_len = KDF_SRTCP_SALT_KEY_LEN;
- break;
- case 6:
- index_len = KDF_SRTP_IDX_LEN;
- o_len = EVP_CIPHER_key_length(cipher);
- break;
+ case 2:
case 7:
- index_len = KDF_SRTP_IDX_LEN;
o_len = KDF_SRTP_SALT_KEY_LEN;
break;
+ case 5:
+ o_len = KDF_SRTCP_SALT_KEY_LEN;
+ break;
default:
return rv;
}
-
- if ((obuffer == NULL) || (keylen > INT_MAX) || (o_len > (int)keylen))
+ if (o_len > (int)keylen)
return rv;
/* set up a couple of work areas for the final logic on the salt */
+ salt_len = KDF_SRTP_SALT_LEN;
memset(iv, 0, KDF_SRTP_IV_LEN);
- memset(master_salt, 0, KDF_SRTP_MAX_SALT_LEN);
+ memset(master_salt, 0, sizeof(master_salt));
memcpy(master_salt, msalt, salt_len);
/* gather some bignums for some math */
return rv;
}
+ index_len = is_srtp(label) ? KDF_SRTP_IDX_LEN : KDF_SRTCP_IDX_LEN;
/* if index is NULL or kdr=0, then index and kdr are not in play */
- if ((index != NULL) && (kdr > 0)) {
+ if (index != NULL && idxlen > 0 && kdr > 0) {
+ if ((int)idxlen < index_len) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_INDEX_LENGTH);
+ goto err;
+ }
if (!BN_bin2bn(index, index_len, bn_index))
goto err;
Ctrl.index = hexindex:000000000000
Ctrl.label = label:0
Output = C61E7A93744F39EE10734AFE3FF7A087
-Result = KDF_CTRL_ERROR
+Result = KDF_DERIVE_ERROR
+Reason = missing cipher
# Negative Test case 2, invalid cipher
FIPSversion = >=4.0.0
Ctrl.label = label:0
Output = C61E7A93744F39EE10734AFE3FF7A087
Result = KDF_CTRL_ERROR
+Reason = invalid cipher
# Negative Test case 3, missing key
FIPSversion = >=4.0.0
Ctrl.label = label:0
Output = C61E7A93744F39EE10734AFE3FF7A087
Result = KDF_DERIVE_ERROR
+Reason = missing key
# Negative Test case 4, missing salt
FIPSversion = >=4.0.0
Ctrl.label = label:0
Output = C61E7A93744F39EE10734AFE3FF7A087
Result = KDF_DERIVE_ERROR
+Reason = missing salt
# Negative Test case 5, invalid label
FIPSversion = >=4.0.0
Ctrl.index = hexindex:000000000000
Ctrl.label = label:8
Output = C61E7A93744F39EE10734AFE3FF7A087
-Result = KDF_DERIVE_ERROR
+Result = KDF_CTRL_ERROR
+Reason = invalid label
# Negative Test case 6, invalid kdr (not power of 2)
FIPSversion = >=4.0.0
Ctrl.index = hexindex:000000000000
Ctrl.label = label:0
Output = C61E7A93744F39EE10734AFE3FF7A087
-Result = KDF_DERIVE_ERROR
+Result = KDF_CTRL_ERROR
+Reason = invalid kdr
# Negative Test case 7, invalid kdr (kdr out of range)
FIPSversion = >=4.0.0
Ctrl.index = hexindex:000000000000
Ctrl.label = label:0
Output = C61E7A93744F39EE10734AFE3FF7A087
-Result = KDF_DERIVE_ERROR
+Result = KDF_CTRL_ERROR
+Reason = invalid kdr
# Additional tests from
# https://github.com/usnistgov/ACVP-Server/tree/master/gen-val/json-files/kdf-components-srtp-1.0
Ctrl.index = hexindex:8E5BDF08FA78
Ctrl.label = label:2
Output = B27816A7A139D73E71A55FCD7006
+
+# The following tests are copies of one of the above tests with
+# invalid sizes for different inputs.
+
+# Test index size too small for label 0 (SRTP)
+FIPSversion = >=4.0.0
+KDF = SRTPKDF
+Ctrl.cipher = cipher:AES-128-CTR
+Ctrl.hexkey = hexkey:8C307F105F79D5D2C26B1A933AE22CD5
+Ctrl.hexsalt = hexsalt:563B4C15458D977B68080242CEE1
+Ctrl.kdr = kdr:1
+Ctrl.index = hexindex:08284B49F5
+Ctrl.label = label:0
+Output = A920DF50EAA111D03FBE9B203121C07D
+Result = KDF_DERIVE_ERROR
+Reason = invalid index length
+
+# Test index size too small for label 4 (SRTCP)
+FIPSversion = >=4.0.0
+KDF = SRTPKDF
+Ctrl.cipher = cipher:AES-128-CTR
+Ctrl.hexkey = hexkey:8C307F105F79D5D2C26B1A933AE22CD5
+Ctrl.hexsalt = hexsalt:563B4C15458D977B68080242CEE1
+Ctrl.kdr = kdr:1
+Ctrl.index = hexindex:69B621
+Ctrl.label = label:4
+Output = FA02251D693645BC1001f83C5A13CB3E3D77F7EA
+Result = KDF_DERIVE_ERROR
+Reason = invalid index length
+
+# Test salt size is too small
+FIPSversion = >=4.0.0
+KDF = SRTPKDF
+Ctrl.cipher = cipher:AES-128-CTR
+Ctrl.hexkey = hexkey:8C307F105F79D5D2C26B1A933AE22CD5
+Ctrl.hexsalt = hexsalt:563B
+Ctrl.kdr = kdr:1
+Ctrl.index = hexindex:69B62109
+Ctrl.label = label:4
+Output = FA02251D693645BC1001f83C5A13CB3E3D77F7EA
+Result = KDF_CTRL_ERROR
+Reason = invalid salt length
+
+# Test invalid key size fails
+FIPSversion = >=4.0.0
+KDF = SRTPKDF
+Ctrl.cipher = cipher:AES-128-CTR
+Ctrl.hexkey = hexkey:8C307F
+Ctrl.hexsalt = hexsalt:563B4C15458D977B68080242CEE1
+Ctrl.kdr = kdr:1
+Ctrl.index = hexindex:69B62109
+Ctrl.label = label:4
+Output = FA02251D693645BC1001f83C5A13CB3E3D77F7EA
+Result = KDF_CTRL_ERROR
+Reason = invalid key length
+
+# Test Case 1.3, variation, zero length index
+FIPSversion = >=4.0.0
+KDF = SRTPKDF
+Ctrl.cipher = cipher:AES-128-CTR
+Ctrl.hexkey = hexkey:E1F97A0D3E018BE0D64FA32C06DE4139
+Ctrl.hexsalt = hexsalt:0EC675AD498AFEEBB6960B3AABE6
+Ctrl.index = hexindex:
+Ctrl.kdr = kdr:1
+Ctrl.label = label:0
+Output = C61E7A93744F39EE10734AFE3FF7A087