diff options
Diffstat (limited to 'freebsd/crypto/openssl/crypto/engine/eng_devcrypto.c')
-rw-r--r-- | freebsd/crypto/openssl/crypto/engine/eng_devcrypto.c | 273 |
1 files changed, 208 insertions, 65 deletions
diff --git a/freebsd/crypto/openssl/crypto/engine/eng_devcrypto.c b/freebsd/crypto/openssl/crypto/engine/eng_devcrypto.c index ed24d478..59ac168e 100644 --- a/freebsd/crypto/openssl/crypto/engine/eng_devcrypto.c +++ b/freebsd/crypto/openssl/crypto/engine/eng_devcrypto.c @@ -1,7 +1,7 @@ #include <machine/rtems-bsd-user-space.h> /* - * Copyright 2017-2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2017-2019 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the OpenSSL license (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -28,7 +28,7 @@ /* #define ENGINE_DEVCRYPTO_DEBUG */ -#ifdef CRYPTO_ALGORITHM_MIN +#if CRYPTO_ALGORITHM_MIN < CRYPTO_ALGORITHM_MAX # define CHECK_BSD_STYLE_MACROS #endif @@ -39,6 +39,15 @@ */ static int cfd; +static int clean_devcrypto_session(struct session_op *sess) { + if (ioctl(cfd, CIOCFSESSION, &sess->ses) < 0) { + SYSerr(SYS_F_IOCTL, errno); + return 0; + } + memset(sess, 0, sizeof(struct session_op)); + return 1; +} + /****************************************************************************** * * Ciphers @@ -51,10 +60,12 @@ static int cfd; struct cipher_ctx { struct session_op sess; - - /* to pass from init to do_cipher */ - const unsigned char *iv; int op; /* COP_ENCRYPT or COP_DECRYPT */ + unsigned long mode; /* EVP_CIPH_*_MODE */ + + /* to handle ctr mode being a stream cipher */ + unsigned char partial[EVP_MAX_BLOCK_LENGTH]; + unsigned int blocksize, num; }; static const struct cipher_data_st { @@ -91,9 +102,9 @@ static const struct cipher_data_st { { NID_aes_256_xts, 16, 256 / 8 * 2, 16, EVP_CIPH_XTS_MODE, CRYPTO_AES_XTS }, #endif #if !defined(CHECK_BSD_STYLE_MACROS) || defined(CRYPTO_AES_ECB) - { NID_aes_128_ecb, 16, 128 / 8, 16, EVP_CIPH_ECB_MODE, CRYPTO_AES_ECB }, - { NID_aes_192_ecb, 16, 192 / 8, 16, EVP_CIPH_ECB_MODE, CRYPTO_AES_ECB }, - { NID_aes_256_ecb, 16, 256 / 8, 16, EVP_CIPH_ECB_MODE, 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 }, #endif #if 0 /* Not yet supported */ { NID_aes_128_gcm, 16, 128 / 8, 16, EVP_CIPH_GCM_MODE, CRYPTO_AES_GCM }, @@ -145,11 +156,17 @@ static int cipher_init(EVP_CIPHER_CTX *ctx, const unsigned char *key, const struct cipher_data_st *cipher_d = get_cipher_data(EVP_CIPHER_CTX_nid(ctx)); - memset(&cipher_ctx->sess, 0, sizeof(cipher_ctx->sess)); + /* cleanup a previous session */ + if (cipher_ctx->sess.ses != 0 && + clean_devcrypto_session(&cipher_ctx->sess) == 0) + return 0; + cipher_ctx->sess.cipher = cipher_d->devcryptoid; cipher_ctx->sess.keylen = cipher_d->keylen; cipher_ctx->sess.key = (void *)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; @@ -164,8 +181,11 @@ static int cipher_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, struct cipher_ctx *cipher_ctx = (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; + size_t nblocks, ivlen; #endif memset(&cryp, 0, sizeof(cryp)); @@ -173,19 +193,28 @@ static int cipher_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, cryp.len = inl; cryp.src = (void *)in; cryp.dst = (void *)out; - cryp.iv = (void *)EVP_CIPHER_CTX_iv_noconst(ctx); + cryp.iv = (void *)iv; cryp.op = cipher_ctx->op; #if !defined(COP_FLAG_WRITE_IV) cryp.flags = 0; - if (EVP_CIPHER_CTX_iv_length(ctx) > 0) { - assert(inl >= EVP_CIPHER_CTX_iv_length(ctx)); - if (!EVP_CIPHER_CTX_encrypting(ctx)) { - unsigned char *ivptr = in + inl - EVP_CIPHER_CTX_iv_length(ctx); - - memcpy(saved_iv, ivptr, EVP_CIPHER_CTX_iv_length(ctx)); + ivlen = EVP_CIPHER_CTX_iv_length(ctx); + if (ivlen > 0) + switch (cipher_ctx->mode) { + case EVP_CIPH_CBC_MODE: + assert(inl >= ivlen); + if (!EVP_CIPHER_CTX_encrypting(ctx)) { + ivptr = in + inl - ivlen; + memcpy(saved_iv, ivptr, ivlen); + } + break; + + case EVP_CIPH_CTR_MODE: + break; + + default: /* should not happen */ + return 0; } - } #else cryp.flags = COP_FLAG_WRITE_IV; #endif @@ -196,32 +225,113 @@ static int cipher_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, } #if !defined(COP_FLAG_WRITE_IV) - if (EVP_CIPHER_CTX_iv_length(ctx) > 0) { - unsigned char *ivptr = saved_iv; + if (ivlen > 0) + switch (cipher_ctx->mode) { + case EVP_CIPH_CBC_MODE: + assert(inl >= ivlen); + if (EVP_CIPHER_CTX_encrypting(ctx)) + ivptr = out + inl - ivlen; + else + ivptr = saved_iv; + + memcpy(iv, ivptr, ivlen); + break; + + case EVP_CIPH_CTR_MODE: + nblocks = (inl + cipher_ctx->blocksize - 1) + / cipher_ctx->blocksize; + do { + ivlen--; + nblocks += iv[ivlen]; + iv[ivlen] = (uint8_t) nblocks; + nblocks >>= 8; + } while (ivlen); + break; + + default: /* should not happen */ + return 0; + } +#endif + + return 1; +} + +static int ctr_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, size_t inl) +{ + struct cipher_ctx *cipher_ctx = + (struct cipher_ctx *)EVP_CIPHER_CTX_get_cipher_data(ctx); + size_t nblocks, len; - assert(inl >= EVP_CIPHER_CTX_iv_length(ctx)); - if (!EVP_CIPHER_CTX_encrypting(ctx)) - ivptr = out + inl - EVP_CIPHER_CTX_iv_length(ctx); + /* initial partial block */ + while (cipher_ctx->num && inl) { + (*out++) = *(in++) ^ cipher_ctx->partial[cipher_ctx->num]; + --inl; + cipher_ctx->num = (cipher_ctx->num + 1) % cipher_ctx->blocksize; + } - memcpy(EVP_CIPHER_CTX_iv_noconst(ctx), ivptr, - EVP_CIPHER_CTX_iv_length(ctx)); + /* full blocks */ + if (inl > (unsigned int) cipher_ctx->blocksize) { + nblocks = inl/cipher_ctx->blocksize; + len = nblocks * cipher_ctx->blocksize; + if (cipher_do_cipher(ctx, out, in, len) < 1) + return 0; + inl -= len; + out += len; + in += len; + } + + /* final partial block */ + if (inl) { + memset(cipher_ctx->partial, 0, cipher_ctx->blocksize); + if (cipher_do_cipher(ctx, cipher_ctx->partial, cipher_ctx->partial, + cipher_ctx->blocksize) < 1) + return 0; + while (inl--) { + out[cipher_ctx->num] = in[cipher_ctx->num] + ^ cipher_ctx->partial[cipher_ctx->num]; + cipher_ctx->num++; + } } -#endif return 1; } -static int cipher_cleanup(EVP_CIPHER_CTX *ctx) +static int cipher_ctrl(EVP_CIPHER_CTX *ctx, int type, int p1, void* p2) { struct cipher_ctx *cipher_ctx = (struct cipher_ctx *)EVP_CIPHER_CTX_get_cipher_data(ctx); + EVP_CIPHER_CTX *to_ctx = (EVP_CIPHER_CTX *)p2; + struct cipher_ctx *to_cipher_ctx; + + switch (type) { + case EVP_CTRL_COPY: + if (cipher_ctx == NULL) + return 1; + /* when copying the context, a new session needs to be initialized */ + to_cipher_ctx = + (struct cipher_ctx *)EVP_CIPHER_CTX_get_cipher_data(to_ctx); + memset(&to_cipher_ctx->sess, 0, sizeof(to_cipher_ctx->sess)); + return cipher_init(to_ctx, cipher_ctx->sess.key, EVP_CIPHER_CTX_iv(ctx), + (cipher_ctx->op == COP_ENCRYPT)); + + case EVP_CTRL_INIT: + memset(&cipher_ctx->sess, 0, sizeof(cipher_ctx->sess)); + return 1; - if (ioctl(cfd, CIOCFSESSION, &cipher_ctx->sess.ses) < 0) { - SYSerr(SYS_F_IOCTL, errno); - return 0; + default: + break; } - return 1; + return -1; +} + +static int cipher_cleanup(EVP_CIPHER_CTX *ctx) +{ + struct cipher_ctx *cipher_ctx = + (struct cipher_ctx *)EVP_CIPHER_CTX_get_cipher_data(ctx); + + return clean_devcrypto_session(&cipher_ctx->sess); } /* @@ -237,6 +347,7 @@ static void prepare_cipher_methods(void) { size_t i; struct session_op sess; + unsigned long cipher_mode; memset(&sess, 0, sizeof(sess)); sess.key = (void *)"01234567890123456789012345678901234567890123456789"; @@ -254,18 +365,26 @@ static void prepare_cipher_methods(void) || ioctl(cfd, CIOCFSESSION, &sess.ses) < 0) continue; + cipher_mode = cipher_data[i].flags & EVP_CIPH_MODE; + if ((known_cipher_methods[i] = EVP_CIPHER_meth_new(cipher_data[i].nid, - cipher_data[i].blocksize, + cipher_mode == EVP_CIPH_CTR_MODE ? 1 : + cipher_data[i].blocksize, cipher_data[i].keylen)) == NULL || !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) || !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) || !EVP_CIPHER_meth_set_cleanup(known_cipher_methods[i], cipher_cleanup) || !EVP_CIPHER_meth_set_impl_ctx_size(known_cipher_methods[i], @@ -342,34 +461,36 @@ static int devcrypto_ciphers(ENGINE *e, const EVP_CIPHER **cipher, struct digest_ctx { struct session_op sess; - int init; + /* This signals that the init function was called, not that it succeeded. */ + int init_called; }; static const struct digest_data_st { int nid; + int blocksize; int digestlen; int devcryptoid; } digest_data[] = { #ifndef OPENSSL_NO_MD5 - { NID_md5, 16, CRYPTO_MD5 }, + { NID_md5, /* MD5_CBLOCK */ 64, 16, CRYPTO_MD5 }, #endif - { NID_sha1, 20, CRYPTO_SHA1 }, + { NID_sha1, SHA_CBLOCK, 20, CRYPTO_SHA1 }, #ifndef OPENSSL_NO_RMD160 # if !defined(CHECK_BSD_STYLE_MACROS) || defined(CRYPTO_RIPEMD160) - { NID_ripemd160, 20, CRYPTO_RIPEMD160 }, + { NID_ripemd160, /* RIPEMD160_CBLOCK */ 64, 20, CRYPTO_RIPEMD160 }, # endif #endif #if !defined(CHECK_BSD_STYLE_MACROS) || defined(CRYPTO_SHA2_224) - { NID_sha224, 224 / 8, CRYPTO_SHA2_224 }, + { NID_sha224, SHA256_CBLOCK, 224 / 8, CRYPTO_SHA2_224 }, #endif #if !defined(CHECK_BSD_STYLE_MACROS) || defined(CRYPTO_SHA2_256) - { NID_sha256, 256 / 8, CRYPTO_SHA2_256 }, + { NID_sha256, SHA256_CBLOCK, 256 / 8, CRYPTO_SHA2_256 }, #endif #if !defined(CHECK_BSD_STYLE_MACROS) || defined(CRYPTO_SHA2_384) - { NID_sha384, 384 / 8, CRYPTO_SHA2_384 }, + { NID_sha384, SHA512_CBLOCK, 384 / 8, CRYPTO_SHA2_384 }, #endif #if !defined(CHECK_BSD_STYLE_MACROS) || defined(CRYPTO_SHA2_512) - { NID_sha512, 512 / 8, CRYPTO_SHA2_512 }, + { NID_sha512, SHA512_CBLOCK, 512 / 8, CRYPTO_SHA2_512 }, #endif }; @@ -407,7 +528,7 @@ static int digest_init(EVP_MD_CTX *ctx) const struct digest_data_st *digest_d = get_digest_data(EVP_MD_CTX_type(ctx)); - digest_ctx->init = 1; + digest_ctx->init_called = 1; memset(&digest_ctx->sess, 0, sizeof(digest_ctx->sess)); digest_ctx->sess.mac = digest_d->devcryptoid; @@ -442,6 +563,9 @@ static int digest_update(EVP_MD_CTX *ctx, const void *data, size_t count) if (count == 0) return 1; + if (digest_ctx == NULL) + return 0; + if (digest_op(digest_ctx, data, count, NULL, COP_FLAG_UPDATE) < 0) { SYSerr(SYS_F_IOCTL, errno); return 0; @@ -455,11 +579,9 @@ static int digest_final(EVP_MD_CTX *ctx, unsigned char *md) struct digest_ctx *digest_ctx = (struct digest_ctx *)EVP_MD_CTX_md_data(ctx); - if (digest_op(digest_ctx, NULL, 0, md, COP_FLAG_FINAL) < 0) { - SYSerr(SYS_F_IOCTL, errno); + if (md == NULL || digest_ctx == NULL) return 0; - } - if (ioctl(cfd, CIOCFSESSION, &digest_ctx->sess.ses) < 0) { + if (digest_op(digest_ctx, NULL, 0, md, COP_FLAG_FINAL) < 0) { SYSerr(SYS_F_IOCTL, errno); return 0; } @@ -475,14 +597,9 @@ static int digest_copy(EVP_MD_CTX *to, const EVP_MD_CTX *from) (struct digest_ctx *)EVP_MD_CTX_md_data(to); struct cphash_op cphash; - if (digest_from == NULL) + if (digest_from == NULL || digest_from->init_called != 1) return 1; - if (digest_from->init != 1) { - SYSerr(SYS_F_IOCTL, EINVAL); - return 0; - } - if (!digest_init(to)) { SYSerr(SYS_F_IOCTL, errno); return 0; @@ -499,7 +616,37 @@ static int digest_copy(EVP_MD_CTX *to, const EVP_MD_CTX *from) static int digest_cleanup(EVP_MD_CTX *ctx) { - return 1; + struct digest_ctx *digest_ctx = + (struct digest_ctx *)EVP_MD_CTX_md_data(ctx); + + if (digest_ctx == NULL) + return 1; + + return clean_devcrypto_session(&digest_ctx->sess); +} + +static int devcrypto_test_digest(size_t digest_data_index) +{ + struct session_op sess1, sess2; + struct cphash_op cphash; + int ret=0; + + memset(&sess1, 0, sizeof(sess1)); + memset(&sess2, 0, sizeof(sess2)); + sess1.mac = digest_data[digest_data_index].devcryptoid; + if (ioctl(cfd, CIOCGSESSION, &sess1) < 0) + return 0; + /* Make sure the driver is capable of hash state copy */ + sess2.mac = sess1.mac; + if (ioctl(cfd, CIOCGSESSION, &sess2) >= 0) { + cphash.src_ses = sess1.ses; + cphash.dst_ses = sess2.ses; + if (ioctl(cfd, CIOCCPHASH, &cphash) >= 0) + ret = 1; + ioctl(cfd, CIOCFSESSION, &sess2.ses); + } + ioctl(cfd, CIOCFSESSION, &sess1.ses); + return ret; } /* @@ -514,24 +661,20 @@ static EVP_MD *known_digest_methods[OSSL_NELEM(digest_data)] = { NULL, }; static void prepare_digest_methods(void) { size_t i; - struct session_op sess; - - memset(&sess, 0, sizeof(sess)); for (i = 0, known_digest_nids_amount = 0; i < OSSL_NELEM(digest_data); i++) { /* - * Check that the algo is really availably by trying to open and close - * a session. + * Check that the algo is usable */ - sess.mac = digest_data[i].devcryptoid; - if (ioctl(cfd, CIOCGSESSION, &sess) < 0 - || ioctl(cfd, CIOCFSESSION, &sess.ses) < 0) + if (!devcrypto_test_digest(i)) continue; if ((known_digest_methods[i] = EVP_MD_meth_new(digest_data[i].nid, NID_undef)) == NULL + || !EVP_MD_meth_set_input_blocksize(known_digest_methods[i], + digest_data[i].blocksize) || !EVP_MD_meth_set_result_size(known_digest_methods[i], digest_data[i].digestlen) || !EVP_MD_meth_set_init(known_digest_methods[i], digest_init) @@ -622,15 +765,10 @@ void engine_load_devcrypto_int() #ifndef ENGINE_DEVCRYPTO_DEBUG if (errno != ENOENT) #endif - fprintf(stderr, "Could not open /dev/crypto: %s\n", strerror(errno)); + fprintf(stderr, "Could not open /dev/crypto: %s\n", strerror(errno)); return; } - prepare_cipher_methods(); -#ifdef IMPLEMENT_DIGEST - prepare_digest_methods(); -#endif - if ((e = ENGINE_new()) == NULL || !ENGINE_set_destroy_function(e, devcrypto_unload)) { ENGINE_free(e); @@ -643,6 +781,11 @@ void engine_load_devcrypto_int() return; } + prepare_cipher_methods(); +#ifdef IMPLEMENT_DIGEST + prepare_digest_methods(); +#endif + if (!ENGINE_set_id(e, "devcrypto") || !ENGINE_set_name(e, "/dev/crypto engine") |