From 501988587567b996c9c4a14239f575e77ed27791 Mon Sep 17 00:00:00 2001 From: Pankaj Gupta Date: Fri, 20 Sep 2019 12:18:16 +0530 Subject: [PATCH 1/2] eng_devcrypto: add support for TLS algorithms offload - aes-128-cbc-hmac-sha1 - aes-256-cbc-hmac-sha1 Requires TLS patches on cryptodev and TLS algorithm support in Linux kernel driver. Signed-off-by: Pankaj Gupta --- crypto/engine/eng_devcrypto.c | 265 +++++++++++++++++++++++++++++----- 1 file changed, 231 insertions(+), 34 deletions(-) diff --git a/crypto/engine/eng_devcrypto.c b/crypto/engine/eng_devcrypto.c index 49e9ce1af3..727a660e75 100644 --- a/crypto/engine/eng_devcrypto.c +++ b/crypto/engine/eng_devcrypto.c @@ -60,6 +60,9 @@ struct cipher_ctx { struct session_op sess; int op; /* COP_ENCRYPT or COP_DECRYPT */ unsigned long mode; /* EVP_CIPH_*_MODE */ + unsigned char *aad; + unsigned int aad_len; + unsigned int len; /* to handle ctr mode being a stream cipher */ unsigned char partial[EVP_MAX_BLOCK_LENGTH]; @@ -73,49 +76,62 @@ static const struct cipher_data_st { int ivlen; int flags; int devcryptoid; + int mackeylen; } cipher_data[] = { #ifndef OPENSSL_NO_DES - { NID_des_cbc, 8, 8, 8, EVP_CIPH_CBC_MODE, CRYPTO_DES_CBC }, - { NID_des_ede3_cbc, 8, 24, 8, EVP_CIPH_CBC_MODE, CRYPTO_3DES_CBC }, + { NID_des_cbc, 8, 8, 8, EVP_CIPH_CBC_MODE, CRYPTO_DES_CBC, 0 }, + { NID_des_ede3_cbc, 8, 24, 8, EVP_CIPH_CBC_MODE, CRYPTO_3DES_CBC, 0 }, #endif #ifndef OPENSSL_NO_BF - { NID_bf_cbc, 8, 16, 8, EVP_CIPH_CBC_MODE, CRYPTO_BLF_CBC }, + { NID_bf_cbc, 8, 16, 8, EVP_CIPH_CBC_MODE, CRYPTO_BLF_CBC, 0 }, #endif #ifndef OPENSSL_NO_CAST - { NID_cast5_cbc, 8, 16, 8, EVP_CIPH_CBC_MODE, CRYPTO_CAST_CBC }, + { NID_cast5_cbc, 8, 16, 8, EVP_CIPH_CBC_MODE, CRYPTO_CAST_CBC, 0 }, #endif - { NID_aes_128_cbc, 16, 128 / 8, 16, EVP_CIPH_CBC_MODE, CRYPTO_AES_CBC }, - { NID_aes_192_cbc, 16, 192 / 8, 16, EVP_CIPH_CBC_MODE, CRYPTO_AES_CBC }, - { NID_aes_256_cbc, 16, 256 / 8, 16, EVP_CIPH_CBC_MODE, CRYPTO_AES_CBC }, + { NID_aes_128_cbc, 16, 128 / 8, 16, EVP_CIPH_CBC_MODE, CRYPTO_AES_CBC, 0 }, + { NID_aes_192_cbc, 16, 192 / 8, 16, EVP_CIPH_CBC_MODE, CRYPTO_AES_CBC, 0 }, + { NID_aes_256_cbc, 16, 256 / 8, 16, EVP_CIPH_CBC_MODE, CRYPTO_AES_CBC, 0 }, + { NID_aes_128_cbc_hmac_sha1, 16, 16, 16, + EVP_CIPH_CBC_MODE | EVP_CIPH_FLAG_AEAD_CIPHER, + CRYPTO_TLS10_AES_CBC_HMAC_SHA1, 20 }, + { NID_aes_256_cbc_hmac_sha1, 16, 32, 16, + EVP_CIPH_CBC_MODE | EVP_CIPH_FLAG_AEAD_CIPHER, + CRYPTO_TLS10_AES_CBC_HMAC_SHA1, 20 }, #ifndef OPENSSL_NO_RC4 - { NID_rc4, 1, 16, 0, EVP_CIPH_STREAM_CIPHER, CRYPTO_ARC4 }, + { NID_rc4, 1, 16, 0, EVP_CIPH_STREAM_CIPHER, CRYPTO_ARC4, 0 }, #endif #if !defined(CHECK_BSD_STYLE_MACROS) || defined(CRYPTO_AES_CTR) - { NID_aes_128_ctr, 16, 128 / 8, 16, EVP_CIPH_CTR_MODE, CRYPTO_AES_CTR }, - { NID_aes_192_ctr, 16, 192 / 8, 16, EVP_CIPH_CTR_MODE, CRYPTO_AES_CTR }, - { NID_aes_256_ctr, 16, 256 / 8, 16, EVP_CIPH_CTR_MODE, CRYPTO_AES_CTR }, + { NID_aes_128_ctr, 16, 128 / 8, 16, EVP_CIPH_CTR_MODE, CRYPTO_AES_CTR, 0 }, + { NID_aes_192_ctr, 16, 192 / 8, 16, EVP_CIPH_CTR_MODE, CRYPTO_AES_CTR, 0 }, + { NID_aes_256_ctr, 16, 256 / 8, 16, EVP_CIPH_CTR_MODE, CRYPTO_AES_CTR, 0 }, #endif #if 0 /* Not yet supported */ - { NID_aes_128_xts, 16, 128 / 8 * 2, 16, EVP_CIPH_XTS_MODE, CRYPTO_AES_XTS }, - { NID_aes_256_xts, 16, 256 / 8 * 2, 16, EVP_CIPH_XTS_MODE, CRYPTO_AES_XTS }, + { NID_aes_128_xts, 16, 128 / 8 * 2, 16, EVP_CIPH_XTS_MODE, CRYPTO_AES_XTS, + 0 }, + { NID_aes_256_xts, 16, 256 / 8 * 2, 16, EVP_CIPH_XTS_MODE, CRYPTO_AES_XTS, + 0 }, #endif #if !defined(CHECK_BSD_STYLE_MACROS) || defined(CRYPTO_AES_ECB) - { NID_aes_128_ecb, 16, 128 / 8, 0, EVP_CIPH_ECB_MODE, CRYPTO_AES_ECB }, - { NID_aes_192_ecb, 16, 192 / 8, 0, EVP_CIPH_ECB_MODE, CRYPTO_AES_ECB }, - { NID_aes_256_ecb, 16, 256 / 8, 0, EVP_CIPH_ECB_MODE, CRYPTO_AES_ECB }, + { NID_aes_128_ecb, 16, 128 / 8, 0, EVP_CIPH_ECB_MODE, CRYPTO_AES_ECB, 0 }, + { NID_aes_192_ecb, 16, 192 / 8, 0, EVP_CIPH_ECB_MODE, CRYPTO_AES_ECB, 0 }, + { NID_aes_256_ecb, 16, 256 / 8, 0, EVP_CIPH_ECB_MODE, CRYPTO_AES_ECB, 0 }, #endif #if 0 /* Not yet supported */ - { NID_aes_128_gcm, 16, 128 / 8, 16, EVP_CIPH_GCM_MODE, CRYPTO_AES_GCM }, - { NID_aes_192_gcm, 16, 192 / 8, 16, EVP_CIPH_GCM_MODE, CRYPTO_AES_GCM }, - { NID_aes_256_gcm, 16, 256 / 8, 16, EVP_CIPH_GCM_MODE, CRYPTO_AES_GCM }, + { NID_aes_128_gcm, 16, 128 / 8, 16, EVP_CIPH_GCM_MODE, CRYPTO_AES_GCM, 0 }, + { NID_aes_192_gcm, 16, 192 / 8, 16, EVP_CIPH_GCM_MODE, CRYPTO_AES_GCM, 0 }, + { NID_aes_256_gcm, 16, 256 / 8, 16, EVP_CIPH_GCM_MODE, CRYPTO_AES_GCM, 0 }, +#endif +#ifdef OPENSSL_NXP_CAAM + { NID_aes_128_gcm, 16, 128 / 8, 16, EVP_CIPH_GCM_MODE, CRYPTO_AES_GCM, 0 }, + { NID_aes_192_gcm, 16, 192 / 8, 16, EVP_CIPH_GCM_MODE, CRYPTO_AES_GCM, 0 }, #endif #ifndef OPENSSL_NO_CAMELLIA { NID_camellia_128_cbc, 16, 128 / 8, 16, EVP_CIPH_CBC_MODE, - CRYPTO_CAMELLIA_CBC }, + CRYPTO_CAMELLIA_CBC, 0 }, { NID_camellia_192_cbc, 16, 192 / 8, 16, EVP_CIPH_CBC_MODE, - CRYPTO_CAMELLIA_CBC }, + CRYPTO_CAMELLIA_CBC, 0 }, { NID_camellia_256_cbc, 16, 256 / 8, 16, EVP_CIPH_CBC_MODE, - CRYPTO_CAMELLIA_CBC }, + CRYPTO_CAMELLIA_CBC, 0 }, #endif }; @@ -141,6 +157,158 @@ static const struct cipher_data_st *get_cipher_data(int nid) return &cipher_data[get_cipher_data_index(nid)]; } +/* + * Save the encryption key provided by upper layers. This function is called + * by EVP_CipherInit_ex to initialize the algorithm's extra data. We can't do + * much here because the mac key is not available. The next call should/will + * be to cryptodev_cbc_hmac_sha1_ctrl with parameter + * EVP_CTRL_AEAD_SET_MAC_KEY, to set the hmac key. There we call CIOCGSESSION + * with both the crypto and hmac keys. + */ +static int cryptodev_init_aead_key(EVP_CIPHER_CTX *ctx, + const unsigned char *key, const unsigned char *iv, int enc) +{ + struct cipher_ctx *state = EVP_CIPHER_CTX_get_cipher_data(ctx); + struct session_op *sess = &state->sess; + int cipher = -1, i; + + for (i = 0; cipher_data[i].devcryptoid; i++) { + if (EVP_CIPHER_CTX_nid(ctx) == cipher_data[i].nid && + EVP_CIPHER_CTX_iv_length(ctx) <= cipher_data[i].ivlen && + EVP_CIPHER_CTX_key_length(ctx) == cipher_data[i].keylen) { + cipher = cipher_data[i].devcryptoid; + break; + } + } + + if (!cipher_data[i].devcryptoid) + return (0); + + memset(sess, 0, sizeof(*sess)); + + sess->key = (void *) key; + sess->keylen = EVP_CIPHER_CTX_key_length(ctx); + sess->cipher = cipher; + + /* for whatever reason, (1) means success */ + return 1; +} + +static int cryptodev_aead_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, size_t len) +{ + struct crypt_auth_op cryp; + struct cipher_ctx *state = EVP_CIPHER_CTX_get_cipher_data(ctx); + struct session_op *sess = &state->sess; + const void *iiv; + unsigned char save_iv[EVP_MAX_IV_LENGTH]; + + if (cfd < 0) + return (0); + if (!len) + return (1); + if ((len % EVP_CIPHER_CTX_block_size(ctx)) != 0) + return (0); + + memset(&cryp, 0, sizeof(cryp)); + + /* TODO: make a seamless integration with cryptodev flags */ + switch (EVP_CIPHER_CTX_nid(ctx)) { + case NID_aes_128_cbc_hmac_sha1: + case NID_aes_256_cbc_hmac_sha1: + cryp.flags = COP_FLAG_AEAD_TLS_TYPE; + } + cryp.ses = sess->ses; + cryp.len = state->len; + cryp.src = (void *) in; + cryp.dst = (void *) out; + cryp.auth_src = state->aad; + cryp.auth_len = state->aad_len; + + cryp.op = EVP_CIPHER_CTX_encrypting(ctx) ? COP_ENCRYPT : COP_DECRYPT; + + if (EVP_CIPHER_CTX_iv_length(ctx) > 0) { + cryp.iv = (void *) EVP_CIPHER_CTX_iv(ctx); + if (!EVP_CIPHER_CTX_encrypting(ctx)) { + iiv = in + len - EVP_CIPHER_CTX_iv_length(ctx); + memcpy(save_iv, iiv, EVP_CIPHER_CTX_iv_length(ctx)); + } + } else + cryp.iv = NULL; + + if (ioctl(cfd, CIOCAUTHCRYPT, &cryp) == -1) { + /* + * XXX need better errror handling this can fail for a number of + * different reasons. + */ + return 0; + } + + if (EVP_CIPHER_CTX_iv_length(ctx) > 0) { + if (EVP_CIPHER_CTX_encrypting(ctx)) + iiv = out + len - EVP_CIPHER_CTX_iv_length(ctx); + else + iiv = save_iv; + + memcpy(EVP_CIPHER_CTX_iv_noconst(ctx), iiv, + EVP_CIPHER_CTX_iv_length(ctx)); + } + return 1; +} + +static int cryptodev_cbc_hmac_sha1_ctrl(EVP_CIPHER_CTX *ctx, int type, + int arg, void *ptr) +{ + switch (type) { + case EVP_CTRL_AEAD_SET_MAC_KEY: + { + /* TODO: what happens with hmac keys larger than 64 bytes? */ + struct cipher_ctx *state = + EVP_CIPHER_CTX_get_cipher_data(ctx); + struct session_op *sess = &state->sess; + + /* the rest should have been set in cryptodev_init_aead_key */ + sess->mackey = ptr; + sess->mackeylen = arg; + if (ioctl(cfd, CIOCGSESSION, sess) == -1) + return 0; + + return 1; + } + case EVP_CTRL_AEAD_TLS1_AAD: + { + /* ptr points to the associated data buffer of 13 bytes */ + struct cipher_ctx *state = + EVP_CIPHER_CTX_get_cipher_data(ctx); + unsigned char *p = ptr; + unsigned int cryptlen = p[arg - 2] << 8 | p[arg - 1]; + unsigned int maclen, padlen; + unsigned int bs = EVP_CIPHER_CTX_block_size(ctx); + + state->aad = ptr; + state->aad_len = arg; + state->len = cryptlen; + + /* TODO: this should be an extension of EVP_CIPHER struct */ + switch (EVP_CIPHER_CTX_nid(ctx)) { + case NID_aes_128_cbc_hmac_sha1: + case NID_aes_256_cbc_hmac_sha1: + maclen = SHA_DIGEST_LENGTH; + } + + /* space required for encryption (not only TLS padding) */ + padlen = maclen; + if (EVP_CIPHER_CTX_encrypting(ctx)) { + cryptlen += maclen; + padlen += bs - (cryptlen % bs); + } + return padlen; + } + default: + return -1; + } +} + /* * Following are the three necessary functions to map OpenSSL functionality * with cryptodev. @@ -165,6 +333,7 @@ static int cipher_init(EVP_CIPHER_CTX *ctx, const unsigned char *key, cipher_ctx->op = enc ? COP_ENCRYPT : COP_DECRYPT; cipher_ctx->mode = cipher_d->flags & EVP_CIPH_MODE; cipher_ctx->blocksize = cipher_d->blocksize; + if (ioctl(cfd, CIOCGSESSION, &cipher_ctx->sess) < 0) { SYSerr(SYS_F_IOCTL, errno); return 0; @@ -180,6 +349,7 @@ static int cipher_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, (struct cipher_ctx *)EVP_CIPHER_CTX_get_cipher_data(ctx); struct crypt_op cryp; unsigned char *iv = EVP_CIPHER_CTX_iv_noconst(ctx); + #if !defined(COP_FLAG_WRITE_IV) unsigned char saved_iv[EVP_MAX_IV_LENGTH]; const unsigned char *ivptr; @@ -340,32 +510,59 @@ static int cipher_cleanup(EVP_CIPHER_CTX *ctx) static int known_cipher_nids[OSSL_NELEM(cipher_data)]; static int known_cipher_nids_amount = -1; /* -1 indicates not yet initialised */ static EVP_CIPHER *known_cipher_methods[OSSL_NELEM(cipher_data)] = { NULL, }; +int (*init) (EVP_CIPHER_CTX *ctx, const unsigned char *key, + const unsigned char *iv, int enc); +int (*do_cipher) (EVP_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, size_t inl); +int (*ctrl) (EVP_CIPHER_CTX *, int type, int arg, void *ptr); static void prepare_cipher_methods(void) { size_t i; struct session_op sess; unsigned long cipher_mode; + unsigned long flags; memset(&sess, 0, sizeof(sess)); sess.key = (void *)"01234567890123456789012345678901234567890123456789"; + sess.mackey = (void *)"123456789ABCDEFGHIJKLMNO"; for (i = 0, known_cipher_nids_amount = 0; i < OSSL_NELEM(cipher_data); i++) { + init = cipher_init; + ctrl = cipher_ctrl; + flags = cipher_data[i].flags + | EVP_CIPH_CUSTOM_COPY + | EVP_CIPH_CTRL_INIT + | EVP_CIPH_FLAG_DEFAULT_ASN1; + /* * Check that the algo is really availably by trying to open and close * a session. */ sess.cipher = cipher_data[i].devcryptoid; sess.keylen = cipher_data[i].keylen; + sess.mackeylen = cipher_data[i].mackeylen; + + cipher_mode = cipher_data[i].flags & EVP_CIPH_MODE; + + do_cipher = (cipher_mode == EVP_CIPH_CTR_MODE ? + ctr_do_cipher : + cipher_do_cipher); + if (cipher_data[i].nid == NID_aes_128_cbc_hmac_sha1 + || cipher_data[i].nid == NID_aes_256_cbc_hmac_sha1) { + init = cryptodev_init_aead_key; + do_cipher = cryptodev_aead_cipher; + ctrl = cryptodev_cbc_hmac_sha1_ctrl; + flags = cipher_data[i].flags; + } + if (ioctl(cfd, CIOCGSESSION, &sess) < 0 || ioctl(cfd, CIOCFSESSION, &sess.ses) < 0) continue; - cipher_mode = cipher_data[i].flags & EVP_CIPH_MODE; - - if ((known_cipher_methods[i] = + if ((known_cipher_methods[i] = EVP_CIPHER_meth_new(cipher_data[i].nid, cipher_mode == EVP_CIPH_CTR_MODE ? 1 : cipher_data[i].blocksize, @@ -373,16 +570,12 @@ static void prepare_cipher_methods(void) || !EVP_CIPHER_meth_set_iv_length(known_cipher_methods[i], cipher_data[i].ivlen) || !EVP_CIPHER_meth_set_flags(known_cipher_methods[i], - cipher_data[i].flags - | EVP_CIPH_CUSTOM_COPY - | EVP_CIPH_CTRL_INIT - | EVP_CIPH_FLAG_DEFAULT_ASN1) - || !EVP_CIPHER_meth_set_init(known_cipher_methods[i], cipher_init) + flags) + || !EVP_CIPHER_meth_set_init(known_cipher_methods[i], init) || !EVP_CIPHER_meth_set_do_cipher(known_cipher_methods[i], - cipher_mode == EVP_CIPH_CTR_MODE ? - ctr_do_cipher : - cipher_do_cipher) - || !EVP_CIPHER_meth_set_ctrl(known_cipher_methods[i], cipher_ctrl) + do_cipher) + /* AEAD Support to be added. */ + || !EVP_CIPHER_meth_set_ctrl(known_cipher_methods[i], ctrl) || !EVP_CIPHER_meth_set_cleanup(known_cipher_methods[i], cipher_cleanup) || !EVP_CIPHER_meth_set_impl_ctx_size(known_cipher_methods[i], @@ -393,6 +586,10 @@ static void prepare_cipher_methods(void) known_cipher_nids[known_cipher_nids_amount++] = cipher_data[i].nid; } + + if (cipher_data[i].nid == NID_aes_128_cbc_hmac_sha1 + || cipher_data[i].nid == NID_aes_256_cbc_hmac_sha1) + EVP_add_cipher(known_cipher_methods[i]); } } -- 2.17.1