diff options
-rw-r--r-- | Makefile.in | 1 | ||||
-rw-r--r-- | build.conf | 6 | ||||
-rw-r--r-- | build/crypto.m4 | 73 | ||||
-rw-r--r-- | build/dso.m4 | 6 | ||||
-rw-r--r-- | crypto/apr_crypto.c | 5 | ||||
-rw-r--r-- | crypto/apr_crypto_commoncrypto.c | 814 | ||||
-rw-r--r-- | include/apr.h.in | 1 | ||||
-rw-r--r-- | include/apr.hnw | 1 | ||||
-rw-r--r-- | include/apr.hw | 1 | ||||
-rw-r--r-- | include/apr_crypto.h | 24 | ||||
-rw-r--r-- | test/testcrypto.c | 396 |
11 files changed, 1286 insertions, 42 deletions
diff --git a/Makefile.in b/Makefile.in index 561718dd7..e2a13c17b 100644 --- a/Makefile.in +++ b/Makefile.in @@ -82,6 +82,7 @@ LDADD_dbm_gdbm = @LDADD_dbm_gdbm@ LDADD_dbm_ndbm = @LDADD_dbm_ndbm@ LDADD_crypto_openssl = @LDADD_crypto_openssl@ LDADD_crypto_nss = @LDADD_crypto_nss@ +LDADD_crypto_commoncrypto = @LDADD_crypto_commoncrypto@ # Create apr-config script suitable for the install tree apr-config.out: $(APR_CONFIG) diff --git a/build.conf b/build.conf index 3c6ad6189..4aa276aa4 100644 --- a/build.conf +++ b/build.conf @@ -51,7 +51,7 @@ headers = include/*.h dsp = libapr.dsp modules = - crypto_openssl crypto_nss dbd_pgsql + crypto_openssl crypto_nss crypto_commoncrypto dbd_pgsql dbd_sqlite2 dbd_sqlite3 dbd_oracle dbd_mysql dbd_freetds dbd_odbc dbm_db dbm_gdbm dbm_ndbm @@ -60,6 +60,10 @@ modules = # we have a recursive makefile for the test files (for now) # test/*.c +[crypto_commoncrypto] +paths = crypto/apr_crypto_commoncrypto.c +target = crypto/apr_crypto_commoncrypto.la + [crypto_openssl] paths = crypto/apr_crypto_openssl.c target = crypto/apr_crypto_openssl.la diff --git a/build/crypto.m4 b/build/crypto.m4 index 23c556b9b..4a99c0746 100644 --- a/build/crypto.m4 +++ b/build/crypto.m4 @@ -25,6 +25,7 @@ AC_DEFUN([APU_CHECK_CRYPTO], [ apu_have_crypto=0 apu_have_openssl=0 apu_have_nss=0 + apu_have_commoncrypto=0 old_libs="$LIBS" old_cppflags="$CPPFLAGS" @@ -32,7 +33,7 @@ AC_DEFUN([APU_CHECK_CRYPTO], [ AC_ARG_WITH([crypto], [APR_HELP_STRING([--with-crypto], [enable crypto support])], [ - cryptolibs="openssl nss" + cryptolibs="openssl nss commoncrypto" if test "$withval" = "yes"; then @@ -61,9 +62,10 @@ AC_DEFUN([APU_CHECK_CRYPTO], [ APU_CHECK_CRYPTO_OPENSSL APU_CHECK_CRYPTO_NSS + APU_CHECK_CRYPTO_COMMONCRYPTO dnl add checks for other varieties of ssl here if test "$apu_have_crypto" = "0"; then - AC_ERROR([Crypto was requested but no crypto library could be enabled; specify the location of a crypto library using --with-openssl, --with-nss, etc.]) + AC_ERROR([Crypto was requested but no crypto library could be enabled; specify the location of a crypto library using --with-openssl, --with-nss, and/or --with-commoncrypto.]) fi fi ], [ @@ -238,4 +240,71 @@ AC_DEFUN([APU_CHECK_CRYPTO_NSS], [ CPPFLAGS="$old_cppflags" LDFLAGS="$old_ldflags" ]) + +AC_DEFUN([APU_CHECK_CRYPTO_COMMONCRYPTO], [ + apu_have_commoncrypto=0 + commoncrypto_have_headers=0 + commoncrypto_have_libs=0 + + old_libs="$LIBS" + old_cppflags="$CPPFLAGS" + old_ldflags="$LDFLAGS" + + AC_ARG_WITH([commoncrypto], + [APR_HELP_STRING([--with-commoncrypto=DIR], [specify location of CommonCrypto])], + [ + if test "$withval" = "yes"; then + AC_CHECK_HEADERS(CommonCrypto/CommonKeyDerivation.h, [commoncrypto_have_headers=1]) + AC_CHECK_LIB(System, CCKeyDerivationPBKDF, AC_CHECK_LIB(System, CCCryptorCreate, [commoncrypto_have_libs=1],,-lcrypto)) + if test "$commoncrypto_have_headers" != "0" && test "$commoncrypto_have_libs" != "0"; then + apu_have_commoncrypto=1 + fi + elif test "$withval" = "no"; then + apu_have_commoncrypto=0 + else + + commoncrypto_CPPFLAGS="-I$withval/include" + commoncrypto_LDFLAGS="-L$withval/lib " + + APR_ADDTO(CPPFLAGS, [$commoncrypto_CPPFLAGS]) + APR_ADDTO(LDFLAGS, [$commoncrypto_LDFLAGS]) + + AC_MSG_NOTICE(checking for commoncrypto in $withval) + AC_CHECK_HEADERS(CommonCrypto/CommonKeyDerivation.h, [commoncrypto_have_headers=1]) + AC_CHECK_LIB(System, CCKeyDerivationPBKDF, AC_CHECK_LIB(System, CCCryptorCreate, [commoncrypto_have_libs=1],,-lcrypto)) + if test "$commoncrypto_have_headers" != "0" && test "$commoncrypto_have_libs" != "0"; then + apu_have_commoncrypto=1 + APR_ADDTO(LDFLAGS, [-L$withval/lib]) + APR_ADDTO(INCLUDES, [-I$withval/include]) + fi + + if test "$apu_have_commoncrypto" != "1"; then + AC_CHECK_HEADERS(CommonCrypto/CommonKeyDerivation.h, [commoncrypto_have_headers=1]) + AC_CHECK_LIB(System, CCKeyDerivationPBKDF, AC_CHECK_LIB(System, CCCryptorCreate, [commoncrypto_have_libs=1],,-lcrypto)) + if test "$commoncrypto_have_headers" != "0" && test "$commoncrypto_have_libs" != "0"; then + apu_have_commoncrypto=1 + APR_ADDTO(LDFLAGS, [-L$withval/lib]) + APR_ADDTO(INCLUDES, [-I$withval/include]) + fi + fi + + fi + ], [ + apu_have_commoncrypto=0 + ]) + + dnl Since we have already done the AC_CHECK_LIB tests, if we have it, + dnl we know the library is there. + if test "$apu_have_commoncrypto" = "1"; then + apu_have_crypto=1 + fi + AC_SUBST(apu_have_commoncrypto) + AC_SUBST(LDADD_crypto_commoncrypto) + AC_SUBST(apu_have_crypto) + + LIBS="$old_libs" + CPPFLAGS="$old_cppflags" + LDFLAGS="$old_ldflags" +]) + dnl diff --git a/build/dso.m4 b/build/dso.m4 index 5589183c1..5ff41d28b 100644 --- a/build/dso.m4 +++ b/build/dso.m4 @@ -36,6 +36,7 @@ AC_DEFUN([APR_MODULAR_DSO], [ objs= test $apu_have_openssl = 1 && objs="$objs crypto/apr_crypto_openssl.lo" test $apu_have_nss = 1 && objs="$objs crypto/apr_crypto_nss.lo" + test $apu_have_commoncrypto = 1 && objs="$objs crypto/apr_crypto_commoncrypto.lo" test $apu_have_oracle = 1 && objs="$objs dbd/apr_dbd_oracle.lo" test $apu_have_pgsql = 1 && objs="$objs dbd/apr_dbd_pgsql.lo" test $apu_have_mysql = 1 && objs="$objs dbd/apr_dbd_mysql.lo" @@ -62,10 +63,10 @@ AC_DEFUN([APR_MODULAR_DSO], [ done fi - LIBS="$LIBS $LDADD_crypto_openssl $LDADD_crypto_nss" + LIBS="$LIBS $LDADD_crypto_openssl $LDADD_crypto_nss $LDADD_crypto_commoncrypto" LIBS="$LIBS $LDADD_dbd_pgsql $LDADD_dbd_sqlite2 $LDADD_dbd_sqlite3 $LDADD_dbd_oracle $LDADD_dbd_mysql $LDADD_dbd_freetds $LDADD_dbd_odbc" LIBS="$LIBS $LDADD_dbm_db $LDADD_dbm_gdbm $LDADD_dbm_ndbm" - APRUTIL_EXPORT_LIBS="$APRUTIL_EXPORT_LIBS $LDADD_crypto_openssl $LDADD_crypto_nss" + APRUTIL_EXPORT_LIBS="$APRUTIL_EXPORT_LIBS $LDADD_crypto_openssl $LDADD_crypto_nss $LDADD_crypto_commoncrypto" APRUTIL_EXPORT_LIBS="$APRUTIL_EXPORT_LIBS $LDADD_dbd_pgsql $LDADD_dbd_sqlite2 $LDADD_dbd_sqlite3 $LDADD_dbd_oracle $LDADD_dbd_mysql $LDADD_dbd_freetds $LDADD_dbd_odbc" APRUTIL_EXPORT_LIBS="$APRUTIL_EXPORT_LIBS $LDADD_dbm_db $LDADD_dbm_gdbm $LDADD_dbm_ndbm" @@ -75,6 +76,7 @@ AC_DEFUN([APR_MODULAR_DSO], [ dsos= test $apu_have_openssl = 1 && dsos="$dsos crypto/apr_crypto_openssl.la" test $apu_have_nss = 1 && dsos="$dsos crypto/apr_crypto_nss.la" + test $apu_have_commoncrypto = 1 && dsos="$dsos crypto/apr_crypto_commoncrypto.la" test $apu_have_oracle = 1 && dsos="$dsos dbd/apr_dbd_oracle.la" test $apu_have_pgsql = 1 && dsos="$dsos dbd/apr_dbd_pgsql.la" test $apu_have_mysql = 1 && dsos="$dsos dbd/apr_dbd_mysql.la" diff --git a/crypto/apr_crypto.c b/crypto/apr_crypto.c index 396528d96..dbc108f7e 100644 --- a/crypto/apr_crypto.c +++ b/crypto/apr_crypto.c @@ -215,6 +215,11 @@ APR_DECLARE(apr_status_t) apr_crypto_get_driver( DRIVER_LOAD("nss", apr_crypto_nss_driver, pool, params, rv, result); } #endif +#if APU_HAVE_COMMONCRYPTO + if (name[0] == 'c' && !strcmp(name, "commoncrypto")) { + DRIVER_LOAD("commoncrypto", apr_crypto_commoncrypto_driver, pool, params, rv, result); + } +#endif #if APU_HAVE_MSCAPI if (name[0] == 'm' && !strcmp(name, "mscapi")) { DRIVER_LOAD("mscapi", apr_crypto_mscapi_driver, pool, params, rv, result); diff --git a/crypto/apr_crypto_commoncrypto.c b/crypto/apr_crypto_commoncrypto.c new file mode 100644 index 000000000..e9136c93a --- /dev/null +++ b/crypto/apr_crypto_commoncrypto.c @@ -0,0 +1,814 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "apr_lib.h" +#include "apu.h" +#include "apr_private.h" +#include "apu_errno.h" + +#include <ctype.h> +#include <assert.h> +#include <stdlib.h> + +#include "apr_strings.h" +#include "apr_time.h" +#include "apr_buckets.h" +#include "apr_random.h" + +#include "apr_crypto_internal.h" + +#if APU_HAVE_CRYPTO + +#include <CommonCrypto/CommonCrypto.h> + +#define LOG_PREFIX "apr_crypto_commoncrypto: " + +struct apr_crypto_t +{ + apr_pool_t *pool; + const apr_crypto_driver_t *provider; + apu_err_t *result; + apr_array_header_t *keys; + apr_hash_t *types; + apr_hash_t *modes; + apr_random_t *rng; +}; + +struct apr_crypto_key_t +{ + apr_pool_t *pool; + const apr_crypto_driver_t *provider; + const apr_crypto_t *f; + CCAlgorithm algorithm; + CCOptions options; + unsigned char *key; + int keyLen; + int ivSize; + apr_size_t blockSize; +}; + +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; + CCCryptorRef ref; +}; + +static int key_3des_192 = APR_KEY_3DES_192; +static int key_aes_128 = APR_KEY_AES_128; +static int key_aes_192 = APR_KEY_AES_192; +static int key_aes_256 = APR_KEY_AES_256; + +static int mode_ecb = APR_MODE_ECB; +static int mode_cbc = APR_MODE_CBC; + +/** + * Fetch the most recent error from this driver. + */ +static apr_status_t crypto_error(const apu_err_t **result, + const apr_crypto_t *f) +{ + *result = f->result; + return APR_SUCCESS; +} + +/** + * Shutdown the crypto library and release resources. + */ +static apr_status_t crypto_shutdown(void) +{ + 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) +{ + + apr_pool_cleanup_register(pool, pool, crypto_shutdown_helper, + apr_pool_cleanup_null); + + return APR_SUCCESS; +} + +/** + * @brief Clean encryption / decryption 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_block_cleanup(apr_crypto_block_t *ctx) +{ + + if (ctx->ref) { + CCCryptorRelease(ctx->ref); + ctx->ref = 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); +} + +/** + * @brief Clean encryption / decryption 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_cleanup(apr_crypto_t *f) +{ + + return APR_SUCCESS; + +} + +static apr_status_t crypto_cleanup_helper(void *data) +{ + apr_crypto_t *f = (apr_crypto_t *) data; + return crypto_cleanup(f); +} + +/** + * @brief Create a context for supporting encryption. Keys, certificates, + * algorithms and other parameters will be set per context. More than + * one context can be created at one time. A cleanup will be automatically + * registered with the given pool to guarantee a graceful shutdown. + * @param f - context pointer will be written here + * @param provider - provider to use + * @param params - array of key parameters + * @param pool - process pool + * @return APR_ENOENGINE when the engine specified does not exist. APR_EINITENGINE + * if the engine cannot be initialised. + */ +static apr_status_t crypto_make(apr_crypto_t **ff, + const apr_crypto_driver_t *provider, const char *params, + apr_pool_t *pool) +{ + apr_crypto_t *f = apr_pcalloc(pool, sizeof(apr_crypto_t)); + apr_status_t rv; + + if (!f) { + return APR_ENOMEM; + } + *ff = f; + f->pool = pool; + f->provider = provider; + + /* seed the secure random number generator */ + f->rng = apr_random_standard_new(pool); + if (!f->rng) { + return APR_ENOMEM; + } + do { + unsigned char seed[8]; + rv = apr_generate_random_bytes(seed, sizeof(seed)); + if (rv != APR_SUCCESS) { + return rv; + } + apr_random_add_entropy(f->rng, seed, sizeof(seed)); + rv = apr_random_secure_ready(f->rng); + } while (rv == APR_ENOTENOUGHENTROPY); + + f->result = apr_pcalloc(pool, sizeof(apu_err_t)); + if (!f->result) { + return APR_ENOMEM; + } + + f->keys = apr_array_make(pool, 10, sizeof(apr_crypto_key_t)); + if (!f->keys) { + return APR_ENOMEM; + } + + f->types = apr_hash_make(pool); + if (!f->types) { + return APR_ENOMEM; + } + apr_hash_set(f->types, "3des192", APR_HASH_KEY_STRING, &(key_3des_192)); + apr_hash_set(f->types, "aes128", APR_HASH_KEY_STRING, &(key_aes_128)); + apr_hash_set(f->types, "aes192", APR_HASH_KEY_STRING, &(key_aes_192)); + apr_hash_set(f->types, "aes256", APR_HASH_KEY_STRING, &(key_aes_256)); + + f->modes = apr_hash_make(pool); + if (!f->modes) { + return APR_ENOMEM; + } + apr_hash_set(f->modes, "ecb", APR_HASH_KEY_STRING, &(mode_ecb)); + apr_hash_set(f->modes, "cbc", APR_HASH_KEY_STRING, &(mode_cbc)); + + apr_pool_cleanup_register(pool, f, crypto_cleanup_helper, + apr_pool_cleanup_null); + + return APR_SUCCESS; + +} + +/** + * @brief Get a hash table of key types, keyed by the name of the type against + * an integer pointer constant. + * + * @param types - hashtable of key types keyed to constants. + * @param f - encryption context + * @return APR_SUCCESS for success + */ +static apr_status_t crypto_get_block_key_types(apr_hash_t **types, + const apr_crypto_t *f) +{ + *types = f->types; + return APR_SUCCESS; +} + +/** + * @brief Get a hash table of key modes, keyed by the name of the mode against + * an integer pointer constant. + * + * @param modes - hashtable of key modes keyed to constants. + * @param f - encryption context + * @return APR_SUCCESS for success + */ +static apr_status_t crypto_get_block_key_modes(apr_hash_t **modes, + const apr_crypto_t *f) +{ + *modes = f->modes; + return APR_SUCCESS; +} + +/** + * @brief Create a key from the given passphrase. By default, the PBKDF2 + * algorithm is used to generate the key from the passphrase. It is expected + * that the same pass phrase will generate the same key, regardless of the + * backend crypto platform used. The key is cleaned up when the context + * is cleaned, and may be reused with multiple encryption or decryption + * operations. + * @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 ivSize The size of the initialisation vector will be returned, based + * on whether an IV is relevant for this type of crypto. + * @param pass The passphrase to use. + * @param passLen The passphrase length in bytes + * @param salt The salt to use. + * @param saltLen The salt length in bytes + * @param type 3DES_192, AES_128, AES_192, AES_256. + * @param mode Electronic Code Book / Cipher Block Chaining. + * @param doPad Pad if necessary. + * @param iterations Iteration count + * @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. + */ +static apr_status_t crypto_passphrase(apr_crypto_key_t **k, apr_size_t *ivSize, + const char *pass, apr_size_t passLen, const unsigned char * salt, + apr_size_t saltLen, const apr_crypto_block_key_type_e type, + const apr_crypto_block_key_mode_e mode, const int doPad, + const int iterations, const apr_crypto_t *f, apr_pool_t *p) +{ + apr_crypto_key_t *key = *k; + + if (!key) { + *k = key = apr_array_push(f->keys); + } + if (!key) { + return APR_ENOMEM; + } + + key->f = f; + key->provider = f->provider; + + /* handle padding */ + key->options = doPad ? kCCOptionPKCS7Padding : 0; + + /* determine the algorithm to be used */ + switch (type) { + + case (APR_KEY_3DES_192): + + /* A 3DES key */ + if (mode == APR_MODE_CBC) { + key->algorithm = kCCAlgorithm3DES; + key->keyLen = kCCKeySize3DES; + key->ivSize = kCCBlockSize3DES; + key->blockSize = kCCBlockSize3DES; + } + else { + key->algorithm = kCCAlgorithm3DES; + key->options += kCCOptionECBMode; + key->keyLen = kCCKeySize3DES; + key->ivSize = 0; + key->blockSize = kCCBlockSize3DES; + } + break; + + case (APR_KEY_AES_128): + + if (mode == APR_MODE_CBC) { + key->algorithm = kCCAlgorithmAES128; + key->keyLen = kCCKeySizeAES128; + key->ivSize = kCCBlockSizeAES128; + key->blockSize = kCCBlockSizeAES128; + } + else { + key->algorithm = kCCAlgorithmAES128; + key->options += kCCOptionECBMode; + key->keyLen = kCCKeySizeAES128; + key->ivSize = 0; + key->blockSize = kCCBlockSizeAES128; + } + break; + + case (APR_KEY_AES_192): + + if (mode == APR_MODE_CBC) { + key->algorithm = kCCAlgorithmAES128; + key->keyLen = kCCKeySizeAES192; + key->ivSize = kCCBlockSizeAES128; + key->blockSize = kCCBlockSizeAES128; + } + else { + key->algorithm = kCCAlgorithmAES128; + key->options += kCCOptionECBMode; + key->keyLen = kCCKeySizeAES192; + key->ivSize = 0; + key->blockSize = kCCBlockSizeAES128; + } + break; + + case (APR_KEY_AES_256): + + if (mode == APR_MODE_CBC) { + key->algorithm = kCCAlgorithmAES128; + key->keyLen = kCCKeySizeAES256; + key->ivSize = kCCBlockSizeAES128; + key->blockSize = kCCBlockSizeAES128; + } + else { + key->algorithm = kCCAlgorithmAES128; + key->options += kCCOptionECBMode; + key->keyLen = kCCKeySizeAES256; + key->ivSize = 0; + key->blockSize = kCCBlockSizeAES128; + } + break; + + default: + + /* TODO: Support CAST, Blowfish */ + + /* unknown key type, give up */ + return APR_EKEYTYPE; + + } + + /* make space for the key */ + key->key = apr_pcalloc(p, key->keyLen); + if (!key->key) { + return APR_ENOMEM; + } + apr_crypto_clear(p, key->key, key->keyLen); + + /* generate the key */ + if ((f->result->rc = CCKeyDerivationPBKDF(kCCPBKDF2, pass, passLen, salt, + saltLen, kCCPRFHmacAlgSHA1, iterations, key->key, key->keyLen)) + == kCCParamError) { + return APR_ENOKEY; + } + + if (ivSize) { + *ivSize = key->ivSize; + } + + return APR_SUCCESS; +} + +/** + * @brief Initialise a context for encrypting arbitrary data using the given key. + * @note If *ctx is NULL, a apr_crypto_block_t will be created from a pool. If + * *ctx is not NULL, *ctx must point at a previously created structure. + * @param ctx The block context returned, see note. + * @param iv Optional initialisation vector. If the buffer pointed to is NULL, + * an IV will be created at random, in space allocated from the pool. + * If the buffer pointed to is not NULL, the IV in the buffer will be + * used. + * @param key The key structure. + * @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. + */ +static apr_status_t crypto_block_encrypt_init(apr_crypto_block_t **ctx, + const unsigned char **iv, const apr_crypto_key_t *key, + apr_size_t *blockSize, apr_pool_t *p) +{ + unsigned char *usedIv; + 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 */ + 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; + } + 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; + } + } + + /* 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; + } + } + + if (blockSize) { + *blockSize = key->blockSize; + } + + return APR_SUCCESS; + +} + +/** + * @brief Encrypt data provided by in, write it to out. + * @note The number of bytes written will be written to outlen. If + * out is NULL, outlen will contain the maximum size of the + * buffer needed to hold the data, including any data + * generated by apr_crypto_block_encrypt_finish below. If *out points + * to NULL, a buffer sufficiently large will be created from + * the pool provided. If *out points to a not-NULL value, this + * value will be used as a buffer instead. + * @param out Address of a buffer to which data will be written, + * see note. + * @param outlen Length of the output will be written here. + * @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. + */ +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_size_t outl = *outlen; + unsigned char *buffer; + + /* are we after the maximum size of the out buffer? */ + if (!out) { + *outlen = CCCryptorGetOutputLength(ctx->ref, inlen, 1); + return APR_SUCCESS; + } + + /* 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_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; + } + default: { + return APR_ECRYPT; + } + } + *outlen = outl; + + return APR_SUCCESS; + +} + +/** + * @brief Encrypt final data block, write it to out. + * @note If necessary the final block will be written out after being + * padded. Typically the final block will be written to the + * same buffer used by apr_crypto_block_encrypt, offset by the + * number of bytes returned as actually written by the + * apr_crypto_block_encrypt() call. After this call, the context + * 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. + * @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. + */ +static apr_status_t crypto_block_encrypt_finish(unsigned char *out, + apr_size_t *outlen, apr_crypto_block_t *ctx) +{ + apr_size_t len = *outlen; + + ctx->f->result->rc = CCCryptorFinal(ctx->ref, out, + CCCryptorGetOutputLength(ctx->ref, 0, 1), &len); + + /* always clean up */ + crypto_block_cleanup(ctx); + + 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; + } + } + *outlen = len; + + return APR_SUCCESS; + +} + +/** + * @brief Initialise a context for decrypting arbitrary data using the given key. + * @note If *ctx is NULL, a apr_crypto_block_t will be created from a pool. If + * *ctx is not NULL, *ctx must point at a previously created structure. + * @param ctx The block context returned, see note. + * @param blockSize The block size of the cipher. + * @param iv Optional initialisation vector. If the buffer pointed to is NULL, + * an IV will be created at random, in space allocated from the pool. + * If the buffer is not NULL, the IV in the buffer will be used. + * @param key The key structure. + * @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. + */ +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; + + 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; + } + default: { + return APR_EINIT; + } + } + + if (blockSize) { + *blockSize = key->blockSize; + } + + return APR_SUCCESS; + +} + +/** + * @brief Decrypt data provided by in, write it to out. + * @note The number of bytes written will be written to outlen. If + * out is NULL, outlen will contain the maximum size of the + * buffer needed to hold the data, including any data + * generated by apr_crypto_block_decrypt_finish below. If *out points + * to NULL, a buffer sufficiently large will be created from + * the pool provided. If *out points to a not-NULL value, this + * value will be used as a buffer instead. + * @param out Address of a buffer to which data will be written, + * see note. + * @param outlen Length of the output will be written here. + * @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. + */ +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_size_t outl = *outlen; + unsigned char *buffer; + + /* are we after the maximum size of the out buffer? */ + if (!out) { + *outlen = CCCryptorGetOutputLength(ctx->ref, inlen, 1); + return APR_SUCCESS; + } + + /* 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_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; + } + default: { + return APR_ECRYPT; + } + } + *outlen = outl; + + return APR_SUCCESS; + +} + +/** + * @brief Decrypt final data block, write it to out. + * @note If necessary the final block will be written out after being + * padded. Typically the final block will be written to the + * same buffer used by apr_crypto_block_decrypt, offset by the + * number of bytes returned as actually written by the + * apr_crypto_block_decrypt() call. After this call, the context + * 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. + * @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. + */ +static apr_status_t crypto_block_decrypt_finish(unsigned char *out, + apr_size_t *outlen, apr_crypto_block_t *ctx) +{ + apr_size_t len = *outlen; + + ctx->f->result->rc = CCCryptorFinal(ctx->ref, out, + CCCryptorGetOutputLength(ctx->ref, 0, 1), &len); + + /* always clean up */ + crypto_block_cleanup(ctx); + + 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; + } + } + *outlen = len; + + return APR_SUCCESS; + +} + +/** + * OSX Common Crypto module. + */ +APR_MODULE_DECLARE_DATA const apr_crypto_driver_t apr_crypto_commoncrypto_driver = +{ + "commoncrypto", crypto_init, crypto_make, 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 +}; + +#endif diff --git a/include/apr.h.in b/include/apr.h.in index b5bc72999..def752ee3 100644 --- a/include/apr.h.in +++ b/include/apr.h.in @@ -680,6 +680,7 @@ typedef int apr_wait_t; #define APU_HAVE_CRYPTO @apu_have_crypto@ #define APU_HAVE_OPENSSL @apu_have_openssl@ #define APU_HAVE_NSS @apu_have_nss@ +#define APU_HAVE_COMMONCRYPTO @apu_have_commoncrypto@ #define APU_HAVE_ICONV @have_iconv@ #define APR_HAS_XLATE (APU_HAVE_ICONV) diff --git a/include/apr.hnw b/include/apr.hnw index e3e214c7f..41e6480e7 100644 --- a/include/apr.hnw +++ b/include/apr.hnw @@ -484,6 +484,7 @@ typedef int apr_wait_t; #ifndef APU_DSO_MODULE_BUILD #define APU_HAVE_OPENSSL 0 #define APU_HAVE_NSS 0 +#define APU_HAVE_COMMONCRYPTO 0 #endif #define APU_HAVE_ICONV 1 diff --git a/include/apr.hw b/include/apr.hw index 39bcbc6a3..6c4ce56ea 100644 --- a/include/apr.hw +++ b/include/apr.hw @@ -657,6 +657,7 @@ typedef int apr_wait_t; #ifndef APU_DSO_MODULE_BUILD #define APU_HAVE_OPENSSL 0 #define APU_HAVE_NSS 0 +#define APU_HAVE_COMMONCRYPTO 0 #endif #define APU_HAVE_ICONV 0 diff --git a/include/apr_crypto.h b/include/apr_crypto.h index de3dd2a95..f835ea6de 100644 --- a/include/apr_crypto.h +++ b/include/apr_crypto.h @@ -40,6 +40,9 @@ extern "C" { #if APU_HAVE_CRYPTO #ifndef APU_CRYPTO_RECOMMENDED_DRIVER +#if APU_HAVE_COMMONCRYPTO +#define APU_CRYPTO_RECOMMENDED_DRIVER "commoncrypto" +#else #if APU_HAVE_OPENSSL #define APU_CRYPTO_RECOMMENDED_DRIVER "openssl" #else @@ -57,6 +60,7 @@ extern "C" { #endif #endif #endif +#endif /** * Symmetric Key types understood by the library. @@ -84,16 +88,16 @@ extern "C" { * the chosen cipher. Padded data is data that is not aligned by block * size and must be padded by the crypto library. * - * OpenSSL NSS Interop - * Align Pad Align Pad Align Pad - * 3DES_192/CBC X X X X X X - * 3DES_192/ECB X X - * AES_256/CBC X X X X X X - * AES_256/ECB X X X X - * AES_192/CBC X X X X - * AES_192/ECB X X X - * AES_128/CBC X X X X - * AES_128/ECB X X X + * OpenSSL CommonCrypto NSS Interop + * Align Pad Align Pad Align Pad Align Pad + * 3DES_192/CBC X X X X X X X X + * 3DES_192/ECB X X X X + * AES_256/CBC X X X X X X X X + * AES_256/ECB X X X X X X + * AES_192/CBC X X X X X X + * AES_192/ECB X X X X X + * AES_128/CBC X X X X X X + * AES_128/ECB X X X X X * * Conclusion: for padded data, use 3DES_192/CBC or AES_256/CBC. For * aligned data, use 3DES_192/CBC, AES_256/CBC or AES_256/ECB. diff --git a/test/testcrypto.c b/test/testcrypto.c index 335c3ae65..9018b80b4 100644 --- a/test/testcrypto.c +++ b/test/testcrypto.c @@ -45,7 +45,8 @@ static const apr_crypto_driver_t *get_driver(abts_case *tc, apr_pool_t *pool, return NULL; } if (APR_ENOTIMPL == rv) { - ABTS_NOT_IMPL(tc, (char *)driver); + ABTS_NOT_IMPL(tc, + apr_psprintf(pool, "Crypto driver '%s' not implemented, skipping", (char *)name)); return NULL; } ABTS_ASSERT(tc, "failed to apr_crypto_get_driver", rv == APR_SUCCESS); @@ -75,6 +76,14 @@ static const apr_crypto_driver_t *get_openssl_driver(abts_case *tc, } +static const apr_crypto_driver_t *get_commoncrypto_driver(abts_case *tc, + apr_pool_t *pool) +{ + + return get_driver(tc, pool, "commoncrypto", NULL); + +} + static apr_crypto_t *make(abts_case *tc, apr_pool_t *pool, const apr_crypto_driver_t *driver) { @@ -167,17 +176,27 @@ static unsigned char *encrypt_block(abts_case *tc, apr_pool_t *pool, else { if (APR_SUCCESS != rv) { apr_crypto_error(&result, f); - fprintf(stderr, "encrypt_init: %s %s native error %d: %s (%s)\n", - description, apr_crypto_driver_name(driver), result->rc, + fprintf(stderr, + "encrypt_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_block_encrypt_init returned APR_ENOKEY", rv != APR_ENOKEY); - ABTS_ASSERT(tc, "apr_crypto_block_encrypt_init returned APR_ENOIV", rv != APR_ENOIV); - ABTS_ASSERT(tc, "apr_crypto_block_encrypt_init returned APR_EKEYTYPE", rv != APR_EKEYTYPE); - ABTS_ASSERT(tc, "apr_crypto_block_encrypt_init returned APR_EKEYLENGTH", rv != APR_EKEYLENGTH); - ABTS_ASSERT(tc, "failed to apr_crypto_block_encrypt_init", rv == APR_SUCCESS); - ABTS_ASSERT(tc, "apr_crypto_block_encrypt_init returned NULL context", block != NULL); + ABTS_ASSERT(tc, "apr_crypto_block_encrypt_init returned APR_ENOKEY", + rv != APR_ENOKEY); + ABTS_ASSERT(tc, "apr_crypto_block_encrypt_init returned APR_ENOIV", + rv != APR_ENOIV); + ABTS_ASSERT(tc, "apr_crypto_block_encrypt_init returned APR_EKEYTYPE", + rv != APR_EKEYTYPE); + ABTS_ASSERT(tc, "apr_crypto_block_encrypt_init returned APR_EKEYLENGTH", + rv != APR_EKEYLENGTH); + ABTS_ASSERT(tc, + "apr_crypto_block_encrypt_init returned APR_ENOTENOUGHENTROPY", + rv != APR_ENOTENOUGHENTROPY); + ABTS_ASSERT(tc, "failed to apr_crypto_block_encrypt_init", + rv == APR_SUCCESS); + ABTS_ASSERT(tc, "apr_crypto_block_encrypt_init returned NULL context", + block != NULL); } if (!block || rv) { return NULL; @@ -187,10 +206,10 @@ static unsigned char *encrypt_block(abts_case *tc, apr_pool_t *pool, rv = apr_crypto_block_encrypt(cipherText, cipherTextLen, in, inlen, block); if (APR_SUCCESS != rv) { apr_crypto_error(&result, f); - fprintf(stderr, "encrypt: %s %s native error %d: %s (%s)\n", - description, apr_crypto_driver_name(driver), result->rc, - result->reason ? result->reason : "", result->msg ? result->msg - : ""); + fprintf(stderr, "encrypt: %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_block_encrypt returned APR_ECRYPT", rv != APR_ECRYPT); ABTS_ASSERT(tc, "failed to apr_crypto_block_encrypt", rv == APR_SUCCESS); @@ -204,13 +223,15 @@ static unsigned char *encrypt_block(abts_case *tc, apr_pool_t *pool, block); if (APR_SUCCESS != rv) { apr_crypto_error(&result, f); - fprintf(stderr, "encrypt_finish: %s %s native error %d: %s (%s)\n", - description, apr_crypto_driver_name(driver), result->rc, - result->reason ? result->reason : "", result->msg ? result->msg - : ""); + fprintf(stderr, + "encrypt_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_block_encrypt_finish returned APR_ECRYPT", rv != APR_ECRYPT); ABTS_ASSERT(tc, "apr_crypto_block_encrypt_finish returned APR_EPADDING", rv != APR_EPADDING); + ABTS_ASSERT(tc, "apr_crypto_block_encrypt_finish returned APR_ENOSPACE", rv != APR_ENOSPACE); ABTS_ASSERT(tc, "failed to apr_crypto_block_encrypt_finish", rv == APR_SUCCESS); *cipherTextLen += len; apr_crypto_block_cleanup(block); @@ -247,8 +268,9 @@ static unsigned char *decrypt_block(abts_case *tc, apr_pool_t *pool, else { if (APR_SUCCESS != rv) { apr_crypto_error(&result, f); - fprintf(stderr, "decrypt_init: %s %s native error %d: %s (%s)\n", - description, apr_crypto_driver_name(driver), result->rc, + fprintf(stderr, + "decrypt_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 : ""); } @@ -268,10 +290,10 @@ static unsigned char *decrypt_block(abts_case *tc, apr_pool_t *pool, cipherTextLen, block); if (APR_SUCCESS != rv) { apr_crypto_error(&result, f); - fprintf(stderr, "decrypt: %s %s native error %d: %s (%s)\n", - description, apr_crypto_driver_name(driver), result->rc, - result->reason ? result->reason : "", result->msg ? result->msg - : ""); + 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_block_decrypt returned APR_ECRYPT", rv != APR_ECRYPT); ABTS_ASSERT(tc, "failed to apr_crypto_block_decrypt", rv == APR_SUCCESS); @@ -285,13 +307,15 @@ static unsigned char *decrypt_block(abts_case *tc, apr_pool_t *pool, block); if (APR_SUCCESS != rv) { apr_crypto_error(&result, f); - fprintf(stderr, "decrypt_finish: %s %s native error %d: %s (%s)\n", - description, apr_crypto_driver_name(driver), result->rc, - result->reason ? result->reason : "", result->msg ? result->msg - : ""); + fprintf(stderr, + "decrypt_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_block_decrypt_finish returned APR_ECRYPT", rv != APR_ECRYPT); ABTS_ASSERT(tc, "apr_crypto_block_decrypt_finish returned APR_EPADDING", rv != APR_EPADDING); + ABTS_ASSERT(tc, "apr_crypto_block_decrypt_finish returned APR_ENOSPACE", rv != APR_ENOSPACE); ABTS_ASSERT(tc, "failed to apr_crypto_block_decrypt_finish", rv == APR_SUCCESS); if (rv) { return NULL; @@ -440,6 +464,40 @@ static void test_crypto_block_nss(abts_case *tc, void *data) } /** + * Simple test of Common Crypto block crypt. + */ +static void test_crypto_block_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_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 0, + in, inlen, "KEY_3DES_192/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_ECB, 0, + in, inlen, "KEY_3DES_192/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 0, in, + inlen, "KEY_AES_256/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_ECB, 0, in, + inlen, "KEY_AES_256/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 0, in, + inlen, "KEY_AES_192/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 0, in, + inlen, "KEY_AES_192/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 0, in, + inlen, "KEY_AES_128/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 0, in, + inlen, "KEY_AES_128/MODE_ECB"); + apr_pool_destroy(pool); + +} + +/** * Encrypt NSS, decrypt OpenSSL. */ static void test_crypto_block_nss_openssl(abts_case *tc, void *data) @@ -518,6 +576,78 @@ static void test_crypto_block_openssl_nss(abts_case *tc, void *data) } /** + * Encrypt OpenSSL, decrypt CommonCrypto. + */ +static void test_crypto_block_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_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 0, in, + inlen, "KEY_3DES_192/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_ECB, 0, in, + inlen, "KEY_3DES_192/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 0, in, + inlen, "KEY_AES_256/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_ECB, 0, in, + inlen, "KEY_AES_256/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 0, in, + inlen, "KEY_AES_192/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 0, in, + inlen, "KEY_AES_192/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 0, in, + inlen, "KEY_AES_128/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 0, in, + inlen, "KEY_AES_128/MODE_ECB"); + apr_pool_destroy(pool); + +} + +/** + * Encrypt OpenSSL, decrypt CommonCrypto. + */ +static void test_crypto_block_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_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 0, in, + inlen, "KEY_3DES_192/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_ECB, 0, in, + inlen, "KEY_3DES_192/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 0, in, + inlen, "KEY_AES_256/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_ECB, 0, in, + inlen, "KEY_AES_256/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 0, in, + inlen, "KEY_AES_192/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 0, in, + inlen, "KEY_AES_192/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 0, in, + inlen, "KEY_AES_128/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 0, in, + inlen, "KEY_AES_128/MODE_ECB"); + apr_pool_destroy(pool); + +} + +/** * Simple test of OpenSSL block crypt. */ static void test_crypto_block_openssl_pad(abts_case *tc, void *data) @@ -597,6 +727,42 @@ static void test_crypto_block_nss_pad(abts_case *tc, void *data) } /** + * Simple test of Common Crypto block crypt. + */ +static void test_crypto_block_commoncrypto_pad(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 *) TEST_STRING; + apr_size_t inlen = sizeof(TEST_STRING); + + apr_pool_create(&pool, NULL); + drivers[0] = get_commoncrypto_driver(tc, pool); + drivers[1] = get_commoncrypto_driver(tc, pool); + + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 1, + in, inlen, "KEY_3DES_192/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_ECB, 1, + in, inlen, "KEY_3DES_192/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 1, in, + inlen, "KEY_AES_256/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_ECB, 1, in, + inlen, "KEY_AES_256/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 1, in, + inlen, "KEY_AES_192/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 1, in, + inlen, "KEY_AES_192/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 1, in, + inlen, "KEY_AES_128/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 1, in, + inlen, "KEY_AES_128/MODE_ECB"); + + apr_pool_destroy(pool); + +} + +/** * Encrypt NSS, decrypt OpenSSL. */ static void test_crypto_block_nss_openssl_pad(abts_case *tc, void *data) @@ -678,6 +844,82 @@ static void test_crypto_block_openssl_nss_pad(abts_case *tc, void *data) } /** + * Encrypt CommonCrypto, decrypt OpenSSL. + */ +static void test_crypto_block_commoncrypto_openssl_pad(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 *) TEST_STRING; + apr_size_t inlen = sizeof(TEST_STRING); + + apr_pool_create(&pool, NULL); + drivers[0] = get_commoncrypto_driver(tc, pool); + drivers[1] = get_openssl_driver(tc, pool); + + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 1, in, + inlen, "KEY_3DES_192/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_ECB, 1, in, + inlen, "KEY_3DES_192/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 1, in, + inlen, "KEY_AES_256/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_ECB, 1, in, + inlen, "KEY_AES_256/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 1, in, + inlen, "KEY_AES_192/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 1, in, + inlen, "KEY_AES_192/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 1, in, + inlen, "KEY_AES_128/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 1, in, + inlen, "KEY_AES_128/MODE_ECB"); + + apr_pool_destroy(pool); + +} + +/** + * Encrypt OpenSSL, decrypt CommonCrypto. + */ +static void test_crypto_block_openssl_commoncrypto_pad(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 *) TEST_STRING; + apr_size_t inlen = sizeof(TEST_STRING); + + apr_pool_create(&pool, NULL); + drivers[0] = get_openssl_driver(tc, pool); + drivers[1] = get_commoncrypto_driver(tc, pool); + + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 1, in, + inlen, "KEY_3DES_192/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_ECB, 1, in, + inlen, "KEY_3DES_192/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 1, in, + inlen, "KEY_AES_256/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_ECB, 1, in, + inlen, "KEY_AES_256/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 1, in, + inlen, "KEY_AES_192/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 1, in, + inlen, "KEY_AES_192/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 1, in, + inlen, "KEY_AES_128/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 1, in, + inlen, "KEY_AES_128/MODE_ECB"); + + apr_pool_destroy(pool); + +} + +/** * Get Types, OpenSSL. */ static void test_crypto_get_block_key_types_openssl(abts_case *tc, void *data) @@ -764,6 +1006,49 @@ static void test_crypto_get_block_key_types_nss(abts_case *tc, void *data) } /** + * Get Types, Common Crypto. + */ +static void test_crypto_get_block_key_types_commoncrypto(abts_case *tc, void *data) +{ + apr_pool_t *pool = NULL; + const apr_crypto_driver_t *driver; + apr_crypto_t *f; + apr_hash_t *types; + int *key_3des_192; + int *key_aes_128; + int *key_aes_192; + int *key_aes_256; + + apr_pool_create(&pool, NULL); + driver = get_commoncrypto_driver(tc, pool); + if (driver) { + + f = make(tc, pool, driver); + apr_crypto_get_block_key_types(&types, f); + + key_3des_192 = apr_hash_get(types, "3des192", APR_HASH_KEY_STRING); + ABTS_PTR_NOTNULL(tc, key_3des_192); + ABTS_INT_EQUAL(tc, *key_3des_192, APR_KEY_3DES_192); + + key_aes_128 = apr_hash_get(types, "aes128", APR_HASH_KEY_STRING); + ABTS_PTR_NOTNULL(tc, key_aes_128); + ABTS_INT_EQUAL(tc, *key_aes_128, APR_KEY_AES_128); + + key_aes_192 = apr_hash_get(types, "aes192", APR_HASH_KEY_STRING); + ABTS_PTR_NOTNULL(tc, key_aes_192); + ABTS_INT_EQUAL(tc, *key_aes_192, APR_KEY_AES_192); + + key_aes_256 = apr_hash_get(types, "aes256", APR_HASH_KEY_STRING); + ABTS_PTR_NOTNULL(tc, key_aes_256); + ABTS_INT_EQUAL(tc, *key_aes_256, APR_KEY_AES_256); + + } + + apr_pool_destroy(pool); + +} + +/** * Get Modes, OpenSSL. */ static void test_crypto_get_block_key_modes_openssl(abts_case *tc, void *data) @@ -829,6 +1114,39 @@ static void test_crypto_get_block_key_modes_nss(abts_case *tc, void *data) } +/** + * Get Modes, Common Crypto. + */ +static void test_crypto_get_block_key_modes_commoncrypto(abts_case *tc, void *data) +{ + apr_pool_t *pool = NULL; + const apr_crypto_driver_t *driver; + apr_crypto_t *f; + apr_hash_t *modes; + int *mode_ecb; + int *mode_cbc; + + apr_pool_create(&pool, NULL); + driver = get_commoncrypto_driver(tc, pool); + if (driver) { + + f = make(tc, pool, driver); + apr_crypto_get_block_key_modes(&modes, f); + + mode_ecb = apr_hash_get(modes, "ecb", APR_HASH_KEY_STRING); + ABTS_PTR_NOTNULL(tc, mode_ecb); + ABTS_INT_EQUAL(tc, *mode_ecb, APR_MODE_ECB); + + mode_cbc = apr_hash_get(modes, "cbc", APR_HASH_KEY_STRING); + ABTS_PTR_NOTNULL(tc, mode_cbc); + ABTS_INT_EQUAL(tc, *mode_cbc, APR_MODE_CBC); + + } + + apr_pool_destroy(pool); + +} + abts_suite *testcrypto(abts_suite *suite) { suite = ADD_SUITE(suite); @@ -848,6 +1166,12 @@ abts_suite *testcrypto(abts_suite *suite) /* 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 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); @@ -860,18 +1184,36 @@ abts_suite *testcrypto(abts_suite *suite) /* test padded encrypt openssl / decrypt nss */ abts_run_test(suite, test_crypto_block_openssl_nss_pad, 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 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 block key types openssl */ abts_run_test(suite, test_crypto_get_block_key_types_openssl, NULL); /* test block key types nss */ abts_run_test(suite, test_crypto_get_block_key_types_nss, NULL); + /* test block key types commoncrypto */ + abts_run_test(suite, test_crypto_get_block_key_types_commoncrypto, NULL); + /* test block key modes openssl */ abts_run_test(suite, test_crypto_get_block_key_modes_openssl, NULL); /* test block key modes nss */ abts_run_test(suite, test_crypto_get_block_key_modes_nss, NULL); + /* test block key modes commoncrypto */ + abts_run_test(suite, test_crypto_get_block_key_modes_commoncrypto, NULL); + return suite; } |