From c4729f6e89f09aead4b86294998659ac55187fe5 Mon Sep 17 00:00:00 2001 From: Conrad Meyer Date: Mon, 9 Jul 2018 07:28:13 +0000 Subject: [PATCH] OCF: Add plain hash modes In part, to support OpenSSL's use of cryptodev, which puts the HMAC pieces in software and only offloads the raw hash primitive. The following cryptodev identifiers are added: * CRYPTO_RIPEMD160 (not hooked up) * CRYPTO_SHA2_224 * CRYPTO_SHA2_256 * CRYPTO_SHA2_384 * CRYPTO_SHA2_512 The plain SHA1 and 2 hashes are plumbed through cryptodev (feels like there is a lot of redundancy here...) and cryptosoft. This adds new auth_hash implementations for the plain hashes, as well as SHA1 (which had a cryptodev.h identifier, but no implementation). Add plain SHA 1 and 2 hash tests to the cryptocheck tool. Motivation stems from John Baldwin's earlier OCF email, https://lists.freebsd.org/pipermail/freebsd-arch/2018-January/018835.html . --- sys/opencrypto/cryptodev.c | 15 ++- sys/opencrypto/cryptodev.h | 7 +- sys/opencrypto/cryptosoft.c | 35 ++++++- sys/opencrypto/xform_auth.h | 5 + sys/opencrypto/xform_sha1.c | 12 +++ sys/opencrypto/xform_sha2.c | 48 +++++++++ tools/tools/crypto/cryptocheck.c | 162 +++++++++++++++++++++++++++++-- 7 files changed, 274 insertions(+), 10 deletions(-) diff --git a/sys/opencrypto/cryptodev.c b/sys/opencrypto/cryptodev.c index e80de0c159a4..605cc0818636 100644 --- a/sys/opencrypto/cryptodev.c +++ b/sys/opencrypto/cryptodev.c @@ -489,10 +489,23 @@ cryptof_ioctl( case CRYPTO_MD5: thash = &auth_hash_md5; break; +#endif case CRYPTO_SHA1: thash = &auth_hash_sha1; break; -#endif + case CRYPTO_SHA2_224: + thash = &auth_hash_sha2_224; + break; + case CRYPTO_SHA2_256: + thash = &auth_hash_sha2_256; + break; + case CRYPTO_SHA2_384: + thash = &auth_hash_sha2_384; + break; + case CRYPTO_SHA2_512: + thash = &auth_hash_sha2_512; + break; + case CRYPTO_NULL_HMAC: thash = &auth_hash_null; break; diff --git a/sys/opencrypto/cryptodev.h b/sys/opencrypto/cryptodev.h index 3c1b7b278b3d..33ab58818f4c 100644 --- a/sys/opencrypto/cryptodev.h +++ b/sys/opencrypto/cryptodev.h @@ -186,7 +186,12 @@ #define CRYPTO_BLAKE2S 30 /* Blake2s hash */ #define CRYPTO_CHACHA20 31 /* Chacha20 stream cipher */ #define CRYPTO_SHA2_224_HMAC 32 -#define CRYPTO_ALGORITHM_MAX 32 /* Keep updated - see below */ +#define CRYPTO_RIPEMD160 33 +#define CRYPTO_SHA2_224 34 +#define CRYPTO_SHA2_256 35 +#define CRYPTO_SHA2_384 36 +#define CRYPTO_SHA2_512 37 +#define CRYPTO_ALGORITHM_MAX 37 /* Keep updated - see below */ #define CRYPTO_ALGO_VALID(x) ((x) >= CRYPTO_ALGORITHM_MIN && \ (x) <= CRYPTO_ALGORITHM_MAX) diff --git a/sys/opencrypto/cryptosoft.c b/sys/opencrypto/cryptosoft.c index dea8499bbf58..fd83eba9f3fe 100644 --- a/sys/opencrypto/cryptosoft.c +++ b/sys/opencrypto/cryptosoft.c @@ -421,6 +421,14 @@ swcr_authcompute(struct cryptodesc *crd, struct swcr_data *sw, caddr_t buf, return err; switch (sw->sw_alg) { + case CRYPTO_SHA1: + case CRYPTO_SHA2_224: + case CRYPTO_SHA2_256: + case CRYPTO_SHA2_384: + case CRYPTO_SHA2_512: + axf->Final(aalg, &ctx); + break; + case CRYPTO_MD5_HMAC: case CRYPTO_SHA1_HMAC: case CRYPTO_SHA2_224_HMAC: @@ -934,9 +942,23 @@ swcr_newsession(device_t dev, u_int32_t *sid, struct cryptoini *cri) case CRYPTO_MD5: axf = &auth_hash_md5; goto auth3common; +#endif case CRYPTO_SHA1: axf = &auth_hash_sha1; + goto auth3common; + case CRYPTO_SHA2_224: + axf = &auth_hash_sha2_224; + goto auth3common; + case CRYPTO_SHA2_256: + axf = &auth_hash_sha2_256; + goto auth3common; + case CRYPTO_SHA2_384: + axf = &auth_hash_sha2_384; + goto auth3common; + case CRYPTO_SHA2_512: + axf = &auth_hash_sha2_512; + auth3common: (*swd)->sw_ictx = malloc(axf->ctxsize, M_CRYPTO_DATA, M_NOWAIT); @@ -950,7 +972,6 @@ swcr_newsession(device_t dev, u_int32_t *sid, struct cryptoini *cri) (*swd)->sw_mlen = cri->cri_mlen; (*swd)->sw_axf = axf; break; -#endif case CRYPTO_AES_128_NIST_GMAC: axf = &auth_hash_nist_gmac_aes_128; @@ -1110,6 +1131,10 @@ swcr_freesession_locked(device_t dev, u_int64_t tid) case CRYPTO_BLAKE2S: case CRYPTO_MD5: case CRYPTO_SHA1: + case CRYPTO_SHA2_224: + case CRYPTO_SHA2_256: + case CRYPTO_SHA2_384: + case CRYPTO_SHA2_512: axf = swd->sw_axf; if (swd->sw_ictx) { @@ -1216,6 +1241,10 @@ swcr_process(device_t dev, struct cryptop *crp, int hint) case CRYPTO_SHA1_KPDK: case CRYPTO_MD5: case CRYPTO_SHA1: + case CRYPTO_SHA2_224: + case CRYPTO_SHA2_256: + case CRYPTO_SHA2_384: + case CRYPTO_SHA2_512: case CRYPTO_BLAKE2B: case CRYPTO_BLAKE2S: if ((crp->crp_etype = swcr_authcompute(crd, sw, @@ -1300,6 +1329,10 @@ swcr_attach(device_t dev) REGISTER(CRYPTO_SHA1_KPDK); REGISTER(CRYPTO_MD5); REGISTER(CRYPTO_SHA1); + REGISTER(CRYPTO_SHA2_224); + REGISTER(CRYPTO_SHA2_256); + REGISTER(CRYPTO_SHA2_384); + REGISTER(CRYPTO_SHA2_512); REGISTER(CRYPTO_RIJNDAEL128_CBC); REGISTER(CRYPTO_AES_XTS); REGISTER(CRYPTO_AES_ICM); diff --git a/sys/opencrypto/xform_auth.h b/sys/opencrypto/xform_auth.h index 04654f9ada5d..bdd492bd117e 100644 --- a/sys/opencrypto/xform_auth.h +++ b/sys/opencrypto/xform_auth.h @@ -73,6 +73,11 @@ extern struct auth_hash auth_hash_hmac_sha2_224; extern struct auth_hash auth_hash_hmac_sha2_256; extern struct auth_hash auth_hash_hmac_sha2_384; extern struct auth_hash auth_hash_hmac_sha2_512; +extern struct auth_hash auth_hash_sha1; +extern struct auth_hash auth_hash_sha2_224; +extern struct auth_hash auth_hash_sha2_256; +extern struct auth_hash auth_hash_sha2_384; +extern struct auth_hash auth_hash_sha2_512; extern struct auth_hash auth_hash_nist_gmac_aes_128; extern struct auth_hash auth_hash_nist_gmac_aes_192; extern struct auth_hash auth_hash_nist_gmac_aes_256; diff --git a/sys/opencrypto/xform_sha1.c b/sys/opencrypto/xform_sha1.c index e5d71bbfe877..44ac8c0e8b77 100644 --- a/sys/opencrypto/xform_sha1.c +++ b/sys/opencrypto/xform_sha1.c @@ -57,6 +57,18 @@ static void SHA1Init_int(void *); static int SHA1Update_int(void *, const u_int8_t *, u_int16_t); static void SHA1Final_int(u_int8_t *, void *); +/* Plain hash */ +struct auth_hash auth_hash_sha1 = { + .type = CRYPTO_SHA1, + .name = "SHA1", + .hashsize = SHA1_HASH_LEN, + .ctxsize = sizeof(SHA1_CTX), + .blocksize = SHA1_BLOCK_LEN, + .Init = SHA1Init_int, + .Update = SHA1Update_int, + .Final = SHA1Final_int, +}; + /* Authentication instances */ struct auth_hash auth_hash_hmac_sha1 = { .type = CRYPTO_SHA1_HMAC, diff --git a/sys/opencrypto/xform_sha2.c b/sys/opencrypto/xform_sha2.c index d9cbbb585de0..0775247acb11 100644 --- a/sys/opencrypto/xform_sha2.c +++ b/sys/opencrypto/xform_sha2.c @@ -61,6 +61,54 @@ static int SHA256Update_int(void *, const u_int8_t *, u_int16_t); static int SHA384Update_int(void *, const u_int8_t *, u_int16_t); static int SHA512Update_int(void *, const u_int8_t *, u_int16_t); +/* Plain hashes */ +struct auth_hash auth_hash_sha2_224 = { + .type = CRYPTO_SHA2_224, + .name = "SHA2-224", + .hashsize = SHA2_224_HASH_LEN, + .ctxsize = sizeof(SHA224_CTX), + .blocksize = SHA2_224_BLOCK_LEN, + .Init = (void (*)(void *)) SHA224_Init, + .Update = SHA224Update_int, + .Final = (void (*)(u_int8_t *, void *)) SHA224_Final, +}; + +struct auth_hash auth_hash_sha2_256 = { + .type = CRYPTO_SHA2_256, + .name = "SHA2-256", + .keysize = SHA2_256_BLOCK_LEN, + .hashsize = SHA2_256_HASH_LEN, + .ctxsize = sizeof(SHA256_CTX), + .blocksize = SHA2_256_BLOCK_LEN, + .Init = (void (*)(void *)) SHA256_Init, + .Update = SHA256Update_int, + .Final = (void (*)(u_int8_t *, void *)) SHA256_Final, +}; + +struct auth_hash auth_hash_sha2_384 = { + .type = CRYPTO_SHA2_384, + .name = "SHA2-384", + .keysize = SHA2_384_BLOCK_LEN, + .hashsize = SHA2_384_HASH_LEN, + .ctxsize = sizeof(SHA384_CTX), + .blocksize = SHA2_384_BLOCK_LEN, + .Init = (void (*)(void *)) SHA384_Init, + .Update = SHA384Update_int, + .Final = (void (*)(u_int8_t *, void *)) SHA384_Final, +}; + +struct auth_hash auth_hash_sha2_512 = { + .type = CRYPTO_SHA2_512, + .name = "SHA2-512", + .keysize = SHA2_512_BLOCK_LEN, + .hashsize = SHA2_512_HASH_LEN, + .ctxsize = sizeof(SHA512_CTX), + .blocksize = SHA2_512_BLOCK_LEN, + .Init = (void (*)(void *)) SHA512_Init, + .Update = SHA512Update_int, + .Final = (void (*)(u_int8_t *, void *)) SHA512_Final, +}; + /* Authentication instances */ struct auth_hash auth_hash_hmac_sha2_224 = { .type = CRYPTO_SHA2_224_HMAC, diff --git a/tools/tools/crypto/cryptocheck.c b/tools/tools/crypto/cryptocheck.c index 8e7629856af0..fa3459734c65 100644 --- a/tools/tools/crypto/cryptocheck.c +++ b/tools/tools/crypto/cryptocheck.c @@ -131,19 +131,29 @@ struct alg { const char *name; int cipher; int mac; - enum { T_HMAC, T_BLKCIPHER, T_AUTHENC, T_GCM } type; + enum { T_HASH, T_HMAC, T_BLKCIPHER, T_AUTHENC, T_GCM } type; const EVP_CIPHER *(*evp_cipher)(void); const EVP_MD *(*evp_md)(void); } algs[] = { - { .name = "sha1", .mac = CRYPTO_SHA1_HMAC, .type = T_HMAC, + { .name = "sha1", .mac = CRYPTO_SHA1, .type = T_HASH, .evp_md = EVP_sha1 }, - { .name = "sha224", .mac = CRYPTO_SHA2_224_HMAC, .type = T_HMAC, + { .name = "sha224", .mac = CRYPTO_SHA2_224, .type = T_HASH, .evp_md = EVP_sha224 }, - { .name = "sha256", .mac = CRYPTO_SHA2_256_HMAC, .type = T_HMAC, + { .name = "sha256", .mac = CRYPTO_SHA2_256, .type = T_HASH, .evp_md = EVP_sha256 }, - { .name = "sha384", .mac = CRYPTO_SHA2_384_HMAC, .type = T_HMAC, + { .name = "sha384", .mac = CRYPTO_SHA2_384, .type = T_HASH, .evp_md = EVP_sha384 }, - { .name = "sha512", .mac = CRYPTO_SHA2_512_HMAC, .type = T_HMAC, + { .name = "sha512", .mac = CRYPTO_SHA2_512, .type = T_HASH, + .evp_md = EVP_sha512 }, + { .name = "sha1hmac", .mac = CRYPTO_SHA1_HMAC, .type = T_HMAC, + .evp_md = EVP_sha1 }, + { .name = "sha224hmac", .mac = CRYPTO_SHA2_224_HMAC, .type = T_HMAC, + .evp_md = EVP_sha224 }, + { .name = "sha256hmac", .mac = CRYPTO_SHA2_256_HMAC, .type = T_HMAC, + .evp_md = EVP_sha256 }, + { .name = "sha384hmac", .mac = CRYPTO_SHA2_384_HMAC, .type = T_HMAC, + .evp_md = EVP_sha384 }, + { .name = "sha512hmac", .mac = CRYPTO_SHA2_512_HMAC, .type = T_HMAC, .evp_md = EVP_sha512 }, { .name = "blake2b", .mac = CRYPTO_BLAKE2B, .type = T_HMAC, .evp_md = EVP_blake2b512 }, @@ -351,6 +361,128 @@ generate_iv(size_t len, struct alg *alg) return (iv); } +static bool +ocf_hash(struct alg *alg, const char *buffer, size_t size, char *digest, + int *cridp) +{ + struct session2_op sop; + struct crypt_op cop; + int fd; + + memset(&sop, 0, sizeof(sop)); + memset(&cop, 0, sizeof(cop)); + sop.crid = crid; + sop.mac = alg->mac; + fd = crget(); + if (ioctl(fd, CIOCGSESSION2, &sop) < 0) { + warn("cryptodev %s HASH not supported for device %s", + alg->name, crfind(crid)); + close(fd); + return (false); + } + + cop.ses = sop.ses; + cop.op = 0; + cop.len = size; + cop.src = (char *)buffer; + cop.dst = NULL; + cop.mac = digest; + cop.iv = NULL; + + if (ioctl(fd, CIOCCRYPT, &cop) < 0) { + warn("cryptodev %s (%zu) HASH failed for device %s", alg->name, + size, crfind(crid)); + close(fd); + return (false); + } + + if (ioctl(fd, CIOCFSESSION, &sop.ses) < 0) + warn("ioctl(CIOCFSESSION)"); + + close(fd); + *cridp = sop.crid; + return (true); +} + +static void +openssl_hash(struct alg *alg, const EVP_MD *md, const void *buffer, + size_t size, void *digest_out, unsigned *digest_sz_out) +{ + EVP_MD_CTX *mdctx; + const char *errs; + int rc; + + errs = ""; + + mdctx = EVP_MD_CTX_create(); + if (mdctx == NULL) + goto err_out; + + rc = EVP_DigestInit_ex(mdctx, md, NULL); + if (rc != 1) + goto err_out; + + rc = EVP_DigestUpdate(mdctx, buffer, size); + if (rc != 1) + goto err_out; + + rc = EVP_DigestFinal_ex(mdctx, digest_out, digest_sz_out); + if (rc != 1) + goto err_out; + + EVP_MD_CTX_destroy(mdctx); + return; + +err_out: + errx(1, "OpenSSL %s HASH failed%s: %s", alg->name, errs, + ERR_error_string(ERR_get_error(), NULL)); +} + +static void +run_hash_test(struct alg *alg, size_t size) +{ + const EVP_MD *md; + char *buffer; + u_int digest_len; + int crid; + char control_digest[EVP_MAX_MD_SIZE], test_digest[EVP_MAX_MD_SIZE]; + + memset(control_digest, 0x3c, sizeof(control_digest)); + memset(test_digest, 0x3c, sizeof(test_digest)); + + md = alg->evp_md(); + assert(EVP_MD_size(md) <= sizeof(control_digest)); + + buffer = alloc_buffer(size); + + /* OpenSSL HASH. */ + digest_len = sizeof(control_digest); + openssl_hash(alg, md, buffer, size, control_digest, &digest_len); + + /* cryptodev HASH. */ + if (!ocf_hash(alg, buffer, size, test_digest, &crid)) + goto out; + if (memcmp(control_digest, test_digest, sizeof(control_digest)) != 0) { + if (memcmp(control_digest, test_digest, EVP_MD_size(md)) == 0) + printf("%s (%zu) mismatch in trailer:\n", + alg->name, size); + else + printf("%s (%zu) mismatch:\n", alg->name, size); + printf("control:\n"); + hexdump(control_digest, sizeof(control_digest), NULL, 0); + printf("test (cryptodev device %s):\n", crfind(crid)); + hexdump(test_digest, sizeof(test_digest), NULL, 0); + goto out; + } + + if (verbose) + printf("%s (%zu) matched (cryptodev device %s)\n", + alg->name, size, crfind(crid)); + +out: + free(buffer); +} + static bool ocf_hmac(struct alg *alg, const char *buffer, size_t size, const char *key, size_t key_len, char *digest, int *cridp) @@ -1031,6 +1163,9 @@ run_test(struct alg *alg, size_t size) { switch (alg->type) { + case T_HASH: + run_hash_test(alg, size); + break; case T_HMAC: run_hmac_test(alg, size); break; @@ -1055,6 +1190,16 @@ run_test_sizes(struct alg *alg, size_t *sizes, u_int nsizes) run_test(alg, sizes[i]); } +static void +run_hash_tests(size_t *sizes, u_int nsizes) +{ + u_int i; + + for (i = 0; i < nitems(algs); i++) + if (algs[i].type == T_HASH) + run_test_sizes(&algs[i], sizes, nsizes); +} + static void run_hmac_tests(size_t *sizes, u_int nsizes) { @@ -1177,7 +1322,9 @@ main(int ac, char **av) } } - if (strcasecmp(algname, "hmac") == 0) + if (strcasecmp(algname, "hash") == 0) + run_hash_tests(sizes, nsizes); + else if (strcasecmp(algname, "hmac") == 0) run_hmac_tests(sizes, nsizes); else if (strcasecmp(algname, "blkcipher") == 0) run_blkcipher_tests(sizes, nsizes); @@ -1186,6 +1333,7 @@ main(int ac, char **av) else if (strcasecmp(algname, "aead") == 0) run_aead_tests(sizes, nsizes); else if (strcasecmp(algname, "all") == 0) { + run_hash_tests(sizes, nsizes); run_hmac_tests(sizes, nsizes); run_blkcipher_tests(sizes, nsizes); run_authenc_tests(sizes, nsizes);