apr-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From minf...@apache.org
Subject svn commit: r1836439 [2/3] - in /apr/apr/trunk: ./ crypto/ include/ include/private/ test/
Date Sun, 22 Jul 2018 13:11:32 GMT
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.



Mime
View raw message