From 5139ddb3433c90e1f7a653dafc921356b8712c25 Mon Sep 17 00:00:00 2001 From: minfrin Date: Wed, 21 Nov 2007 21:01:50 +0000 Subject: Expose the SSL EVP interface to encrypt and decrypt arbitrary blocks of data, using symmetrical keys. Experimental support for asymmetrical public/private keys as supported by OpenSSL v0.9.9. git-svn-id: http://svn.apache.org/repos/asf/apr/apr-util/trunk@597209 13f79535-47bb-0310-9956-ffa450edef68 --- include/apr_buckets.h | 18 +++- include/apr_ssl.h | 157 ++++++++++++++++++++++++++++++ include/private/apr_ssl_openssl_private.h | 41 ++++++++ 3 files changed, 214 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/apr_buckets.h b/include/apr_buckets.h index 829c635c..2fe85195 100644 --- a/include/apr_buckets.h +++ b/include/apr_buckets.h @@ -971,7 +971,16 @@ APU_DECLARE_NONSTD(void) apr_bucket_free(void *block); } while (0) /** - * read the data from the bucket + * Read the data from the bucket. + * + * If it is not practical to return all + * the data in the bucket, the current bucket is split and replaced by + * two buckets, the first representing the data returned in this call, + * and the second representing the rest of the data as yet unread. The + * original bucket will become the first bucket after this call. + * + * (It is assumed that the bucket is a member of a brigade when this + * function is called). * @param e The bucket to read from * @param str The location to store the data in * @param len The amount of data read @@ -988,7 +997,12 @@ APU_DECLARE_NONSTD(void) apr_bucket_free(void *block); #define apr_bucket_setaside(e,p) (e)->type->setaside(e,p) /** - * Split one bucket in two. + * Split one bucket in two at the point provided. + * + * Once split, the original bucket becomes the first of the two new buckets. + * + * (It is assumed that the bucket is a member of a brigade when this + * function is called). * @param e The bucket to split * @param point The offset to split the bucket at */ diff --git a/include/apr_ssl.h b/include/apr_ssl.h index 45fe498a..99ab9bde 100644 --- a/include/apr_ssl.h +++ b/include/apr_ssl.h @@ -254,6 +254,163 @@ APU_DECLARE(apr_status_t) apr_pollset_remove_ssl_socket(apr_ssl_socket_t *); APU_DECLARE(apr_status_t) apr_ssl_socket_set_poll_events(apr_ssl_socket_t *, apr_int16_t); + + +/** + * Values that determine how a created factory will be used. + */ +typedef enum { + APR_EVP_FACTORY_SYM, /**< Factory is for symmetrical operations */ + APR_EVP_FACTORY_ASYM /**< Factory is for asymmetrical operations */ +} apr_evp_factory_type_e; + +/** + * Values that determine whether we need to encrypt or decrypt. + */ +typedef enum { + APR_EVP_DECRYPT=0, + APR_EVP_ENCRYPT=1 +} apr_evp_crypt_type_e; + +/** + * Values that determine which key to use during encrypt or decrypt. + */ +typedef enum { + APR_EVP_KEY_SYM=0, /* Use a passphrase / symmetrical */ + APR_EVP_KEY_PUBLIC=1, /* Use the public key / asymmetrical */ + APR_EVP_KEY_PRIVATE=2 /* Use the private key / asymetrical */ +} apr_evp_crypt_key_e; + +/** + * Structure for referencing an evp "factory" + */ +typedef struct apu_evp_factory apr_evp_factory_t; + +/** + * Structure for referencing an EVP PKEY context. + */ +typedef struct apu_evp_crypt apr_evp_crypt_t; + +/** + * @fn apr_status_t apr_evp_factory_create(apr_evp_factory_t **newFactory, + const char *privateKeyFilename, + const char *certificateFilename, + const char *cipherName, + const char *passphrase, + const char *engine, + const char *digest, + apr_evp_factory_type_e purpose, + apr_pool_t *pool) + * @brief Attempts to create an EVP "factory". The "factory" is then + * used to create contexts to keep track of encryption. + * @param newFactory The newly created factory + * @param privateKeyFilename Private key filename to use for assetrical encryption + * @param certificateFilename X509 certificate file to use for assymetrical encryption + * @param cipherName Name of cipher to use for symmetrical encryption + * @param passphrase Passphrase to use for assymetrical encryption + * @param purpose Constant that determines how the created factory will be used + * @param pool The pool to use for memory allocations + * @return an APR_ status code. APR_ENOCERT will be returned if the certificates + * cannot be loaded, APR_ENOCIPHER if the cipher cannot be found. + * APR_ENODIGEST if the digest cannot be found. APR_ENOTIMPL will + * be returned if not supported. + */ +APU_DECLARE(apr_status_t) apr_evp_factory_create(apr_evp_factory_t **newFactory, + const char *privateKeyFn, + const char *certFn, + const char *cipherName, + const char *passphrase, + const char *engine, + const char *digest, + apr_evp_factory_type_e purpose, + apr_pool_t *pool); + +/** + * @fn apr_status_t apr_evp_crypt_init(apr_evp_factory_t *, + * apr_evp_crypt_t **e, + * apr_evp_crypt_type_e type, + * apr_evp_crypt_key_e key, + * apr_pool_t *p) + * @brief Initialise a context for encrypting arbitrary data. + * @note If *e is NULL, a apr_evp_crypt_t will be created from a pool. If + * *e is not NULL, *e must point at a previously created structure. + * @param factory The EVP factory containing keys to use. + * @param evp The evp context returned, see note. + * @param type Whether to encrypt or decrypt. + * @param key Which key to use. + * @param p The pool to use. + * @return APR_EINIT if initialisation unsuccessful. Returns + * APR_ENOTIMPL if not supported. + */ +APR_DECLARE(apr_status_t) apr_evp_crypt_init(apr_evp_factory_t *, + apr_evp_crypt_t **e, + apr_evp_crypt_type_e type, + apr_evp_crypt_key_e key, + apr_pool_t *p); + +/** + * @fn apr_status_t apr_evp_crypt(apr_evp_crypt_t *evp, + * unsigned char *out, + * apr_size_t *outlen, + * const unsigned char *in, + * apr_size_t inlen) + * @brief Encrypt/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. + * @param evp The evp 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_EGENERAL if an error occurred. Returns APR_ENOTIMPL if + * not supported. + */ +APR_DECLARE(apr_status_t) apr_evp_crypt(apr_evp_crypt_t *, + unsigned char **out, + apr_size_t *outlen, + const unsigned char *in, + apr_size_t inlen); + +/** + * @fn apr_status_t apr_evp_crypt_finish(apr_evp_crypt_t *, + * unsigned char *out, + * apr_size_t *outlen) + * @brief Encrypt final data block, write it to out. + * @note If necessary the final block will be written out after being + * padded. After this call, the context is cleaned and can be + * reused by apr_env_encrypt_init() or apr_env_decrypt_init(). + * @param evp The evp context to use. + * @param out Address of a buffer to which data will be written. + * @param outlen Length of the output will be written here. + * @return APR_EGENERAL if an error occurred. Returns APR_ENOTIMPL if + * not supported. + */ +APR_DECLARE(apr_status_t) apr_evp_crypt_finish(apr_evp_crypt_t *e, + unsigned char *out, + apr_size_t *outlen); + + +/** + * @fn apr_status_t apr_evp_crypt_cleanup(apr_evp_crypt_t *e) + * @brief Clean encryption / decryption context. + * @note After cleanup, a context is free to be reused if necessary. + * @param evp The evp context to use. + * @return Returns APR_ENOTIMPL if not supported. + */ +APR_DECLARE(apr_status_t) apr_evp_crypt_cleanup(apr_evp_crypt_t *e); + +/** + * @fn apr_status_t apr_evp_factory_cleanup(apr_evp_factory_t *f) + * @brief Clean encryption / decryption factory. + * @note After cleanup, a factory is free to be reused if necessary. + * @param f The factory to use. + * @return Returns APR_ENOTIMPL if not supported. + */ +APR_DECLARE(apr_status_t) apr_evp_factory_cleanup(apr_evp_factory_t *f); + + /** @} */ #ifdef __cplusplus } diff --git a/include/private/apr_ssl_openssl_private.h b/include/private/apr_ssl_openssl_private.h index af968d40..3ef3a982 100644 --- a/include/private/apr_ssl_openssl_private.h +++ b/include/private/apr_ssl_openssl_private.h @@ -32,6 +32,47 @@ struct apu_ssl_socket_data { int sslErr; /** SSL_get_error() code */ }; +typedef struct apu_evp_data apu_evp_data_t; + +/** + * EVP factory structure + */ +struct apu_evp_factory { + apr_pool_t *pool; /**< pool to use for memory allocations */ + apr_evp_factory_type_e purpose; /**< Purpose of the factory */ + apu_evp_data_t *evpData; /**< Pointer to implementation specific data */ +}; + +/** + * Define the cipher context structure used as a handle by + * the generic apu_evp_* functions. + */ +struct apu_evp_data { + const EVP_CIPHER *cipher; + const EVP_MD *md; + unsigned char salt[8]; + unsigned char key[EVP_MAX_KEY_LENGTH]; + unsigned char iv[EVP_MAX_IV_LENGTH]; + const char *privateKeyFilename; + const char *certificateFilename; +#if HAVE_DECL_EVP_PKEY_CTX_NEW + SSL_CTX *sslCtx; + SSL *ssl; + EVP_PKEY *pubkey; + EVP_PKEY *privkey; +#endif +}; + +struct apu_evp_crypt { + apr_pool_t *pool; + EVP_CIPHER_CTX *cipherCtx; +#if HAVE_DECL_EVP_PKEY_CTX_NEW + EVP_PKEY_CTX *pkeyCtx; +#endif + apr_evp_factory_type_e purpose; + apr_evp_crypt_type_e type; + apr_evp_crypt_key_e key; +}; #endif /* APU_HAVE_OPENSSL */ -- cgit v1.2.1