diff options
Diffstat (limited to 'src/lib/crypt.c')
-rw-r--r-- | src/lib/crypt.c | 577 |
1 files changed, 263 insertions, 314 deletions
diff --git a/src/lib/crypt.c b/src/lib/crypt.c index ad679501..756fcccc 100644 --- a/src/lib/crypt.c +++ b/src/lib/crypt.c @@ -1,8 +1,7 @@ /* * Ouroboros - Copyright (C) 2016 - 2024 * - * Elliptic curve Diffie-Hellman key exchange and - * AES encryption for flows using OpenSSL + * Cryptographic operations * * Dimitri Staessens <dimitri@ouroboros.rocks> * Sander Vrijders <sander@ouroboros.rocks> @@ -20,436 +19,386 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., http://www.fsf.org/about/contact/. */ + #include <config.h> #include <ouroboros/crypt.h> #include <ouroboros/errno.h> +#ifdef HAVE_OPENSSL + #include "crypt/openssl.h" +#endif /* HAVE_OPENSSL */ #include <assert.h> #include <string.h> -#ifdef HAVE_OPENSSL - -#include <ouroboros/hash.h> -#include <ouroboros/random.h> - -#include <openssl/evp.h> -#include <openssl/ec.h> -#include <openssl/pem.h> - -#include <openssl/bio.h> +struct crypt_ctx { + uint16_t flags; + void * ctx; + uint8_t key[SYMMKEYSZ]; +}; -#define IVSZ 16 -/* SYMMKEYSZ defined in dev.c */ +struct auth_ctx { + void * store; +}; -/* - * Derive the common secret from - * your public key pair (kp) - * the remote public key (pub). - * Store it in a preallocated buffer (s). - */ -static int __openssl_ecdh_derive_secret(EVP_PKEY * kp, - EVP_PKEY * pub, - uint8_t * s) +int crypt_dh_pkp_create(void ** pkp, + uint8_t * pk) { - EVP_PKEY_CTX * ctx; - int ret; - uint8_t * secret; - size_t secret_len; - - ctx = EVP_PKEY_CTX_new(kp, NULL); - if (ctx == NULL) - goto fail_new; - - ret = EVP_PKEY_derive_init(ctx); - if (ret != 1) - goto fail_ctx; - - ret = EVP_PKEY_derive_set_peer(ctx, pub); - if (ret != 1) - goto fail_ctx; - - ret = EVP_PKEY_derive(ctx, NULL, &secret_len); - if (ret != 1) - goto fail_ctx; - - if (secret_len < SYMMKEYSZ) - goto fail_ctx; - - secret = OPENSSL_malloc(secret_len); - if (secret == NULL) - goto fail_ctx; - - ret = EVP_PKEY_derive(ctx, secret, &secret_len); - if (ret != 1) - goto fail_derive; - - /* Hash the secret for use as AES key. */ - mem_hash(HASH_SHA3_256, s, secret, secret_len); +#ifdef HAVE_OPENSSL + assert(pkp != NULL); + *pkp = NULL; + return openssl_ecdh_pkp_create(pkp, pk); +#else + (void) pkp; + (void) pk; - OPENSSL_free(secret); - EVP_PKEY_CTX_free(ctx); + *pkp = NULL; return 0; - - fail_derive: - OPENSSL_free(secret); - fail_ctx: - EVP_PKEY_CTX_free(ctx); - fail_new: - return -ECRYPT; +#endif } -static int __openssl_ecdh_gen_key(void ** kp) +void crypt_dh_pkp_destroy(void * pkp) { - EVP_PKEY_CTX * ctx = NULL; - EVP_PKEY_CTX * kctx = NULL; - EVP_PKEY * params = NULL; - int ret; - - ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL); - if (ctx == NULL) - goto fail_new_id; - - ret = EVP_PKEY_paramgen_init(ctx); - if (ret != 1) - goto fail_paramgen; - - ret = EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, NID_X9_62_prime256v1); - if (ret != 1) - goto fail_paramgen; - - ret = EVP_PKEY_paramgen(ctx, ¶ms); - if (ret != 1) - goto fail_paramgen; - - kctx = EVP_PKEY_CTX_new(params, NULL); - if (kctx == NULL) - goto fail_keygen_init; - - ret = EVP_PKEY_keygen_init(kctx); - if (ret != 1) - goto fail_keygen; - - ret = EVP_PKEY_keygen(kctx, (EVP_PKEY **) kp); - if (ret != 1) - goto fail_keygen; +#ifdef HAVE_OPENSSL + openssl_ecdh_pkp_destroy(pkp); +#else + (void) pkp; + return; +#endif +} - EVP_PKEY_free(params); - EVP_PKEY_CTX_free(kctx); - EVP_PKEY_CTX_free(ctx); +int crypt_dh_derive(void * pkp, + buffer_t pk, + uint8_t * s) +{ +#ifdef HAVE_OPENSSL + return openssl_ecdh_derive(pkp, pk, s); +#else + (void) pkp; + (void) pk; - return 0; + memset(s, 0, SYMMKEYSZ); - fail_keygen: - EVP_PKEY_CTX_free(kctx); - fail_keygen_init: - EVP_PKEY_free(params); - fail_paramgen: - EVP_PKEY_CTX_free(ctx); - fail_new_id: return -ECRYPT; +#endif } -static ssize_t openssl_ecdh_pkp_create(void ** pkp, - uint8_t * pk) +int crypt_encrypt(struct crypt_ctx * ctx, + buffer_t in, + buffer_t * out) { - uint8_t * pos; - ssize_t len; - - assert(pkp != NULL); - assert(*pkp == NULL); - assert(pk != NULL); - - if (__openssl_ecdh_gen_key(pkp) < 0) - return -ECRYPT; - - assert(*pkp != NULL); - - pos = pk; /* i2d_PUBKEY increments the pointer, don't use buf! */ - len = i2d_PUBKEY(*pkp, &pos); - if (len < 0) { - EVP_PKEY_free(*pkp); - return -ECRYPT; + if (ctx->flags == 0) { + clrbuf(*out); + return 0; } - return len; -} +#ifdef HAVE_OPENSSL + return openssl_encrypt(ctx->ctx, ctx->key, in, out); +#else + (void) in; + (void) out; -static void openssl_ecdh_pkp_destroy(void * pkp) -{ - EVP_PKEY_free((EVP_PKEY *) pkp); + return -ECRYPT; +#endif } -static int openssl_ecdh_derive(void * pkp, - buffer_t pk, - uint8_t * s) +int crypt_decrypt(struct crypt_ctx * ctx, + buffer_t in, + buffer_t * out) { - uint8_t * pos; - EVP_PKEY * pub; - - pos = pk.data; /* d2i_PUBKEY increments the pointer, don't use key ptr! */ - pub = d2i_PUBKEY(NULL, (const uint8_t **) &pos, (long) pk.len); - if (pub == NULL) - return -ECRYPT; - - if (__openssl_ecdh_derive_secret(pkp, pub, s) < 0) { - EVP_PKEY_free(pub); - return -ECRYPT; + if (ctx->flags == 0) { + clrbuf(*out); + return 0; } - EVP_PKEY_free(pub); +#ifdef HAVE_OPENSSL + return openssl_decrypt(ctx->ctx, ctx->key, in, out); +#else + (void) in; + (void) out; - return 0; + return -ECRYPT; +#endif } -/* - * AES encryption calls. If FRCT is disabled, we should generate a - * 128-bit random IV and append it to the packet. If the flow is - * reliable, we could initialize the context once, and consider the - * stream a single encrypted message to avoid initializing the - * encryption context for each packet. - */ - -static int openssl_encrypt(void * ctx, - uint8_t * key, - struct shm_du_buff * sdb) +struct crypt_ctx * crypt_create_ctx(uint16_t flags, + const uint8_t * key) { - uint8_t * out; - uint8_t * in; - uint8_t * head; - uint8_t iv[IVSZ]; - int in_sz; - int out_sz; - int tmp_sz; - int ret; - - in = shm_du_buff_head(sdb); - in_sz = shm_du_buff_tail(sdb) - in; - - assert(in_sz > 0); - - if (random_buffer(iv, IVSZ) < 0) - goto fail_iv; - - out = malloc(in_sz + EVP_MAX_BLOCK_LENGTH); - if (out == NULL) - goto fail_iv; + struct crypt_ctx * crypt; - EVP_CIPHER_CTX_reset(ctx); + crypt = malloc(sizeof(*crypt)); + if (crypt == NULL) + goto fail_crypt; - ret = EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv); - if (ret != 1) - goto fail_encrypt_init; + memset(crypt, 0, sizeof(*crypt)); - ret = EVP_EncryptUpdate(ctx, out, &tmp_sz, in, in_sz); - if (ret != 1) - goto fail_encrypt; - - out_sz = tmp_sz; - ret = EVP_EncryptFinal_ex(ctx, out + tmp_sz, &tmp_sz); - if (ret != 1) - goto fail_encrypt; - - out_sz += tmp_sz; - - EVP_CIPHER_CTX_cleanup(ctx); - - assert(out_sz >= in_sz); + crypt->flags = flags; + if (key != NULL) + memcpy(crypt->key, key, SYMMKEYSZ); +#ifdef HAVE_OPENSSL + crypt->ctx=openssl_crypt_create_ctx(); + if (crypt->ctx == NULL) + goto fail_ctx; +#endif + return crypt; +#ifdef HAVE_OPENSSL + fail_ctx: + free(crypt); +#endif + fail_crypt: + return NULL; +} - head = shm_du_buff_head_alloc(sdb, IVSZ); - if (head == NULL) - goto fail_encrypt; +void crypt_destroy_ctx(struct crypt_ctx * crypt) +{ + if (crypt == NULL) + return; - if (shm_du_buff_tail_alloc(sdb, out_sz - in_sz) == NULL) - goto fail_tail_alloc; +#ifdef HAVE_OPENSSL + assert(crypt->ctx != NULL); + openssl_crypt_destroy_ctx(crypt->ctx); +#else + assert(crypt->ctx == NULL); +#endif + free(crypt); +} - memcpy(head, iv, IVSZ); - memcpy(in, out, out_sz); +int crypt_load_privkey_file(const char * path, + void ** key) +{ + *key = NULL; - free(out); +#ifdef HAVE_OPENSSL + return openssl_load_privkey_file(path, key); +#else + (void) path; return 0; - - fail_tail_alloc: - shm_du_buff_head_release(sdb, IVSZ); - fail_encrypt: - EVP_CIPHER_CTX_cleanup(ctx); - fail_encrypt_init: - free(out); - fail_iv: - return -ECRYPT; +#endif } -static int openssl_decrypt(void * ctx, - uint8_t * key, - struct shm_du_buff * sdb) +int crypt_load_privkey_str(const char * str, + void ** key) { - uint8_t * in; - uint8_t * out; - uint8_t iv[IVSZ]; - int ret; - int out_sz; - int in_sz; - int tmp_sz; + *key = NULL; - in_sz = shm_du_buff_len(sdb); - if (in_sz < IVSZ) - return -ECRYPT; - - in = shm_du_buff_head_release(sdb, IVSZ); +#ifdef HAVE_OPENSSL + return openssl_load_privkey_str(str, key); +#else + (void) str; - memcpy(iv, in, IVSZ); + return 0; +#endif +} - in = shm_du_buff_head(sdb); - in_sz = shm_du_buff_tail(sdb) - in; +int crypt_load_pubkey_str(const char * str, + void ** key) +{ + *key = NULL; - out = malloc(in_sz); - if (out == NULL) - goto fail_malloc; +#ifdef HAVE_OPENSSL + return openssl_load_pubkey_str(str, key); +#else + (void) str; - EVP_CIPHER_CTX_reset(ctx); + return 0; +#endif +} - ret = EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv); - if (ret != 1) - goto fail_decrypt_init; +int crypt_cmp_key(const void * key1, + const void * key2) +{ +#ifdef HAVE_OPENSSL + return openssl_cmp_key(key1, key2); +#else + (void) key1; + (void) key2; - ret = EVP_DecryptUpdate(ctx, out, &tmp_sz, in, in_sz); - if (ret != 1) - goto fail_decrypt; + return 0; +#endif +} - out_sz = tmp_sz; +void crypt_free_key(void * key) +{ + if (key == NULL) + return; - ret = EVP_DecryptFinal_ex(ctx, out + tmp_sz, &tmp_sz); - if (ret != 1) - goto fail_decrypt; +#ifdef HAVE_OPENSSL + openssl_free_key(key); +#endif +} - out_sz += tmp_sz; +int crypt_load_crt_file(const char * path, + void ** crt) +{ + *crt = NULL; - assert(out_sz <= in_sz); +#ifdef HAVE_OPENSSL + return openssl_load_crt_file(path, crt); +#else + (void) path; - shm_du_buff_tail_release(sdb, in_sz - out_sz); + return 0; +#endif +} - memcpy(in, out, out_sz); +int crypt_load_crt_str(const char * str, + void ** crt) +{ + *crt = NULL; - free(out); +#ifdef HAVE_OPENSSL + return openssl_load_crt_str(str, crt); +#else + (void) str; return 0; - - fail_decrypt: - EVP_CIPHER_CTX_cleanup(ctx); - fail_decrypt_init: - free(out); - fail_malloc: - return -ECRYPT; - +#endif } -static int openssl_crypt_init(void ** ctx) +int crypt_get_pubkey_crt(void * crt, + void ** pk) { - *ctx = EVP_CIPHER_CTX_new(); - if (*ctx == NULL) - return -ECRYPT; + assert(crt != NULL); + assert(pk != NULL); + +#ifdef HAVE_OPENSSL + return openssl_get_pubkey_crt(crt, pk); +#else + (void) crt; + + clrbuf(*pk); return 0; +#endif } -static void openssl_crypt_fini(void * ctx) +void crypt_free_crt(void * crt) { - EVP_CIPHER_CTX_free(ctx); + if (crt == NULL) + return; +#ifdef HAVE_OPENSSL + openssl_free_crt(crt); +#endif } -#endif /* HAVE_OPENSSL */ - -int crypt_dh_pkp_create(void ** pkp, - uint8_t * pk) +int crypt_crt_str(void * crt, + char * buf) { #ifdef HAVE_OPENSSL - assert(pkp != NULL); - *pkp = NULL; - return openssl_ecdh_pkp_create(pkp, pk); + return openssl_crt_str(crt, buf); #else - (void) pkp; - (void) pk; - - *pkp = NULL; + (void) crt; + (void) buf; return 0; #endif } -void crypt_dh_pkp_destroy(void * pkp) +int crypt_check_crt_name(void * crt, + const char * name) { #ifdef HAVE_OPENSSL - openssl_ecdh_pkp_destroy(pkp); + return openssl_check_crt_name(crt, name); #else - (void) pkp; - return; + (void) crt; + (void) name; + + return 0; #endif } -int crypt_dh_derive(void * pkp, - buffer_t pk, - uint8_t * s) +struct auth_ctx * auth_create_ctx(void) { -#ifdef HAVE_OPENSSL - return openssl_ecdh_derive(pkp, pk, s); -#else - (void) pkp; - (void) pk; + struct auth_ctx * ctx; - memset(s, 0, SYMMKEYSZ); + ctx = malloc(sizeof(*ctx)); + if (ctx == NULL) + goto fail_malloc; - return -ECRYPT; + memset(ctx, 0, sizeof(*ctx)); +#ifdef HAVE_OPENSSL + ctx->store = openssl_auth_create_store(); + if (ctx->store == NULL) + goto fail_store; +#endif + return ctx; +#ifdef HAVE_OPENSSL + fail_store: + free(ctx); #endif + fail_malloc: + return NULL; } -int crypt_encrypt(struct crypt_info * info, - struct shm_du_buff * sdb) +void auth_destroy_ctx(struct auth_ctx * ctx) { - if (info->flags == 0) - return 0; + if (ctx == NULL) + return; +#ifdef HAVE_OPENSSL + openssl_auth_destroy_store(ctx->store); +#endif + free(ctx); +} + +int auth_add_crt_to_store(struct auth_ctx * ctx, + void * crt) +{ + assert(ctx != NULL); + assert(crt != NULL); #ifdef HAVE_OPENSSL - return openssl_encrypt(info->ctx, info->key, sdb); + return openssl_auth_add_crt_to_store(ctx->store, crt); #else - (void) sdb; + (void) ctx; + (void) crt; - return 0; + return -1; #endif } -int crypt_decrypt(struct crypt_info * info, - struct shm_du_buff * sdb) +int auth_verify_crt(struct auth_ctx * ctx, + void * crt) { - if (info->flags == 0) - return 0; - #ifdef HAVE_OPENSSL - return openssl_decrypt(info->ctx, info->key, sdb); + return openssl_verify_crt(ctx->store, crt); #else - (void) sdb; + (void) ctx; + (void) crt; - return -ECRYPT; + return 0; #endif } -int crypt_init(struct crypt_info * info) +int auth_sign(void * pkp, + buffer_t msg, + buffer_t * sig) { #ifdef HAVE_OPENSSL - return openssl_crypt_init(&info->ctx); + return openssl_sign(pkp, msg, sig); #else - info->ctx = NULL; + (void) pkp; + (void) msg; + (void) sig; + + clrbuf(*sig); + return 0; #endif } -void crypt_fini(struct crypt_info * info) +int auth_verify_sig(void * pk, + buffer_t msg, + buffer_t sig) { #ifdef HAVE_OPENSSL - openssl_crypt_fini(info->ctx); + return openssl_verify_sig(pk, msg, sig); #else - (void) info; - assert(info->ctx == NULL); + (void) pk; + (void) msg; + (void) sig; + + return 0; #endif } |