diff options
Diffstat (limited to 'crypto/apr_crypto_nss.c')
-rw-r--r-- | crypto/apr_crypto_nss.c | 780 |
1 files changed, 0 insertions, 780 deletions
diff --git a/crypto/apr_crypto_nss.c b/crypto/apr_crypto_nss.c deleted file mode 100644 index 89ba1274..00000000 --- a/crypto/apr_crypto_nss.c +++ /dev/null @@ -1,780 +0,0 @@ -/* 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 "apu.h" - -#include "apu_config.h" -#include "apu_errno.h" - -#include <ctype.h> -#include <stdlib.h> - -#include "apr_strings.h" -#include "apr_time.h" -#include "apr_buckets.h" - -#include "apr_crypto_internal.h" - -#if APU_HAVE_CRYPTO - -#include <prerror.h> - -#ifdef HAVE_NSS_NSS_H -#include <nss/nss.h> -#endif -#ifdef HAVE_NSS_H -#include <nss.h> -#endif - -#ifdef HAVE_NSS_PK11PUB_H -#include <nss/pk11pub.h> -#endif -#ifdef HAVE_PK11PUB_H -#include <pk11pub.h> -#endif - -struct apr_crypto_config_t { -}; - -struct apr_crypto_key_t { - CK_MECHANISM_TYPE cipherMech; - SECOidTag cipherOid; - PK11SymKey *symKey; - int ivSize; -}; - -struct apr_crypto_block_t { - const apr_crypto_t *factory; - apr_pool_t *pool; - PK11Context *ctx; - apr_crypto_key_t *key; - int blockSize; -}; - - -/** - * Shutdown the crypto library and release resources. - * - * It is safe to shut down twice. - */ -static apr_status_t crypto_shutdown(apr_pool_t *pool) -{ - if (NSS_IsInitialized()) { - SECStatus s = NSS_Shutdown(); - if (s != SECSuccess) { - return APR_EINIT; - } - } - return APR_SUCCESS; -} - -static apr_status_t crypto_shutdown_helper(void *data) -{ - apr_pool_t *pool = (apr_pool_t *) data; - return crypto_shutdown(pool); -} - -/** - * Initialise the crypto library and perform one time initialisation. - */ -static apr_status_t crypto_init(apr_pool_t *pool, const apr_array_header_t *params, int *rc) -{ - SECStatus s; - const char *dir = NULL; - const char *keyPrefix = NULL; - const char *certPrefix = NULL; - const char *secmod = NULL; - PRUint32 flags = 0; - struct apr_crypto_param_t *ents = params ? (struct apr_crypto_param_t *)params->elts : NULL; - int i = 0; - - /* sanity check - we can only initialise NSS once */ - if (NSS_IsInitialized()) { - return APR_EREINIT; - } - - apr_pool_cleanup_register(pool, pool, - crypto_shutdown_helper, - apr_pool_cleanup_null); - - for (i = 0; params && i < params->nelts; i++) { - switch (ents[i].type) { - case APR_CRYPTO_CA_TYPE_DIR: - dir = ents[i].path; - break; - case APR_CRYPTO_CERT_TYPE_KEY3_DB: - keyPrefix = ents[i].path; - break; - case APR_CRYPTO_CA_TYPE_CERT7_DB: - certPrefix = ents[i].path; - break; - case APR_CRYPTO_CA_TYPE_SECMOD: - secmod = ents[i].path; - break; - default: - return APR_EINIT; - } - } - - 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 (rc) { - *rc = PR_GetError(); - } - return APR_ECRYPT; - } - - return APR_SUCCESS; - -} - -/** - * @brief Clean encryption / decryption context. - * @note After cleanup, a context is free to be reused if necessary. - * @param driver - driver to use - * @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 *block) -{ - - if (block->ctx) { - PK11_DestroyContext(block->ctx, PR_TRUE); - block->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); -} - -/** - * @brief Clean encryption / decryption factory. - * @note After cleanup, a factory is free to be reused if necessary. - * @param driver - driver to use - * @param f The factory to use. - * @return Returns APR_ENOTIMPL if not supported. - */ -static apr_status_t crypto_cleanup(apr_crypto_t *f) -{ - apr_crypto_key_t *key; - if (f->keys) { - while ((key = apr_array_pop(f->keys))) { - if (key->symKey) { - PK11_FreeSymKey(key->symKey); - key->symKey = NULL; - } - } - } - 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 driver - driver to use - * @param pool - process pool - * @param params - array of key parameters - * @param factory - factory pointer will be written here - * @return APR_ENOENGINE when the engine specified does not exist. APR_EINITENGINE - * if the engine cannot be initialised. - */ -static apr_status_t crypto_factory(apr_pool_t *pool, - const apr_array_header_t *params, - apr_crypto_t **factory) -{ - apr_crypto_config_t *config = NULL; - /* struct apr_crypto_param_t *ents = params ? (struct apr_crypto_param_t *)params->elts : NULL; */ - /* int i = 0; */ - apr_crypto_t *f; - - f = apr_pcalloc(pool, sizeof(apr_crypto_t)); - if (!f) { - return APR_ENOMEM; - } - *factory = f; - f->pool = pool; - config = f->config = apr_pcalloc(pool, sizeof(apr_crypto_config_t)); - if (!config) { - return APR_ENOMEM; - } - 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)); - - apr_pool_cleanup_register(pool, f, - crypto_cleanup_helper, - apr_pool_cleanup_null); - - /* - for (i = 0; params && i < params->nelts; i++) { - switch (ents[i].type) { - default: - f->result->rc = -1; - f->result->reason = "The NSS module currently supports " - "no per factory initialisation parameters at this time, but " - "may do in future."; - return APR_EINIT; - } - } - */ - - 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 driver - driver to use - * @param p The pool to use. - * @param f The context to use. - * @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 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. - * @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_pool_t *p, - const apr_crypto_t *f, - 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, - apr_crypto_key_t **k, - apr_size_t *ivSize) -{ - apr_status_t rv = APR_SUCCESS; - PK11SlotInfo * slot; - SECItem passItem; - SECItem saltItem; - SECAlgorithmID *algid; - void *wincx = NULL; /* what is wincx? */ - apr_crypto_key_t *key = *k; - - if (!key) { - *k = key = apr_array_push(f->keys); - } - if (!key) { - return APR_ENOMEM; - } - - /* decide on what cipher mechanism we will be using */ - switch (type) { - - case (KEY_3DES_192) : - if (MODE_CBC == mode) { - key->cipherOid = SEC_OID_DES_EDE3_CBC; - } - else if (MODE_ECB == mode) { - return APR_ENOCIPHER; - /* No OID for CKM_DES3_ECB; */ - } - break; - case (KEY_AES_128) : - if (MODE_CBC == mode) { - key->cipherOid = SEC_OID_AES_128_CBC; - } - else { - key->cipherOid = SEC_OID_AES_128_ECB; - } - break; - case (KEY_AES_192) : - if (MODE_CBC == mode) { - key->cipherOid = SEC_OID_AES_192_CBC; - } - else { - key->cipherOid = SEC_OID_AES_192_ECB; - } - break; - case (KEY_AES_256) : - if (MODE_CBC == mode) { - key->cipherOid = SEC_OID_AES_256_CBC; - } - else { - key->cipherOid = SEC_OID_AES_256_ECB; - } - break; - default: - /* unknown key type, give up */ - return APR_EKEYTYPE; - } - - /* AES_128_CBC --> CKM_AES_CBC --> CKM_AES_CBC_PAD */ - key->cipherMech = PK11_AlgtagToMechanism(key->cipherOid); - if (key->cipherMech == CKM_INVALID_MECHANISM) { - return APR_ENOCIPHER; - } - if (doPad) { - CK_MECHANISM_TYPE paddedMech; - paddedMech = PK11_GetPadMechanism(key->cipherMech); - if (CKM_INVALID_MECHANISM == paddedMech || key->cipherMech == paddedMech) { - return APR_EPADDING; - } - key->cipherMech = paddedMech; - } - - /* Turn the raw passphrase and salt into SECItems */ - passItem.data = (unsigned char*)pass; - passItem.len = passLen; - saltItem.data = (unsigned char*)salt; - saltItem.len = saltLen; - - /* generate the key */ - /* pbeAlg and cipherAlg are the same. NSS decides the keylength. */ - algid = PK11_CreatePBEV2AlgorithmID(key->cipherOid, key->cipherOid, SEC_OID_HMAC_SHA1, 0, iterations, &saltItem); - if (algid) { - slot = PK11_GetBestSlot(key->cipherMech, wincx); - if (slot) { - key->symKey = PK11_PBEKeyGen(slot, algid, &passItem, PR_FALSE, wincx); - PK11_FreeSlot(slot); - } - 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; - } - } - - key->ivSize = PK11_GetIVLength(key->cipherMech); - if (ivSize) { - *ivSize = key->ivSize; - } - - return rv; -} - -/** - * @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 p The pool to use. - * @param f The block factory to use. - * @param key The key structure. - * @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 ctx The block context returned, see note. - * @param blockSize The block size of the cipher. - * @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_pool_t *p, - const apr_crypto_t *f, - const apr_crypto_key_t *key, - const unsigned char **iv, - apr_crypto_block_t **ctx, - apr_size_t *blockSize) -{ - PRErrorCode perr; - SECItem * secParam; - SECItem ivItem; - 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->factory = f; - block->pool = p; - - 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) { - usedIv = apr_pcalloc(p, key->ivSize); - if (!usedIv) { - return APR_ENOMEM; - } - SECStatus 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; - secParam = PK11_ParamFromIV(key->cipherMech, &ivItem); - } - else { - secParam = PK11_GenerateNewParam(key->cipherMech, key->symKey); - } - block->blockSize = PK11_GetBlockSize(key->cipherMech, secParam); - block->ctx = PK11_CreateContextBySymKey(key->cipherMech, CKA_ENCRYPT, key->symKey, secParam); - - /* did an error occur? */ - perr = PORT_GetError(); - if (perr || !block->ctx) { - f->result->rc = perr; - f->result->msg = PR_ErrorToName(perr); - return APR_EINIT; - } - - if (blockSize) { - *blockSize = PK11_GetBlockSize(key->cipherMech, secParam); - } - - 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 ctx The block context to use. - * @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. - * @return APR_ECRYPT if an error occurred. Returns APR_ENOTIMPL if - * not implemented. - */ -static apr_status_t crypto_block_encrypt(apr_crypto_block_t *block, - unsigned char **out, - apr_size_t *outlen, - const unsigned char *in, - apr_size_t inlen) -{ - - unsigned char *buffer; - int outl = (int) *outlen; - if (!out) { - *outlen = inlen + block->blockSize; - return APR_SUCCESS; - } - if (!*out) { - buffer = apr_palloc(block->pool, inlen + block->blockSize); - if (!buffer) { - return APR_ENOMEM; - } - *out = buffer; - } - - SECStatus s = PK11_CipherOp(block->ctx, *out, &outl, inlen, (unsigned char*)in, inlen); - if (s != SECSuccess) { - PRErrorCode perr = PORT_GetError(); - if (perr) { - block->factory->result->rc = perr; - block->factory->result->msg = PR_ErrorToName(perr); - } - 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 ctx The block context to use. - * @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. - * @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(apr_crypto_block_t *block, - unsigned char *out, - apr_size_t *outlen) -{ - - apr_status_t rv = APR_SUCCESS; - unsigned int outl = *outlen; - - SECStatus s = PK11_DigestFinal(block->ctx, out, &outl, block->blockSize); - *outlen = outl; - - if (s != SECSuccess) { - PRErrorCode perr = PORT_GetError(); - if (perr) { - block->factory->result->rc = perr; - block->factory->result->msg = PR_ErrorToName(perr); - } - rv = APR_ECRYPT; - } - crypto_block_cleanup(block); - - return rv; - -} - -/** - * @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 p The pool to use. - * @param f The block factory to use. - * @param key The key structure. - * @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 ctx The block context returned, see note. - * @param blockSize The block size of the cipher. - * @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_pool_t *p, - const apr_crypto_t *f, - const apr_crypto_key_t *key, - const unsigned char *iv, - apr_crypto_block_t **ctx, - apr_size_t *blockSize) -{ - PRErrorCode perr; - SECItem * secParam; - apr_crypto_block_t *block = *ctx; - if (!block) { - *ctx = block = apr_pcalloc(p, sizeof(apr_crypto_block_t)); - } - if (!block) { - return APR_ENOMEM; - } - block->factory = f; - block->pool = p; - - 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; - secParam = PK11_ParamFromIV(key->cipherMech, &ivItem); - } - else { - secParam = PK11_GenerateNewParam(key->cipherMech, key->symKey); - } - block->blockSize = PK11_GetBlockSize(key->cipherMech, secParam); - block->ctx = PK11_CreateContextBySymKey(key->cipherMech, CKA_DECRYPT, key->symKey, secParam); - - /* did an error occur? */ - perr = PORT_GetError(); - if (perr || !block->ctx) { - f->result->rc = perr; - f->result->msg = PR_ErrorToName(perr); - return APR_EINIT; - } - - if (blockSize) { - *blockSize = PK11_GetBlockSize(key->cipherMech, secParam); - } - - 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_final 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 ctx The block context to use. - * @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. - * @return APR_ECRYPT if an error occurred. Returns APR_ENOTIMPL if - * not implemented. - */ -static apr_status_t crypto_block_decrypt(apr_crypto_block_t *block, - unsigned char **out, - apr_size_t *outlen, - const unsigned char *in, - apr_size_t inlen) -{ - - unsigned char *buffer; - int outl = (int) *outlen; - if (!out) { - *outlen = inlen + block->blockSize; - return APR_SUCCESS; - } - if (!*out) { - buffer = apr_palloc(block->pool, inlen + block->blockSize); - if (!buffer) { - return APR_ENOMEM; - } - *out = buffer; - } - - SECStatus s = PK11_CipherOp(block->ctx, *out, &outl, inlen, (unsigned char*)in, inlen); - if (s != SECSuccess) { - PRErrorCode perr = PORT_GetError(); - if (perr) { - block->factory->result->rc = perr; - block->factory->result->msg = PR_ErrorToName(perr); - } - 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_evp_crypt, offset by the number of - * bytes returned as actually written by the apr_evp_crypt() - * call. After this call, the context is cleaned and can be - * reused by apr_env_encrypt_init() or apr_env_decrypt_init(). - * @param ctx The block context to use. - * @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. - * @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(apr_crypto_block_t *block, - unsigned char *out, - apr_size_t *outlen) -{ - - apr_status_t rv = APR_SUCCESS; - unsigned int outl = *outlen; - - SECStatus s = PK11_DigestFinal(block->ctx, out, &outl, block->blockSize); - *outlen = outl; - - if (s != SECSuccess) { - PRErrorCode perr = PORT_GetError(); - if (perr) { - block->factory->result->rc = perr; - block->factory->result->msg = PR_ErrorToName(perr); - } - rv = APR_ECRYPT; - } - crypto_block_cleanup(block); - - return rv; - -} - -/** - * OpenSSL module. - */ -APU_MODULE_DECLARE_DATA const apr_crypto_driver_t apr_crypto_nss_driver = { - "nss", - crypto_init, - crypto_factory, - 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 -}; - -#endif |