You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@apr.apache.org by mi...@apache.org on 2018/07/22 13:11:32 UTC

svn commit: r1836439 [2/3] - in /apr/apr/trunk: ./ crypto/ include/ include/private/ test/

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
  * </PRE>
  *
  * <PRE>
@@ -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.



Re: svn commit: r1836439 [2/3] - in /apr/apr/trunk: ./ crypto/ include/ include/private/ test/

Posted by Graham Leggett <mi...@sharp.fm>.
On 23 Jul 2018, at 01:26, Yann Ylavic <yl...@gmail.com> wrote:

> On Sun, Jul 22, 2018 at 3:11 PM,  <mi...@apache.org> wrote:
>> --- apr/apr/trunk/crypto/apr_crypto_openssl.c (original)
>> +++ apr/apr/trunk/crypto/apr_crypto_openssl.c Sun Jul 22 13:11:32 2018
>> 
>> @@ -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;
>> +}
> 
> So you reverted this...
> 
>> +
>> +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;
>> +}
>> -    return apr_crypto_lib_init("openssl", params, result, pool);
> 
> ... and this (including for the other libs), because?

Because it was an accident. I missed this one when merging.

Let me take a look at this tomorrow.

> The goal was to allow the initialization of the crypto libs
> independently from DSOs (openssl, for instance, does not play very
> well there).
> 
> In httpd there is (at least) APR, the httpd core, mod_ssl and mod_md
> that can all use the crypto library, how is each one supposed to
> initialize it? I thought it was nice for APR to provide a single
> initializer, once for all, with the lifetime of the given pool (as
> usual)…

I've raised this issue before, but there was little interest in solving it - glad to see this has got some traction.

I believe libraries like NSS are reference counted and initialise themselves sensibly. Not sure about the behaviour of openssl, however the openssl people should be able to explain what people should be doing.

Regards,
Graham
—


Re: svn commit: r1836439 [2/3] - in /apr/apr/trunk: ./ crypto/ include/ include/private/ test/

Posted by Yann Ylavic <yl...@gmail.com>.
On Sun, Jul 22, 2018 at 3:11 PM,  <mi...@apache.org> wrote:
> --- apr/apr/trunk/crypto/apr_crypto_openssl.c (original)
> +++ apr/apr/trunk/crypto/apr_crypto_openssl.c Sun Jul 22 13:11:32 2018
>
> @@ -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;
> +}

So you reverted this...

> +
> +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;
> +}
> -    return apr_crypto_lib_init("openssl", params, result, pool);

... and this (including for the other libs), because?

The goal was to allow the initialization of the crypto libs
independently from DSOs (openssl, for instance, does not play very
well there).

In httpd there is (at least) APR, the httpd core, mod_ssl and mod_md
that can all use the crypto library, how is each one supposed to
initialize it? I thought it was nice for APR to provide a single
initializer, once for all, with the lifetime of the given pool (as
usual)...


Regards,
Yann.