diff options
author | Pavan Deolasee | 2017-06-14 05:42:18 +0000 |
---|---|---|
committer | Pavan Deolasee | 2017-06-14 05:42:18 +0000 |
commit | 15dd5274c323fb93e4e3ea9ad2185aaaec10f79c (patch) | |
tree | 9dafb4c7f735d9429ea461dc792933af87493c33 /contrib/pgcrypto/openssl.c | |
parent | dfbb88e3bbb526dcb204b456b9e5cfd9d10d0d0a (diff) | |
parent | d5cb3bab564e0927ffac7c8729eacf181a12dd40 (diff) |
Merge from PG master upto d5cb3bab564e0927ffac7c8729eacf181a12dd40
This is the result of the "git merge remotes/PGSQL/master" upto the said commit
point. We have done some basic analysis, fixed compilation problems etc, but
bulk of the logical problems in conflict resolution etc will be handled by
subsequent commits.
Diffstat (limited to 'contrib/pgcrypto/openssl.c')
-rw-r--r-- | contrib/pgcrypto/openssl.c | 970 |
1 files changed, 372 insertions, 598 deletions
diff --git a/contrib/pgcrypto/openssl.c b/contrib/pgcrypto/openssl.c index 976af70591..f71a933407 100644 --- a/contrib/pgcrypto/openssl.c +++ b/contrib/pgcrypto/openssl.c @@ -34,11 +34,11 @@ #include "px.h" #include <openssl/evp.h> -#include <openssl/blowfish.h> -#include <openssl/cast.h> -#include <openssl/des.h> -#include <openssl/rand.h> #include <openssl/err.h> +#include <openssl/rand.h> + +#include "utils/memutils.h" +#include "utils/resowner.h" /* * Max lengths we might want to handle. @@ -47,170 +47,76 @@ #define MAX_IV (128/8) /* - * Compatibility with OpenSSL 0.9.6 - * - * It needs AES and newer DES and digest API. - */ -#if OPENSSL_VERSION_NUMBER >= 0x00907000L - -/* - * Nothing needed for OpenSSL 0.9.7+ + * Hashes */ -#include <openssl/aes.h> -#else /* old OPENSSL */ - /* - * Emulate OpenSSL AES. + * To make sure we don't leak OpenSSL handles on abort, we keep OSSLDigest + * objects in a linked list, allocated in TopMemoryContext. We use the + * ResourceOwner mechanism to free them on abort. */ - -#include "rijndael.c" - -#define AES_ENCRYPT 1 -#define AES_DECRYPT 0 -#define AES_KEY rijndael_ctx - -static int -AES_set_encrypt_key(const uint8 *key, int kbits, AES_KEY *ctx) +typedef struct OSSLDigest { - aes_set_key(ctx, key, kbits, 1); - return 0; -} + const EVP_MD *algo; + EVP_MD_CTX *ctx; -static int -AES_set_decrypt_key(const uint8 *key, int kbits, AES_KEY *ctx) -{ - aes_set_key(ctx, key, kbits, 0); - return 0; -} + ResourceOwner owner; + struct OSSLDigest *next; + struct OSSLDigest *prev; +} OSSLDigest; -static void -AES_ecb_encrypt(const uint8 *src, uint8 *dst, AES_KEY *ctx, int enc) -{ - memcpy(dst, src, 16); - if (enc) - aes_ecb_encrypt(ctx, dst, 16); - else - aes_ecb_decrypt(ctx, dst, 16); -} +static OSSLDigest *open_digests = NULL; +static bool digest_resowner_callback_registered = false; static void -AES_cbc_encrypt(const uint8 *src, uint8 *dst, int len, AES_KEY *ctx, uint8 *iv, int enc) +free_openssl_digest(OSSLDigest *digest) { - memcpy(dst, src, len); - if (enc) - { - aes_cbc_encrypt(ctx, iv, dst, len); - memcpy(iv, dst + len - 16, 16); - } + EVP_MD_CTX_destroy(digest->ctx); + if (digest->prev) + digest->prev->next = digest->next; else - { - aes_cbc_decrypt(ctx, iv, dst, len); - memcpy(iv, src + len - 16, 16); - } + open_digests = digest->next; + if (digest->next) + digest->next->prev = digest->prev; + pfree(digest); } /* - * Emulate DES_* API - */ - -#define DES_key_schedule des_key_schedule -#define DES_cblock des_cblock -#define DES_set_key(k, ks) \ - des_set_key((k), *(ks)) -#define DES_ecb_encrypt(i, o, k, e) \ - des_ecb_encrypt((i), (o), *(k), (e)) -#define DES_ncbc_encrypt(i, o, l, k, iv, e) \ - des_ncbc_encrypt((i), (o), (l), *(k), (iv), (e)) -#define DES_ecb3_encrypt(i, o, k1, k2, k3, e) \ - des_ecb3_encrypt((des_cblock *)(i), (des_cblock *)(o), \ - *(k1), *(k2), *(k3), (e)) -#define DES_ede3_cbc_encrypt(i, o, l, k1, k2, k3, iv, e) \ - des_ede3_cbc_encrypt((i), (o), \ - (l), *(k1), *(k2), *(k3), (iv), (e)) - -/* - * Emulate newer digest API. + * Close any open OpenSSL handles on abort. */ - static void -EVP_MD_CTX_init(EVP_MD_CTX *ctx) +digest_free_callback(ResourceReleasePhase phase, + bool isCommit, + bool isTopLevel, + void *arg) { - memset(ctx, 0, sizeof(*ctx)); -} + OSSLDigest *curr; + OSSLDigest *next; -static int -EVP_MD_CTX_cleanup(EVP_MD_CTX *ctx) -{ - px_memset(ctx, 0, sizeof(*ctx)); - return 1; -} + if (phase != RESOURCE_RELEASE_AFTER_LOCKS) + return; -static int -EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *md, void *engine) -{ - EVP_DigestInit(ctx, md); - return 1; -} - -static int -EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *res, unsigned int *len) -{ - EVP_DigestFinal(ctx, res, len); - return 1; -} -#endif /* old OpenSSL */ - -/* - * Provide SHA2 for older OpenSSL < 0.9.8 - */ -#if OPENSSL_VERSION_NUMBER < 0x00908000L - -#include "sha2.c" -#include "internal-sha2.c" - -typedef void (*init_f) (PX_MD *md); - -static int -compat_find_digest(const char *name, PX_MD **res) -{ - init_f init = NULL; - - if (pg_strcasecmp(name, "sha224") == 0) - init = init_sha224; - else if (pg_strcasecmp(name, "sha256") == 0) - init = init_sha256; - else if (pg_strcasecmp(name, "sha384") == 0) - init = init_sha384; - else if (pg_strcasecmp(name, "sha512") == 0) - init = init_sha512; - else - return PXE_NO_HASH; + next = open_digests; + while (next) + { + curr = next; + next = curr->next; - *res = px_alloc(sizeof(PX_MD)); - init(*res); - return 0; + if (curr->owner == CurrentResourceOwner) + { + if (isCommit) + elog(WARNING, "pgcrypto digest reference leak: digest %p still referenced", curr); + free_openssl_digest(curr); + } + } } -#else -#define compat_find_digest(name, res) (PXE_NO_HASH) -#endif - -/* - * Hashes - */ - -typedef struct OSSLDigest -{ - const EVP_MD *algo; - EVP_MD_CTX ctx; -} OSSLDigest; static unsigned digest_result_size(PX_MD *h) { OSSLDigest *digest = (OSSLDigest *) h->p.ptr; - return EVP_MD_CTX_size(&digest->ctx); + return EVP_MD_CTX_size(digest->ctx); } static unsigned @@ -218,7 +124,7 @@ digest_block_size(PX_MD *h) { OSSLDigest *digest = (OSSLDigest *) h->p.ptr; - return EVP_MD_CTX_block_size(&digest->ctx); + return EVP_MD_CTX_block_size(digest->ctx); } static void @@ -226,7 +132,7 @@ digest_reset(PX_MD *h) { OSSLDigest *digest = (OSSLDigest *) h->p.ptr; - EVP_DigestInit_ex(&digest->ctx, digest->algo, NULL); + EVP_DigestInit_ex(digest->ctx, digest->algo, NULL); } static void @@ -234,7 +140,7 @@ digest_update(PX_MD *h, const uint8 *data, unsigned dlen) { OSSLDigest *digest = (OSSLDigest *) h->p.ptr; - EVP_DigestUpdate(&digest->ctx, data, dlen); + EVP_DigestUpdate(digest->ctx, data, dlen); } static void @@ -242,7 +148,7 @@ digest_finish(PX_MD *h, uint8 *dst) { OSSLDigest *digest = (OSSLDigest *) h->p.ptr; - EVP_DigestFinal_ex(&digest->ctx, dst, NULL); + EVP_DigestFinal_ex(digest->ctx, dst, NULL); } static void @@ -250,9 +156,7 @@ digest_free(PX_MD *h) { OSSLDigest *digest = (OSSLDigest *) h->p.ptr; - EVP_MD_CTX_cleanup(&digest->ctx); - - px_free(digest); + free_openssl_digest(digest); px_free(h); } @@ -264,6 +168,7 @@ int px_find_digest(const char *name, PX_MD **res) { const EVP_MD *md; + EVP_MD_CTX *ctx; PX_MD *h; OSSLDigest *digest; @@ -273,17 +178,43 @@ px_find_digest(const char *name, PX_MD **res) OpenSSL_add_all_algorithms(); } + if (!digest_resowner_callback_registered) + { + RegisterResourceReleaseCallback(digest_free_callback, NULL); + digest_resowner_callback_registered = true; + } + md = EVP_get_digestbyname(name); if (md == NULL) - return compat_find_digest(name, res); + return PXE_NO_HASH; - digest = px_alloc(sizeof(*digest)); - digest->algo = md; + /* + * Create an OSSLDigest object, an OpenSSL MD object, and a PX_MD object. + * The order is crucial, to make sure we don't leak anything on + * out-of-memory or other error. + */ + digest = MemoryContextAlloc(TopMemoryContext, sizeof(*digest)); - EVP_MD_CTX_init(&digest->ctx); - if (EVP_DigestInit_ex(&digest->ctx, digest->algo, NULL) == 0) + ctx = EVP_MD_CTX_create(); + if (!ctx) + { + pfree(digest); return -1; + } + if (EVP_DigestInit_ex(ctx, md, NULL) == 0) + { + pfree(digest); + return -1; + } + + digest->algo = md; + digest->ctx = ctx; + digest->owner = CurrentResourceOwner; + digest->next = open_digests; + digest->prev = NULL; + open_digests = digest; + /* The PX_MD object is allocated in the current memory context. */ h = px_alloc(sizeof(*h)); h->result_size = digest_result_size; h->block_size = digest_block_size; @@ -300,60 +231,101 @@ px_find_digest(const char *name, PX_MD **res) /* * Ciphers * - * The problem with OpenSSL is that the EVP* family - * of functions does not allow enough flexibility - * and forces some of the parameters (keylen, - * padding) to SSL defaults. - * - * So need to manage ciphers ourselves. + * We use OpenSSL's EVP* family of functions for these. */ +/* + * prototype for the EVP functions that return an algorithm, e.g. + * EVP_aes_128_cbc(). + */ +typedef const EVP_CIPHER *(*ossl_EVP_cipher_func) (void); + +/* + * ossl_cipher contains the static information about each cipher. + */ struct ossl_cipher { int (*init) (PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv); - int (*encrypt) (PX_Cipher *c, const uint8 *data, unsigned dlen, uint8 *res); - int (*decrypt) (PX_Cipher *c, const uint8 *data, unsigned dlen, uint8 *res); - + ossl_EVP_cipher_func cipher_func; int block_size; int max_key_size; - int stream_cipher; }; -typedef struct +/* + * OSSLCipher contains the state for using a cipher. A separate OSSLCipher + * object is allocated in each px_find_cipher() call. + * + * To make sure we don't leak OpenSSL handles on abort, we keep OSSLCipher + * objects in a linked list, allocated in TopMemoryContext. We use the + * ResourceOwner mechanism to free them on abort. + */ +typedef struct OSSLCipher { - union - { - struct - { - BF_KEY key; - int num; - } bf; - struct - { - DES_key_schedule key_schedule; - } des; - struct - { - DES_key_schedule k1, - k2, - k3; - } des3; - CAST_KEY cast_key; - AES_KEY aes_key; - } u; + EVP_CIPHER_CTX *evp_ctx; + const EVP_CIPHER *evp_ciph; uint8 key[MAX_KEY]; uint8 iv[MAX_IV]; unsigned klen; unsigned init; const struct ossl_cipher *ciph; -} ossldata; -/* generic */ + ResourceOwner owner; + struct OSSLCipher *next; + struct OSSLCipher *prev; +} OSSLCipher; + +static OSSLCipher *open_ciphers = NULL; +static bool cipher_resowner_callback_registered = false; + +static void +free_openssl_cipher(OSSLCipher *od) +{ + EVP_CIPHER_CTX_free(od->evp_ctx); + if (od->prev) + od->prev->next = od->next; + else + open_ciphers = od->next; + if (od->next) + od->next->prev = od->prev; + pfree(od); +} + +/* + * Close any open OpenSSL cipher handles on abort. + */ +static void +cipher_free_callback(ResourceReleasePhase phase, + bool isCommit, + bool isTopLevel, + void *arg) +{ + OSSLCipher *curr; + OSSLCipher *next; + + if (phase != RESOURCE_RELEASE_AFTER_LOCKS) + return; + + next = open_ciphers; + while (next) + { + curr = next; + next = curr->next; + + if (curr->owner == CurrentResourceOwner) + { + if (isCommit) + elog(WARNING, "pgcrypto cipher reference leak: cipher %p still referenced", curr); + free_openssl_cipher(curr); + } + } +} + +/* Common routines for all algorithms */ static unsigned gen_ossl_block_size(PX_Cipher *c) { - ossldata *od = (ossldata *) c->ptr; + OSSLCipher *od = (OSSLCipher *) c->ptr; return od->ciph->block_size; } @@ -361,7 +333,7 @@ gen_ossl_block_size(PX_Cipher *c) static unsigned gen_ossl_key_size(PX_Cipher *c) { - ossldata *od = (ossldata *) c->ptr; + OSSLCipher *od = (OSSLCipher *) c->ptr; return od->ciph->max_key_size; } @@ -370,7 +342,7 @@ static unsigned gen_ossl_iv_size(PX_Cipher *c) { unsigned ivlen; - ossldata *od = (ossldata *) c->ptr; + OSSLCipher *od = (OSSLCipher *) c->ptr; ivlen = od->ciph->block_size; return ivlen; @@ -379,13 +351,60 @@ gen_ossl_iv_size(PX_Cipher *c) static void gen_ossl_free(PX_Cipher *c) { - ossldata *od = (ossldata *) c->ptr; + OSSLCipher *od = (OSSLCipher *) c->ptr; - px_memset(od, 0, sizeof(*od)); - px_free(od); + free_openssl_cipher(od); px_free(c); } +static int +gen_ossl_decrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, + uint8 *res) +{ + OSSLCipher *od = c->ptr; + int outlen; + + if (!od->init) + { + if (!EVP_DecryptInit_ex(od->evp_ctx, od->evp_ciph, NULL, NULL, NULL)) + return PXE_CIPHER_INIT; + if (!EVP_CIPHER_CTX_set_key_length(od->evp_ctx, od->klen)) + return PXE_CIPHER_INIT; + if (!EVP_DecryptInit_ex(od->evp_ctx, NULL, NULL, od->key, od->iv)) + return PXE_CIPHER_INIT; + od->init = true; + } + + if (!EVP_DecryptUpdate(od->evp_ctx, res, &outlen, data, dlen)) + return PXE_DECRYPT_FAILED; + + return 0; +} + +static int +gen_ossl_encrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, + uint8 *res) +{ + OSSLCipher *od = c->ptr; + int outlen; + + if (!od->init) + { + if (!EVP_EncryptInit_ex(od->evp_ctx, od->evp_ciph, NULL, NULL, NULL)) + return PXE_CIPHER_INIT; + if (!EVP_CIPHER_CTX_set_key_length(od->evp_ctx, od->klen)) + return PXE_CIPHER_INIT; + if (!EVP_EncryptInit_ex(od->evp_ctx, NULL, NULL, od->key, od->iv)) + return PXE_CIPHER_INIT; + od->init = true; + } + + if (!EVP_EncryptUpdate(od->evp_ctx, res, &outlen, data, dlen)) + return PXE_ERR_GENERIC; + + return 0; +} + /* Blowfish */ /* @@ -407,24 +426,40 @@ bf_check_supported_key_len(void) static const uint8 data[8] = {0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10}; static const uint8 res[8] = {0xc0, 0x45, 0x04, 0x01, 0x2e, 0x4e, 0x1f, 0x53}; - static uint8 out[8]; - - BF_KEY bf_key; + uint8 out[8]; + EVP_CIPHER_CTX *evp_ctx; + int outlen; + int status = 0; /* encrypt with 448bits key and verify output */ - BF_set_key(&bf_key, 56, key); - BF_ecb_encrypt(data, out, &bf_key, BF_ENCRYPT); + evp_ctx = EVP_CIPHER_CTX_new(); + if (!evp_ctx) + return 0; + if (!EVP_EncryptInit_ex(evp_ctx, EVP_bf_ecb(), NULL, NULL, NULL)) + goto leave; + if (!EVP_CIPHER_CTX_set_key_length(evp_ctx, 56)) + goto leave; + if (!EVP_EncryptInit_ex(evp_ctx, NULL, NULL, key, NULL)) + goto leave; + + if (!EVP_EncryptUpdate(evp_ctx, out, &outlen, data, 8)) + goto leave; if (memcmp(out, res, 8) != 0) - return 0; /* Output does not match -> strong cipher is + goto leave; /* Output does not match -> strong cipher is * not supported */ - return 1; + status = 1; + +leave: + EVP_CIPHER_CTX_free(evp_ctx); + return status; } static int bf_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv) { - ossldata *od = c->ptr; + OSSLCipher *od = c->ptr; + unsigned bs = gen_ossl_block_size(c); static int bf_is_strong = -1; /* @@ -440,74 +475,13 @@ bf_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv) return PXE_KEY_TOO_BIG; /* Key len is supported. We can use it. */ - BF_set_key(&od->u.bf.key, klen, key); + od->klen = klen; + memcpy(od->key, key, klen); + if (iv) - memcpy(od->iv, iv, BF_BLOCK); + memcpy(od->iv, iv, bs); else - memset(od->iv, 0, BF_BLOCK); - od->u.bf.num = 0; - return 0; -} - -static int -bf_ecb_encrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, uint8 *res) -{ - unsigned bs = gen_ossl_block_size(c); - unsigned i; - ossldata *od = c->ptr; - - for (i = 0; i < dlen / bs; i++) - BF_ecb_encrypt(data + i * bs, res + i * bs, &od->u.bf.key, BF_ENCRYPT); - return 0; -} - -static int -bf_ecb_decrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, uint8 *res) -{ - unsigned bs = gen_ossl_block_size(c), - i; - ossldata *od = c->ptr; - - for (i = 0; i < dlen / bs; i++) - BF_ecb_encrypt(data + i * bs, res + i * bs, &od->u.bf.key, BF_DECRYPT); - return 0; -} - -static int -bf_cbc_encrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, uint8 *res) -{ - ossldata *od = c->ptr; - - BF_cbc_encrypt(data, res, dlen, &od->u.bf.key, od->iv, BF_ENCRYPT); - return 0; -} - -static int -bf_cbc_decrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, uint8 *res) -{ - ossldata *od = c->ptr; - - BF_cbc_encrypt(data, res, dlen, &od->u.bf.key, od->iv, BF_DECRYPT); - return 0; -} - -static int -bf_cfb64_encrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, uint8 *res) -{ - ossldata *od = c->ptr; - - BF_cfb64_encrypt(data, res, dlen, &od->u.bf.key, od->iv, - &od->u.bf.num, BF_ENCRYPT); - return 0; -} - -static int -bf_cfb64_decrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, uint8 *res) -{ - ossldata *od = c->ptr; - - BF_cfb64_encrypt(data, res, dlen, &od->u.bf.key, od->iv, - &od->u.bf.num, BF_DECRYPT); + memset(od->iv, 0, bs); return 0; } @@ -516,70 +490,17 @@ bf_cfb64_decrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, uint8 *res) static int ossl_des_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv) { - ossldata *od = c->ptr; - DES_cblock xkey; + OSSLCipher *od = c->ptr; + unsigned bs = gen_ossl_block_size(c); - memset(&xkey, 0, sizeof(xkey)); - memcpy(&xkey, key, klen > 8 ? 8 : klen); - DES_set_key(&xkey, &od->u.des.key_schedule); - memset(&xkey, 0, sizeof(xkey)); + od->klen = 8; + memset(od->key, 0, 8); + memcpy(od->key, key, klen > 8 ? 8 : klen); if (iv) - memcpy(od->iv, iv, 8); + memcpy(od->iv, iv, bs); else - memset(od->iv, 0, 8); - return 0; -} - -static int -ossl_des_ecb_encrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, - uint8 *res) -{ - unsigned bs = gen_ossl_block_size(c); - unsigned i; - ossldata *od = c->ptr; - - for (i = 0; i < dlen / bs; i++) - DES_ecb_encrypt((DES_cblock *) (data + i * bs), - (DES_cblock *) (res + i * bs), - &od->u.des.key_schedule, 1); - return 0; -} - -static int -ossl_des_ecb_decrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, - uint8 *res) -{ - unsigned bs = gen_ossl_block_size(c); - unsigned i; - ossldata *od = c->ptr; - - for (i = 0; i < dlen / bs; i++) - DES_ecb_encrypt((DES_cblock *) (data + i * bs), - (DES_cblock *) (res + i * bs), - &od->u.des.key_schedule, 0); - return 0; -} - -static int -ossl_des_cbc_encrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, - uint8 *res) -{ - ossldata *od = c->ptr; - - DES_ncbc_encrypt(data, res, dlen, &od->u.des.key_schedule, - (DES_cblock *) od->iv, 1); - return 0; -} - -static int -ossl_des_cbc_decrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, - uint8 *res) -{ - ossldata *od = c->ptr; - - DES_ncbc_encrypt(data, res, dlen, &od->u.des.key_schedule, - (DES_cblock *) od->iv, 0); + memset(od->iv, 0, bs); return 0; } @@ -588,83 +509,17 @@ ossl_des_cbc_decrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, static int ossl_des3_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv) { - ossldata *od = c->ptr; - DES_cblock xkey1, - xkey2, - xkey3; - - memset(&xkey1, 0, sizeof(xkey1)); - memset(&xkey2, 0, sizeof(xkey2)); - memset(&xkey3, 0, sizeof(xkey3)); - memcpy(&xkey1, key, klen > 8 ? 8 : klen); - if (klen > 8) - memcpy(&xkey2, key + 8, (klen - 8) > 8 ? 8 : (klen - 8)); - if (klen > 16) - memcpy(&xkey3, key + 16, (klen - 16) > 8 ? 8 : (klen - 16)); - - DES_set_key(&xkey1, &od->u.des3.k1); - DES_set_key(&xkey2, &od->u.des3.k2); - DES_set_key(&xkey3, &od->u.des3.k3); - memset(&xkey1, 0, sizeof(xkey1)); - memset(&xkey2, 0, sizeof(xkey2)); - memset(&xkey3, 0, sizeof(xkey3)); - - if (iv) - memcpy(od->iv, iv, 8); - else - memset(od->iv, 0, 8); - return 0; -} - -static int -ossl_des3_ecb_encrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, - uint8 *res) -{ + OSSLCipher *od = c->ptr; unsigned bs = gen_ossl_block_size(c); - unsigned i; - ossldata *od = c->ptr; - for (i = 0; i < dlen / bs; i++) - DES_ecb3_encrypt((void *) (data + i * bs), (void *) (res + i * bs), - &od->u.des3.k1, &od->u.des3.k2, &od->u.des3.k3, 1); - return 0; -} - -static int -ossl_des3_ecb_decrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, - uint8 *res) -{ - unsigned bs = gen_ossl_block_size(c); - unsigned i; - ossldata *od = c->ptr; - - for (i = 0; i < dlen / bs; i++) - DES_ecb3_encrypt((void *) (data + i * bs), (void *) (res + i * bs), - &od->u.des3.k1, &od->u.des3.k2, &od->u.des3.k3, 0); - return 0; -} - -static int -ossl_des3_cbc_encrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, - uint8 *res) -{ - ossldata *od = c->ptr; + od->klen = 24; + memset(od->key, 0, 24); + memcpy(od->key, key, klen > 24 ? 24 : klen); - DES_ede3_cbc_encrypt(data, res, dlen, - &od->u.des3.k1, &od->u.des3.k2, &od->u.des3.k3, - (DES_cblock *) od->iv, 1); - return 0; -} - -static int -ossl_des3_cbc_decrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, - uint8 *res) -{ - ossldata *od = c->ptr; - - DES_ede3_cbc_encrypt(data, res, dlen, - &od->u.des3.k1, &od->u.des3.k2, &od->u.des3.k3, - (DES_cblock *) od->iv, 0); + if (iv) + memcpy(od->iv, iv, bs); + else + memset(od->iv, 0, bs); return 0; } @@ -673,10 +528,12 @@ ossl_des3_cbc_decrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, static int ossl_cast_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv) { - ossldata *od = c->ptr; + OSSLCipher *od = c->ptr; unsigned bs = gen_ossl_block_size(c); - CAST_set_key(&od->u.cast_key, klen, key); + od->klen = klen; + memcpy(od->key, key, klen); + if (iv) memcpy(od->iv, iv, bs); else @@ -684,54 +541,12 @@ ossl_cast_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv) return 0; } -static int -ossl_cast_ecb_encrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, uint8 *res) -{ - unsigned bs = gen_ossl_block_size(c); - ossldata *od = c->ptr; - const uint8 *end = data + dlen - bs; - - for (; data <= end; data += bs, res += bs) - CAST_ecb_encrypt(data, res, &od->u.cast_key, CAST_ENCRYPT); - return 0; -} - -static int -ossl_cast_ecb_decrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, uint8 *res) -{ - unsigned bs = gen_ossl_block_size(c); - ossldata *od = c->ptr; - const uint8 *end = data + dlen - bs; - - for (; data <= end; data += bs, res += bs) - CAST_ecb_encrypt(data, res, &od->u.cast_key, CAST_DECRYPT); - return 0; -} - -static int -ossl_cast_cbc_encrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, uint8 *res) -{ - ossldata *od = c->ptr; - - CAST_cbc_encrypt(data, res, dlen, &od->u.cast_key, od->iv, CAST_ENCRYPT); - return 0; -} - -static int -ossl_cast_cbc_decrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, uint8 *res) -{ - ossldata *od = c->ptr; - - CAST_cbc_encrypt(data, res, dlen, &od->u.cast_key, od->iv, CAST_DECRYPT); - return 0; -} - /* AES */ static int ossl_aes_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv) { - ossldata *od = c->ptr; + OSSLCipher *od = c->ptr; unsigned bs = gen_ossl_block_size(c); if (klen <= 128 / 8) @@ -749,96 +564,68 @@ ossl_aes_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv) memcpy(od->iv, iv, bs); else memset(od->iv, 0, bs); + return 0; } static int -ossl_aes_key_init(ossldata *od, int type) +ossl_aes_ecb_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv) { + OSSLCipher *od = c->ptr; int err; - /* - * Strong key support could be missing on some openssl installations. We - * must check return value from set key function. - */ - if (type == AES_ENCRYPT) - err = AES_set_encrypt_key(od->key, od->klen * 8, &od->u.aes_key); - else - err = AES_set_decrypt_key(od->key, od->klen * 8, &od->u.aes_key); + err = ossl_aes_init(c, key, klen, iv); + if (err) + return err; - if (err == 0) + switch (od->klen) { - od->init = 1; - return 0; + case 128 / 8: + od->evp_ciph = EVP_aes_128_ecb(); + break; + case 192 / 8: + od->evp_ciph = EVP_aes_192_ecb(); + break; + case 256 / 8: + od->evp_ciph = EVP_aes_256_ecb(); + break; + default: + /* shouldn't happen */ + err = PXE_CIPHER_INIT; + break; } - od->init = 0; - return PXE_KEY_TOO_BIG; -} - -static int -ossl_aes_ecb_encrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, - uint8 *res) -{ - unsigned bs = gen_ossl_block_size(c); - ossldata *od = c->ptr; - const uint8 *end = data + dlen - bs; - int err; - - if (!od->init) - if ((err = ossl_aes_key_init(od, AES_ENCRYPT)) != 0) - return err; - for (; data <= end; data += bs, res += bs) - AES_ecb_encrypt(data, res, &od->u.aes_key, AES_ENCRYPT); - return 0; -} - -static int -ossl_aes_ecb_decrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, - uint8 *res) -{ - unsigned bs = gen_ossl_block_size(c); - ossldata *od = c->ptr; - const uint8 *end = data + dlen - bs; - int err; - - if (!od->init) - if ((err = ossl_aes_key_init(od, AES_DECRYPT)) != 0) - return err; - - for (; data <= end; data += bs, res += bs) - AES_ecb_encrypt(data, res, &od->u.aes_key, AES_DECRYPT); - return 0; + return err; } static int -ossl_aes_cbc_encrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, - uint8 *res) +ossl_aes_cbc_init(PX_Cipher *c, const uint8 *key, unsigned klen, const uint8 *iv) { - ossldata *od = c->ptr; + OSSLCipher *od = c->ptr; int err; - if (!od->init) - if ((err = ossl_aes_key_init(od, AES_ENCRYPT)) != 0) - return err; - - AES_cbc_encrypt(data, res, dlen, &od->u.aes_key, od->iv, AES_ENCRYPT); - return 0; -} + err = ossl_aes_init(c, key, klen, iv); + if (err) + return err; -static int -ossl_aes_cbc_decrypt(PX_Cipher *c, const uint8 *data, unsigned dlen, - uint8 *res) -{ - ossldata *od = c->ptr; - int err; - - if (!od->init) - if ((err = ossl_aes_key_init(od, AES_DECRYPT)) != 0) - return err; + switch (od->klen) + { + case 128 / 8: + od->evp_ciph = EVP_aes_128_cbc(); + break; + case 192 / 8: + od->evp_ciph = EVP_aes_192_cbc(); + break; + case 256 / 8: + od->evp_ciph = EVP_aes_256_cbc(); + break; + default: + /* shouldn't happen */ + err = PXE_CIPHER_INIT; + break; + } - AES_cbc_encrypt(data, res, dlen, &od->u.aes_key, od->iv, AES_DECRYPT); - return 0; + return err; } /* @@ -864,58 +651,71 @@ static PX_Alias ossl_aliases[] = { }; static const struct ossl_cipher ossl_bf_cbc = { - bf_init, bf_cbc_encrypt, bf_cbc_decrypt, - 64 / 8, 448 / 8, 0 + bf_init, + EVP_bf_cbc, + 64 / 8, 448 / 8 }; static const struct ossl_cipher ossl_bf_ecb = { - bf_init, bf_ecb_encrypt, bf_ecb_decrypt, - 64 / 8, 448 / 8, 0 + bf_init, + EVP_bf_ecb, + 64 / 8, 448 / 8 }; static const struct ossl_cipher ossl_bf_cfb = { - bf_init, bf_cfb64_encrypt, bf_cfb64_decrypt, - 64 / 8, 448 / 8, 1 + bf_init, + EVP_bf_cfb, + 64 / 8, 448 / 8 }; static const struct ossl_cipher ossl_des_ecb = { - ossl_des_init, ossl_des_ecb_encrypt, ossl_des_ecb_decrypt, - 64 / 8, 64 / 8, 0 + ossl_des_init, + EVP_des_ecb, + 64 / 8, 64 / 8 }; static const struct ossl_cipher ossl_des_cbc = { - ossl_des_init, ossl_des_cbc_encrypt, ossl_des_cbc_decrypt, - 64 / 8, 64 / 8, 0 + ossl_des_init, + EVP_des_cbc, + 64 / 8, 64 / 8 }; static const struct ossl_cipher ossl_des3_ecb = { - ossl_des3_init, ossl_des3_ecb_encrypt, ossl_des3_ecb_decrypt, - 64 / 8, 192 / 8, 0 + ossl_des3_init, + EVP_des_ede3_ecb, + 64 / 8, 192 / 8 }; static const struct ossl_cipher ossl_des3_cbc = { - ossl_des3_init, ossl_des3_cbc_encrypt, ossl_des3_cbc_decrypt, - 64 / 8, 192 / 8, 0 + ossl_des3_init, + EVP_des_ede3_cbc, + 64 / 8, 192 / 8 }; static const struct ossl_cipher ossl_cast_ecb = { - ossl_cast_init, ossl_cast_ecb_encrypt, ossl_cast_ecb_decrypt, - 64 / 8, 128 / 8, 0 + ossl_cast_init, + EVP_cast5_ecb, + 64 / 8, 128 / 8 }; static const struct ossl_cipher ossl_cast_cbc = { - ossl_cast_init, ossl_cast_cbc_encrypt, ossl_cast_cbc_decrypt, - 64 / 8, 128 / 8, 0 + ossl_cast_init, + EVP_cast5_cbc, + 64 / 8, 128 / 8 }; static const struct ossl_cipher ossl_aes_ecb = { - ossl_aes_init, ossl_aes_ecb_encrypt, ossl_aes_ecb_decrypt, - 128 / 8, 256 / 8, 0 + ossl_aes_ecb_init, + NULL, /* EVP_aes_XXX_ecb(), determined in init + * function */ + 128 / 8, 256 / 8 }; static const struct ossl_cipher ossl_aes_cbc = { - ossl_aes_init, ossl_aes_cbc_encrypt, ossl_aes_cbc_decrypt, - 128 / 8, 256 / 8, 0 + ossl_aes_cbc_init, + NULL, /* EVP_aes_XXX_cbc(), determined in init + * function */ + 128 / 8, 256 / 8 }; /* @@ -949,7 +749,8 @@ px_find_cipher(const char *name, PX_Cipher **res) { const struct ossl_cipher_lookup *i; PX_Cipher *c = NULL; - ossldata *od; + EVP_CIPHER_CTX *ctx; + OSSLCipher *od; name = px_resolve_alias(ossl_aliases, name); for (i = ossl_cipher_types; i->name; i++) @@ -958,75 +759,48 @@ px_find_cipher(const char *name, PX_Cipher **res) if (i->name == NULL) return PXE_NO_CIPHER; - od = px_alloc(sizeof(*od)); - memset(od, 0, sizeof(*od)); + if (!cipher_resowner_callback_registered) + { + RegisterResourceReleaseCallback(cipher_free_callback, NULL); + cipher_resowner_callback_registered = true; + } + + /* + * Create an OSSLCipher object, an EVP_CIPHER_CTX object and a PX_Cipher. + * The order is crucial, to make sure we don't leak anything on + * out-of-memory or other error. + */ + od = MemoryContextAllocZero(TopMemoryContext, sizeof(*od)); od->ciph = i->ciph; + /* Allocate an EVP_CIPHER_CTX object. */ + ctx = EVP_CIPHER_CTX_new(); + if (!ctx) + { + pfree(od); + return PXE_CIPHER_INIT; + } + + od->evp_ctx = ctx; + od->owner = CurrentResourceOwner; + od->next = open_ciphers; + od->prev = NULL; + open_ciphers = od; + + if (i->ciph->cipher_func) + od->evp_ciph = i->ciph->cipher_func(); + + /* The PX_Cipher is allocated in current memory context */ c = px_alloc(sizeof(*c)); c->block_size = gen_ossl_block_size; c->key_size = gen_ossl_key_size; c->iv_size = gen_ossl_iv_size; c->free = gen_ossl_free; c->init = od->ciph->init; - c->encrypt = od->ciph->encrypt; - c->decrypt = od->ciph->decrypt; + c->encrypt = gen_ossl_encrypt; + c->decrypt = gen_ossl_decrypt; c->ptr = od; *res = c; return 0; } - - -static int openssl_random_init = 0; - -/* - * OpenSSL random should re-feeded occasionally. From /dev/urandom - * preferably. - */ -static void -init_openssl_rand(void) -{ - if (RAND_get_rand_method() == NULL) - RAND_set_rand_method(RAND_SSLeay()); - openssl_random_init = 1; -} - -int -px_get_random_bytes(uint8 *dst, unsigned count) -{ - int res; - - if (!openssl_random_init) - init_openssl_rand(); - - res = RAND_bytes(dst, count); - if (res == 1) - return count; - - return PXE_OSSL_RAND_ERROR; -} - -int -px_get_pseudo_random_bytes(uint8 *dst, unsigned count) -{ - int res; - - if (!openssl_random_init) - init_openssl_rand(); - - res = RAND_pseudo_bytes(dst, count); - if (res == 0 || res == 1) - return count; - - return PXE_OSSL_RAND_ERROR; -} - -int -px_add_entropy(const uint8 *data, unsigned count) -{ - /* - * estimate 0 bits - */ - RAND_add(data, count, 0); - return 0; -} |