summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorminfrin <minfrin@13f79535-47bb-0310-9956-ffa450edef68>2018-07-22 13:11:32 +0000
committerminfrin <minfrin@13f79535-47bb-0310-9956-ffa450edef68>2018-07-22 13:11:32 +0000
commit354661950b5d0e706d7999f6010e7bfe7179dd9a (patch)
treeaefd75f4281d7deaea6d25e66b18f63f8bc256ea
parent31e0a7191079906aa37a4142b1fd98014333fc47 (diff)
downloadlibapr-354661950b5d0e706d7999f6010e7bfe7179dd9a.tar.gz
apr_crypto: Add support for digest functions, with hashing, signing
and verifying. git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@1836439 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--CHANGES3
-rw-r--r--crypto/apr_crypto.c74
-rw-r--r--crypto/apr_crypto_commoncrypto.c969
-rw-r--r--crypto/apr_crypto_nss.c1005
-rw-r--r--crypto/apr_crypto_openssl.c904
-rw-r--r--include/apr_crypto.h556
-rw-r--r--include/apu_errno.h7
-rw-r--r--include/private/apr_crypto_internal.h77
-rw-r--r--test/testcrypto.c948
9 files changed, 3981 insertions, 562 deletions
diff --git a/CHANGES b/CHANGES
index d510cb342..b201082c7 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,9 @@
-*- coding: utf-8 -*-
Changes for APR 2.0.0
+ *) apr_crypto: Add support for digest functions, with hashing, signing
+ and verifying. [Graham Leggett]
+
*) apr_json: Add support for encoding and decoding RFC8259 JSON.
[Moriyoshi Koizumi <mozo mozo jp>]
diff --git a/crypto/apr_crypto.c b/crypto/apr_crypto.c
index bda84b2a2..24e36f30a 100644
--- a/crypto/apr_crypto.c
+++ b/crypto/apr_crypto.c
@@ -54,6 +54,12 @@ APR_TYPEDEF_STRUCT(apr_crypto_block_t,
const apr_crypto_t *f;
)
+APR_TYPEDEF_STRUCT(apr_crypto_digest_t,
+ apr_pool_t *pool;
+ apr_crypto_driver_t *provider;
+ const apr_crypto_t *f;
+)
+
typedef struct apr_crypto_clear_t {
void *buffer;
apr_size_t size;
@@ -199,6 +205,24 @@ APR_DECLARE(int) apr_crypto_equals(const void *buf1, const void *buf2,
return 1 & ((diff - 1) >> 8);
}
+APR_DECLARE(apr_crypto_key_rec_t *) apr_crypto_key_rec_make(
+ apr_crypto_key_type ktype, apr_pool_t *p)
+{
+ apr_crypto_key_rec_t *key = apr_pcalloc(p, sizeof(apr_crypto_key_rec_t));
+ key->ktype = ktype;
+ return key;
+}
+
+APR_DECLARE(apr_crypto_digest_rec_t *) apr_crypto_digest_rec_make(
+ apr_crypto_digest_type_e dtype, apr_pool_t *p)
+{
+ apr_crypto_digest_rec_t *rec = apr_pcalloc(p, sizeof(apr_crypto_digest_rec_t));
+ if (rec) {
+ rec->dtype = dtype;
+ }
+ return rec;
+}
+
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)
@@ -645,6 +669,21 @@ APR_DECLARE(apr_status_t) apr_crypto_make(apr_crypto_t **f,
}
/**
+ * @brief Get a hash table of digests, keyed by the name of the digest against
+ * a pointer to apr_crypto_digest_t, which in turn begins with an
+ * integer.
+ *
+ * @param digests - hashtable of 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)
+{
+ return f->provider->get_block_key_digests(digests, 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, which in turn begins with an
* integer.
@@ -876,6 +915,30 @@ APR_DECLARE(apr_status_t) apr_crypto_block_decrypt_finish(unsigned char *out,
return ctx->provider->block_decrypt_finish(out, outlen, ctx);
}
+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)
+{
+ return key->provider->digest_init(d, key, rec, p);
+}
+
+APR_DECLARE(apr_status_t) apr_crypto_digest_update(apr_crypto_digest_t *digest,
+ const unsigned char *in, apr_size_t inlen)
+{
+ return digest->provider->digest_update(digest, in, inlen);
+}
+
+APR_DECLARE(apr_status_t) apr_crypto_digest_final(apr_crypto_digest_t *digest)
+{
+ return digest->provider->digest_final(digest);
+}
+
+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)
+{
+ return key->provider->digest(key, rec, in, inlen, p);
+}
+
/**
* @brief Clean encryption / decryption context.
* @note After cleanup, a context is free to be reused if necessary.
@@ -888,6 +951,17 @@ APR_DECLARE(apr_status_t) apr_crypto_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_DECLARE(apr_status_t) apr_crypto_digest_cleanup(apr_crypto_digest_t *ctx)
+{
+ return ctx->provider->digest_cleanup(ctx);
+}
+
+/**
* @brief Clean encryption / decryption context.
* @note After cleanup, a context is free to be reused if necessary.
* @param f The context to use.
diff --git a/crypto/apr_crypto_commoncrypto.c b/crypto/apr_crypto_commoncrypto.c
index 83886bce3..f2095bcd7 100644
--- a/crypto/apr_crypto_commoncrypto.c
+++ b/crypto/apr_crypto_commoncrypto.c
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include "apr.h"
#include "apr_lib.h"
#include "apu.h"
#include "apr_private.h"
@@ -33,6 +34,7 @@
#if APU_HAVE_CRYPTO
#include <CommonCrypto/CommonCrypto.h>
+#include <CommonCrypto/CommonDigest.h>
#define LOG_PREFIX "apr_crypto_commoncrypto: "
@@ -41,6 +43,7 @@ struct apr_crypto_t
apr_pool_t *pool;
const apr_crypto_driver_t *provider;
apu_err_t *result;
+ apr_hash_t *digests;
apr_hash_t *types;
apr_hash_t *modes;
apr_random_t *rng;
@@ -51,12 +54,16 @@ struct apr_crypto_key_t
apr_pool_t *pool;
const apr_crypto_driver_t *provider;
const apr_crypto_t *f;
+ const apr_crypto_key_rec_t *rec;
+ unsigned char *key;
+ void *hash;
CCAlgorithm algorithm;
CCOptions options;
- unsigned char *key;
int keyLen;
int ivSize;
+ CCHmacAlgorithm hmac;
apr_size_t blockSize;
+ apr_size_t digestSize;
};
struct apr_crypto_block_t
@@ -68,6 +75,27 @@ struct apr_crypto_block_t
CCCryptorRef ref;
};
+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;
+ CCHmacContext *hmac;
+ void *hash;
+ unsigned char *md;
+};
+
+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 },
@@ -95,16 +123,25 @@ static apr_status_t crypto_error(const apu_err_t **result,
*/
static apr_status_t crypto_shutdown(void)
{
- return apr_crypto_lib_term("commoncrypto");
+ 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)
{
- return apr_crypto_lib_init("commoncrypto", params, result, pool);
+
+ apr_pool_cleanup_register(pool, pool, crypto_shutdown_helper,
+ apr_pool_cleanup_null);
+
+ return APR_SUCCESS;
}
/**
@@ -132,6 +169,25 @@ static apr_status_t crypto_block_cleanup_helper(void *data)
}
/**
+ * @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.
+ */
+static apr_status_t crypto_digest_cleanup(apr_crypto_digest_t *ctx)
+{
+
+ 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.
@@ -168,6 +224,7 @@ static apr_status_t crypto_make(apr_crypto_t **ff,
{
apr_crypto_t *f = apr_pcalloc(pool, sizeof(apr_crypto_t));
apr_status_t rv;
+ int i;
if (!f) {
return APR_ENOMEM;
@@ -196,21 +253,34 @@ static apr_status_t crypto_make(apr_crypto_t **ff,
return APR_ENOMEM;
}
+ f->digests = apr_hash_make(pool);
+ if (!f->digests) {
+ return APR_ENOMEM;
+ }
+ apr_hash_set(f->digests, "md2", APR_HASH_KEY_STRING, &(key_digests[i = 0]));
+ apr_hash_set(f->digests, "md4", APR_HASH_KEY_STRING, &(key_digests[++i]));
+ apr_hash_set(f->digests, "md5", APR_HASH_KEY_STRING, &(key_digests[++i]));
+ 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]));
apr_pool_cleanup_register(pool, f, crypto_cleanup_helper,
apr_pool_cleanup_null);
@@ -220,6 +290,21 @@ static apr_status_t crypto_make(apr_crypto_t **ff,
}
/**
+ * @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.
*
@@ -350,6 +435,36 @@ static apr_status_t crypto_cipher_mechanism(apr_crypto_key_t *key,
return APR_SUCCESS;
}
+static apr_status_t crypto_digest_mechanism(apr_crypto_key_t *key,
+ const apr_crypto_block_key_digest_e digest, apr_pool_t *p)
+{
+ /* determine the digest algorithm to be used */
+ switch (digest) {
+ case APR_CRYPTO_DIGEST_MD5:
+ key->digestSize = CC_MD5_DIGEST_LENGTH;
+ break;
+ case APR_CRYPTO_DIGEST_SHA1:
+ key->digestSize = CC_SHA1_DIGEST_LENGTH;
+ break;
+ case APR_CRYPTO_DIGEST_SHA224:
+ key->digestSize = CC_SHA224_DIGEST_LENGTH;
+ break;
+ case APR_CRYPTO_DIGEST_SHA256:
+ key->digestSize = CC_SHA256_DIGEST_LENGTH;
+ break;
+ case APR_CRYPTO_DIGEST_SHA384:
+ key->digestSize = CC_SHA384_DIGEST_LENGTH;
+ break;
+ case APR_CRYPTO_DIGEST_SHA512:
+ key->digestSize = CC_SHA512_DIGEST_LENGTH;
+ break;
+ default:
+ return APR_ENODIGEST;
+ }
+
+ return APR_SUCCESS;
+}
+
/**
* @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
@@ -379,19 +494,21 @@ static apr_status_t crypto_key(apr_crypto_key_t **k,
return APR_ENOMEM;
}
+ 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 ((f->result->rc = CCKeyDerivationPBKDF(kCCPBKDF2,
rec->k.passphrase.pass, rec->k.passphrase.passLen,
@@ -406,6 +523,12 @@ static apr_status_t crypto_key(apr_crypto_key_t **k,
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;
@@ -417,6 +540,87 @@ static apr_status_t crypto_key(apr_crypto_key_t **k,
break;
}
+ case APR_CRYPTO_KTYPE_HASH: {
+
+ /* decide on what digest mechanism we will be using */
+ rv = crypto_digest_mechanism(key, rec->k.hash.digest, p);
+ if (APR_SUCCESS != rv) {
+ return rv;
+ }
+
+ switch (rec->k.hash.digest) {
+ case APR_CRYPTO_DIGEST_MD5:
+ key->digestSize = CC_MD5_DIGEST_LENGTH;
+ break;
+ case APR_CRYPTO_DIGEST_SHA1:
+ key->digestSize = CC_SHA1_DIGEST_LENGTH;
+ break;
+ case APR_CRYPTO_DIGEST_SHA224:
+ key->digestSize = CC_SHA224_DIGEST_LENGTH;
+ break;
+ case APR_CRYPTO_DIGEST_SHA256:
+ key->digestSize = CC_SHA256_DIGEST_LENGTH;
+ break;
+ case APR_CRYPTO_DIGEST_SHA384:
+ key->digestSize = CC_SHA384_DIGEST_LENGTH;
+ break;
+ case APR_CRYPTO_DIGEST_SHA512:
+ key->digestSize = CC_SHA512_DIGEST_LENGTH;
+ break;
+ default:
+ return APR_ENODIGEST;
+ }
+
+ break;
+ }
+ case APR_CRYPTO_KTYPE_HMAC: {
+
+ /* 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;
+ }
+
+ /* decide on what digest mechanism we will be using */
+ rv = crypto_digest_mechanism(key, rec->k.hmac.digest, p);
+ if (APR_SUCCESS != rv) {
+ return rv;
+ }
+
+ key->hmac = rec->k.hmac.digest;
+
+ switch (rec->k.hmac.digest) {
+ case APR_CRYPTO_DIGEST_MD5:
+ key->hmac = kCCHmacAlgMD5;
+ break;
+ case APR_CRYPTO_DIGEST_SHA1:
+ key->hmac = kCCHmacAlgSHA1;
+ break;
+ case APR_CRYPTO_DIGEST_SHA224:
+ key->hmac = kCCHmacAlgSHA224;
+ break;
+ case APR_CRYPTO_DIGEST_SHA256:
+ key->hmac = kCCHmacAlgSHA256;
+ break;
+ case APR_CRYPTO_DIGEST_SHA384:
+ key->hmac = kCCHmacAlgSHA384;
+ break;
+ case APR_CRYPTO_DIGEST_SHA512:
+ key->hmac = kCCHmacAlgSHA512;
+ break;
+ default:
+ return APR_ENODIGEST;
+ }
+
+ break;
+ }
+
+ case APR_CRYPTO_KTYPE_CMAC: {
+
+ return APR_ENOTIMPL;
+
+ }
+
default: {
return APR_ENOKEY;
@@ -463,6 +667,7 @@ static apr_status_t crypto_passphrase(apr_crypto_key_t **k, apr_size_t *ivSize,
{
apr_status_t rv;
apr_crypto_key_t *key = *k;
+ apr_crypto_key_rec_t *rec;
if (!key) {
*k = key = apr_pcalloc(p, sizeof *key);
@@ -473,6 +678,11 @@ static apr_status_t crypto_passphrase(apr_crypto_key_t **k, apr_size_t *ivSize,
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);
@@ -530,59 +740,72 @@ static apr_status_t crypto_block_encrypt_init(apr_crypto_block_t **ctx,
apr_pool_cleanup_register(p, block, crypto_block_cleanup_helper,
apr_pool_cleanup_null);
- /* generate an IV, if necessary */
- usedIv = NULL;
- if (key->ivSize) {
- if (iv == NULL) {
- return APR_ENOIV;
- }
- if (*iv == NULL) {
- apr_status_t status;
- usedIv = apr_pcalloc(p, key->ivSize);
- if (!usedIv) {
- return APR_ENOMEM;
+ switch (key->rec->ktype) {
+
+ case APR_CRYPTO_KTYPE_PASSPHRASE:
+ case APR_CRYPTO_KTYPE_SECRET: {
+
+ /* generate an IV, if necessary */
+ usedIv = NULL;
+ if (key->ivSize) {
+ if (iv == NULL) {
+ return APR_ENOIV;
}
- apr_crypto_clear(p, usedIv, key->ivSize);
- status = apr_random_secure_bytes(block->f->rng, usedIv,
- key->ivSize);
- if (APR_SUCCESS != status) {
- return status;
+ if (*iv == NULL) {
+ apr_status_t status;
+ usedIv = apr_pcalloc(p, key->ivSize);
+ if (!usedIv) {
+ return APR_ENOMEM;
+ }
+ apr_crypto_clear(p, usedIv, key->ivSize);
+ status = apr_random_secure_bytes(block->f->rng, usedIv,
+ key->ivSize);
+ if (APR_SUCCESS != status) {
+ return status;
+ }
+ *iv = usedIv;
+ } else {
+ usedIv = (unsigned char *) *iv;
}
- *iv = usedIv;
}
- else {
- usedIv = (unsigned char *) *iv;
+
+ /* create a new context for encryption */
+ switch ((block->f->result->rc = CCCryptorCreate(kCCEncrypt,
+ key->algorithm, key->options, key->key, key->keyLen, usedIv,
+ &block->ref))) {
+ case kCCSuccess: {
+ break;
+ }
+ case kCCParamError: {
+ return APR_EINIT;
+ }
+ case kCCMemoryFailure: {
+ return APR_ENOMEM;
+ }
+ case kCCAlignmentError: {
+ return APR_EPADDING;
+ }
+ case kCCUnimplemented: {
+ return APR_ENOTIMPL;
+ }
+ default: {
+ return APR_EINIT;
+ }
}
- }
- /* create a new context for encryption */
- switch ((block->f->result->rc = CCCryptorCreate(kCCEncrypt, key->algorithm,
- key->options, key->key, key->keyLen, usedIv, &block->ref))) {
- case kCCSuccess: {
- break;
- }
- case kCCParamError: {
- return APR_EINIT;
- }
- case kCCMemoryFailure: {
- return APR_ENOMEM;
- }
- case kCCAlignmentError: {
- return APR_EPADDING;
- }
- case kCCUnimplemented: {
- return APR_ENOTIMPL;
+ if (blockSize) {
+ *blockSize = key->blockSize;
+ }
+
+ return APR_SUCCESS;
+
}
default: {
- return APR_EINIT;
- }
- }
- if (blockSize) {
- *blockSize = key->blockSize;
- }
+ return APR_EINVAL;
- return APR_SUCCESS;
+ }
+ }
}
@@ -606,43 +829,56 @@ static apr_status_t crypto_block_encrypt_init(apr_crypto_block_t **ctx,
*/
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)
{
- apr_size_t outl = *outlen;
- unsigned char *buffer;
+ switch (block->key->rec->ktype) {
- /* are we after the maximum size of the out buffer? */
- if (!out) {
- *outlen = CCCryptorGetOutputLength(ctx->ref, inlen, 1);
- return APR_SUCCESS;
- }
+ case APR_CRYPTO_KTYPE_PASSPHRASE:
+ case APR_CRYPTO_KTYPE_SECRET: {
- /* must we allocate the output buffer from a pool? */
- if (!*out) {
- outl = CCCryptorGetOutputLength(ctx->ref, inlen, 1);
- buffer = apr_palloc(ctx->pool, outl);
- if (!buffer) {
- return APR_ENOMEM;
+ apr_size_t outl = *outlen;
+ unsigned char *buffer;
+
+ /* are we after the maximum size of the out buffer? */
+ if (!out) {
+ *outlen = CCCryptorGetOutputLength(block->ref, inlen, 1);
+ return APR_SUCCESS;
}
- apr_crypto_clear(ctx->pool, buffer, outl);
- *out = buffer;
- }
- switch ((ctx->f->result->rc = CCCryptorUpdate(ctx->ref, in, inlen, (*out),
- outl, &outl))) {
- case kCCSuccess: {
- break;
- }
- case kCCBufferTooSmall: {
- return APR_ENOSPACE;
+ /* must we allocate the output buffer from a pool? */
+ if (!*out) {
+ outl = CCCryptorGetOutputLength(block->ref, inlen, 1);
+ buffer = apr_palloc(block->pool, outl);
+ if (!buffer) {
+ return APR_ENOMEM;
+ }
+ apr_crypto_clear(block->pool, buffer, outl);
+ *out = buffer;
+ }
+
+ switch ((block->f->result->rc = CCCryptorUpdate(block->ref, in, inlen, (*out),
+ outl, &outl))) {
+ case kCCSuccess: {
+ break;
+ }
+ case kCCBufferTooSmall: {
+ return APR_ENOSPACE;
+ }
+ default: {
+ return APR_ECRYPT;
+ }
+ }
+ *outlen = outl;
+
+ return APR_SUCCESS;
+
}
default: {
- return APR_ECRYPT;
+
+ return APR_EINVAL;
+
}
}
- *outlen = outl;
-
- return APR_SUCCESS;
}
@@ -665,36 +901,49 @@ static apr_status_t crypto_block_encrypt(unsigned char **out,
* @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_size_t len = *outlen;
+ switch (block->key->rec->ktype) {
- ctx->f->result->rc = CCCryptorFinal(ctx->ref, out,
- CCCryptorGetOutputLength(ctx->ref, 0, 1), &len);
+ case APR_CRYPTO_KTYPE_PASSPHRASE:
+ case APR_CRYPTO_KTYPE_SECRET: {
- /* always clean up */
- crypto_block_cleanup(ctx);
+ apr_size_t len = *outlen;
+
+ block->f->result->rc = CCCryptorFinal(block->ref, out,
+ CCCryptorGetOutputLength(block->ref, 0, 1), &len);
+
+ /* always clean up */
+ crypto_block_cleanup(block);
+
+ switch (block->f->result->rc) {
+ case kCCSuccess: {
+ break;
+ }
+ case kCCBufferTooSmall: {
+ return APR_ENOSPACE;
+ }
+ case kCCAlignmentError: {
+ return APR_EPADDING;
+ }
+ case kCCDecodeError: {
+ return APR_ECRYPT;
+ }
+ default: {
+ return APR_ECRYPT;
+ }
+ }
+ *outlen = len;
+
+ return APR_SUCCESS;
- switch (ctx->f->result->rc) {
- case kCCSuccess: {
- break;
- }
- case kCCBufferTooSmall: {
- return APR_ENOSPACE;
- }
- case kCCAlignmentError: {
- return APR_EPADDING;
- }
- case kCCDecodeError: {
- return APR_ECRYPT;
}
default: {
- return APR_ECRYPT;
+
+ return APR_EINVAL;
+
}
}
- *outlen = len;
-
- return APR_SUCCESS;
}
@@ -717,55 +966,69 @@ static apr_status_t crypto_block_decrypt_init(apr_crypto_block_t **ctx,
apr_size_t *blockSize, const unsigned char *iv,
const apr_crypto_key_t *key, apr_pool_t *p)
{
- apr_crypto_block_t *block = *ctx;
- if (!block) {
- *ctx = block = apr_pcalloc(p, sizeof(apr_crypto_block_t));
- }
- if (!block) {
- return APR_ENOMEM;
- }
- block->f = key->f;
- block->pool = p;
- block->provider = key->provider;
+ switch (key->rec->ktype) {
- apr_pool_cleanup_register(p, block, crypto_block_cleanup_helper,
- apr_pool_cleanup_null);
+ case APR_CRYPTO_KTYPE_PASSPHRASE:
+ case APR_CRYPTO_KTYPE_SECRET: {
- /* generate an IV, if necessary */
- if (key->ivSize) {
- if (iv == NULL) {
- return APR_ENOIV;
+ apr_crypto_block_t *block = *ctx;
+ if (!block) {
+ *ctx = block = apr_pcalloc(p, sizeof(apr_crypto_block_t));
+ }
+ if (!block) {
+ return APR_ENOMEM;
+ }
+ 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);
+
+ /* generate an IV, if necessary */
+ if (key->ivSize) {
+ if (iv == NULL) {
+ return APR_ENOIV;
+ }
}
- }
- /* create a new context for decryption */
- switch ((block->f->result->rc = CCCryptorCreate(kCCDecrypt, key->algorithm,
- key->options, key->key, key->keyLen, iv, &block->ref))) {
- case kCCSuccess: {
- break;
- }
- case kCCParamError: {
- return APR_EINIT;
- }
- case kCCMemoryFailure: {
- return APR_ENOMEM;
- }
- case kCCAlignmentError: {
- return APR_EPADDING;
- }
- case kCCUnimplemented: {
- return APR_ENOTIMPL;
+ /* create a new context for decryption */
+ switch ((block->f->result->rc = CCCryptorCreate(kCCDecrypt, key->algorithm,
+ key->options, key->key, key->keyLen, iv, &block->ref))) {
+ case kCCSuccess: {
+ break;
+ }
+ case kCCParamError: {
+ return APR_EINIT;
+ }
+ case kCCMemoryFailure: {
+ return APR_ENOMEM;
+ }
+ case kCCAlignmentError: {
+ return APR_EPADDING;
+ }
+ case kCCUnimplemented: {
+ return APR_ENOTIMPL;
+ }
+ default: {
+ return APR_EINIT;
+ }
+ }
+
+ if (blockSize) {
+ *blockSize = key->blockSize;
+ }
+
+ return APR_SUCCESS;
+
}
default: {
- return APR_EINIT;
- }
- }
- if (blockSize) {
- *blockSize = key->blockSize;
- }
+ return APR_EINVAL;
- return APR_SUCCESS;
+ }
+ }
}
@@ -789,43 +1052,56 @@ static apr_status_t crypto_block_decrypt_init(apr_crypto_block_t **ctx,
*/
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)
{
- apr_size_t outl = *outlen;
- unsigned char *buffer;
+ switch (block->key->rec->ktype) {
- /* are we after the maximum size of the out buffer? */
- if (!out) {
- *outlen = CCCryptorGetOutputLength(ctx->ref, inlen, 1);
- return APR_SUCCESS;
- }
+ case APR_CRYPTO_KTYPE_PASSPHRASE:
+ case APR_CRYPTO_KTYPE_SECRET: {
- /* must we allocate the output buffer from a pool? */
- if (!*out) {
- outl = CCCryptorGetOutputLength(ctx->ref, inlen, 1);
- buffer = apr_palloc(ctx->pool, outl);
- if (!buffer) {
- return APR_ENOMEM;
+ apr_size_t outl = *outlen;
+ unsigned char *buffer;
+
+ /* are we after the maximum size of the out buffer? */
+ if (!out) {
+ *outlen = CCCryptorGetOutputLength(block->ref, inlen, 1);
+ return APR_SUCCESS;
}
- apr_crypto_clear(ctx->pool, buffer, outl);
- *out = buffer;
- }
- switch ((ctx->f->result->rc = CCCryptorUpdate(ctx->ref, in, inlen, (*out),
- outl, &outl))) {
- case kCCSuccess: {
- break;
- }
- case kCCBufferTooSmall: {
- return APR_ENOSPACE;
+ /* must we allocate the output buffer from a pool? */
+ if (!*out) {
+ outl = CCCryptorGetOutputLength(block->ref, inlen, 1);
+ buffer = apr_palloc(block->pool, outl);
+ if (!buffer) {
+ return APR_ENOMEM;
+ }
+ apr_crypto_clear(block->pool, buffer, outl);
+ *out = buffer;
+ }
+
+ switch ((block->f->result->rc = CCCryptorUpdate(block->ref, in, inlen, (*out),
+ outl, &outl))) {
+ case kCCSuccess: {
+ break;
+ }
+ case kCCBufferTooSmall: {
+ return APR_ENOSPACE;
+ }
+ default: {
+ return APR_ECRYPT;
+ }
+ }
+ *outlen = outl;
+
+ return APR_SUCCESS;
+
}
default: {
- return APR_ECRYPT;
+
+ return APR_EINVAL;
+
}
}
- *outlen = outl;
-
- return APR_SUCCESS;
}
@@ -848,37 +1124,333 @@ static apr_status_t crypto_block_decrypt(unsigned char **out,
* @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_size_t len = *outlen;
+ switch (block->key->rec->ktype) {
+
+ case APR_CRYPTO_KTYPE_PASSPHRASE:
+ case APR_CRYPTO_KTYPE_SECRET: {
+
+ apr_size_t len = *outlen;
- ctx->f->result->rc = CCCryptorFinal(ctx->ref, out,
- CCCryptorGetOutputLength(ctx->ref, 0, 1), &len);
+ block->f->result->rc = CCCryptorFinal(block->ref, out,
+ CCCryptorGetOutputLength(block->ref, 0, 1), &len);
- /* always clean up */
- crypto_block_cleanup(ctx);
+ /* always clean up */
+ crypto_block_cleanup(block);
+
+ switch (block->f->result->rc) {
+ case kCCSuccess: {
+ break;
+ }
+ case kCCBufferTooSmall: {
+ return APR_ENOSPACE;
+ }
+ case kCCAlignmentError: {
+ return APR_EPADDING;
+ }
+ case kCCDecodeError: {
+ return APR_ECRYPT;
+ }
+ default: {
+ return APR_ECRYPT;
+ }
+ }
+ *outlen = len;
+
+ return APR_SUCCESS;
+
+ }
+ default: {
+
+ return APR_EINVAL;
+
+ }
+ }
+
+}
+
+static apr_status_t crypto_digest_init(apr_crypto_digest_t **ctx,
+ const apr_crypto_key_t *key, apr_crypto_digest_rec_t *rec, apr_pool_t *p)
+{
+
+ apr_crypto_digest_t *digest = *ctx;
+
+ if (!digest) {
+ *ctx = 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;
+
+ apr_pool_cleanup_register(p, digest, crypto_digest_cleanup_helper,
+ apr_pool_cleanup_null);
+
+ switch (digest->key->rec->ktype) {
+
+ case APR_CRYPTO_KTYPE_HASH: {
+
+ switch (key->rec->k.hash.digest) {
+ case APR_CRYPTO_DIGEST_MD5:
+ digest->hash = apr_pcalloc(p, sizeof(CC_MD5_CTX));
+ CC_MD5_Init(digest->hash);
+ break;
+ case APR_CRYPTO_DIGEST_SHA1:
+ digest->hash = apr_pcalloc(p, sizeof(CC_SHA1_CTX));
+ CC_SHA1_Init(digest->hash);
+ break;
+ case APR_CRYPTO_DIGEST_SHA224:
+ digest->hash = apr_pcalloc(p, sizeof(CC_SHA256_CTX));
+ CC_SHA224_Init(digest->hash);
+ break;
+ case APR_CRYPTO_DIGEST_SHA256:
+ digest->hash = apr_pcalloc(p, sizeof(CC_SHA256_CTX));
+ CC_SHA256_Init(digest->hash);
+ break;
+ case APR_CRYPTO_DIGEST_SHA384:
+ digest->hash = apr_pcalloc(p, sizeof(CC_SHA512_CTX));
+ CC_SHA384_Init(digest->hash);
+ break;
+ case APR_CRYPTO_DIGEST_SHA512:
+ digest->hash = apr_pcalloc(p, sizeof(CC_SHA512_CTX));
+ CC_SHA512_Init(digest->hash);
+ break;
+ default:
+ return APR_ENODIGEST;
+ }
- switch (ctx->f->result->rc) {
- case kCCSuccess: {
break;
}
- case kCCBufferTooSmall: {
- return APR_ENOSPACE;
+ case APR_CRYPTO_KTYPE_HMAC: {
+
+ digest->hmac = apr_pcalloc(p, sizeof(CCHmacContext));
+ if (!digest->hmac) {
+ return APR_ENOMEM;
+ }
+
+ CCHmacInit(digest->hmac, key->hmac, key->rec->k.hmac.secret,
+ key->rec->k.hmac.secretLen);
+
+ break;
}
- case kCCAlignmentError: {
- return APR_EPADDING;
+
+ case APR_CRYPTO_KTYPE_CMAC: {
+
+ return APR_ENOTIMPL;
+
}
- case kCCDecodeError: {
- return APR_ECRYPT;
+
+ 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: {
+
+ switch (digest->key->rec->k.hash.digest) {
+ case APR_CRYPTO_DIGEST_MD5:
+ CC_MD5_Update(digest->hash, in, inlen);
+ break;
+ case APR_CRYPTO_DIGEST_SHA1:
+ CC_SHA1_Update(digest->hash, in, inlen);
+ break;
+ case APR_CRYPTO_DIGEST_SHA224:
+ CC_SHA224_Update(digest->hash, in, inlen);
+ break;
+ case APR_CRYPTO_DIGEST_SHA256:
+ CC_SHA256_Update(digest->hash, in, inlen);
+ break;
+ case APR_CRYPTO_DIGEST_SHA384:
+ CC_SHA384_Update(digest->hash, in, inlen);
+ break;
+ case APR_CRYPTO_DIGEST_SHA512:
+ CC_SHA512_Update(digest->hash, in, inlen);
+ break;
+ default:
+ return APR_ENODIGEST;
+ }
+
+ break;
+ }
+ case APR_CRYPTO_KTYPE_HMAC: {
+
+ CCHmacUpdate(digest->hmac, in, inlen);
+
+ break;
+ }
+
+ case APR_CRYPTO_KTYPE_CMAC: {
+
+ return APR_ENOTIMPL;
+
+ }
+
default: {
- return APR_ECRYPT;
+
+ return APR_EINVAL;
+
}
}
- *outlen = len;
return APR_SUCCESS;
+}
+
+static apr_status_t crypto_digest_final(apr_crypto_digest_t *digest)
+{
+
+ switch (digest->key->rec->ktype) {
+
+ case APR_CRYPTO_KTYPE_HASH: {
+
+ size_t len = digest->key->digestSize;
+
+ /* 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);
+ }
+
+ switch (digest->key->rec->k.hash.digest) {
+ case APR_CRYPTO_DIGEST_MD5:
+ CC_MD5_Final(digest->rec->d.hash.s, digest->hash);
+ break;
+ case APR_CRYPTO_DIGEST_SHA1:
+ CC_SHA1_Final(digest->rec->d.hash.s, digest->hash);
+ break;
+ case APR_CRYPTO_DIGEST_SHA224:
+ CC_SHA224_Final(digest->rec->d.hash.s, digest->hash);
+ break;
+ case APR_CRYPTO_DIGEST_SHA256:
+ CC_SHA256_Final(digest->rec->d.hash.s, digest->hash);
+ break;
+ case APR_CRYPTO_DIGEST_SHA384:
+ CC_SHA384_Final(digest->rec->d.hash.s, digest->hash);
+ break;
+ case APR_CRYPTO_DIGEST_SHA512:
+ CC_SHA512_Final(digest->rec->d.hash.s, digest->hash);
+ break;
+ default:
+ return APR_ENODIGEST;
+ }
+
+ break;
+ }
+ case APR_CRYPTO_KTYPE_HMAC: {
+
+ apr_status_t status = APR_SUCCESS;
+
+ size_t len = digest->key->digestSize;
+
+ 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 */
+ CCHmacFinal(digest->hmac, digest->rec->d.sign.s);
+
+ 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 */
+ CCHmacFinal(digest->hmac, digest->rec->d.verify.s);
+
+ if (digest->rec->d.verify.slen
+ == digest->rec->d.verify.vlen) {
+ status =
+ apr_crypto_equals(digest->rec->d.verify.s,
+ digest->rec->d.verify.v,
+ digest->rec->d.verify.slen) ?
+ APR_SUCCESS : APR_ENOVERIFY;
+ } else {
+ status = APR_ENOVERIFY;
+ }
+
+ break;
+ }
+ default: {
+ status = APR_ENODIGEST;
+ break;
+ }
+ }
+
+ return status;
+
+ }
+
+ case APR_CRYPTO_KTYPE_CMAC: {
+
+ return APR_ENOTIMPL;
+
+ }
+
+ default: {
+
+ return APR_EINVAL;
+
+ }
+ }
+
+ return APR_SUCCESS;
+}
+
+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;
}
/**
@@ -886,11 +1458,14 @@ static apr_status_t crypto_block_decrypt_finish(unsigned char *out,
*/
APR_MODULE_DECLARE_DATA const apr_crypto_driver_t apr_crypto_commoncrypto_driver =
{
- "commoncrypto", crypto_init, crypto_make, crypto_get_block_key_types,
+ "commoncrypto", 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_block_decrypt, crypto_block_decrypt_finish,
+ 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
};
diff --git a/crypto/apr_crypto_nss.c b/crypto/apr_crypto_nss.c
index 52898f69d..37ffe0862 100644
--- a/crypto/apr_crypto_nss.c
+++ b/crypto/apr_crypto_nss.c
@@ -51,6 +51,7 @@ struct apr_crypto_t {
const apr_crypto_driver_t *provider;
apu_err_t *result;
apr_crypto_config_t *config;
+ apr_hash_t *digests;
apr_hash_t *types;
apr_hash_t *modes;
};
@@ -63,8 +64,11 @@ struct apr_crypto_key_t {
apr_pool_t *pool;
const apr_crypto_driver_t *provider;
const apr_crypto_t *f;
+ const apr_crypto_key_rec_t *rec;
CK_MECHANISM_TYPE cipherMech;
+ CK_MECHANISM_TYPE hashMech;
SECOidTag cipherOid;
+ SECOidTag hashAlg;
PK11SymKey *symKey;
int ivSize;
int keyLength;
@@ -75,11 +79,30 @@ struct apr_crypto_block_t {
const apr_crypto_driver_t *provider;
const apr_crypto_t *f;
PK11Context *ctx;
- apr_crypto_key_t *key;
+ const apr_crypto_key_t *key;
SECItem *secParam;
int blockSize;
};
+struct apr_crypto_digest_t {
+ apr_pool_t *pool;
+ const apr_crypto_driver_t *provider;
+ const apr_crypto_t *f;
+ apr_crypto_digest_rec_t *rec;
+ PK11Context *ctx;
+ const apr_crypto_key_t *key;
+ SECItem *secParam;
+};
+
+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 },
@@ -112,16 +135,128 @@ static apr_status_t crypto_error(const apu_err_t **result,
*/
static apr_status_t crypto_shutdown(void)
{
- return apr_crypto_lib_term("nss");
+ if (NSS_IsInitialized()) {
+ SECStatus s = NSS_Shutdown();
+ if (s != SECSuccess) {
+ fprintf(stderr, "NSS failed to shutdown, possible leak: %d: %s",
+ PR_GetError(), PR_ErrorToName(s));
+ return APR_EINIT;
+ }
+ }
+ 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)
{
- return apr_crypto_lib_init("nss", params, result, pool);
+ SECStatus s;
+ const char *dir = NULL;
+ const char *keyPrefix = NULL;
+ const char *certPrefix = NULL;
+ const char *secmod = NULL;
+ int noinit = 0;
+ PRUint32 flags = 0;
+
+ struct {
+ const char *field;
+ const char *value;
+ int set;
+ } fields[] = {
+ { "dir", NULL, 0 },
+ { "key3", NULL, 0 },
+ { "cert7", NULL, 0 },
+ { "secmod", NULL, 0 },
+ { "noinit", NULL, 0 },
+ { NULL, NULL, 0 }
+ };
+ const char *ptr;
+ size_t klen;
+ char **elts = NULL;
+ char *elt;
+ int i = 0, j;
+ apr_status_t status;
+
+ if (params) {
+ if (APR_SUCCESS != (status = apr_tokenize_to_argv(params, &elts, pool))) {
+ return status;
+ }
+ while ((elt = elts[i])) {
+ ptr = strchr(elt, '=');
+ if (ptr) {
+ for (klen = ptr - elt; klen && apr_isspace(elt[klen - 1]); --klen)
+ ;
+ ptr++;
+ }
+ else {
+ for (klen = strlen(elt); klen && apr_isspace(elt[klen - 1]); --klen)
+ ;
+ }
+ elt[klen] = 0;
+
+ for (j = 0; fields[j].field != NULL; ++j) {
+ if (klen && !strcasecmp(fields[j].field, elt)) {
+ fields[j].set = 1;
+ if (ptr) {
+ fields[j].value = ptr;
+ }
+ break;
+ }
+ }
+
+ i++;
+ }
+ dir = fields[0].value;
+ keyPrefix = fields[1].value;
+ certPrefix = fields[2].value;
+ secmod = fields[3].value;
+ noinit = fields[4].set;
+ }
+
+ /* if we've been asked to bypass, do so here */
+ if (noinit) {
+ return APR_SUCCESS;
+ }
+
+ /* sanity check - we can only initialise NSS once */
+ if (NSS_IsInitialized()) {
+ return APR_EREINIT;
+ }
+
+ if (keyPrefix || certPrefix || secmod) {
+ s = NSS_Initialize(dir, certPrefix, keyPrefix, secmod, flags);
+ }
+ else if (dir) {
+ s = NSS_InitReadWrite(dir);
+ }
+ else {
+ s = NSS_NoDB_Init(NULL);
+ }
+ if (s != SECSuccess) {
+ if (result) {
+ /* Note: all memory must be owned by the caller, in case we're unloaded */
+ apu_err_t *err = apr_pcalloc(pool, sizeof(apu_err_t));
+ err->rc = PR_GetError();
+ err->msg = apr_pstrdup(pool, PR_ErrorToName(s));
+ err->reason = apr_pstrdup(pool, "Error during 'nss' initialisation");
+ *result = err;
+ }
+
+ return APR_ECRYPT;
+ }
+
+ apr_pool_cleanup_register(pool, pool, crypto_shutdown_helper,
+ apr_pool_cleanup_null);
+
+ return APR_SUCCESS;
+
}
/**
@@ -147,12 +282,41 @@ static apr_status_t crypto_block_cleanup(apr_crypto_block_t *block)
}
+/**
+ * @brief Clean sign / verify context.
+ * @note After cleanup, a context is free to be reused if necessary.
+ * @param f The context to use.
+ * @return Returns APR_ENOTIMPL if not supported.
+ */
+static apr_status_t crypto_digest_cleanup(apr_crypto_digest_t *digest)
+{
+
+ if (digest->secParam) {
+ SECITEM_FreeItem(digest->secParam, PR_TRUE);
+ digest->secParam = NULL;
+ }
+
+ if (digest->ctx) {
+ PK11_DestroyContext(digest->ctx, PR_TRUE);
+ digest->ctx = NULL;
+ }
+
+ return APR_SUCCESS;
+
+}
+
static apr_status_t crypto_block_cleanup_helper(void *data)
{
apr_crypto_block_t *block = (apr_crypto_block_t *) data;
return crypto_block_cleanup(block);
}
+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);
+}
+
static apr_status_t crypto_key_cleanup(void *data)
{
apr_crypto_key_t *key = data;
@@ -197,6 +361,7 @@ static apr_status_t crypto_make(apr_crypto_t **ff,
{
apr_crypto_config_t *config = NULL;
apr_crypto_t *f;
+ int i;
f = apr_pcalloc(pool, sizeof(apr_crypto_t));
if (!f) {
@@ -214,21 +379,34 @@ static apr_status_t crypto_make(apr_crypto_t **ff,
return APR_ENOMEM;
}
+ f->digests = apr_hash_make(pool);
+ if (!f->digests) {
+ return APR_ENOMEM;
+ }
+ apr_hash_set(f->digests, "md2", APR_HASH_KEY_STRING, &(key_digests[i = 0]));
+ apr_hash_set(f->digests, "md4", APR_HASH_KEY_STRING, &(key_digests[++i]));
+ apr_hash_set(f->digests, "md5", APR_HASH_KEY_STRING, &(key_digests[++i]));
+ 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]));
apr_pool_cleanup_register(pool, f, crypto_cleanup_helper,
apr_pool_cleanup_null);
@@ -238,6 +416,21 @@ static apr_status_t crypto_make(apr_crypto_t **ff,
}
/**
+ * @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.
*
@@ -385,19 +578,21 @@ static apr_status_t crypto_key(apr_crypto_key_t **k,
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);
- 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);
+ if (APR_SUCCESS != rv) {
+ return rv;
+ }
+
/* Turn the raw passphrase and salt into SECItems */
passItem.data = (unsigned char*) rec->k.passphrase.pass;
passItem.len = rec->k.passphrase.passLen;
@@ -419,11 +614,27 @@ static apr_status_t crypto_key(apr_crypto_key_t **k,
SECOID_DestroyAlgorithmID(algid, PR_TRUE);
}
+ /* sanity check? */
+ if (!key->symKey) {
+ PRErrorCode perr = PORT_GetError();
+ if (perr) {
+ f->result->rc = perr;
+ f->result->msg = PR_ErrorToName(perr);
+ rv = APR_ENOKEY;
+ }
+ }
+
break;
}
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);
+ if (APR_SUCCESS != rv) {
+ return rv;
+ }
+
/*
* NSS is by default in FIPS mode, which disallows the use of unencrypted
* symmetrical keys. As per http://permalink.gmane.org/gmane.comp.mozilla.crypto/7947
@@ -505,24 +716,115 @@ static apr_status_t crypto_key(apr_crypto_key_t **k,
PK11_FreeSlot(slot);
}
+ /* sanity check? */
+ if (!key->symKey) {
+ PRErrorCode perr = PORT_GetError();
+ if (perr) {
+ f->result->rc = perr;
+ f->result->msg = PR_ErrorToName(perr);
+ rv = APR_ENOKEY;
+ }
+ }
+
break;
}
- default: {
+ case APR_CRYPTO_KTYPE_HASH: {
+
+ switch (rec->k.hash.digest) {
+ case APR_CRYPTO_DIGEST_MD5:
+ key->hashAlg = SEC_OID_MD5;
+ break;
+ case APR_CRYPTO_DIGEST_SHA1:
+ key->hashAlg = SEC_OID_SHA1;
+ break;
+ case APR_CRYPTO_DIGEST_SHA224:
+ key->hashAlg = SEC_OID_SHA224;
+ break;
+ case APR_CRYPTO_DIGEST_SHA256:
+ key->hashAlg = SEC_OID_SHA256;
+ break;
+ case APR_CRYPTO_DIGEST_SHA384:
+ key->hashAlg = SEC_OID_SHA384;
+ break;
+ case APR_CRYPTO_DIGEST_SHA512:
+ key->hashAlg = SEC_OID_SHA512;
+ break;
+ default:
+ return APR_ENODIGEST;
+ }
- return APR_ENOKEY;
+ break;
+ }
+ case APR_CRYPTO_KTYPE_HMAC: {
+
+ /* decide on what cipher mechanism we will be using */
+ rv = crypto_cipher_mechanism(key, rec->type, rec->mode, rec->pad);
+ if (APR_SUCCESS != rv) {
+ return rv;
+ }
+
+ switch (rec->k.hmac.digest) {
+ case APR_CRYPTO_DIGEST_MD5:
+ key->hashMech = CKM_MD5_HMAC;
+ break;
+ case APR_CRYPTO_DIGEST_SHA1:
+ key->hashMech = CKM_SHA_1_HMAC;
+ break;
+ case APR_CRYPTO_DIGEST_SHA224:
+ key->hashMech = CKM_SHA224_HMAC;
+ break;
+ case APR_CRYPTO_DIGEST_SHA256:
+ key->hashMech = CKM_SHA256_HMAC;
+ break;
+ case APR_CRYPTO_DIGEST_SHA384:
+ key->hashMech = CKM_SHA384_HMAC;
+ break;
+ case APR_CRYPTO_DIGEST_SHA512:
+ key->hashMech = CKM_SHA512_HMAC;
+ break;
+ default:
+ return APR_ENODIGEST;
+ }
+
+ /* generate the key */
+ slot = PK11_GetBestSlot(key->hashMech, NULL);
+ if (slot) {
+
+ /* prepare the key to wrap */
+ secretItem.data = (unsigned char *) rec->k.hmac.secret;
+ secretItem.len = rec->k.hmac.secretLen;
+
+ key->symKey = PK11_ImportSymKey(slot, key->hashMech, PK11_OriginDerive,
+ CKA_SIGN, &secretItem, NULL);
+ /* sanity check? */
+ if (!key->symKey) {
+ PRErrorCode perr = PORT_GetError();
+ if (perr) {
+ f->result->rc = perr;
+ f->result->msg = PR_ErrorToName(perr);
+ rv = APR_ENOKEY;
+ }
+ }
+
+ PK11_FreeSlot(slot);
+ }
+
+ break;
}
+
+ case APR_CRYPTO_KTYPE_CMAC: {
+
+ return APR_ENOTIMPL;
+
}
- /* sanity check? */
- if (!key->symKey) {
- PRErrorCode perr = PORT_GetError();
- if (perr) {
- f->result->rc = perr;
- f->result->msg = PR_ErrorToName(perr);
- rv = APR_ENOKEY;
- }
+ default: {
+
+ return APR_ENOKEY;
+
+ }
}
return rv;
@@ -569,6 +871,7 @@ static apr_status_t crypto_passphrase(apr_crypto_key_t **k, apr_size_t *ivSize,
SECAlgorithmID *algid;
void *wincx = NULL; /* what is wincx? */
apr_crypto_key_t *key = *k;
+ apr_crypto_key_rec_t *rec;
if (!key) {
*k = key = apr_pcalloc(p, sizeof *key);
@@ -581,6 +884,11 @@ static apr_status_t crypto_passphrase(apr_crypto_key_t **k, apr_size_t *ivSize,
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);
@@ -658,54 +966,68 @@ static apr_status_t crypto_block_encrypt_init(apr_crypto_block_t **ctx,
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);
- if (key->ivSize) {
- if (iv == NULL) {
- return APR_ENOIV;
- }
- if (*iv == NULL) {
- SECStatus s;
- usedIv = apr_pcalloc(p, key->ivSize);
- if (!usedIv) {
- return APR_ENOMEM;
- }
- apr_crypto_clear(p, usedIv, key->ivSize);
- s = PK11_GenerateRandom(usedIv, key->ivSize);
- if (s != SECSuccess) {
+ switch (key->rec->ktype) {
+
+ case APR_CRYPTO_KTYPE_PASSPHRASE:
+ case APR_CRYPTO_KTYPE_SECRET: {
+
+ if (key->ivSize) {
+ if (iv == NULL) {
return APR_ENOIV;
}
- *iv = usedIv;
+ if (*iv == NULL) {
+ SECStatus s;
+ usedIv = apr_pcalloc(p, key->ivSize);
+ if (!usedIv) {
+ return APR_ENOMEM;
+ }
+ apr_crypto_clear(p, usedIv, key->ivSize);
+ s = PK11_GenerateRandom(usedIv, key->ivSize);
+ if (s != SECSuccess) {
+ return APR_ENOIV;
+ }
+ *iv = usedIv;
+ }
+ else {
+ usedIv = (unsigned char *) *iv;
+ }
+ ivItem.data = usedIv;
+ ivItem.len = key->ivSize;
+ block->secParam = PK11_ParamFromIV(key->cipherMech, &ivItem);
}
else {
- usedIv = (unsigned char *) *iv;
+ block->secParam = PK11_GenerateNewParam(key->cipherMech, key->symKey);
+ }
+ block->blockSize = PK11_GetBlockSize(key->cipherMech, block->secParam);
+ block->ctx = PK11_CreateContextBySymKey(key->cipherMech, CKA_ENCRYPT,
+ key->symKey, block->secParam);
+
+ /* did an error occur? */
+ perr = PORT_GetError();
+ if (perr || !block->ctx) {
+ key->f->result->rc = perr;
+ key->f->result->msg = PR_ErrorToName(perr);
+ return APR_EINIT;
}
- ivItem.data = usedIv;
- ivItem.len = key->ivSize;
- block->secParam = PK11_ParamFromIV(key->cipherMech, &ivItem);
- }
- else {
- block->secParam = PK11_GenerateNewParam(key->cipherMech, key->symKey);
- }
- block->blockSize = PK11_GetBlockSize(key->cipherMech, block->secParam);
- block->ctx = PK11_CreateContextBySymKey(key->cipherMech, CKA_ENCRYPT,
- key->symKey, block->secParam);
- /* did an error occur? */
- perr = PORT_GetError();
- if (perr || !block->ctx) {
- key->f->result->rc = perr;
- key->f->result->msg = PR_ErrorToName(perr);
- return APR_EINIT;
- }
+ if (blockSize) {
+ *blockSize = PK11_GetBlockSize(key->cipherMech, block->secParam);
+ }
+
+ return APR_SUCCESS;
- if (blockSize) {
- *blockSize = PK11_GetBlockSize(key->cipherMech, block->secParam);
}
+ default: {
- return APR_SUCCESS;
+ return APR_EINVAL;
+
+ }
+ }
}
@@ -731,36 +1053,48 @@ 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 *block)
{
+ switch (block->key->rec->ktype) {
- unsigned char *buffer;
- int outl = (int) *outlen;
- SECStatus s;
- if (!out) {
- *outlen = inlen + block->blockSize;
- return APR_SUCCESS;
- }
- if (!*out) {
- buffer = apr_palloc(block->pool, inlen + block->blockSize);
- if (!buffer) {
- return APR_ENOMEM;
+ case APR_CRYPTO_KTYPE_PASSPHRASE:
+ case APR_CRYPTO_KTYPE_SECRET: {
+
+ unsigned char *buffer;
+ int outl = (int) *outlen;
+ SECStatus s;
+ if (!out) {
+ *outlen = inlen + block->blockSize;
+ return APR_SUCCESS;
+ }
+ if (!*out) {
+ buffer = apr_palloc(block->pool, inlen + block->blockSize);
+ if (!buffer) {
+ return APR_ENOMEM;
+ }
+ apr_crypto_clear(block->pool, buffer, inlen + block->blockSize);
+ *out = buffer;
}
- apr_crypto_clear(block->pool, buffer, inlen + block->blockSize);
- *out = buffer;
- }
- s = PK11_CipherOp(block->ctx, *out, &outl, inlen, (unsigned char*) in,
- inlen);
- if (s != SECSuccess) {
- PRErrorCode perr = PORT_GetError();
- if (perr) {
- block->f->result->rc = perr;
- block->f->result->msg = PR_ErrorToName(perr);
+ s = PK11_CipherOp(block->ctx, *out, &outl, inlen, (unsigned char*) in,
+ inlen);
+ if (s != SECSuccess) {
+ PRErrorCode perr = PORT_GetError();
+ if (perr) {
+ block->f->result->rc = perr;
+ block->f->result->msg = PR_ErrorToName(perr);
+ }
+ return APR_ECRYPT;
}
- return APR_ECRYPT;
+ *outlen = outl;
+
+ return APR_SUCCESS;
+
}
- *outlen = outl;
+ default: {
- return APR_SUCCESS;
+ return APR_EINVAL;
+
+ }
+ }
}
@@ -785,24 +1119,36 @@ static apr_status_t crypto_block_encrypt(unsigned char **out,
static apr_status_t crypto_block_encrypt_finish(unsigned char *out,
apr_size_t *outlen, apr_crypto_block_t *block)
{
+ switch (block->key->rec->ktype) {
- apr_status_t rv = APR_SUCCESS;
- unsigned int outl = *outlen;
+ case APR_CRYPTO_KTYPE_PASSPHRASE:
+ case APR_CRYPTO_KTYPE_SECRET: {
- SECStatus s = PK11_DigestFinal(block->ctx, out, &outl, block->blockSize);
- *outlen = outl;
+ apr_status_t rv = APR_SUCCESS;
+ unsigned int outl = *outlen;
- if (s != SECSuccess) {
- PRErrorCode perr = PORT_GetError();
- if (perr) {
- block->f->result->rc = perr;
- block->f->result->msg = PR_ErrorToName(perr);
+ SECStatus s = PK11_DigestFinal(block->ctx, out, &outl, block->blockSize);
+ *outlen = outl;
+
+ if (s != SECSuccess) {
+ PRErrorCode perr = PORT_GetError();
+ if (perr) {
+ block->f->result->rc = perr;
+ block->f->result->msg = PR_ErrorToName(perr);
+ }
+ rv = APR_ECRYPT;
}
- rv = APR_ECRYPT;
+ crypto_block_cleanup(block);
+
+ return rv;
+
}
- crypto_block_cleanup(block);
+ default: {
- return rv;
+ return APR_EINVAL;
+
+ }
+ }
}
@@ -825,50 +1171,64 @@ static apr_status_t crypto_block_decrypt_init(apr_crypto_block_t **ctx,
apr_size_t *blockSize, const unsigned char *iv,
const apr_crypto_key_t *key, apr_pool_t *p)
{
- PRErrorCode perr;
- apr_crypto_block_t *block = *ctx;
- if (!block) {
- *ctx = block = apr_pcalloc(p, sizeof(apr_crypto_block_t));
- }
- if (!block) {
- return APR_ENOMEM;
- }
- block->f = key->f;
- block->pool = p;
- block->provider = key->provider;
+ switch (key->rec->ktype) {
- apr_pool_cleanup_register(p, block, crypto_block_cleanup_helper,
- apr_pool_cleanup_null);
+ case APR_CRYPTO_KTYPE_PASSPHRASE:
+ case APR_CRYPTO_KTYPE_SECRET: {
- if (key->ivSize) {
- SECItem ivItem;
- if (iv == NULL) {
- return APR_ENOIV; /* Cannot initialise without an IV */
+ PRErrorCode perr;
+ apr_crypto_block_t *block = *ctx;
+ if (!block) {
+ *ctx = block = apr_pcalloc(p, sizeof(apr_crypto_block_t));
+ }
+ if (!block) {
+ return APR_ENOMEM;
+ }
+ 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);
+
+ if (key->ivSize) {
+ SECItem ivItem;
+ if (iv == NULL) {
+ return APR_ENOIV; /* Cannot initialise without an IV */
+ }
+ ivItem.data = (unsigned char*) iv;
+ ivItem.len = key->ivSize;
+ block->secParam = PK11_ParamFromIV(key->cipherMech, &ivItem);
+ }
+ else {
+ block->secParam = PK11_GenerateNewParam(key->cipherMech, key->symKey);
+ }
+ block->blockSize = PK11_GetBlockSize(key->cipherMech, block->secParam);
+ block->ctx = PK11_CreateContextBySymKey(key->cipherMech, CKA_DECRYPT,
+ key->symKey, block->secParam);
+
+ /* did an error occur? */
+ perr = PORT_GetError();
+ if (perr || !block->ctx) {
+ key->f->result->rc = perr;
+ key->f->result->msg = PR_ErrorToName(perr);
+ return APR_EINIT;
}
- ivItem.data = (unsigned char*) iv;
- ivItem.len = key->ivSize;
- block->secParam = PK11_ParamFromIV(key->cipherMech, &ivItem);
- }
- else {
- block->secParam = PK11_GenerateNewParam(key->cipherMech, key->symKey);
- }
- block->blockSize = PK11_GetBlockSize(key->cipherMech, block->secParam);
- block->ctx = PK11_CreateContextBySymKey(key->cipherMech, CKA_DECRYPT,
- key->symKey, block->secParam);
- /* did an error occur? */
- perr = PORT_GetError();
- if (perr || !block->ctx) {
- key->f->result->rc = perr;
- key->f->result->msg = PR_ErrorToName(perr);
- return APR_EINIT;
- }
+ if (blockSize) {
+ *blockSize = PK11_GetBlockSize(key->cipherMech, block->secParam);
+ }
+
+ return APR_SUCCESS;
- if (blockSize) {
- *blockSize = PK11_GetBlockSize(key->cipherMech, block->secParam);
}
+ default: {
- return APR_SUCCESS;
+ return APR_EINVAL;
+
+ }
+ }
}
@@ -894,36 +1254,48 @@ 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 *block)
{
+ switch (block->key->rec->ktype) {
- unsigned char *buffer;
- int outl = (int) *outlen;
- SECStatus s;
- if (!out) {
- *outlen = inlen + block->blockSize;
- return APR_SUCCESS;
- }
- if (!*out) {
- buffer = apr_palloc(block->pool, inlen + block->blockSize);
- if (!buffer) {
- return APR_ENOMEM;
+ case APR_CRYPTO_KTYPE_PASSPHRASE:
+ case APR_CRYPTO_KTYPE_SECRET: {
+
+ unsigned char *buffer;
+ int outl = (int) *outlen;
+ SECStatus s;
+ if (!out) {
+ *outlen = inlen + block->blockSize;
+ return APR_SUCCESS;
+ }
+ if (!*out) {
+ buffer = apr_palloc(block->pool, inlen + block->blockSize);
+ if (!buffer) {
+ return APR_ENOMEM;
+ }
+ apr_crypto_clear(block->pool, buffer, inlen + block->blockSize);
+ *out = buffer;
}
- apr_crypto_clear(block->pool, buffer, inlen + block->blockSize);
- *out = buffer;
- }
- s = PK11_CipherOp(block->ctx, *out, &outl, inlen, (unsigned char*) in,
- inlen);
- if (s != SECSuccess) {
- PRErrorCode perr = PORT_GetError();
- if (perr) {
- block->f->result->rc = perr;
- block->f->result->msg = PR_ErrorToName(perr);
+ s = PK11_CipherOp(block->ctx, *out, &outl, inlen, (unsigned char*) in,
+ inlen);
+ if (s != SECSuccess) {
+ PRErrorCode perr = PORT_GetError();
+ if (perr) {
+ block->f->result->rc = perr;
+ block->f->result->msg = PR_ErrorToName(perr);
+ }
+ return APR_ECRYPT;
}
- return APR_ECRYPT;
+ *outlen = outl;
+
+ return APR_SUCCESS;
+
}
- *outlen = outl;
+ default: {
- return APR_SUCCESS;
+ return APR_EINVAL;
+
+ }
+ }
}
@@ -948,37 +1320,326 @@ static apr_status_t crypto_block_decrypt(unsigned char **out,
static apr_status_t crypto_block_decrypt_finish(unsigned char *out,
apr_size_t *outlen, apr_crypto_block_t *block)
{
+ switch (block->key->rec->ktype) {
- apr_status_t rv = APR_SUCCESS;
- unsigned int outl = *outlen;
+ case APR_CRYPTO_KTYPE_PASSPHRASE:
+ case APR_CRYPTO_KTYPE_SECRET: {
- SECStatus s = PK11_DigestFinal(block->ctx, out, &outl, block->blockSize);
- *outlen = outl;
+ apr_status_t rv = APR_SUCCESS;
+ unsigned int outl = *outlen;
- if (s != SECSuccess) {
- PRErrorCode perr = PORT_GetError();
- if (perr) {
- block->f->result->rc = perr;
- block->f->result->msg = PR_ErrorToName(perr);
+ SECStatus s = PK11_DigestFinal(block->ctx, out, &outl, block->blockSize);
+ *outlen = outl;
+
+ if (s != SECSuccess) {
+ PRErrorCode perr = PORT_GetError();
+ if (perr) {
+ block->f->result->rc = perr;
+ block->f->result->msg = PR_ErrorToName(perr);
+ }
+ rv = APR_ECRYPT;
}
- rv = APR_ECRYPT;
+ crypto_block_cleanup(block);
+
+ return rv;
+
}
- crypto_block_cleanup(block);
+ default: {
- return rv;
+ return APR_EINVAL;
+
+ }
+ }
+
+}
+
+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)
+{
+ PRErrorCode perr;
+ SECStatus s;
+ 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;
+
+ apr_pool_cleanup_register(p, digest, crypto_digest_cleanup_helper,
+ apr_pool_cleanup_null);
+
+ switch (key->rec->ktype) {
+
+ case APR_CRYPTO_KTYPE_HASH: {
+
+ digest->ctx = PK11_CreateDigestContext(key->hashAlg);
+
+ s = PK11_DigestBegin(digest->ctx);
+ if (s != SECSuccess) {
+ PRErrorCode perr = PORT_GetError();
+ if (perr) {
+ digest->f->result->rc = perr;
+ digest->f->result->msg = PR_ErrorToName(perr);
+ }
+ return APR_ECRYPT;
+ }
+
+ return APR_SUCCESS;
+
+ }
+ case APR_CRYPTO_KTYPE_HMAC: {
+
+ digest->secParam = PK11_GenerateNewParam(key->cipherMech, key->symKey);
+ digest->ctx = PK11_CreateContextBySymKey(key->hashMech, CKA_SIGN,
+ key->symKey, digest->secParam);
+
+ /* did an error occur? */
+ perr = PORT_GetError();
+ if (perr || !digest->ctx) {
+ key->f->result->rc = perr;
+ key->f->result->msg = PR_ErrorToName(perr);
+ return APR_EINIT;
+ }
+
+ s = PK11_DigestBegin(digest->ctx);
+ if (s != SECSuccess) {
+ PRErrorCode perr = PORT_GetError();
+ if (perr) {
+ digest->f->result->rc = perr;
+ digest->f->result->msg = PR_ErrorToName(perr);
+ }
+ return APR_ECRYPT;
+ }
+
+ return APR_SUCCESS;
+
+ }
+ case APR_CRYPTO_KTYPE_CMAC: {
+
+ return APR_ENOTIMPL;
+
+ }
+ default: {
+
+ return APR_EINVAL;
+
+ }
+ }
+
+}
+
+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:
+ case APR_CRYPTO_KTYPE_HMAC: {
+
+ SECStatus s;
+
+ s = PK11_DigestOp(digest->ctx, (unsigned char*) in,
+ inlen);
+ if (s != SECSuccess) {
+ PRErrorCode perr = PORT_GetError();
+ if (perr) {
+ digest->f->result->rc = perr;
+ digest->f->result->msg = PR_ErrorToName(perr);
+ }
+ return APR_ECRYPT;
+ }
+
+ return APR_SUCCESS;
+
+ }
+ case APR_CRYPTO_KTYPE_CMAC: {
+
+ return APR_ENOTIMPL;
+
+ }
+ 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:
+ case APR_CRYPTO_KTYPE_HMAC: {
+
+ apr_status_t status = APR_SUCCESS;
+ unsigned int len;
+
+ /* first, determine the signature length */
+ SECStatus s = PK11_DigestFinal(digest->ctx, NULL, &len, 0);
+ if (s != SECSuccess) {
+ PRErrorCode perr = PORT_GetError();
+ if (perr) {
+ digest->f->result->rc = perr;
+ digest->f->result->msg = PR_ErrorToName(perr);
+ }
+ status = APR_ECRYPT;
+ }
+ else {
+
+ 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 */
+ SECStatus s = PK11_DigestFinal(digest->ctx,
+ digest->rec->d.hash.s, &len, digest->rec->d.hash.slen);
+ if (s != SECSuccess) {
+ PRErrorCode perr = PORT_GetError();
+ if (perr) {
+ digest->f->result->rc = perr;
+ digest->f->result->msg = PR_ErrorToName(perr);
+ }
+ status = APR_ECRYPT;
+ }
+
+ break;
+ }
+ 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 */
+ SECStatus s = PK11_DigestFinal(digest->ctx,
+ digest->rec->d.sign.s, &len, digest->rec->d.sign.slen);
+ if (s != SECSuccess) {
+ PRErrorCode perr = PORT_GetError();
+ if (perr) {
+ digest->f->result->rc = perr;
+ digest->f->result->msg = PR_ErrorToName(perr);
+ }
+ 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 */
+ SECStatus s = PK11_DigestFinal(digest->ctx,
+ digest->rec->d.verify.s, &len,
+ digest->rec->d.verify.slen);
+ if (s != SECSuccess) {
+ PRErrorCode perr = PORT_GetError();
+ if (perr) {
+ digest->f->result->rc = perr;
+ digest->f->result->msg = PR_ErrorToName(perr);
+ }
+ status = APR_ECRYPT;
+ } else if (digest->rec->d.verify.slen
+ == digest->rec->d.verify.vlen) {
+ status =
+ apr_crypto_equals(digest->rec->d.verify.s,
+ digest->rec->d.verify.v,
+ digest->rec->d.verify.slen) ?
+ APR_SUCCESS : APR_ENOVERIFY;
+ } else {
+ status = APR_ENOVERIFY;
+ }
+
+ break;
+ }
+ default: {
+ status = APR_ENODIGEST;
+ }
+ }
+
+ }
+
+ crypto_digest_cleanup(digest);
+
+ return status;
+
+ }
+ case APR_CRYPTO_KTYPE_CMAC: {
+
+ return APR_ENOTIMPL;
+
+ }
+ 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;
}
/**
* NSS module.
*/
APR_MODULE_DECLARE_DATA const apr_crypto_driver_t apr_crypto_nss_driver = {
- "nss", crypto_init, crypto_make, crypto_get_block_key_types,
+ "nss", 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
};
diff --git a/crypto/apr_crypto_openssl.c b/crypto/apr_crypto_openssl.c
index b7bed223a..b1b5f9071 100644
--- a/crypto/apr_crypto_openssl.c
+++ b/crypto/apr_crypto_openssl.c
@@ -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 apu_err_t **result,
*/
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)
{
- return apr_crypto_lib_init("openssl", params, result, pool);
+#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)
+{
+ 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(apr_crypto_block_t *ctx)
{
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_helper(void *data)
}
/**
+ * @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_crypto_t **ff,
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_crypto_t **ff,
}
/**
+ * @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_crypto_key_t **k,
}
}
+ 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_crypto_key_t **k,
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_crypto_key_t **k,
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_crypto_key_t **k,
/* 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(apr_crypto_key_t **k, apr_size_t *ivSize,
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(apr_crypto_key_t **k, apr_size_t *ivSize,
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_init(apr_crypto_block_t **ctx,
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;
+ 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;
}
- 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))) {
+
+ /* 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_init(apr_crypto_block_t **ctx,
*/
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(unsigned char **out,
* @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_init(apr_crypto_block_t **ctx,
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_init(apr_crypto_block_t **ctx,
*/
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(unsigned char **out,
* @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;
- if (EVP_DecryptFinal_ex(ctx->cipherCtx, out, &len) == 0) {
- rc = APR_EPADDING;
}
- else {
- *outlen = len;
+ default: {
+
+ return APR_EINVAL;
+
}
- 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
};
diff --git a/include/apr_crypto.h b/include/apr_crypto.h
index bc92b31b5..14ea44d51 100644
--- a/include/apr_crypto.h
+++ b/include/apr_crypto.h
@@ -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 void *buf1, const void *buf2,
* @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_error(const apu_err_t **result,
* @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_block_key_modes(apr_hash_t **modes,
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(apr_crypto_key_t **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_passphrase(apr_crypto_key_t **key,
* @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_block_encrypt_init(
* @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_block_encrypt(unsigned char **out,
* 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_block_encrypt_finish(unsigned char *out,
* @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_block_decrypt_init(
* @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_block_decrypt(unsigned char **out,
* 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_block_decrypt_finish(unsigned char *out,
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_cleanup(apr_crypto_t *f);
* @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
diff --git a/include/apu_errno.h b/include/apu_errno.h
index 58585b714..7d967add6 100644
--- a/include/apu_errno.h
+++ b/include/apu_errno.h
@@ -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)
/** @} */
/**
diff --git a/include/private/apr_crypto_internal.h b/include/private/apr_crypto_internal.h
index 77581bd15..936d6dc50 100644
--- a/include/private/apr_crypto_internal.h
+++ b/include/private/apr_crypto_internal.h
@@ -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.
diff --git a/test/testcrypto.c b/test/testcrypto.c
index bfcb73665..9261d1887 100644
--- a/test/testcrypto.c
+++ b/test/testcrypto.c
@@ -113,6 +113,117 @@ static apr_crypto_t *make(abts_case *tc, apr_pool_t *pool,
}
+static const apr_crypto_key_t *keyhash(abts_case *tc, apr_pool_t *pool,
+ const apr_crypto_driver_t *driver, const apr_crypto_t *f,
+ apr_crypto_block_key_digest_e digest, const char *description)
+{
+ apr_crypto_key_t *key = NULL;
+ const apu_err_t *result = NULL;
+ apr_crypto_key_rec_t *rec = apr_crypto_key_rec_make(APR_CRYPTO_KTYPE_HASH,
+ pool);
+ apr_status_t rv;
+
+ if (!driver) {
+ return NULL;
+ }
+
+ if (!f) {
+ return NULL;
+ }
+
+ rec->k.hash.digest = digest;
+
+ /* init the key */
+ rv = apr_crypto_key(&key, rec, f, pool);
+ if (APR_ENOCIPHER == rv || APR_ENODIGEST == rv) {
+ apr_crypto_error(&result, f);
+ ABTS_NOT_IMPL(tc,
+ apr_psprintf(pool, "skipped: %s %s key return APR_ENOTIMPL: error %d: %s (%s)\n", description, apr_crypto_driver_name(driver), result->rc, result->reason ? result->reason : "", result->msg ? result->msg : ""));
+ return NULL;
+ }
+ else {
+ if (APR_SUCCESS != rv) {
+ apr_crypto_error(&result, f);
+ fprintf(stderr, "key: %s %s apr error %d / native error %d: %s (%s)\n",
+ description, apr_crypto_driver_name(driver), rv, result->rc,
+ result->reason ? result->reason : "",
+ result->msg ? result->msg : "");
+ }
+ ABTS_ASSERT(tc, "apr_crypto_key returned APR_EKEYLENGTH", rv != APR_EKEYLENGTH);
+ ABTS_ASSERT(tc, "apr_crypto_key returned APR_ENOKEY", rv != APR_ENOKEY);
+ ABTS_ASSERT(tc, "apr_crypto_key returned APR_EPADDING",
+ rv != APR_EPADDING);
+ ABTS_ASSERT(tc, "apr_crypto_key returned APR_EKEYTYPE",
+ rv != APR_EKEYTYPE);
+ ABTS_ASSERT(tc, "failed to apr_crypto_key", rv == APR_SUCCESS);
+ ABTS_ASSERT(tc, "apr_crypto_key returned NULL context", key != NULL);
+ }
+ if (rv) {
+ return NULL;
+ }
+ return key;
+
+}
+
+static const apr_crypto_key_t *keyhmac(abts_case *tc, apr_pool_t *pool,
+ const apr_crypto_driver_t *driver, const apr_crypto_t *f,
+ apr_crypto_block_key_digest_e digest, apr_crypto_block_key_type_e type,
+ apr_crypto_block_key_mode_e mode, int doPad, apr_size_t secretLen,
+ const char *description)
+{
+ apr_crypto_key_t *key = NULL;
+ const apu_err_t *result = NULL;
+ apr_crypto_key_rec_t *rec = apr_crypto_key_rec_make(APR_CRYPTO_KTYPE_HMAC,
+ pool);
+ apr_status_t rv;
+
+ if (!driver) {
+ return NULL;
+ }
+
+ if (!f) {
+ return NULL;
+ }
+
+ rec->type = type;
+ rec->mode = mode;
+ rec->pad = doPad;
+ rec->k.hmac.digest = digest;
+ rec->k.hmac.secret = apr_pcalloc(pool, secretLen);
+ rec->k.hmac.secretLen = secretLen;
+
+ /* init the key */
+ rv = apr_crypto_key(&key, rec, f, pool);
+ if (APR_ENOCIPHER == rv || APR_ENODIGEST == rv) {
+ apr_crypto_error(&result, f);
+ ABTS_NOT_IMPL(tc,
+ apr_psprintf(pool, "skipped: %s %s key return APR_ENOTIMPL: error %d: %s (%s)\n", description, apr_crypto_driver_name(driver), result->rc, result->reason ? result->reason : "", result->msg ? result->msg : ""));
+ return NULL;
+ }
+ else {
+ if (APR_SUCCESS != rv) {
+ apr_crypto_error(&result, f);
+ fprintf(stderr, "key: %s %s apr error %d / native error %d: %s (%s)\n",
+ description, apr_crypto_driver_name(driver), rv, result->rc,
+ result->reason ? result->reason : "",
+ result->msg ? result->msg : "");
+ }
+ ABTS_ASSERT(tc, "apr_crypto_key returned APR_EKEYLENGTH", rv != APR_EKEYLENGTH);
+ ABTS_ASSERT(tc, "apr_crypto_key returned APR_ENOKEY", rv != APR_ENOKEY);
+ ABTS_ASSERT(tc, "apr_crypto_key returned APR_EPADDING",
+ rv != APR_EPADDING);
+ ABTS_ASSERT(tc, "apr_crypto_key returned APR_EKEYTYPE",
+ rv != APR_EKEYTYPE);
+ ABTS_ASSERT(tc, "failed to apr_crypto_key", rv == APR_SUCCESS);
+ ABTS_ASSERT(tc, "apr_crypto_key returned NULL context", key != NULL);
+ }
+ if (rv) {
+ return NULL;
+ }
+ return key;
+
+}
+
static const apr_crypto_key_t *keysecret(abts_case *tc, apr_pool_t *pool,
const apr_crypto_driver_t *driver, const apr_crypto_t *f,
apr_crypto_block_key_type_e type, apr_crypto_block_key_mode_e mode,
@@ -120,14 +231,18 @@ static const apr_crypto_key_t *keysecret(abts_case *tc, apr_pool_t *pool,
{
apr_crypto_key_t *key = NULL;
const apu_err_t *result = NULL;
- apr_crypto_key_rec_t *rec = apr_pcalloc(pool, sizeof(apr_crypto_key_rec_t));
+ apr_crypto_key_rec_t *rec = apr_crypto_key_rec_make(APR_CRYPTO_KTYPE_SECRET,
+ pool);
apr_status_t rv;
+ if (!driver) {
+ return NULL;
+ }
+
if (!f) {
return NULL;
}
- rec->ktype = APR_CRYPTO_KTYPE_SECRET;
rec->type = type;
rec->mode = mode;
rec->pad = doPad;
@@ -178,6 +293,10 @@ static const apr_crypto_key_t *passphrase(abts_case *tc, apr_pool_t *pool,
const char *salt = "salt";
apr_status_t rv;
+ if (!driver) {
+ return NULL;
+ }
+
if (!f) {
return NULL;
}
@@ -228,6 +347,10 @@ static const apr_crypto_key_t *keypassphrase(abts_case *tc, apr_pool_t *pool,
apr_crypto_key_rec_t *rec = apr_pcalloc(pool, sizeof(apr_crypto_key_rec_t));
apr_status_t rv;
+ if (!driver) {
+ return NULL;
+ }
+
if (!f) {
return NULL;
}
@@ -450,6 +573,275 @@ static unsigned char *decrypt_block(abts_case *tc, apr_pool_t *pool,
}
+static apr_status_t sign_block(abts_case *tc, apr_pool_t *pool,
+ const apr_crypto_driver_t *driver, const apr_crypto_t *f,
+ const apr_crypto_key_t *key, const unsigned char *in,
+ const apr_size_t inlen, unsigned char **signature,
+ apr_size_t *signatureLen,
+ apr_size_t *blockSize, const char *description)
+{
+
+ apr_crypto_digest_t *digest = NULL;
+ const apu_err_t *result = NULL;
+ apr_crypto_digest_rec_t *rec = apr_crypto_digest_rec_make(
+ APR_CRYPTO_DTYPE_SIGN, pool);
+ apr_status_t rv;
+
+ if (!driver || !f || !key || !in) {
+ return APR_EGENERAL;
+ }
+
+ /* init the signature */
+ rv = apr_crypto_digest_init(&digest, key, rec, pool);
+ if (APR_ENOTIMPL == rv) {
+ ABTS_NOT_IMPL(tc, "apr_crypto_digest_init returned APR_ENOTIMPL");
+ }
+ else {
+ if (APR_SUCCESS != rv) {
+ apr_crypto_error(&result, f);
+ fprintf(stderr,
+ "sign_init: %s %s (APR %d) native error %d: %s (%s)\n",
+ description, apr_crypto_driver_name(driver), rv, result->rc,
+ result->reason ? result->reason : "",
+ result->msg ? result->msg : "");
+ }
+ ABTS_ASSERT(tc, "apr_crypto_digest_init returned APR_ENOKEY",
+ rv != APR_ENOKEY);
+ ABTS_ASSERT(tc, "apr_crypto_digest_init returned APR_ENOIV",
+ rv != APR_ENOIV);
+ ABTS_ASSERT(tc, "apr_crypto_digest_init returned APR_EKEYTYPE",
+ rv != APR_EKEYTYPE);
+ ABTS_ASSERT(tc, "apr_crypto_digest_init returned APR_EKEYLENGTH",
+ rv != APR_EKEYLENGTH);
+ ABTS_ASSERT(tc,
+ "apr_crypto_digest_init returned APR_ENOTENOUGHENTROPY",
+ rv != APR_ENOTENOUGHENTROPY);
+ ABTS_ASSERT(tc, "failed to apr_crypto_digest_init",
+ rv == APR_SUCCESS);
+ ABTS_ASSERT(tc, "apr_crypto_digest_init returned NULL context",
+ digest != NULL);
+ }
+ if (!digest || rv) {
+ return rv;
+ }
+
+ /* sign the block */
+ rv = apr_crypto_digest_update(digest, in, inlen);
+ if (APR_SUCCESS != rv) {
+ apr_crypto_error(&result, f);
+ fprintf(stderr, "sign: %s %s (APR %d) native error %d: %s (%s)\n",
+ description, apr_crypto_driver_name(driver), rv, result->rc,
+ result->reason ? result->reason : "",
+ result->msg ? result->msg : "");
+ }
+ ABTS_ASSERT(tc, "apr_crypto_digest returned APR_ECRYPT", rv != APR_ECRYPT);
+ ABTS_ASSERT(tc, "failed to apr_crypto_digest", rv == APR_SUCCESS);
+ if (rv) {
+ return rv;
+ }
+
+ /* finalise the sign */
+ rv = apr_crypto_digest_final(digest);
+ if (APR_SUCCESS != rv) {
+ apr_crypto_error(&result, f);
+ fprintf(stderr,
+ "sign_finish: %s %s (APR %d) native error %d: %s (%s)\n",
+ description, apr_crypto_driver_name(driver), rv, result->rc,
+ result->reason ? result->reason : "",
+ result->msg ? result->msg : "");
+ }
+ ABTS_ASSERT(tc, "apr_crypto_digest_final returned APR_ECRYPT", rv != APR_ECRYPT);
+ ABTS_ASSERT(tc, "apr_crypto_digest_final returned APR_EPADDING", rv != APR_EPADDING);
+ ABTS_ASSERT(tc, "apr_crypto_digest_final returned APR_ENOSPACE", rv != APR_ENOSPACE);
+ ABTS_ASSERT(tc, "failed to apr_crypto_digest_final", rv == APR_SUCCESS);
+ ABTS_ASSERT(tc, "apr_crypto_digest_final failed to allocate buffer", rec->d.sign.s != NULL);
+
+ apr_crypto_digest_cleanup(digest);
+
+ *signature = rec->d.sign.s;
+ *signatureLen = rec->d.sign.slen;
+
+ return rv;
+
+}
+
+static apr_status_t hash_block(abts_case *tc, apr_pool_t *pool,
+ const apr_crypto_driver_t *driver, const apr_crypto_t *f,
+ const apr_crypto_key_t *key, const unsigned char *in,
+ const apr_size_t inlen, unsigned char **hash,
+ apr_size_t *hashLen,
+ apr_size_t *blockSize, const char *description)
+{
+
+ apr_crypto_digest_t *digest = NULL;
+ const apu_err_t *result = NULL;
+ apr_crypto_digest_rec_t *rec = apr_crypto_digest_rec_make(
+ APR_CRYPTO_DTYPE_HASH, pool);
+ apr_status_t rv;
+
+ if (!driver || !f || !key || !in) {
+ return APR_EGENERAL;
+ }
+
+ rec->d.hash.digest = APR_CRYPTO_DIGEST_SHA256;
+
+ /* init the signature */
+ rv = apr_crypto_digest_init(&digest, key, rec, pool);
+ if (APR_ENOTIMPL == rv) {
+ ABTS_NOT_IMPL(tc, "apr_crypto_digest_init returned APR_ENOTIMPL");
+ }
+ else {
+ if (APR_SUCCESS != rv) {
+ apr_crypto_error(&result, f);
+ fprintf(stderr,
+ "sign_init: %s %s (APR %d) native error %d: %s (%s)\n",
+ description, apr_crypto_driver_name(driver), rv, result->rc,
+ result->reason ? result->reason : "",
+ result->msg ? result->msg : "");
+ }
+ ABTS_ASSERT(tc, "apr_crypto_digest_init returned APR_ENOKEY",
+ rv != APR_ENOKEY);
+ ABTS_ASSERT(tc, "apr_crypto_digest_init returned APR_ENOIV",
+ rv != APR_ENOIV);
+ ABTS_ASSERT(tc, "apr_crypto_digest_init returned APR_EKEYTYPE",
+ rv != APR_EKEYTYPE);
+ ABTS_ASSERT(tc, "apr_crypto_digest_init returned APR_EKEYLENGTH",
+ rv != APR_EKEYLENGTH);
+ ABTS_ASSERT(tc,
+ "apr_crypto_digest_init returned APR_ENOTENOUGHENTROPY",
+ rv != APR_ENOTENOUGHENTROPY);
+ ABTS_ASSERT(tc, "failed to apr_crypto_digest_init",
+ rv == APR_SUCCESS);
+ ABTS_ASSERT(tc, "apr_crypto_digest_init returned NULL context",
+ digest != NULL);
+ }
+ if (!digest || rv) {
+ return rv;
+ }
+
+ /* sign the block */
+ rv = apr_crypto_digest_update(digest, in, inlen);
+ if (APR_SUCCESS != rv) {
+ apr_crypto_error(&result, f);
+ fprintf(stderr, "sign: %s %s (APR %d) native error %d: %s (%s)\n",
+ description, apr_crypto_driver_name(driver), rv, result->rc,
+ result->reason ? result->reason : "",
+ result->msg ? result->msg : "");
+ }
+ ABTS_ASSERT(tc, "apr_crypto_digest returned APR_ECRYPT", rv != APR_ECRYPT);
+ ABTS_ASSERT(tc, "failed to apr_crypto_digest", rv == APR_SUCCESS);
+ if (rv) {
+ return rv;
+ }
+
+ /* finalise the sign */
+ rv = apr_crypto_digest_final(digest);
+ if (APR_SUCCESS != rv) {
+ apr_crypto_error(&result, f);
+ fprintf(stderr,
+ "sign_finish: %s %s (APR %d) native error %d: %s (%s)\n",
+ description, apr_crypto_driver_name(driver), rv, result->rc,
+ result->reason ? result->reason : "",
+ result->msg ? result->msg : "");
+ }
+ ABTS_ASSERT(tc, "apr_crypto_digest_final returned APR_ECRYPT", rv != APR_ECRYPT);
+ ABTS_ASSERT(tc, "apr_crypto_digest_final returned APR_EPADDING", rv != APR_EPADDING);
+ ABTS_ASSERT(tc, "apr_crypto_digest_final returned APR_ENOSPACE", rv != APR_ENOSPACE);
+ ABTS_ASSERT(tc, "failed to apr_crypto_digest_final", rv == APR_SUCCESS);
+ ABTS_ASSERT(tc, "apr_crypto_digest_final failed to allocate buffer", rec->d.hash.s != NULL);
+
+ apr_crypto_digest_cleanup(digest);
+
+ *hash = rec->d.hash.s;
+ *hashLen = rec->d.hash.slen;
+
+ return rv;
+
+}
+
+static apr_status_t verify_block(abts_case *tc, apr_pool_t *pool,
+ const apr_crypto_driver_t *driver, const apr_crypto_t *f,
+ const apr_crypto_key_t *key, const unsigned char *in,
+ apr_size_t inlen, const unsigned char *signature,
+ apr_size_t signatureLen,
+ apr_size_t *blockSize, const char *description)
+{
+
+ apr_crypto_digest_t *digest = NULL;
+ const apu_err_t *result = NULL;
+ apr_crypto_digest_rec_t *rec = apr_crypto_digest_rec_make(
+ APR_CRYPTO_DTYPE_VERIFY, pool);
+ apr_status_t rv;
+
+ if (!driver || !f || !key || !in || !signature) {
+ return APR_EGENERAL;
+ }
+
+ rec->d.verify.v = signature;
+ rec->d.verify.vlen = signatureLen;
+
+ /* init the decryption */
+ rv = apr_crypto_digest_init(&digest, key, rec, pool);
+ if (APR_ENOTIMPL == rv) {
+ ABTS_NOT_IMPL(tc, "apr_crypto_digest_init returned APR_ENOTIMPL");
+ }
+ else {
+ if (APR_SUCCESS != rv) {
+ apr_crypto_error(&result, f);
+ fprintf(stderr,
+ "digest_init: %s %s (APR %d) native error %d: %s (%s)\n",
+ description, apr_crypto_driver_name(driver), rv, result->rc,
+ result->reason ? result->reason : "",
+ result->msg ? result->msg : "");
+ }
+ ABTS_ASSERT(tc, "apr_crypto_digest_init returned APR_ENOKEY", rv != APR_ENOKEY);
+ ABTS_ASSERT(tc, "apr_crypto_digest_init returned APR_ENOIV", rv != APR_ENOIV);
+ ABTS_ASSERT(tc, "apr_crypto_digest_init returned APR_EKEYTYPE", rv != APR_EKEYTYPE);
+ ABTS_ASSERT(tc, "apr_crypto_digest_init returned APR_EKEYLENGTH", rv != APR_EKEYLENGTH);
+ ABTS_ASSERT(tc, "failed to apr_crypto_digest_init", rv == APR_SUCCESS);
+ ABTS_ASSERT(tc, "apr_crypto_digest_init returned NULL context", digest != NULL);
+ }
+ if (!digest || rv) {
+ return APR_EGENERAL;
+ }
+
+ /* decrypt the block */
+ rv = apr_crypto_digest_update(digest, in, inlen);
+ if (APR_SUCCESS != rv) {
+ apr_crypto_error(&result, f);
+ fprintf(stderr, "decrypt: %s %s (APR %d) native error %d: %s (%s)\n",
+ description, apr_crypto_driver_name(driver), rv, result->rc,
+ result->reason ? result->reason : "",
+ result->msg ? result->msg : "");
+ }
+ ABTS_ASSERT(tc, "apr_crypto_digest returned APR_ECRYPT", rv != APR_ECRYPT);
+ ABTS_ASSERT(tc, "failed to apr_crypto_digest", rv == APR_SUCCESS);
+ ABTS_ASSERT(tc, "apr_crypto_digest failed to allocate buffer", signature != NULL);
+ if (rv) {
+ return APR_EGENERAL;
+ }
+
+ /* finalise the decryption */
+ rv = apr_crypto_digest_final(digest);
+ if (APR_SUCCESS != rv) {
+ apr_crypto_error(&result, f);
+ fprintf(stderr,
+ "verify_finish: %s %s (APR %d) native error %d: %s (%s)\n",
+ description, apr_crypto_driver_name(driver), rv, result->rc,
+ result->reason ? result->reason : "",
+ result->msg ? result->msg : "");
+ }
+ ABTS_ASSERT(tc, "apr_crypto_digest_final returned APR_ECRYPT", rv != APR_ECRYPT);
+ ABTS_ASSERT(tc, "apr_crypto_digest_final returned APR_EPADDING", rv != APR_EPADDING);
+ ABTS_ASSERT(tc, "apr_crypto_digest_final returned APR_ENOSPACE", rv != APR_ENOSPACE);
+ ABTS_ASSERT(tc, "failed to apr_crypto_digest_final", rv == APR_SUCCESS);
+
+ apr_crypto_digest_cleanup(digest);
+
+ return rv;
+
+}
+
/**
* Interoperability test.
*
@@ -550,6 +942,130 @@ static void crypto_block_cross(abts_case *tc, apr_pool_t *pool,
}
/**
+ * Interoperability test.
+ *
+ * data must point at an array of two driver structures. Data will be signed
+ * with the first driver, and verified with the second.
+ *
+ * If the two drivers interoperate, the test passes.
+ */
+static void crypto_cross_hash(abts_case *tc, apr_pool_t *pool,
+ const apr_crypto_driver_t **drivers,
+ const apr_crypto_block_key_digest_e digest,
+ const unsigned char *in, apr_size_t inlen,
+ const char *description)
+{
+ const apr_crypto_driver_t *driver1 = drivers[0];
+ const apr_crypto_driver_t *driver2 = drivers[1];
+ apr_crypto_t *f1 = NULL;
+ apr_crypto_t *f2 = NULL;
+ const apr_crypto_key_t *key7 = NULL;
+ const apr_crypto_key_t *key8 = NULL;
+
+ apr_size_t blockSize = 0;
+ unsigned char *hash1 = NULL;
+ unsigned char *hash2 = NULL;
+ apr_size_t hash1Len = 0;
+ apr_size_t hash2Len = 0;
+
+ apr_status_t rv;
+
+ f1 = make(tc, pool, driver1);
+ f2 = make(tc, pool, driver2);
+
+ key7 = keyhash(tc, pool, driver1, f1, digest, description);
+ key8 = keyhash(tc, pool, driver2, f2, digest, description);
+
+ blockSize = 0;
+ rv = hash_block(tc, pool, driver1, f1, key7, in, inlen,
+ &hash1, &hash1Len, &blockSize, description);
+
+ if (APR_SUCCESS != rv && driver1 && driver2) {
+ fprintf(stderr, "key hash cross error %d: %s %s/%s\n", rv, description,
+ apr_crypto_driver_name(driver1),
+ apr_crypto_driver_name(driver2));
+ }
+
+ rv = hash_block(tc, pool, driver2, f2, key8, in,
+ inlen, &hash2, &hash2Len, &blockSize,
+ description);
+
+ if (APR_SUCCESS != rv && driver1 && driver2) {
+ fprintf(stderr, "key hash cross error %d: %s %s/%s\n", rv, description,
+ apr_crypto_driver_name(driver1),
+ apr_crypto_driver_name(driver2));
+ }
+
+ if (driver1 && driver2
+ && (!hash1 || !hash2 || hash1Len != hash2Len
+ || memcmp(hash1, hash2, hash1Len))) {
+ fprintf(stderr, "key hash cross mismatch (hash): %s %s/%s\n", description,
+ apr_crypto_driver_name(driver1),
+ apr_crypto_driver_name(driver2));
+ }
+
+}
+
+/**
+ * Interoperability test.
+ *
+ * data must point at an array of two driver structures. Data will be signed
+ * with the first driver, and verified with the second.
+ *
+ * If the two drivers interoperate, the test passes.
+ */
+static void crypto_cross_sign(abts_case *tc, apr_pool_t *pool,
+ const apr_crypto_driver_t **drivers,
+ const apr_crypto_block_key_digest_e digest,
+ const apr_crypto_block_key_type_e type,
+ const apr_crypto_block_key_mode_e mode, int doPad,
+ const unsigned char *in, apr_size_t inlen, apr_size_t secretLen,
+ const char *description)
+{
+ const apr_crypto_driver_t *driver1 = drivers[0];
+ const apr_crypto_driver_t *driver2 = drivers[1];
+ apr_crypto_t *f1 = NULL;
+ apr_crypto_t *f2 = NULL;
+ const apr_crypto_key_t *key7 = NULL;
+ const apr_crypto_key_t *key8 = NULL;
+
+ apr_size_t blockSize = 0;
+ unsigned char *signature = NULL;
+ apr_size_t signatureLen = 0;
+
+ apr_status_t rv;
+
+ f1 = make(tc, pool, driver1);
+ f2 = make(tc, pool, driver2);
+
+ key7 = keyhmac(tc, pool, driver1, f1, digest, type, mode, doPad, secretLen,
+ description);
+ key8 = keyhmac(tc, pool, driver2, f2, digest, type, mode, doPad, secretLen,
+ description);
+
+ blockSize = 0;
+ rv = sign_block(tc, pool, driver1, f1, key7, in, inlen,
+ &signature, &signatureLen, &blockSize, description);
+
+ if (APR_SUCCESS != rv && driver1 && driver2) {
+ fprintf(stderr, "key hmac cross mismatch (sign): %s %s/%s\n", description,
+ apr_crypto_driver_name(driver1),
+ apr_crypto_driver_name(driver2));
+ }
+
+ rv = verify_block(tc, pool, driver2, f2, key8, in,
+ inlen, signature, signatureLen, &blockSize,
+ description);
+
+ if (APR_SUCCESS != rv && driver1 && driver2) {
+ fprintf(stderr, "key hmac cross mismatch (verify): %s %s/%s\n", description,
+ apr_crypto_driver_name(driver1),
+ apr_crypto_driver_name(driver2));
+ }
+
+}
+
+/**
* Test initialisation.
*/
static void test_crypto_init(abts_case *tc, void *data)
@@ -559,10 +1075,7 @@ static void test_crypto_init(abts_case *tc, void *data)
apr_pool_create(&pool, NULL);
- /* Use root pool (top level init) so that the crypto lib is
- * not cleanup on pool destroy below (e.g. openssl can't re-init).
- */
- rv = apr_crypto_init(apr_pool_parent_get(pool));
+ rv = apr_crypto_init(pool);
ABTS_ASSERT(tc, "failed to init apr_crypto", rv == APR_SUCCESS);
apr_pool_destroy(pool);
@@ -661,6 +1174,62 @@ static void test_crypto_block_openssl(abts_case *tc, void *data)
}
/**
+ * Simple test of OpenSSL block signatures.
+ */
+static void test_crypto_digest_openssl(abts_case *tc, void *data)
+{
+ apr_pool_t *pool = NULL;
+ const apr_crypto_driver_t *drivers[] = { NULL, NULL };
+
+ const unsigned char *in = (const unsigned char *) ALIGNED_STRING;
+ apr_size_t inlen = sizeof(ALIGNED_STRING);
+
+ apr_pool_create(&pool, NULL);
+ drivers[0] = get_openssl_driver(tc, pool);
+ drivers[1] = get_openssl_driver(tc, pool);
+ crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_3DES_192, APR_MODE_CBC, 0, in, inlen, 24,
+ "KEY_3DES_192/MODE_CBC");
+ crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_3DES_192, APR_MODE_ECB, 0, in, inlen, 24,
+ "KEY_3DES_192/MODE_ECB");
+ crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_AES_256, APR_MODE_CBC, 0, in, inlen, 32,
+ "KEY_AES_256/MODE_CBC");
+ crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_AES_256, APR_MODE_ECB, 0, in, inlen, 32,
+ "KEY_AES_256/MODE_ECB");
+ crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_AES_192, APR_MODE_CBC, 0, in, inlen, 24,
+ "KEY_AES_192/MODE_CBC");
+ crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_AES_192, APR_MODE_ECB, 0, in, inlen, 24,
+ "KEY_AES_192/MODE_ECB");
+ crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_AES_128, APR_MODE_CBC, 0, in, inlen, 16,
+ "KEY_AES_128/MODE_CBC");
+ crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_AES_128, APR_MODE_ECB, 0, in, inlen, 16,
+ "KEY_AES_128/MODE_ECB");
+
+ crypto_cross_hash(tc, pool, drivers, APR_CRYPTO_DIGEST_MD5, in, inlen,
+ "DIGEST MD5");
+ crypto_cross_hash(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA1, in, inlen,
+ "DIGEST SHA1");
+ crypto_cross_hash(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA224, in, inlen,
+ "DIGEST SHA224");
+ crypto_cross_hash(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256, in, inlen,
+ "DIGEST SHA256");
+ crypto_cross_hash(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA384, in, inlen,
+ "DIGEST SHA384");
+ crypto_cross_hash(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA512, in, inlen,
+ "DIGEST SHA512");
+
+ apr_pool_destroy(pool);
+
+}
+
+/**
* Simple test of NSS block crypt.
*/
static void test_crypto_block_nss(abts_case *tc, void *data)
@@ -695,6 +1264,61 @@ static void test_crypto_block_nss(abts_case *tc, void *data)
}
/**
+ * Simple test of NSS block sign/verify.
+ */
+static void test_crypto_digest_nss(abts_case *tc, void *data)
+{
+ apr_pool_t *pool = NULL;
+ const apr_crypto_driver_t *drivers[] = { NULL, NULL };
+
+ const unsigned char *in = (const unsigned char *) ALIGNED_STRING;
+ apr_size_t inlen = sizeof(ALIGNED_STRING);
+
+ apr_pool_create(&pool, NULL);
+ drivers[0] = get_nss_driver(tc, pool);
+ drivers[1] = get_nss_driver(tc, pool);
+ crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_3DES_192, APR_MODE_CBC, 0, in, inlen, 24,
+ "KEY_3DES_192/MODE_CBC");
+ /* KEY_3DES_192 / MODE_ECB doesn't work on NSS */
+ /* crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256, KEY_3DES_192, MODE_ECB, 0, in, inlen, "KEY_3DES_192/MODE_ECB"); */
+ crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_AES_256, APR_MODE_CBC, 0, in, inlen, 32,
+ "KEY_AES_256/MODE_CBC");
+ crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_AES_256, APR_MODE_ECB, 0, in, inlen, 32,
+ "KEY_AES_256/MODE_ECB");
+ crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_AES_192, APR_MODE_CBC, 0, in, inlen, 24,
+ "KEY_AES_192/MODE_CBC");
+ crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_AES_192, APR_MODE_ECB, 0, in, inlen, 24,
+ "KEY_AES_192/MODE_ECB");
+ crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_AES_128, APR_MODE_CBC, 0, in, inlen, 16,
+ "KEY_AES_128/MODE_CBC");
+ crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_AES_128, APR_MODE_ECB, 0, in, inlen, 16,
+ "KEY_AES_128/MODE_ECB");
+
+ crypto_cross_hash(tc, pool, drivers, APR_CRYPTO_DIGEST_MD5, in, inlen,
+ "DIGEST MD5");
+ crypto_cross_hash(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA1, in, inlen,
+ "DIGEST SHA1");
+ crypto_cross_hash(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA224, in, inlen,
+ "DIGEST SHA224");
+ crypto_cross_hash(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256, in, inlen,
+ "DIGEST SHA256");
+ crypto_cross_hash(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA384, in, inlen,
+ "DIGEST SHA384");
+ crypto_cross_hash(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA512, in, inlen,
+ "DIGEST SHA512");
+
+ apr_pool_destroy(pool);
+
+}
+
+/**
* Simple test of Common Crypto block crypt.
*/
static void test_crypto_block_commoncrypto(abts_case *tc, void *data)
@@ -729,6 +1353,62 @@ static void test_crypto_block_commoncrypto(abts_case *tc, void *data)
}
/**
+ * Simple test of Common Crypto block sign.
+ */
+static void test_crypto_digest_commoncrypto(abts_case *tc, void *data)
+{
+ apr_pool_t *pool = NULL;
+ const apr_crypto_driver_t *drivers[] = { NULL, NULL };
+
+ const unsigned char *in = (const unsigned char *) ALIGNED_STRING;
+ apr_size_t inlen = sizeof(ALIGNED_STRING);
+
+ apr_pool_create(&pool, NULL);
+ drivers[0] = get_commoncrypto_driver(tc, pool);
+ drivers[1] = get_commoncrypto_driver(tc, pool);
+ crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_3DES_192, APR_MODE_CBC, 0, in, inlen, 24,
+ "KEY_3DES_192/MODE_CBC");
+ crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_3DES_192, APR_MODE_ECB, 0, in, inlen, 24,
+ "KEY_3DES_192/MODE_ECB");
+ crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_AES_256, APR_MODE_CBC, 0, in, inlen, 32,
+ "KEY_AES_256/MODE_CBC");
+ crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_AES_256, APR_MODE_ECB, 0, in, inlen, 32,
+ "KEY_AES_256/MODE_ECB");
+ crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_AES_192, APR_MODE_CBC, 0, in, inlen, 24,
+ "KEY_AES_192/MODE_CBC");
+ crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_AES_192, APR_MODE_ECB, 0, in, inlen, 24,
+ "KEY_AES_192/MODE_ECB");
+ crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_AES_128, APR_MODE_CBC, 0, in, inlen, 16,
+ "KEY_AES_128/MODE_CBC");
+ crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_AES_128, APR_MODE_ECB, 0, in, inlen, 16,
+ "KEY_AES_128/MODE_ECB");
+
+ crypto_cross_hash(tc, pool, drivers, APR_CRYPTO_DIGEST_MD5, in, inlen,
+ "DIGEST MD5");
+ crypto_cross_hash(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA1, in, inlen,
+ "DIGEST SHA1");
+ crypto_cross_hash(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA224, in, inlen,
+ "DIGEST SHA224");
+ crypto_cross_hash(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256, in, inlen,
+ "DIGEST SHA256");
+ crypto_cross_hash(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA384, in, inlen,
+ "DIGEST SHA384");
+ crypto_cross_hash(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA512, in, inlen,
+ "DIGEST SHA512");
+
+ apr_pool_destroy(pool);
+
+}
+
+/**
* Encrypt NSS, decrypt OpenSSL.
*/
static void test_crypto_block_nss_openssl(abts_case *tc, void *data)
@@ -801,6 +1481,120 @@ static void test_crypto_block_openssl_nss(abts_case *tc, void *data)
}
/**
+ * Sign NSS, verify OpenSSL.
+ */
+static void test_crypto_digest_nss_openssl(abts_case *tc, void *data)
+{
+ apr_pool_t *pool = NULL;
+ const apr_crypto_driver_t *drivers[] = { NULL, NULL };
+
+ const unsigned char *in = (const unsigned char *) ALIGNED_STRING;
+ apr_size_t inlen = sizeof(ALIGNED_STRING);
+
+ apr_pool_create(&pool, NULL);
+ drivers[0] = get_nss_driver(tc, pool);
+ drivers[1] = get_openssl_driver(tc, pool);
+ crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_3DES_192, APR_MODE_CBC, 0, in, inlen, 24,
+ "KEY_3DES_192/MODE_CBC");
+ /* KEY_3DES_192 / MODE_ECB doesn't work on NSS */
+/* crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_3DES_192, APR_MODE_ECB, 0, in, inlen, 24,
+ "KEY_3DES_192/MODE_ECB");*/
+ crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_AES_256, APR_MODE_CBC, 0, in, inlen, 32,
+ "KEY_AES_256/MODE_CBC");
+ crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_AES_256, APR_MODE_ECB, 0, in, inlen, 32,
+ "KEY_AES_256/MODE_ECB");
+ crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_AES_192, APR_MODE_CBC, 0, in, inlen, 24,
+ "KEY_AES_192/MODE_CBC");
+ crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_AES_192, APR_MODE_ECB, 0, in, inlen, 24,
+ "KEY_AES_192/MODE_ECB");
+ crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_AES_128, APR_MODE_CBC, 0, in, inlen, 16,
+ "KEY_AES_128/MODE_CBC");
+ crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_AES_128, APR_MODE_ECB, 0, in, inlen, 16,
+ "KEY_AES_128/MODE_ECB");
+
+ crypto_cross_hash(tc, pool, drivers, APR_CRYPTO_DIGEST_MD5, in, inlen,
+ "DIGEST MD5");
+ crypto_cross_hash(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA1, in, inlen,
+ "DIGEST SHA1");
+ crypto_cross_hash(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA224, in, inlen,
+ "DIGEST SHA224");
+ crypto_cross_hash(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256, in, inlen,
+ "DIGEST SHA256");
+ crypto_cross_hash(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA384, in, inlen,
+ "DIGEST SHA384");
+ crypto_cross_hash(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA512, in, inlen,
+ "DIGEST SHA512");
+
+ apr_pool_destroy(pool);
+
+}
+
+/**
+ * Sign OpenSSL, verify NSS.
+ */
+static void test_crypto_digest_openssl_nss(abts_case *tc, void *data)
+{
+ apr_pool_t *pool = NULL;
+ const apr_crypto_driver_t *drivers[] = { NULL, NULL };
+
+ const unsigned char *in = (const unsigned char *) ALIGNED_STRING;
+ apr_size_t inlen = sizeof(ALIGNED_STRING);
+
+ apr_pool_create(&pool, NULL);
+ drivers[0] = get_openssl_driver(tc, pool);
+ drivers[1] = get_nss_driver(tc, pool);
+ crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_3DES_192, APR_MODE_CBC, 0, in, inlen, 24,
+ "KEY_3DES_192/MODE_CBC");
+ /* KEY_3DES_192 / MODE_ECB doesn't work on NSS */
+/* crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_3DES_192, APR_MODE_ECB, 0, in, inlen, 24,
+ "KEY_3DES_192/MODE_ECB");*/
+ crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_AES_256, APR_MODE_CBC, 0, in, inlen, 32,
+ "KEY_AES_256/MODE_CBC");
+ crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_AES_256, APR_MODE_ECB, 0, in, inlen, 32,
+ "KEY_AES_256/MODE_ECB");
+ crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_AES_192, APR_MODE_CBC, 0, in, inlen, 24,
+ "KEY_AES_192/MODE_CBC");
+ crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_AES_192, APR_MODE_ECB, 0, in, inlen, 24,
+ "KEY_AES_192/MODE_ECB");
+ crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_AES_128, APR_MODE_CBC, 0, in, inlen, 16,
+ "KEY_AES_128/MODE_CBC");
+ crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_AES_128, APR_MODE_ECB, 0, in, inlen, 16,
+ "KEY_AES_128/MODE_ECB");
+
+ crypto_cross_hash(tc, pool, drivers, APR_CRYPTO_DIGEST_MD5, in, inlen,
+ "DIGEST MD5");
+ crypto_cross_hash(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA1, in, inlen,
+ "DIGEST SHA1");
+ crypto_cross_hash(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA224, in, inlen,
+ "DIGEST SHA224");
+ crypto_cross_hash(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256, in, inlen,
+ "DIGEST SHA256");
+ crypto_cross_hash(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA384, in, inlen,
+ "DIGEST SHA384");
+ crypto_cross_hash(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA512, in, inlen,
+ "DIGEST SHA512");
+
+ apr_pool_destroy(pool);
+
+}
+
+/**
* Encrypt OpenSSL, decrypt CommonCrypto.
*/
static void test_crypto_block_openssl_commoncrypto(abts_case *tc, void *data)
@@ -837,6 +1631,63 @@ static void test_crypto_block_openssl_commoncrypto(abts_case *tc, void *data)
}
/**
+ * Sign OpenSSL, verify CommonCrypto.
+ */
+static void test_crypto_digest_openssl_commoncrypto(abts_case *tc, void *data)
+{
+ apr_pool_t *pool = NULL;
+ const apr_crypto_driver_t *drivers[] = { NULL, NULL };
+
+ const unsigned char *in = (const unsigned char *) ALIGNED_STRING;
+ apr_size_t inlen = sizeof(ALIGNED_STRING);
+
+ apr_pool_create(&pool, NULL);
+ drivers[0] = get_openssl_driver(tc, pool);
+ drivers[1] = get_commoncrypto_driver(tc, pool);
+ crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_3DES_192, APR_MODE_CBC, 0, in, inlen, 24,
+ "KEY_3DES_192/MODE_CBC");
+ /* KEY_3DES_192 / MODE_ECB doesn't work on NSS */
+/* crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_3DES_192, APR_MODE_ECB, 0, in, inlen, 24,
+ "KEY_3DES_192/MODE_ECB");*/
+ crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_AES_256, APR_MODE_CBC, 0, in, inlen, 32,
+ "KEY_AES_256/MODE_CBC");
+ crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_AES_256, APR_MODE_ECB, 0, in, inlen, 32,
+ "KEY_AES_256/MODE_ECB");
+ crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_AES_192, APR_MODE_CBC, 0, in, inlen, 24,
+ "KEY_AES_192/MODE_CBC");
+ crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_AES_192, APR_MODE_ECB, 0, in, inlen, 24,
+ "KEY_AES_192/MODE_ECB");
+ crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_AES_128, APR_MODE_CBC, 0, in, inlen, 16,
+ "KEY_AES_128/MODE_CBC");
+ crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_AES_128, APR_MODE_ECB, 0, in, inlen, 16,
+ "KEY_AES_128/MODE_ECB");
+
+ crypto_cross_hash(tc, pool, drivers, APR_CRYPTO_DIGEST_MD5, in, inlen,
+ "DIGEST MD5");
+ crypto_cross_hash(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA1, in, inlen,
+ "DIGEST SHA1");
+ crypto_cross_hash(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA224, in, inlen,
+ "DIGEST SHA224");
+ crypto_cross_hash(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256, in, inlen,
+ "DIGEST SHA256");
+ crypto_cross_hash(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA384, in, inlen,
+ "DIGEST SHA384");
+ crypto_cross_hash(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA512, in, inlen,
+ "DIGEST SHA512");
+
+ apr_pool_destroy(pool);
+
+}
+
+/**
* Encrypt OpenSSL, decrypt CommonCrypto.
*/
static void test_crypto_block_commoncrypto_openssl(abts_case *tc, void *data)
@@ -873,6 +1724,63 @@ static void test_crypto_block_commoncrypto_openssl(abts_case *tc, void *data)
}
/**
+ * Sign OpenSSL, verify CommonCrypto.
+ */
+static void test_crypto_digest_commoncrypto_openssl(abts_case *tc, void *data)
+{
+ apr_pool_t *pool = NULL;
+ const apr_crypto_driver_t *drivers[] = { NULL, NULL };
+
+ const unsigned char *in = (const unsigned char *) ALIGNED_STRING;
+ apr_size_t inlen = sizeof(ALIGNED_STRING);
+
+ apr_pool_create(&pool, NULL);
+ drivers[0] = get_commoncrypto_driver(tc, pool);
+ drivers[1] = get_openssl_driver(tc, pool);
+ crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_3DES_192, APR_MODE_CBC, 0, in, inlen, 24,
+ "KEY_3DES_192/MODE_CBC");
+ /* KEY_3DES_192 / MODE_ECB doesn't work on NSS */
+/* crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_3DES_192, APR_MODE_ECB, 0, in, inlen, 24,
+ "KEY_3DES_192/MODE_ECB");*/
+ crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_AES_256, APR_MODE_CBC, 0, in, inlen, 32,
+ "KEY_AES_256/MODE_CBC");
+ crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_AES_256, APR_MODE_ECB, 0, in, inlen, 32,
+ "KEY_AES_256/MODE_ECB");
+ crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_AES_192, APR_MODE_CBC, 0, in, inlen, 24,
+ "KEY_AES_192/MODE_CBC");
+ crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_AES_192, APR_MODE_ECB, 0, in, inlen, 24,
+ "KEY_AES_192/MODE_ECB");
+ crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_AES_128, APR_MODE_CBC, 0, in, inlen, 16,
+ "KEY_AES_128/MODE_CBC");
+ crypto_cross_sign(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256,
+ APR_KEY_AES_128, APR_MODE_ECB, 0, in, inlen, 16,
+ "KEY_AES_128/MODE_ECB");
+
+ crypto_cross_hash(tc, pool, drivers, APR_CRYPTO_DIGEST_MD5, in, inlen,
+ "DIGEST MD5");
+ crypto_cross_hash(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA1, in, inlen,
+ "DIGEST SHA1");
+ crypto_cross_hash(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA224, in, inlen,
+ "DIGEST SHA224");
+ crypto_cross_hash(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA256, in, inlen,
+ "DIGEST SHA256");
+ crypto_cross_hash(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA384, in, inlen,
+ "DIGEST SHA384");
+ crypto_cross_hash(tc, pool, drivers, APR_CRYPTO_DIGEST_SHA512, in, inlen,
+ "DIGEST SHA512");
+
+ apr_pool_destroy(pool);
+
+}
+
+/**
* Simple test of OpenSSL block crypt.
*/
static void test_crypto_block_openssl_pad(abts_case *tc, void *data)
@@ -1699,7 +2607,7 @@ abts_suite *testcrypto(abts_suite *suite)
{
suite = ADD_SUITE(suite);
- /* test simple init and shutdown (keep first) */
+ /* test simple init and shutdown */
abts_run_test(suite, test_crypto_init, NULL);
/* test key parsing - openssl */
@@ -1714,45 +2622,71 @@ abts_suite *testcrypto(abts_suite *suite)
/* test a simple encrypt / decrypt operation - openssl */
abts_run_test(suite, test_crypto_block_openssl, NULL);
+ /* test a simple sign / verify operation - openssl */
+ abts_run_test(suite, test_crypto_digest_openssl, NULL);
+
/* test a padded encrypt / decrypt operation - openssl */
abts_run_test(suite, test_crypto_block_openssl_pad, NULL);
/* test a simple encrypt / decrypt operation - nss */
abts_run_test(suite, test_crypto_block_nss, NULL);
+ /* test a simple sign / verify operation - nss */
+ abts_run_test(suite, test_crypto_digest_nss, NULL);
+
/* test a padded encrypt / decrypt operation - nss */
abts_run_test(suite, test_crypto_block_nss_pad, NULL);
/* test a simple encrypt / decrypt operation - commoncrypto */
abts_run_test(suite, test_crypto_block_commoncrypto, NULL);
+ /* test a simple sign / verify operation - commoncrypto */
+ abts_run_test(suite, test_crypto_digest_commoncrypto, NULL);
+
/* test a padded encrypt / decrypt operation - commoncrypto */
abts_run_test(suite, test_crypto_block_commoncrypto_pad, NULL);
+
/* test encrypt nss / decrypt openssl */
abts_run_test(suite, test_crypto_block_nss_openssl, NULL);
/* test padded encrypt nss / decrypt openssl */
abts_run_test(suite, test_crypto_block_nss_openssl_pad, NULL);
+ /* test sign nss / verify openssl */
+ abts_run_test(suite, test_crypto_digest_nss_openssl, NULL);
+
+
/* test encrypt openssl / decrypt nss */
abts_run_test(suite, test_crypto_block_openssl_nss, NULL);
/* test padded encrypt openssl / decrypt nss */
abts_run_test(suite, test_crypto_block_openssl_nss_pad, NULL);
+ /* test sign openssl / verify nss */
+ abts_run_test(suite, test_crypto_digest_openssl_nss, NULL);
+
+
/* test encrypt openssl / decrypt commoncrypto */
abts_run_test(suite, test_crypto_block_openssl_commoncrypto, NULL);
/* test padded encrypt openssl / decrypt commoncrypto */
abts_run_test(suite, test_crypto_block_openssl_commoncrypto_pad, NULL);
+ /* test sign openssl / verify commoncrypto */
+ abts_run_test(suite, test_crypto_digest_openssl_commoncrypto, NULL);
+
+
/* test encrypt commoncrypto / decrypt openssl */
abts_run_test(suite, test_crypto_block_commoncrypto_openssl, NULL);
/* test padded encrypt commoncrypto / decrypt openssl */
abts_run_test(suite, test_crypto_block_commoncrypto_openssl_pad, NULL);
+ /* test sign commoncrypto / verify openssl */
+ abts_run_test(suite, test_crypto_digest_commoncrypto_openssl, NULL);
+
+
/* test block key types openssl */
abts_run_test(suite, test_crypto_get_block_key_types_openssl, NULL);