From commits-return-14536-archive-asf-public=cust-asf.ponee.io@apr.apache.org Sun Jul 22 15:11:36 2018 Return-Path: X-Original-To: archive-asf-public@cust-asf.ponee.io Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by mx-eu-01.ponee.io (Postfix) with SMTP id 402C7180677 for ; Sun, 22 Jul 2018 15:11:34 +0200 (CEST) Received: (qmail 63605 invoked by uid 500); 22 Jul 2018 13:11:33 -0000 Mailing-List: contact commits-help@apr.apache.org; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: Reply-To: dev@apr.apache.org List-Id: Delivered-To: mailing list commits@apr.apache.org Received: (qmail 63596 invoked by uid 99); 22 Jul 2018 13:11:33 -0000 Received: from Unknown (HELO svn01-us-west.apache.org) (209.188.14.144) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 22 Jul 2018 13:11:33 +0000 Received: from svn01-us-west.apache.org (localhost [127.0.0.1]) by svn01-us-west.apache.org (ASF Mail Server at svn01-us-west.apache.org) with ESMTP id 860C23A023C for ; Sun, 22 Jul 2018 13:11:32 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1836439 [2/3] - in /apr/apr/trunk: ./ crypto/ include/ include/private/ test/ Date: Sun, 22 Jul 2018 13:11:32 -0000 To: commits@apr.apache.org From: minfrin@apache.org X-Mailer: svnmailer-1.0.9 Message-Id: <20180722131132.860C23A023C@svn01-us-west.apache.org> Modified: apr/apr/trunk/crypto/apr_crypto_openssl.c URL: http://svn.apache.org/viewvc/apr/apr/trunk/crypto/apr_crypto_openssl.c?rev=1836439&r1=1836438&r2=1836439&view=diff ============================================================================== --- apr/apr/trunk/crypto/apr_crypto_openssl.c (original) +++ apr/apr/trunk/crypto/apr_crypto_openssl.c Sun Jul 22 13:11:32 2018 @@ -37,8 +37,20 @@ #define LOG_PREFIX "apr_crypto_openssl: " -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) -#define EVP_CIPHER_CTX_reset EVP_CIPHER_CTX_cleanup +#ifndef APR_USE_OPENSSL_PRE_1_1_API +#if defined(LIBRESSL_VERSION_NUMBER) +/* LibreSSL declares OPENSSL_VERSION_NUMBER == 2.0 but does not include most + * changes from OpenSSL >= 1.1 (new functions, macros, deprecations, ...), so + * we have to work around this... + */ +#define APR_USE_OPENSSL_PRE_1_1_API (1) +#define APR_USE_OPENSSL_PRE_1_1_1_API (1) +#define APR_USE_OPENSSL_PRE_1_0_API (0) +#else +#define APR_USE_OPENSSL_PRE_1_1_API (OPENSSL_VERSION_NUMBER < 0x10100000L) +#define APR_USE_OPENSSL_PRE_1_1_1_API (OPENSSL_VERSION_NUMBER < 0x10101000L) +#define APR_USE_OPENSSL_PRE_1_0_API (OPENSSL_VERSION_NUMBER < 0x10000000L) +#endif #endif struct apr_crypto_t { @@ -48,6 +60,7 @@ struct apr_crypto_t { apr_crypto_config_t *config; apr_hash_t *types; apr_hash_t *modes; + apr_hash_t *digests; }; struct apr_crypto_config_t { @@ -58,7 +71,10 @@ struct apr_crypto_key_t { apr_pool_t *pool; const apr_crypto_driver_t *provider; const apr_crypto_t *f; - const EVP_CIPHER * cipher; + const apr_crypto_key_rec_t *rec; + const EVP_CIPHER *cipher; + const EVP_MD *hmac; + EVP_PKEY *pkey; unsigned char *key; int keyLen; int doPad; @@ -69,6 +85,7 @@ struct apr_crypto_block_t { apr_pool_t *pool; const apr_crypto_driver_t *provider; const apr_crypto_t *f; + const apr_crypto_key_t *key; EVP_CIPHER_CTX *cipherCtx; int initialised; int ivSize; @@ -76,6 +93,26 @@ struct apr_crypto_block_t { int doPad; }; +struct apr_crypto_digest_t { + apr_pool_t *pool; + const apr_crypto_driver_t *provider; + const apr_crypto_t *f; + const apr_crypto_key_t *key; + apr_crypto_digest_rec_t *rec; + EVP_MD_CTX *mdCtx; + int initialised; + int digestSize; +}; + +static struct apr_crypto_block_key_digest_t key_digests[] = +{ +{ APR_CRYPTO_DIGEST_MD5, 16, 64 }, +{ APR_CRYPTO_DIGEST_SHA1, 20, 64 }, +{ APR_CRYPTO_DIGEST_SHA224, 28, 64 }, +{ APR_CRYPTO_DIGEST_SHA256, 32, 64 }, +{ APR_CRYPTO_DIGEST_SHA384, 48, 128 }, +{ APR_CRYPTO_DIGEST_SHA512, 64, 128 } }; + static struct apr_crypto_block_key_type_t key_types[] = { { APR_KEY_3DES_192, 24, 8, 8 }, @@ -106,16 +143,87 @@ static apr_status_t crypto_error(const a */ static apr_status_t crypto_shutdown(void) { - return apr_crypto_lib_term("openssl"); + ERR_free_strings(); + EVP_cleanup(); + ENGINE_cleanup(); + return APR_SUCCESS; +} + +static apr_status_t crypto_shutdown_helper(void *data) +{ + return crypto_shutdown(); } /** * Initialise the crypto library and perform one time initialisation. */ static apr_status_t crypto_init(apr_pool_t *pool, const char *params, - const apu_err_t **result) + const apu_err_t **result) +{ +#if APR_USE_OPENSSL_PRE_1_1_API + (void)CRYPTO_malloc_init(); +#else + OPENSSL_malloc_init(); +#endif + ERR_load_crypto_strings(); + /* SSL_load_error_strings(); */ + OpenSSL_add_all_algorithms(); + ENGINE_load_builtin_engines(); + ENGINE_register_all_complete(); + + apr_pool_cleanup_register(pool, pool, crypto_shutdown_helper, + apr_pool_cleanup_null); + + return APR_SUCCESS; +} + +#if OPENSSL_VERSION_NUMBER < 0x0090802fL + +/* Code taken from OpenSSL 0.9.8b, see + * https://github.com/openssl/openssl/commit/cf6bc84148cb15af09b292394aaf2b45f0d5af0d + */ + +EVP_CIPHER_CTX *EVP_CIPHER_CTX_new(void) +{ + EVP_CIPHER_CTX *ctx = OPENSSL_malloc(sizeof *ctx); + if (ctx) + EVP_CIPHER_CTX_init(ctx); + return ctx; +} + +void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *ctx) +{ + if (ctx) { + EVP_CIPHER_CTX_cleanup(ctx); + OPENSSL_free(ctx); + } +} + +#endif + +#ifdef APR_USE_OPENSSL_PRE_1_1_API +#define EVP_MD_CTX_new EVP_MD_CTX_create +#define EVP_MD_CTX_free EVP_MD_CTX_destroy +#endif + +/** + * @brief Clean key. + * @param key The key to use. + * @return Returns APR_ENOTIMPL if not supported. + */ +static apr_status_t crypto_key_cleanup(apr_crypto_key_t *key) +{ + if (key->pkey) { + EVP_PKEY_free(key->pkey); + } + + return APR_SUCCESS; +} + +static apr_status_t crypto_key_cleanup_helper(void *data) { - return apr_crypto_lib_init("openssl", params, result, pool); + apr_crypto_key_t *key = (apr_crypto_key_t *) data; + return crypto_key_cleanup(key); } /** @@ -128,7 +236,15 @@ static apr_status_t crypto_block_cleanup { if (ctx->initialised) { - EVP_CIPHER_CTX_free(ctx->cipherCtx); + if (ctx->cipherCtx) { +#if APR_USE_OPENSSL_PRE_1_1_API + EVP_CIPHER_CTX_cleanup(ctx->cipherCtx); +#else + EVP_CIPHER_CTX_reset(ctx->cipherCtx); + EVP_CIPHER_CTX_free(ctx->cipherCtx); +#endif + ctx->cipherCtx = NULL; + } ctx->initialised = 0; } @@ -143,6 +259,33 @@ static apr_status_t crypto_block_cleanup } /** + * @brief Clean sign / verify context. + * @note After cleanup, a context is free to be reused if necessary. + * @param ctx The block context to use. + * @return Returns APR_ENOTIMPL if not supported. + */ +static apr_status_t crypto_digest_cleanup(apr_crypto_digest_t *ctx) +{ + + if (ctx->initialised) { + if (ctx->mdCtx) { + EVP_MD_CTX_free(ctx->mdCtx); + ctx->mdCtx = NULL; + } + ctx->initialised = 0; + } + + return APR_SUCCESS; + +} + +static apr_status_t crypto_digest_cleanup_helper(void *data) +{ + apr_crypto_digest_t *digest = (apr_crypto_digest_t *) data; + return crypto_digest_cleanup(digest); +} + +/** * @brief Clean encryption / decryption context. * @note After cleanup, a context is free to be reused if necessary. * @param f The context to use. @@ -250,21 +393,37 @@ static apr_status_t crypto_make(apr_cryp return APR_ENOMEM; } + f->digests = apr_hash_make(pool); + if (!f->digests) { + return APR_ENOMEM; + } + apr_hash_set(f->digests, "md5", APR_HASH_KEY_STRING, &(key_digests[i = 0])); + apr_hash_set(f->digests, "sha1", APR_HASH_KEY_STRING, &(key_digests[++i])); + apr_hash_set(f->digests, "sha224", APR_HASH_KEY_STRING, &(key_digests[++i])); + apr_hash_set(f->digests, "sha256", APR_HASH_KEY_STRING, &(key_digests[++i])); + apr_hash_set(f->digests, "sha384", APR_HASH_KEY_STRING, &(key_digests[++i])); + apr_hash_set(f->digests, "sha512", APR_HASH_KEY_STRING, &(key_digests[++i])); + f->types = apr_hash_make(pool); if (!f->types) { return APR_ENOMEM; } - apr_hash_set(f->types, "3des192", APR_HASH_KEY_STRING, &(key_types[0])); - apr_hash_set(f->types, "aes128", APR_HASH_KEY_STRING, &(key_types[1])); - apr_hash_set(f->types, "aes192", APR_HASH_KEY_STRING, &(key_types[2])); - apr_hash_set(f->types, "aes256", APR_HASH_KEY_STRING, &(key_types[3])); + apr_hash_set(f->types, "3des192", APR_HASH_KEY_STRING, &(key_types[i = 0])); + apr_hash_set(f->types, "aes128", APR_HASH_KEY_STRING, &(key_types[++i])); + apr_hash_set(f->types, "aes192", APR_HASH_KEY_STRING, &(key_types[++i])); + apr_hash_set(f->types, "aes256", APR_HASH_KEY_STRING, &(key_types[++i])); f->modes = apr_hash_make(pool); if (!f->modes) { return APR_ENOMEM; } - apr_hash_set(f->modes, "ecb", APR_HASH_KEY_STRING, &(key_modes[0])); - apr_hash_set(f->modes, "cbc", APR_HASH_KEY_STRING, &(key_modes[1])); + apr_hash_set(f->modes, "ecb", APR_HASH_KEY_STRING, &(key_modes[i = 0])); + apr_hash_set(f->modes, "cbc", APR_HASH_KEY_STRING, &(key_modes[++i])); + + f->digests = apr_hash_make(pool); + if (!f->digests) { + return APR_ENOMEM; + } apr_pool_cleanup_register(pool, f, crypto_cleanup_helper, apr_pool_cleanup_null); @@ -286,6 +445,21 @@ static apr_status_t crypto_make(apr_cryp } /** + * @brief Get a hash table of key digests, keyed by the name of the digest against + * a pointer to apr_crypto_block_key_digest_t. + * + * @param digests - hashtable of key digests keyed to constants. + * @param f - encryption context + * @return APR_SUCCESS for success + */ +static apr_status_t crypto_get_block_key_digests(apr_hash_t **digests, + const apr_crypto_t *f) +{ + *digests = f->digests; + return APR_SUCCESS; +} + +/** * @brief Get a hash table of key types, keyed by the name of the type against * a pointer to apr_crypto_block_key_type_t. * @@ -415,19 +589,24 @@ static apr_status_t crypto_key(apr_crypt } } + apr_pool_cleanup_register(p, key, crypto_key_cleanup_helper, + apr_pool_cleanup_null); + + key->pool = p; key->f = f; key->provider = f->provider; - - /* decide on what cipher mechanism we will be using */ - rv = crypto_cipher_mechanism(key, rec->type, rec->mode, rec->pad, p); - if (APR_SUCCESS != rv) { - return rv; - } + key->rec = rec; switch (rec->ktype) { case APR_CRYPTO_KTYPE_PASSPHRASE: { + /* decide on what cipher mechanism we will be using */ + rv = crypto_cipher_mechanism(key, rec->type, rec->mode, rec->pad, p); + if (APR_SUCCESS != rv) { + return rv; + } + /* generate the key */ if (PKCS5_PBKDF2_HMAC_SHA1(rec->k.passphrase.pass, rec->k.passphrase.passLen, @@ -442,6 +621,12 @@ static apr_status_t crypto_key(apr_crypt case APR_CRYPTO_KTYPE_SECRET: { + /* decide on what cipher mechanism we will be using */ + rv = crypto_cipher_mechanism(key, rec->type, rec->mode, rec->pad, p); + if (APR_SUCCESS != rv) { + return rv; + } + /* sanity check - key correct size? */ if (rec->k.secret.secretLen != key->keyLen) { return APR_EKEYLENGTH; @@ -452,6 +637,115 @@ static apr_status_t crypto_key(apr_crypt break; } + case APR_CRYPTO_KTYPE_HASH: { + + switch (rec->k.hash.digest) { + case APR_CRYPTO_DIGEST_MD5: + key->hmac = EVP_md5(); + break; + case APR_CRYPTO_DIGEST_SHA1: + key->hmac = EVP_sha1(); + break; + case APR_CRYPTO_DIGEST_SHA224: + key->hmac = EVP_sha224(); + break; + case APR_CRYPTO_DIGEST_SHA256: + key->hmac = EVP_sha256(); + break; + case APR_CRYPTO_DIGEST_SHA384: + key->hmac = EVP_sha384(); + break; + case APR_CRYPTO_DIGEST_SHA512: + key->hmac = EVP_sha512(); + break; + default: + return APR_ENODIGEST; + } + + break; + } + case APR_CRYPTO_KTYPE_HMAC: { + + apr_crypto_config_t *config = f->config; + + /* create hmac key */ + if (!(key->pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, config->engine, + rec->k.hmac.secret, rec->k.hmac.secretLen))) { + return APR_ENOKEY; + } + + switch (rec->k.hmac.digest) { + case APR_CRYPTO_DIGEST_MD5: + key->hmac = EVP_md5(); + break; + case APR_CRYPTO_DIGEST_SHA1: + key->hmac = EVP_sha1(); + break; + case APR_CRYPTO_DIGEST_SHA224: + key->hmac = EVP_sha224(); + break; + case APR_CRYPTO_DIGEST_SHA256: + key->hmac = EVP_sha256(); + break; + case APR_CRYPTO_DIGEST_SHA384: + key->hmac = EVP_sha384(); + break; + case APR_CRYPTO_DIGEST_SHA512: + key->hmac = EVP_sha512(); + break; + default: + return APR_ENODIGEST; + } + + break; + } + + case APR_CRYPTO_KTYPE_CMAC: { + +#ifndef APR_USE_OPENSSL_PRE_1_1_1_API + apr_crypto_config_t *config = f->config; + + /* decide on what cipher mechanism we will be using */ + rv = crypto_cipher_mechanism(key, rec->type, rec->mode, rec->pad, p); + if (APR_SUCCESS != rv) { + return rv; + } + + /* create cmac key */ + if (!(key->pkey = EVP_PKEY_new_CMAC_key(config->engine, + rec->k.cmac.secret, rec->k.cmac.secretLen, key->cipher))) { + return APR_ENOKEY; + } + + switch (rec->k.hmac.hmac) { + case APR_CRYPTO_DIGEST_MD5: + key->hmac = EVP_md5(); + break; + case APR_CRYPTO_DIGEST_SHA1: + key->hmac = EVP_sha1(); + break; + case APR_CRYPTO_DIGEST_SHA224: + key->hmac = EVP_sha224(); + break; + case APR_CRYPTO_DIGEST_SHA256: + key->hmac = EVP_sha256(); + break; + case APR_CRYPTO_DIGEST_SHA384: + key->hmac = EVP_sha384(); + break; + case APR_CRYPTO_DIGEST_SHA512: + key->hmac = EVP_sha512(); + break; + default: + return APR_ENODIGEST; + } + +#else + return APR_ENOTIMPL; +#endif + + break; + } default: { @@ -465,7 +759,7 @@ static apr_status_t crypto_key(apr_crypt /* note: openssl incorrectly returns non zero IV size values for ECB * algorithms, so work around this by ignoring the IV size. */ - if (APR_MODE_ECB != rec->mode) { + if (APR_MODE_ECB != rec->mode && key->cipher) { key->ivSize = EVP_CIPHER_iv_length(key->cipher); } @@ -507,6 +801,7 @@ static apr_status_t crypto_passphrase(ap const int iterations, const apr_crypto_t *f, apr_pool_t *p) { apr_crypto_key_t *key = *k; + apr_crypto_key_rec_t *rec; apr_status_t rv; if (!key) { @@ -518,6 +813,11 @@ static apr_status_t crypto_passphrase(ap key->f = f; key->provider = f->provider; + key->rec = rec = apr_pcalloc(p, sizeof(apr_crypto_key_rec_t)); + if (!key->rec) { + return APR_ENOMEM; + } + rec->ktype = APR_CRYPTO_KTYPE_PASSPHRASE; /* decide on what cipher mechanism we will be using */ rv = crypto_cipher_mechanism(key, type, mode, doPad, p); @@ -578,59 +878,73 @@ static apr_status_t crypto_block_encrypt block->f = key->f; block->pool = p; block->provider = key->provider; + block->key = key; apr_pool_cleanup_register(p, block, crypto_block_cleanup_helper, apr_pool_cleanup_null); - /* create a new context for encryption */ - if (!block->initialised) { - block->cipherCtx = EVP_CIPHER_CTX_new(); - block->initialised = 1; - } + switch (key->rec->ktype) { - /* generate an IV, if necessary */ - usedIv = NULL; - if (key->ivSize) { - if (iv == NULL) { - return APR_ENOIV; - } - if (*iv == NULL) { - usedIv = apr_pcalloc(p, key->ivSize); - if (!usedIv) { - return APR_ENOMEM; - } - apr_crypto_clear(p, usedIv, key->ivSize); - if (!((RAND_status() == 1) - && (RAND_bytes(usedIv, key->ivSize) == 1))) { + case APR_CRYPTO_KTYPE_PASSPHRASE: + case APR_CRYPTO_KTYPE_SECRET: { + + /* create a new context for encryption */ + if (!block->initialised) { + block->cipherCtx = EVP_CIPHER_CTX_new(); + block->initialised = 1; + } + + /* generate an IV, if necessary */ + usedIv = NULL; + if (key->ivSize) { + if (iv == NULL) { return APR_ENOIV; } - *iv = usedIv; - } - else { - usedIv = (unsigned char *) *iv; + if (*iv == NULL) { + usedIv = apr_pcalloc(p, key->ivSize); + if (!usedIv) { + return APR_ENOMEM; + } + apr_crypto_clear(p, usedIv, key->ivSize); + if (!((RAND_status() == 1) + && (RAND_bytes(usedIv, key->ivSize) == 1))) { + return APR_ENOIV; + } + *iv = usedIv; + } + else { + usedIv = (unsigned char *) *iv; + } } - } - /* set up our encryption context */ + /* set up our encryption context */ #if CRYPTO_OPENSSL_CONST_BUFFERS - if (!EVP_EncryptInit_ex(block->cipherCtx, key->cipher, config->engine, - key->key, usedIv)) { + if (!EVP_EncryptInit_ex(block->cipherCtx, key->cipher, config->engine, + key->key, usedIv)) { #else if (!EVP_EncryptInit_ex(block->cipherCtx, key->cipher, config->engine, (unsigned char *) key->key, (unsigned char *) usedIv)) { #endif - return APR_EINIT; - } + return APR_EINIT; + } - /* Clear up any read padding */ - if (!EVP_CIPHER_CTX_set_padding(block->cipherCtx, key->doPad)) { - return APR_EPADDING; - } + /* Clear up any read padding */ + if (!EVP_CIPHER_CTX_set_padding(block->cipherCtx, key->doPad)) { + return APR_EPADDING; + } + + if (blockSize) { + *blockSize = EVP_CIPHER_block_size(key->cipher); + } + + return APR_SUCCESS; - if (blockSize) { - *blockSize = EVP_CIPHER_block_size(key->cipher); } + default: { - return APR_SUCCESS; + return APR_EINVAL; + + } + } } @@ -654,39 +968,52 @@ static apr_status_t crypto_block_encrypt */ static apr_status_t crypto_block_encrypt(unsigned char **out, apr_size_t *outlen, const unsigned char *in, apr_size_t inlen, - apr_crypto_block_t *ctx) + apr_crypto_block_t *block) { - int outl = *outlen; - unsigned char *buffer; + switch (block->key->rec->ktype) { - /* are we after the maximum size of the out buffer? */ - if (!out) { - *outlen = inlen + EVP_MAX_BLOCK_LENGTH; - return APR_SUCCESS; - } + case APR_CRYPTO_KTYPE_PASSPHRASE: + case APR_CRYPTO_KTYPE_SECRET: { - /* must we allocate the output buffer from a pool? */ - if (!*out) { - buffer = apr_palloc(ctx->pool, inlen + EVP_MAX_BLOCK_LENGTH); - if (!buffer) { - return APR_ENOMEM; + int outl = *outlen; + unsigned char *buffer; + + /* are we after the maximum size of the out buffer? */ + if (!out) { + *outlen = inlen + EVP_MAX_BLOCK_LENGTH; + return APR_SUCCESS; + } + + /* must we allocate the output buffer from a pool? */ + if (!*out) { + buffer = apr_palloc(block->pool, inlen + EVP_MAX_BLOCK_LENGTH); + if (!buffer) { + return APR_ENOMEM; + } + apr_crypto_clear(block->pool, buffer, inlen + EVP_MAX_BLOCK_LENGTH); + *out = buffer; } - apr_crypto_clear(ctx->pool, buffer, inlen + EVP_MAX_BLOCK_LENGTH); - *out = buffer; - } #if CRYPT_OPENSSL_CONST_BUFFERS - if (!EVP_EncryptUpdate(ctx->cipherCtx, (*out), &outl, in, inlen)) { + if (!EVP_EncryptUpdate(block->cipherCtx, (*out), &outl, in, inlen)) { #else - if (!EVP_EncryptUpdate(ctx->cipherCtx, (*out), &outl, - (unsigned char *) in, inlen)) { + if (!EVP_EncryptUpdate(block->cipherCtx, (*out), &outl, + (unsigned char *) in, inlen)) { #endif - EVP_CIPHER_CTX_reset(ctx->cipherCtx); - return APR_ECRYPT; + crypto_block_cleanup(block); + return APR_ECRYPT; + } + *outlen = outl; + + return APR_SUCCESS; + } - *outlen = outl; + default: { - return APR_SUCCESS; + return APR_EINVAL; + + } + } } @@ -709,20 +1036,33 @@ static apr_status_t crypto_block_encrypt * @return APR_ENOTIMPL if not implemented. */ static apr_status_t crypto_block_encrypt_finish(unsigned char *out, - apr_size_t *outlen, apr_crypto_block_t *ctx) + apr_size_t *outlen, apr_crypto_block_t *block) { - apr_status_t rc = APR_SUCCESS; - int len = *outlen; + switch (block->key->rec->ktype) { + + case APR_CRYPTO_KTYPE_PASSPHRASE: + case APR_CRYPTO_KTYPE_SECRET: { + + apr_status_t rc = APR_SUCCESS; + int len = *outlen; + + if (EVP_EncryptFinal_ex(block->cipherCtx, out, &len) == 0) { + rc = APR_EPADDING; + } + else { + *outlen = len; + } + crypto_block_cleanup(block); + + return rc; - if (EVP_EncryptFinal_ex(ctx->cipherCtx, out, &len) == 0) { - rc = APR_EPADDING; - } - else { - *outlen = len; } - EVP_CIPHER_CTX_reset(ctx->cipherCtx); + default: { + + return APR_EINVAL; - return rc; + } + } } @@ -756,43 +1096,57 @@ static apr_status_t crypto_block_decrypt block->f = key->f; block->pool = p; block->provider = key->provider; + block->key = key; apr_pool_cleanup_register(p, block, crypto_block_cleanup_helper, apr_pool_cleanup_null); - /* create a new context for encryption */ - if (!block->initialised) { - block->cipherCtx = EVP_CIPHER_CTX_new(); - block->initialised = 1; - } + switch (key->rec->ktype) { - /* generate an IV, if necessary */ - if (key->ivSize) { - if (iv == NULL) { - return APR_ENOIV; + case APR_CRYPTO_KTYPE_PASSPHRASE: + case APR_CRYPTO_KTYPE_SECRET: { + + /* create a new context for encryption */ + if (!block->initialised) { + block->cipherCtx = EVP_CIPHER_CTX_new(); + block->initialised = 1; } - } - /* set up our encryption context */ + /* generate an IV, if necessary */ + if (key->ivSize) { + if (iv == NULL) { + return APR_ENOIV; + } + } + + /* set up our encryption context */ #if CRYPTO_OPENSSL_CONST_BUFFERS - if (!EVP_DecryptInit_ex(block->cipherCtx, key->cipher, config->engine, - key->key, iv)) { + if (!EVP_DecryptInit_ex(block->cipherCtx, key->cipher, config->engine, + key->key, iv)) { #else - if (!EVP_DecryptInit_ex(block->cipherCtx, key->cipher, config->engine, (unsigned char *) key->key, (unsigned char *) iv)) { + if (!EVP_DecryptInit_ex(block->cipherCtx, key->cipher, config->engine, (unsigned char *) key->key, (unsigned char *) iv)) { #endif - return APR_EINIT; - } + return APR_EINIT; + } - /* Clear up any read padding */ - if (!EVP_CIPHER_CTX_set_padding(block->cipherCtx, key->doPad)) { - return APR_EPADDING; - } + /* Clear up any read padding */ + if (!EVP_CIPHER_CTX_set_padding(block->cipherCtx, key->doPad)) { + return APR_EPADDING; + } + + if (blockSize) { + *blockSize = EVP_CIPHER_block_size(key->cipher); + } + + return APR_SUCCESS; - if (blockSize) { - *blockSize = EVP_CIPHER_block_size(key->cipher); } + default: { - return APR_SUCCESS; + return APR_EINVAL; + + } + } } @@ -816,39 +1170,53 @@ static apr_status_t crypto_block_decrypt */ static apr_status_t crypto_block_decrypt(unsigned char **out, apr_size_t *outlen, const unsigned char *in, apr_size_t inlen, - apr_crypto_block_t *ctx) + apr_crypto_block_t *block) { - int outl = *outlen; - unsigned char *buffer; + switch (block->key->rec->ktype) { - /* are we after the maximum size of the out buffer? */ - if (!out) { - *outlen = inlen + EVP_MAX_BLOCK_LENGTH; - return APR_SUCCESS; - } + case APR_CRYPTO_KTYPE_PASSPHRASE: + case APR_CRYPTO_KTYPE_SECRET: { - /* must we allocate the output buffer from a pool? */ - if (!(*out)) { - buffer = apr_palloc(ctx->pool, inlen + EVP_MAX_BLOCK_LENGTH); - if (!buffer) { - return APR_ENOMEM; + int outl = *outlen; + unsigned char *buffer; + + /* are we after the maximum size of the out buffer? */ + if (!out) { + *outlen = inlen + EVP_MAX_BLOCK_LENGTH; + return APR_SUCCESS; + } + + /* must we allocate the output buffer from a pool? */ + if (!(*out)) { + buffer = apr_palloc(block->pool, inlen + EVP_MAX_BLOCK_LENGTH); + if (!buffer) { + return APR_ENOMEM; + } + apr_crypto_clear(block->pool, buffer, inlen + EVP_MAX_BLOCK_LENGTH); + *out = buffer; } - apr_crypto_clear(ctx->pool, buffer, inlen + EVP_MAX_BLOCK_LENGTH); - *out = buffer; - } #if CRYPT_OPENSSL_CONST_BUFFERS - if (!EVP_DecryptUpdate(ctx->cipherCtx, *out, &outl, in, inlen)) { + if (!EVP_DecryptUpdate(block->cipherCtx, *out, &outl, in, inlen)) { #else - if (!EVP_DecryptUpdate(ctx->cipherCtx, *out, &outl, (unsigned char *) in, - inlen)) { + if (!EVP_DecryptUpdate(block->cipherCtx, *out, &outl, (unsigned char *) in, + inlen)) { #endif - EVP_CIPHER_CTX_reset(ctx->cipherCtx); - return APR_ECRYPT; + crypto_block_cleanup(block); + + return APR_ECRYPT; + } + *outlen = outl; + + return APR_SUCCESS; + } - *outlen = outl; + default: { - return APR_SUCCESS; + return APR_EINVAL; + + } + } } @@ -871,33 +1239,279 @@ static apr_status_t crypto_block_decrypt * @return APR_ENOTIMPL if not implemented. */ static apr_status_t crypto_block_decrypt_finish(unsigned char *out, - apr_size_t *outlen, apr_crypto_block_t *ctx) + apr_size_t *outlen, apr_crypto_block_t *block) { - apr_status_t rc = APR_SUCCESS; - int len = *outlen; + switch (block->key->rec->ktype) { + + case APR_CRYPTO_KTYPE_PASSPHRASE: + case APR_CRYPTO_KTYPE_SECRET: { + + apr_status_t rc = APR_SUCCESS; + int len = *outlen; + + if (EVP_DecryptFinal_ex(block->cipherCtx, out, &len) == 0) { + rc = APR_EPADDING; + } + else { + *outlen = len; + } + crypto_block_cleanup(block); + + return rc; + + } + default: { + + return APR_EINVAL; - if (EVP_DecryptFinal_ex(ctx->cipherCtx, out, &len) == 0) { - rc = APR_EPADDING; } - else { - *outlen = len; } - EVP_CIPHER_CTX_reset(ctx->cipherCtx); - return rc; +} + +static apr_status_t crypto_digest_init(apr_crypto_digest_t **d, + const apr_crypto_key_t *key, apr_crypto_digest_rec_t *rec, apr_pool_t *p) +{ + apr_crypto_config_t *config = key->f->config; + apr_crypto_digest_t *digest = *d; + if (!digest) { + *d = digest = apr_pcalloc(p, sizeof(apr_crypto_digest_t)); + } + if (!digest) { + return APR_ENOMEM; + } + digest->f = key->f; + digest->pool = p; + digest->provider = key->provider; + digest->key = key; + digest->rec = rec; + + /* create a new context for digest */ + if (!digest->initialised) { + digest->mdCtx = EVP_MD_CTX_new(); + digest->initialised = 1; + } + + apr_pool_cleanup_register(p, digest, crypto_digest_cleanup_helper, + apr_pool_cleanup_null); + + switch (key->rec->ktype) { + + case APR_CRYPTO_KTYPE_HASH: { + + if (1 + != EVP_DigestInit_ex(digest->mdCtx, key->hmac, + config->engine)) { + return APR_EINIT; + } + + break; + } + case APR_CRYPTO_KTYPE_HMAC: + case APR_CRYPTO_KTYPE_CMAC: { + if (1 + != EVP_DigestSignInit(digest->mdCtx, NULL, key->hmac, + config->engine, key->pkey)) { + return APR_EINIT; + } + break; + } + default: { + return APR_EINVAL; + } + } + + return APR_SUCCESS; + +} + +static apr_status_t crypto_digest_update(apr_crypto_digest_t *digest, + const unsigned char *in, apr_size_t inlen) +{ + switch (digest->key->rec->ktype) { + + case APR_CRYPTO_KTYPE_HASH: { + + if (1 != EVP_DigestUpdate(digest->mdCtx, in, inlen)) { + crypto_digest_cleanup(digest); + return APR_ECRYPT; + } + + return APR_SUCCESS; + + } + + case APR_CRYPTO_KTYPE_HMAC: + case APR_CRYPTO_KTYPE_CMAC: { + + if (1 != EVP_DigestSignUpdate(digest->mdCtx, in, inlen)) { + crypto_digest_cleanup(digest); + return APR_ECRYPT; + } + + return APR_SUCCESS; + + } + default: { + return APR_EINVAL; + } + } + +} + +static apr_status_t crypto_digest_final(apr_crypto_digest_t *digest) +{ + + switch (digest->key->rec->ktype) { + + case APR_CRYPTO_KTYPE_HASH: { + + apr_status_t status = APR_SUCCESS; + + unsigned int len = EVP_MD_CTX_size(digest->mdCtx); + + switch (digest->rec->dtype) { + case APR_CRYPTO_DTYPE_HASH: { + + /* must we allocate the output buffer from a pool? */ + if (!digest->rec->d.hash.s || digest->rec->d.hash.slen != len) { + digest->rec->d.hash.slen = len; + digest->rec->d.hash.s = apr_palloc(digest->pool, len); + if (!digest->rec->d.hash.s) { + return APR_ENOMEM; + } + apr_crypto_clear(digest->pool, digest->rec->d.hash.s, len); + } + + /* then, determine the signature */ + if (EVP_DigestFinal_ex(digest->mdCtx, digest->rec->d.hash.s, &len) + == 0) { + status = APR_ECRYPT; + } + + break; + } + default: + status = APR_ENODIGEST; + } + + crypto_digest_cleanup(digest); + + return status; + + } + + case APR_CRYPTO_KTYPE_HMAC: + case APR_CRYPTO_KTYPE_CMAC: { + + apr_status_t status = APR_SUCCESS; + + size_t len; + + /* first, determine the signature length */ + if (1 != EVP_DigestSignFinal(digest->mdCtx, NULL, &len)) { + status = APR_ECRYPT; + } else { + + switch (digest->rec->dtype) { + case APR_CRYPTO_DTYPE_SIGN: { + + /* must we allocate the output buffer from a pool? */ + if (!digest->rec->d.sign.s || digest->rec->d.sign.slen != len) { + digest->rec->d.sign.slen = len; + digest->rec->d.sign.s = apr_palloc(digest->pool, len); + if (!digest->rec->d.sign.s) { + return APR_ENOMEM; + } + apr_crypto_clear(digest->pool, digest->rec->d.sign.s, len); + } + + /* then, determine the signature */ + if (EVP_DigestSignFinal(digest->mdCtx, digest->rec->d.sign.s, + &len) == 0) { + status = APR_ECRYPT; + } + + break; + } + case APR_CRYPTO_DTYPE_VERIFY: { + + /* must we allocate the output buffer from a pool? */ + if (!digest->rec->d.verify.s + || digest->rec->d.verify.slen != len) { + digest->rec->d.verify.slen = len; + digest->rec->d.verify.s = apr_palloc(digest->pool, len); + if (!digest->rec->d.verify.s) { + return APR_ENOMEM; + } + apr_crypto_clear(digest->pool, digest->rec->d.verify.s, + len); + } + + /* then, determine the signature */ + if (EVP_DigestSignFinal(digest->mdCtx, digest->rec->d.verify.s, + &len) == 0) { + status = APR_ECRYPT; + } else if (digest->rec->d.verify.slen + == digest->rec->d.verify.vlen) { + status = + CRYPTO_memcmp(digest->rec->d.verify.s, + digest->rec->d.verify.v, + digest->rec->d.verify.slen) ? + APR_ENOVERIFY : APR_SUCCESS; + } else { + status = APR_ENOVERIFY; + } + + break; + } + default: + status = APR_ENODIGEST; + } + + } + + crypto_digest_cleanup(digest); + + return status; + + } + default: { + return APR_EINVAL; + } + } + +} + +static apr_status_t crypto_digest( + const apr_crypto_key_t *key, apr_crypto_digest_rec_t *rec, const unsigned char *in, + apr_size_t inlen, apr_pool_t *p) +{ + apr_crypto_digest_t *digest = NULL; + apr_status_t status = APR_SUCCESS; + + status = crypto_digest_init(&digest, key, rec, p); + if (APR_SUCCESS == status) { + status = crypto_digest_update(digest, in, inlen); + if (APR_SUCCESS == status) { + status = crypto_digest_final(digest); + } + } + return status; } /** * OpenSSL module. */ APR_MODULE_DECLARE_DATA const apr_crypto_driver_t apr_crypto_openssl_driver = { - "openssl", crypto_init, crypto_make, crypto_get_block_key_types, + "openssl", crypto_init, crypto_make, crypto_get_block_key_digests, crypto_get_block_key_types, crypto_get_block_key_modes, crypto_passphrase, crypto_block_encrypt_init, crypto_block_encrypt, crypto_block_encrypt_finish, crypto_block_decrypt_init, crypto_block_decrypt, crypto_block_decrypt_finish, - crypto_block_cleanup, crypto_cleanup, crypto_shutdown, crypto_error, + crypto_digest_init, crypto_digest_update, crypto_digest_final, crypto_digest, + crypto_block_cleanup, crypto_digest_cleanup, crypto_cleanup, crypto_shutdown, crypto_error, crypto_key }; Modified: apr/apr/trunk/include/apr_crypto.h URL: http://svn.apache.org/viewvc/apr/apr/trunk/include/apr_crypto.h?rev=1836439&r1=1836438&r2=1836439&view=diff ============================================================================== --- apr/apr/trunk/include/apr_crypto.h (original) +++ apr/apr/trunk/include/apr_crypto.h Sun Jul 22 13:11:32 2018 @@ -42,17 +42,31 @@ extern "C" { #ifndef APU_CRYPTO_RECOMMENDED_DRIVER #if APU_HAVE_COMMONCRYPTO +/** Recommended driver for this platform */ #define APU_CRYPTO_RECOMMENDED_DRIVER "commoncrypto" -#elif APU_HAVE_OPENSSL +#else +#if APU_HAVE_OPENSSL +/** Recommended driver for this platform */ #define APU_CRYPTO_RECOMMENDED_DRIVER "openssl" -#elif APU_HAVE_NSS +#else +#if APU_HAVE_NSS +/** Recommended driver for this platform */ #define APU_CRYPTO_RECOMMENDED_DRIVER "nss" -#elif APU_HAVE_MSCNG +#else +#if APU_HAVE_MSCNG +/** Recommended driver for this platform */ #define APU_CRYPTO_RECOMMENDED_DRIVER "mscng" -#elif APU_HAVE_MSCAPI +#else +#if APU_HAVE_MSCAPI +/** Recommended driver for this platform */ #define APU_CRYPTO_RECOMMENDED_DRIVER "mscapi" +#else +#endif +#endif +#endif +#endif +#endif #endif -#endif /* APU_CRYPTO_RECOMMENDED_DRIVER */ /** * Symmetric Key types understood by the library. @@ -95,6 +109,9 @@ extern "C" { * aligned data, use 3DES_192/CBC, AES_256/CBC or AES_256/ECB. */ +/** + * Types of ciphers. + */ typedef enum { APR_KEY_NONE, APR_KEY_3DES_192, /** 192 bit (3-Key) 3DES */ @@ -104,6 +121,9 @@ typedef enum /** 256 bit AES */ } apr_crypto_block_key_type_e; +/** + * Types of modes supported by the ciphers. + */ typedef enum { APR_MODE_NONE, /** An error condition */ @@ -112,56 +132,370 @@ typedef enum /** Cipher Block Chaining */ } apr_crypto_block_key_mode_e; -/* These are opaque structs. Instantiation is up to each backend */ +/** + * Types of digests supported by the apr_crypto_key() function. + */ +typedef enum +{ + APR_CRYPTO_DIGEST_NONE, /** An error condition */ + APR_CRYPTO_DIGEST_MD5, /** MD5 */ + APR_CRYPTO_DIGEST_SHA1, /** SHA1 */ + APR_CRYPTO_DIGEST_SHA224, /** SHA224 */ + APR_CRYPTO_DIGEST_SHA256, /** SHA256 */ + APR_CRYPTO_DIGEST_SHA384, /** SHA384 */ + APR_CRYPTO_DIGEST_SHA512, /** SHA512 */ +} apr_crypto_block_key_digest_e; + +/** + * Structure returned by the crypto_get_block_key_digests() function. + */ +typedef struct apr_crypto_block_key_digest_t { + /** The digest used with this crypto operation. */ + apr_crypto_block_key_digest_e type; + /** The digest size used with this digest operation */ + int digestsize; + /** The block size used with this digest operation */ + int blocksize; +} apr_crypto_block_key_digest_t; + +/** + * Structure representing a backend crypto driver. + * + * This structure is created with apr_crypto_get_driver(). + */ typedef struct apr_crypto_driver_t apr_crypto_driver_t; + +/** + * Structure to support a group of crypto operations. + * + * This structure is created with apr_crypto_make(). + */ typedef struct apr_crypto_t apr_crypto_t; + +/** + * Structure representing the configuration of the given backend + * crypto library. + */ typedef struct apr_crypto_config_t apr_crypto_config_t; + +/** + * Structure representing a key prepared for encryption, decryption, + * signing or verifying. + * + * This structure is created using the apr_crypto_key() function. + */ typedef struct apr_crypto_key_t apr_crypto_key_t; + +/** + * Structure representing a block context for encryption, decryption, + * signing or verifying. + * + * This structure is created using the apr_crypto_block_encrypt_init() + * and apr_crypto_block_decrypt_init() functions. + */ typedef struct apr_crypto_block_t apr_crypto_block_t; +/** + * Structure representing a digest context for signing or verifying. + * + * This structure is created using the apr_crypto_digest_init() function. + */ +typedef struct apr_crypto_digest_t apr_crypto_digest_t; + +/** + * Structure returned by the crypto_get_block_key_types() function. + */ typedef struct apr_crypto_block_key_type_t { + /** The cipher used with this crypto operation. */ apr_crypto_block_key_type_e type; + /** The key size used with this crypto operation */ int keysize; + /** The block size used with this crypto operation */ int blocksize; + /** The initialisation vector size used with this crypto operation */ int ivsize; } apr_crypto_block_key_type_t; +/** + * Structure returned by the crypto_get_block_key_modes() function. + */ typedef struct apr_crypto_block_key_mode_t { + /** The mode used with this crypto operation. */ apr_crypto_block_key_mode_e mode; } apr_crypto_block_key_mode_t; +/** + * Structure describing a key to be derived from PBKDF2 to be passed by the + * apr_crypto_key() function. + * + * Derived keys are used for encryption and decryption. + * + * Implementations must use apr_crypto_key_rec_make() to allocate + * this structure. + */ typedef struct apr_crypto_passphrase_t { + /** The passphrase used by the key generation algorithm */ const char *pass; + /** The length of the passphrase */ apr_size_t passLen; + /** The salt used by the key derivation algorithm */ const unsigned char * salt; + /** The length of the salt. */ apr_size_t saltLen; + /** The number of iterations used by the key derivation function */ int iterations; } apr_crypto_passphrase_t; +/** + * Structure describing a raw key to be passed by the + * apr_crypto_key() function. + * + * Raw keys are used for encryption and decryption, and must match + * the correct sizes for each cipher. + * + * Implementations must use apr_crypto_key_rec_make() to allocate + * this structure. + */ typedef struct apr_crypto_secret_t { + /** The raw secret key used for encrypt / decrypt. Must be + * the same size as the block size of the cipher being used. + */ const unsigned char *secret; + /** The length of the secret key. */ apr_size_t secretLen; } apr_crypto_secret_t; +/** + * Structure describing a simple digest hash to be generated by the + * apr_crypto_key() function. + * + * Implementations must use apr_crypto_key_rec_make() to allocate + * this structure. + */ +typedef struct apr_crypto_key_hash_t { + /** The digest used for the HMAC. */ + apr_crypto_block_key_digest_e digest; +} apr_crypto_key_hash_t; + +/** + * Structure describing a HMAC key and digest to be generated by the + * apr_crypto_key() function. + * + * Implementations must use apr_crypto_key_rec_make() to allocate + * this structure. + */ +typedef struct apr_crypto_key_hmac_t { + /** The secret used for the HMAC */ + const unsigned char *secret; + /** The length of the secret used for the HMAC */ + apr_size_t secretLen; + /** The digest used for the HMAC. */ + apr_crypto_block_key_digest_e digest; +} apr_crypto_key_hmac_t; + +/** + * Structure describing a CMAC key and digest to be generated by the + * apr_crypto_key() function. + * + * Implementations must use apr_crypto_key_rec_make() to allocate + * this structure. + */ +typedef struct apr_crypto_key_cmac_t { + /** The secret used for the CMAC */ + const unsigned char *secret; + /** The length of the secret used for the CMAC */ + apr_size_t secretLen; + /** The digest used for the CMAC. */ + apr_crypto_block_key_digest_e digest; +} apr_crypto_key_cmac_t; + +/** + * Structure used to create a hashed digest. + * + * Implementations must use apr_crypto_digest_rec_make() to allocate + * this structure. + */ +typedef struct apr_crypto_digest_hash_t { + /** The message digest */ + unsigned char *s; + /** The length of the message digest */ + apr_size_t slen; + /** The digest algorithm */ + apr_crypto_block_key_digest_e digest; +} apr_crypto_digest_hash_t; + +/** + * Structure used to create a signature. + * + * Implementations must use apr_crypto_digest_rec_make() to allocate + * this structure. + */ +typedef struct apr_crypto_digest_sign_t { + /** The message digest */ + unsigned char *s; + /** The length of the message digest */ + apr_size_t slen; + /** The digest algorithm */ + apr_crypto_block_key_digest_e digest; +} apr_crypto_digest_sign_t; + +/** + * Structure used to create a signature for verification. + * + * Implementations must use apr_crypto_digest_rec_make() to allocate + * this structure. + */ +typedef struct apr_crypto_digest_verify_t { + /** The message digest generated */ + unsigned char *s; + /** The length of the message digest */ + apr_size_t slen; + /** The message digest to be verified against */ + const unsigned char *v; + /** The length of the message digest */ + apr_size_t vlen; + /** The digest algorithm */ + apr_crypto_block_key_digest_e digest; +} apr_crypto_digest_verify_t; + +/** + * Types of keys supported by the apr_crypto_key() function and the + * apr_crypto_key_rec_t structure. + */ typedef enum { - /** Key is derived from a passphrase */ + /** + * Key is derived from a passphrase. + * + * Used with the encrypt / decrypt functions. + */ APR_CRYPTO_KTYPE_PASSPHRASE = 1, - /** Key is derived from a raw key */ - APR_CRYPTO_KTYPE_SECRET = 2, + /** + * Key is derived from a raw key. + * + * Used with the encrypt / decrypt functions. + */ + APR_CRYPTO_KTYPE_SECRET = 2, + /** + * Simple digest, no key. + * + * Used with the digest functions. + */ + APR_CRYPTO_KTYPE_HASH = 3, + /** + * HMAC Key is derived from a raw key. + * + * Used with the digest functions. + */ + APR_CRYPTO_KTYPE_HMAC = 4, + /** + * CMAC Key is derived from a raw key. + * + * Used with the digest functions. + */ + APR_CRYPTO_KTYPE_CMAC = 5, } apr_crypto_key_type; +/** + * Types of digests supported by the apr_crypto_digest() functions and the + * apr_crypto_digest_rec_t structure. + */ +typedef enum { + /** + * Simple digest operation. + * + * Use with apr_crypto_key_rec_t APR_CRYPTO_KTYPE_HASH. + */ + APR_CRYPTO_DTYPE_HASH = 1, + /** + * Sign operation. + * + * Use with apr_crypto_key_rec_t APR_CRYPTO_KTYPE_HMAC or + * APR_CRYPTO_KTYPE_CMAC. + */ + APR_CRYPTO_DTYPE_SIGN = 2, + /** + * Verify operation. + * + * Use with apr_crypto_key_rec_t APR_CRYPTO_KTYPE_HMAC or + * APR_CRYPTO_KTYPE_CMAC. + */ + APR_CRYPTO_DTYPE_VERIFY = 3, +} apr_crypto_digest_type_e; + +/** + * Structure describing a key to be generated by the + * apr_crypto_key() function. + * + * Implementations must use apr_crypto_key_rec_make() to allocate + * this structure. + */ typedef struct apr_crypto_key_rec_t { + /** The type of the key. */ apr_crypto_key_type ktype; + /** The cipher used with this crypto operation. */ apr_crypto_block_key_type_e type; + /** The mode used with this crypto operation. */ apr_crypto_block_key_mode_e mode; + /** Non zero if padding should be used with this crypto operation. */ int pad; + /** Details of each key, based on the key type. */ union { + /** + * This key is generated using a PBE algorithm from a given + * passphrase, and can be used to encrypt / decrypt. + * + * Key type: APR_CRYPTO_KTYPE_PASSPHRASE + */ apr_crypto_passphrase_t passphrase; + /** + * This is a raw key matching the block size of the given + * cipher, and can be used to encrypt / decrypt. + * + * Key type: APR_CRYPTO_KTYPE_SECRET + */ apr_crypto_secret_t secret; + /** + * This represents a simple digest with no key. + * + * Key type: APR_CRYPTO_KTYPE_HASH + */ + apr_crypto_key_hash_t hash; + /** + * This is a key of arbitrary length used with an HMAC. + * + * Key type: APR_CRYPTO_KTYPE_HMAC + */ + apr_crypto_key_hmac_t hmac; + /** + * This is a key of arbitrary length used with a CMAC. + * + * Key type: APR_CRYPTO_KTYPE_CMAC + */ + apr_crypto_key_cmac_t cmac; } k; } apr_crypto_key_rec_t; /** + * Structure describing a digest to be hashed, signed or verified. + * + * This structure is passed to the apr_crypto_digest_init() and + * apr_crypto_digest() functions. + * + * Implementations must use apr_crypto_digest_rec_make() to allocate + * this structure. + */ +typedef struct apr_crypto_digest_rec_t { + /** The type of the digest record. */ + apr_crypto_digest_type_e dtype; + /** Details of each digest, based on the digest type. */ + union { + apr_crypto_digest_hash_t hash; + apr_crypto_digest_sign_t sign; + apr_crypto_digest_verify_t verify; + } d; +} apr_crypto_digest_rec_t; + +/** * @brief Perform once-only initialisation. Call once only. * * @param pool - pool to register any shutdown cleanups, etc @@ -229,8 +563,9 @@ APR_DECLARE(int) apr_crypto_equals(const * @remarks OpenSSL: currently no params are supported. */ APR_DECLARE(apr_status_t) apr_crypto_get_driver( - const apr_crypto_driver_t **driver, const char *name, - const char *params, const apu_err_t **result, apr_pool_t *pool); + const apr_crypto_driver_t **driver, + const char *name, const char *params, const apu_err_t **result, + apr_pool_t *pool); /** * @brief Return the name of the driver. @@ -266,9 +601,21 @@ APR_DECLARE(apr_status_t) apr_crypto_err * @remarks OpenSSL: the params can have "engine" as a key, followed by an equal * sign and a value. */ -APR_DECLARE(apr_status_t) - apr_crypto_make(apr_crypto_t **f, const apr_crypto_driver_t *driver, - const char *params, apr_pool_t *pool); +APR_DECLARE(apr_status_t) apr_crypto_make(apr_crypto_t **f, + const apr_crypto_driver_t *driver, const char *params, + apr_pool_t *pool); + +/** + * @brief Get a hash table of key digests, keyed by the name of the digest against + * a pointer to apr_crypto_block_key_digest_t, which in turn begins with an + * integer. + * + * @param digests - hashtable of key digests keyed to constants. + * @param f - encryption context + * @return APR_SUCCESS for success + */ +APR_DECLARE(apr_status_t) apr_crypto_get_block_key_digests(apr_hash_t **digests, + const apr_crypto_t *f); /** * @brief Get a hash table of key types, keyed by the name of the type against @@ -295,20 +642,42 @@ APR_DECLARE(apr_status_t) apr_crypto_get const apr_crypto_t *f); /** + * @brief Create a key record to be passed to apr_crypto_key(). + * @param ktype The apr_crypto_key_type to use. + * @param p The pool to use. + * @return Returns a blank structure of the correct size. + */ +APR_DECLARE(apr_crypto_key_rec_t *) apr_crypto_key_rec_make( + apr_crypto_key_type ktype, apr_pool_t *p); + +/** + * @brief Create a digest record to be passed to apr_crypto_digest_init(). + * @param dtype The type of digest record to create. + * @param p The pool to use. + * @return Returns a blank structure of the correct size. + */ +APR_DECLARE(apr_crypto_digest_rec_t *) apr_crypto_digest_rec_make( + apr_crypto_digest_type_e dtype, apr_pool_t *p); + +/** * @brief Create a key from the provided secret or passphrase. The key is cleaned - * up when the context is cleaned, and may be reused with multiple encryption - * or decryption operations. + * up when the context is cleaned, and may be reused with multiple + * encryption, decryption, signing or verifying operations. The choice of + * key type much match the intended operation. * @note If *key is NULL, a apr_crypto_key_t will be created from a pool. If * *key is not NULL, *key must point at a previously created structure. * @param key The key returned, see note. * @param rec The key record, from which the key will be derived. * @param f The context to use. * @param p The pool to use. - * @return Returns APR_ENOKEY if the pass phrase is missing or empty, or if a backend - * error occurred while generating the key. APR_ENOCIPHER if the type or mode - * is not supported by the particular backend. APR_EKEYTYPE if the key type is - * not known. APR_EPADDING if padding was requested but is not supported. - * APR_ENOTIMPL if not implemented. + * @return APR_ENOKEY if the pass phrase is missing or empty, or if a backend + * error occurred while generating the key. + * @return APR_ENOCIPHER if the type or mode + * is not supported by the particular backend. + * @return APR_EKEYTYPE if the key type is + * not known. + * @return APR_EPADDING if padding was requested but is not supported. + * @return APR_ENOTIMPL if not implemented. */ APR_DECLARE(apr_status_t) apr_crypto_key(apr_crypto_key_t **key, const apr_crypto_key_rec_t *rec, const apr_crypto_t *f, apr_pool_t *p); @@ -335,11 +704,14 @@ APR_DECLARE(apr_status_t) apr_crypto_key * @param iterations Number of iterations to use in algorithm * @param f The context to use. * @param p The pool to use. - * @return Returns APR_ENOKEY if the pass phrase is missing or empty, or if a backend - * error occurred while generating the key. APR_ENOCIPHER if the type or mode - * is not supported by the particular backend. APR_EKEYTYPE if the key type is - * not known. APR_EPADDING if padding was requested but is not supported. - * APR_ENOTIMPL if not implemented. + * @return APR_ENOKEY if the pass phrase is missing or empty, or if a backend + * error occurred while generating the key. + * @return APR_ENOCIPHER if the type or mode + * is not supported by the particular backend. + * @return APR_EKEYTYPE if the key type is + * not known. + * @return APR_EPADDING if padding was requested but is not supported. + * @return APR_ENOTIMPL if not implemented. * @deprecated Replaced by apr_crypto_key(). */ APR_DECLARE(apr_status_t) apr_crypto_passphrase(apr_crypto_key_t **key, @@ -361,9 +733,10 @@ APR_DECLARE(apr_status_t) apr_crypto_pas * @param key The key structure to use. * @param blockSize The block size of the cipher. * @param p The pool to use. - * @return Returns APR_ENOIV if an initialisation vector is required but not specified. - * Returns APR_EINIT if the backend failed to initialise the context. Returns - * APR_ENOTIMPL if not implemented. + * @return APR_ENOIV if an initialisation vector is required but not specified. + * @return APR_EINIT if the backend failed to initialise the context. + * @return APR_ENOTIMPL if not implemented. + * @return APR_EINVAL if the key type does not support the given operation. */ APR_DECLARE(apr_status_t) apr_crypto_block_encrypt_init( apr_crypto_block_t **ctx, const unsigned char **iv, @@ -384,8 +757,9 @@ APR_DECLARE(apr_status_t) apr_crypto_blo * @param in Address of the buffer to read. * @param inlen Length of the buffer to read. * @param ctx The block context to use. - * @return APR_ECRYPT if an error occurred. Returns APR_ENOTIMPL if - * not implemented. + * @return APR_ECRYPT if an error occurred. + * @return APR_ENOTIMPL if not implemented. + * @return APR_EINVAL if the key type does not support the given operation. */ APR_DECLARE(apr_status_t) apr_crypto_block_encrypt(unsigned char **out, apr_size_t *outlen, const unsigned char *in, apr_size_t inlen, @@ -401,13 +775,14 @@ APR_DECLARE(apr_status_t) apr_crypto_blo * is cleaned and can be reused by apr_crypto_block_encrypt_init(). * @param out Address of a buffer to which data will be written. This * buffer must already exist, and is usually the same - * buffer used by apr_evp_crypt(). See note. + * buffer used by apr_crypto_block_encrypt(). See note. * @param outlen Length of the output will be written here. * @param ctx The block context to use. * @return APR_ECRYPT if an error occurred. * @return APR_EPADDING if padding was enabled and the block was incorrectly * formatted. * @return APR_ENOTIMPL if not implemented. + * @return APR_EINVAL if the key type does not support the given operation. */ APR_DECLARE(apr_status_t) apr_crypto_block_encrypt_finish(unsigned char *out, apr_size_t *outlen, apr_crypto_block_t *ctx); @@ -421,9 +796,10 @@ APR_DECLARE(apr_status_t) apr_crypto_blo * @param iv Optional initialisation vector. * @param key The key structure to use. * @param p The pool to use. - * @return Returns APR_ENOIV if an initialisation vector is required but not specified. - * Returns APR_EINIT if the backend failed to initialise the context. Returns - * APR_ENOTIMPL if not implemented. + * @return APR_ENOIV if an initialisation vector is required but not specified. + * @return APR_EINIT if the backend failed to initialise the context. + * @return APR_ENOTIMPL if not implemented. + * @return APR_EINVAL if the key type does not support the given operation. */ APR_DECLARE(apr_status_t) apr_crypto_block_decrypt_init( apr_crypto_block_t **ctx, apr_size_t *blockSize, @@ -444,8 +820,9 @@ APR_DECLARE(apr_status_t) apr_crypto_blo * @param in Address of the buffer to read. * @param inlen Length of the buffer to read. * @param ctx The block context to use. - * @return APR_ECRYPT if an error occurred. Returns APR_ENOTIMPL if - * not implemented. + * @return APR_ECRYPT if an error occurred. + * @return APR_ENOTIMPL if not implemented. + * @return APR_EINVAL if the key type does not support the given operation. */ APR_DECLARE(apr_status_t) apr_crypto_block_decrypt(unsigned char **out, apr_size_t *outlen, const unsigned char *in, apr_size_t inlen, @@ -461,13 +838,14 @@ APR_DECLARE(apr_status_t) apr_crypto_blo * is cleaned and can be reused by apr_crypto_block_decrypt_init(). * @param out Address of a buffer to which data will be written. This * buffer must already exist, and is usually the same - * buffer used by apr_evp_crypt(). See note. + * buffer used by apr_crypto_block_decrypt(). See note. * @param outlen Length of the output will be written here. * @param ctx The block context to use. * @return APR_ECRYPT if an error occurred. * @return APR_EPADDING if padding was enabled and the block was incorrectly * formatted. * @return APR_ENOTIMPL if not implemented. + * @return APR_EINVAL if the key type does not support the given operation. */ APR_DECLARE(apr_status_t) apr_crypto_block_decrypt_finish(unsigned char *out, apr_size_t *outlen, apr_crypto_block_t *ctx); @@ -481,6 +859,103 @@ APR_DECLARE(apr_status_t) apr_crypto_blo APR_DECLARE(apr_status_t) apr_crypto_block_cleanup(apr_crypto_block_t *ctx); /** + * @brief Initialise a context for hashing, signing or verifying arbitrary + * data. + * + * This function supports: + * - Simple hashing (MD5, SHA1, SHA224, SHA256, SHA384, SHA512). + * - HMAC (with a secret key) + * - CMAC (with a secret key) + * + * Details of the key and the type of digest to be performed are + * passed in the constant apr_crypto_key_t structure, which can be + * reused by many calls to apr_crypto_digest_init(). + * + * Details of this particular operation are read from and written to + * the apr_crypto_digest_rec_t structure, which is expected to + * contain the message digest to be verified, as well as message + * digest generated during the hashing or signing process. This + * structure will be modified by each digest operation, and cannot be + * shared. + * @note If *d is NULL, a apr_crypto_digest_t will be created from a pool. If + * *d is not NULL, *d must point at a previously created structure. + * @param d The digest context returned, see note. + * @param key The key structure to use. + * @param rec The digest record indicating whether we want to sign or verify. + * This record contains digest we want to verify against, as well as + * the signature we have generated. + * @param p The pool to use. + * @return APR_SUCCESS if successful. + * @return APR_ENOIV if an initialisation vector is required but not specified. + * @return APR_EINIT if the backend failed to initialise the context. + * @return APR_ENOTIMPL if not implemented. + * @return APR_EINVAL if the key type does not support the given operation. + */ +APR_DECLARE(apr_status_t) apr_crypto_digest_init(apr_crypto_digest_t **d, + const apr_crypto_key_t *key, apr_crypto_digest_rec_t *rec, apr_pool_t *p); + +/** + * @brief Update the digest with data provided by in. + * @param digest The block context to use. + * @param in Address of the buffer to digest. + * @param inlen Length of the buffer to digest. + * @return APR_SUCCESS if successful. + * @return APR_ECRYPT if an error occurred. + * @return APR_ENOTIMPL if not implemented. + * @return APR_EINVAL if the key type does not support the given operation. + */ +APR_DECLARE(apr_status_t) apr_crypto_digest_update(apr_crypto_digest_t *digest, + const unsigned char *in, apr_size_t inlen); + +/** + * @brief Finalise the digest and write the result. + * + * The result is written to the apr_crypto_digest_rec_t structure + * passed into apr_crypto_digest_init(). + * + * If verification is requested, this function will return the + * result of the verification. + * @note After this call, the context is cleaned and can be reused by + * apr_crypto_digest_init(). + * @param digest The digest context to use. + * @return APR_SUCCESS if hash, signing or verification was successful. + * @return APR_ENOVERIFY if the verification failed. + * @return APR_ECRYPT if an error occurred. + * @return APR_EPADDING if padding was enabled and the block was incorrectly + * formatted. + * @return APR_ENOTIMPL if not implemented. + * @return APR_EINVAL if the key type does not support the given operation. + */ +APR_DECLARE(apr_status_t) apr_crypto_digest_final(apr_crypto_digest_t *digest); + +/** + * @brief One shot digest on a single memory buffer. + * @param key The key structure to use. + * @param rec The digest record indicating whether we want to sign or verify. + * This record contains digest we want to verify against, as well as + * the signature we have generated. This record will contain the digest + * calculated. + * @param in Address of the buffer to digest. + * @param inlen Length of the buffer to digest. + * @param p The pool to use. + * @return APR_ENOIV if an initialisation vector is required but not specified. + * @return APR_EINIT if the backend failed to initialise the context. + * @return APR_ENOTIMPL if not implemented. + * @return APR_EINVAL if the key type does not support the given operation. + */ +APR_DECLARE(apr_status_t) apr_crypto_digest(const apr_crypto_key_t *key, + apr_crypto_digest_rec_t *rec, const unsigned char *in, apr_size_t inlen, + apr_pool_t *p); + +/** + * @brief Clean digest context. + * @note After cleanup, a digest context is free to be reused if necessary. + * @param ctx The digest context to use. + * @return Returns APR_ENOTIMPL if not supported. + */ +APR_DECLARE(apr_status_t) apr_crypto_digest_cleanup(apr_crypto_digest_t *ctx); + +/** * @brief Clean encryption / decryption context. * @note After cleanup, a context is free to be reused if necessary. * @param f The context to use. @@ -494,9 +969,8 @@ APR_DECLARE(apr_status_t) apr_crypto_cle * @param driver - driver to use * @return Returns APR_ENOTIMPL if not supported. */ -APR_DECLARE(apr_status_t) - apr_crypto_shutdown(const apr_crypto_driver_t *driver); - +APR_DECLARE(apr_status_t) apr_crypto_shutdown( + const apr_crypto_driver_t *driver); #if APU_HAVE_CRYPTO_PRNG Modified: apr/apr/trunk/include/apu_errno.h URL: http://svn.apache.org/viewvc/apr/apr/trunk/include/apu_errno.h?rev=1836439&r1=1836438&r2=1836439&view=diff ============================================================================== --- apr/apr/trunk/include/apu_errno.h (original) +++ apr/apr/trunk/include/apu_errno.h Sun Jul 22 13:11:32 2018 @@ -51,6 +51,7 @@ extern "C" { * APR_ENOENGINE The engine provided was not recognised * APR_EINITENGINE The engine could not be initialised * APR_EREINIT Underlying crypto has already been initialised + * APR_ENOVERIFY The signature verification failed * * *
@@ -83,6 +84,8 @@ extern "C" {
 #define APR_EINITENGINE      (APR_UTIL_START_STATUS + 11)
 /** @see APR_STATUS_IS_EREINIT */
 #define APR_EREINIT          (APR_UTIL_START_STATUS + 12)
+/** @see APR_STATUS_IS_ENOVERIFY */
+#define APR_ENOVERIFY        (APR_UTIL_START_STATUS + 13)
 /** @} */
 
 /**
@@ -151,6 +154,10 @@ extern "C" {
  * Crypto has already been initialised
  */
 #define APR_STATUS_IS_EREINIT(s)        ((s) == APR_EREINIT)
+/**
+ * The signature verification failed
+ */
+#define APR_STATUS_IS_ENOVERIFY(s)        ((s) == APR_ENOVERIFY)
 /** @} */
 
 /**

Modified: apr/apr/trunk/include/private/apr_crypto_internal.h
URL: http://svn.apache.org/viewvc/apr/apr/trunk/include/private/apr_crypto_internal.h?rev=1836439&r1=1836438&r2=1836439&view=diff
==============================================================================
--- apr/apr/trunk/include/private/apr_crypto_internal.h (original)
+++ apr/apr/trunk/include/private/apr_crypto_internal.h Sun Jul 22 13:11:32 2018
@@ -58,6 +58,17 @@ struct apr_crypto_driver_t {
             const char *params, apr_pool_t *pool);
 
     /**
+     * @brief Get a hash table of key digests, keyed by the name of the digest against
+     * a pointer to apr_crypto_block_key_digest_t.
+     *
+     * @param digests - hashtable of key digests keyed to constants.
+     * @param f - encryption context
+     * @return APR_SUCCESS for success
+     */
+    apr_status_t (*get_block_key_digests)(apr_hash_t **types,
+            const apr_crypto_t *f);
+
+    /**
      * @brief Get a hash table of key types, keyed by the name of the type against
      * a pointer to apr_crypto_block_key_type_t.
      *
@@ -237,6 +248,64 @@ struct apr_crypto_driver_t {
             apr_size_t *outlen, apr_crypto_block_t *ctx);
 
     /**
+     * @brief Initialise a context for signing or verifying arbitrary data using the
+     *        given key.
+     * @note If *d is NULL, a apr_crypto_digest_t will be created from a pool. If
+     *       *d is not NULL, *d must point at a previously created structure.
+     * @param d The digest context returned, see note.
+     * @param key The key structure to use.
+     * @param rec The digest record.
+     * @param p The pool to use.
+     * @return APR_ENOIV if an initialisation vector is required but not specified.
+     * @return APR_EINIT if the backend failed to initialise the context.
+     * @return APR_ENOTIMPL if not implemented.
+     * @return APR_NOKEY if the key type does not support the given operation.
+     */
+    apr_status_t (*digest_init)(apr_crypto_digest_t **d,
+            const apr_crypto_key_t *key, apr_crypto_digest_rec_t *rec, apr_pool_t *p);
+
+    /**
+     * @brief Update the digest with data provided by in.
+     * @param in Address of the buffer to read.
+     * @param inlen Length of the buffer to read.
+     * @param digest The digest context to use.
+     * @return APR_ECRYPT if an error occurred.
+     * @return APR_ENOTIMPL if not implemented.
+     * @return APR_NOKEY if the key type does not support the given operation.
+     */
+    apr_status_t (*digest_update)(apr_crypto_digest_t *digest,
+            const unsigned char *in, apr_size_t inlen);
+
+    /**
+     * @brief Finalise the digest and write the result.
+     * @note After this call, the context is cleaned and can be reused by
+     *   apr_crypto_digest_init().
+     * @param digest The digest context to use.
+     * @return APR_ECRYPT if an error occurred.
+     * @return APR_EPADDING if padding was enabled and the block was incorrectly
+     *         formatted.
+     * @return APR_ENOTIMPL if not implemented.
+     * @return APR_NOKEY if the key type does not support the given operation.
+     */
+    apr_status_t (*digest_final)(apr_crypto_digest_t *digest);
+
+    /**
+     * @brief One shot digest on a single memory buffer.
+     * @param key The key structure to use.
+     * @param rec The digest record.
+     * @param in Address of the buffer to digest.
+     * @param inlen Length of the buffer to digest.
+     * @param p The pool to use.
+     * @return APR_ENOIV if an initialisation vector is required but not specified.
+     * @return APR_EINIT if the backend failed to initialise the context.
+     * @return APR_ENOTIMPL if not implemented.
+     * @return APR_NOKEY if the key type does not support the given operation.
+     */
+    apr_status_t (*digest)(const apr_crypto_key_t *key,
+            apr_crypto_digest_rec_t *rec, const unsigned char *in,
+            apr_size_t inlen, apr_pool_t *p);
+
+    /**
      * @brief Clean encryption / decryption context.
      * @note After cleanup, a context is free to be reused if necessary.
      * @param ctx The block context to use.
@@ -245,6 +314,14 @@ struct apr_crypto_driver_t {
     apr_status_t (*block_cleanup)(apr_crypto_block_t *ctx);
 
     /**
+     * @brief Clean sign / verify context.
+     * @note After cleanup, a context is free to be reused if necessary.
+     * @param ctx The digest context to use.
+     * @return Returns APR_ENOTIMPL if not supported.
+     */
+    apr_status_t (*digest_cleanup)(apr_crypto_digest_t *ctx);
+
+    /**
      * @brief Clean encryption / decryption context.
      * @note After cleanup, a context is free to be reused if necessary.
      * @param f The context to use.