diff options
Diffstat (limited to 'src/lib/crypt.c')
| -rw-r--r-- | src/lib/crypt.c | 647 |
1 files changed, 623 insertions, 24 deletions
diff --git a/src/lib/crypt.c b/src/lib/crypt.c index 8b18140e..a050fe38 100644 --- a/src/lib/crypt.c +++ b/src/lib/crypt.c @@ -22,32 +22,244 @@ #include <config.h> -#include <ouroboros/crypt.h> #include <ouroboros/errno.h> +#include <ouroboros/random.h> +#include <ouroboros/crypt.h> + #ifdef HAVE_OPENSSL - #include "crypt/openssl.h" -#endif /* HAVE_OPENSSL */ +#include <openssl/evp.h> +#include "crypt/openssl.h" +#endif #include <assert.h> +#include <stdio.h> #include <string.h> +#include <sys/stat.h> + +struct nid_map { + uint16_t nid; + const char * name; +}; + +static const struct nid_map cipher_nid_map[] = { + {NID_aes_128_gcm, "aes-128-gcm"}, + {NID_aes_192_gcm, "aes-192-gcm"}, + {NID_aes_256_gcm, "aes-256-gcm"}, + {NID_chacha20_poly1305, "chacha20-poly1305"}, + {NID_aes_128_ctr, "aes-128-ctr"}, + {NID_aes_192_ctr, "aes-192-ctr"}, + {NID_aes_256_ctr, "aes-256-ctr"}, + {NID_undef, NULL} +}; + +const uint16_t crypt_supported_nids[] = { +#ifdef HAVE_OPENSSL + NID_aes_128_gcm, + NID_aes_192_gcm, + NID_aes_256_gcm, + NID_chacha20_poly1305, + NID_aes_128_ctr, + NID_aes_192_ctr, + NID_aes_256_ctr, +#endif + NID_undef +}; + +static const struct nid_map kex_nid_map[] = { + {NID_X9_62_prime256v1, "prime256v1"}, + {NID_secp384r1, "secp384r1"}, + {NID_secp521r1, "secp521r1"}, + {NID_X25519, "X25519"}, + {NID_X448, "X448"}, + {NID_ffdhe2048, "ffdhe2048"}, + {NID_ffdhe3072, "ffdhe3072"}, + {NID_ffdhe4096, "ffdhe4096"}, + {NID_MLKEM512, "ML-KEM-512"}, + {NID_MLKEM768, "ML-KEM-768"}, + {NID_MLKEM1024, "ML-KEM-1024"}, + {NID_X25519MLKEM768, "X25519MLKEM768"}, + {NID_X448MLKEM1024, "X448MLKEM1024"}, + {NID_undef, NULL} +}; + +const uint16_t kex_supported_nids[] = { +#ifdef HAVE_OPENSSL + NID_X9_62_prime256v1, + NID_secp384r1, + NID_secp521r1, + NID_X25519, + NID_X448, + NID_ffdhe2048, + NID_ffdhe3072, + NID_ffdhe4096, +#ifdef HAVE_OPENSSL_PQC + NID_MLKEM512, + NID_MLKEM768, + NID_MLKEM1024, + NID_X25519MLKEM768, + NID_X448MLKEM1024, +#endif +#endif + NID_undef +}; + +static const struct nid_map md_nid_map[] = { + {NID_sha256, "sha256"}, + {NID_sha384, "sha384"}, + {NID_sha512, "sha512"}, + {NID_sha3_256, "sha3-256"}, + {NID_sha3_384, "sha3-384"}, + {NID_sha3_512, "sha3-512"}, + {NID_blake2b512, "blake2b512"}, + {NID_blake2s256, "blake2s256"}, + {NID_undef, NULL} +}; + +const uint16_t md_supported_nids[] = { +#ifdef HAVE_OPENSSL + NID_sha256, + NID_sha384, + NID_sha512, + NID_sha3_256, + NID_sha3_384, + NID_sha3_512, + NID_blake2b512, + NID_blake2s256, +#endif + NID_undef +}; struct crypt_ctx { - void * ctx; - uint8_t key[SYMMKEYSZ]; + void * ctx; /* Encryption context */ }; struct auth_ctx { void * store; }; -int crypt_dh_pkp_create(void ** pkp, - uint8_t * pk) +static int parse_kex_value(const char * value, + struct sec_config * cfg) +{ + SET_KEX_ALGO(cfg, value); + if (cfg->x.nid == NID_undef) + return -ENOTSUP; + + return 0; +} + +/* not in header, but non-static for unit testing */ +int parse_sec_config(struct sec_config * cfg, + FILE * fp) +{ + char line[256]; + char * equals; + char * key; + char * value; + + assert(cfg != NULL); + assert(fp != NULL); + + /* Set defaults */ + SET_KEX_ALGO_NID(cfg, NID_X9_62_prime256v1); + cfg->x.mode = KEM_MODE_SERVER_ENCAP; + SET_KEX_KDF_NID(cfg, NID_sha256); + SET_KEX_CIPHER_NID(cfg, NID_aes_256_gcm); + SET_KEX_DIGEST_NID(cfg, NID_sha256); + + while (fgets(line, sizeof(line), fp) != NULL) { + char * trimmed; + + /* Skip comments and empty lines */ + if (line[0] == '#' || line[0] == '\n') + continue; + + /* Check for 'none' keyword */ + trimmed = trim_whitespace(line); + if (strcmp(trimmed, "none") == 0) { + memset(cfg, 0, sizeof(*cfg)); + return 0; + } + + /* Find the = separator */ + equals = strchr(line, '='); + if (equals == NULL) + continue; + + /* Split into key and value */ + *equals = '\0'; + key = trim_whitespace(line); + value = trim_whitespace(equals + 1); + + /* Parse key exchange field */ + if (strcmp(key, "kex") == 0) { + if (parse_kex_value(value, cfg) < 0) + return -EINVAL; + } else if (strcmp(key, "cipher") == 0) { + SET_KEX_CIPHER(cfg, value); + if (cfg->c.nid == NID_undef) + return -EINVAL; + } else if (strcmp(key, "kdf") == 0) { + SET_KEX_KDF(cfg, value); + if (cfg->k.nid == NID_undef) + return -EINVAL; + } else if (strcmp(key, "digest") == 0) { + SET_KEX_DIGEST(cfg, value); + if (cfg->d.nid == NID_undef) + return -EINVAL; + } else if (strcmp(key, "kem_mode") == 0) { + if (strcmp(value, "server") == 0) { + cfg->x.mode = KEM_MODE_SERVER_ENCAP; + } else if (strcmp(value, "client") == 0) { + cfg->x.mode = KEM_MODE_CLIENT_ENCAP; + } else { + return -EINVAL; + } + } + } + + return 0; +} + +/* Parse key exchange config from file */ +int load_sec_config_file(struct sec_config * cfg, + const char * path) +{ + FILE * fp; + int ret; + + assert(cfg != NULL); + assert(path != NULL); + + fp = fopen(path, "r"); + if (fp == NULL) { + /* File doesn't exist - disable encryption */ + CLEAR_KEX_ALGO(cfg); + return 0; + } + + ret = parse_sec_config(cfg, fp); + + fclose(fp); + + return ret; +} + +int kex_pkp_create(struct sec_config * cfg, + void ** pkp, + uint8_t * pk) { #ifdef HAVE_OPENSSL + assert(cfg != NULL); assert(pkp != NULL); + *pkp = NULL; - return openssl_ecdh_pkp_create(pkp, pk); + + if (cfg->x.str == NULL || kex_validate_nid(cfg->x.nid) < 0) + return -ENOTSUP; + + return openssl_pkp_create(cfg->x.str, (EVP_PKEY **) pkp, pk); #else + (void) cfg; (void) pkp; (void) pk; @@ -57,12 +269,12 @@ int crypt_dh_pkp_create(void ** pkp, #endif } -void crypt_dh_pkp_destroy(void * pkp) +void kex_pkp_destroy(void * pkp) { if (pkp == NULL) return; #ifdef HAVE_OPENSSL - openssl_ecdh_pkp_destroy(pkp); + openssl_pkp_destroy((EVP_PKEY *) pkp); #else (void) pkp; @@ -70,12 +282,18 @@ void crypt_dh_pkp_destroy(void * pkp) #endif } -int crypt_dh_derive(void * pkp, - buffer_t pk, - uint8_t * s) +int kex_dhe_derive(struct sec_config * cfg, + void * pkp, + buffer_t pk, + uint8_t * s) { + assert(cfg != NULL); + + if (kex_validate_nid(cfg->x.nid) < 0) + return -ENOTSUP; + #ifdef HAVE_OPENSSL - return openssl_ecdh_derive(pkp, pk, s); + return openssl_dhe_derive((EVP_PKEY *) pkp, pk, cfg->k.nid, s); #else (void) pkp; (void) pk; @@ -86,6 +304,244 @@ int crypt_dh_derive(void * pkp, #endif } +ssize_t kex_kem_encap(buffer_t pk, + uint8_t * ct, + int kdf, + uint8_t * s) +{ +#ifdef HAVE_OPENSSL + return openssl_kem_encap(pk, ct, kdf, s); +#else + (void) pk; + (void) ct; + (void) kdf; + + memset(s, 0, SYMMKEYSZ); + + return -ECRYPT; +#endif +} + +ssize_t kex_kem_encap_raw(buffer_t pk, + uint8_t * ct, + int kdf, + uint8_t * s) +{ +#ifdef HAVE_OPENSSL + return openssl_kem_encap_raw(pk, ct, kdf, s); +#else + (void) pk; + (void) ct; + (void) kdf; + + memset(s, 0, SYMMKEYSZ); + + return -ECRYPT; +#endif +} + +int kex_kem_decap(void * pkp, + buffer_t ct, + int kdf, + uint8_t * s) +{ +#ifdef HAVE_OPENSSL + return openssl_kem_decap((EVP_PKEY *) pkp, ct, kdf, s); +#else + (void) pkp; + (void) ct; + (void) kdf; + + memset(s, 0, SYMMKEYSZ); + + return -ECRYPT; +#endif +} + +int kex_get_algo_from_pk_der(buffer_t pk, + char * algo) +{ +#ifdef HAVE_OPENSSL + return openssl_get_algo_from_pk_der(pk, algo); +#else + (void) pk; + algo[0] = '\0'; + + return -ECRYPT; +#endif +} + +int kex_get_algo_from_pk_raw(buffer_t pk, + char * algo) +{ +#ifdef HAVE_OPENSSL + return openssl_get_algo_from_pk_raw(pk, algo); +#else + (void) pk; + algo[0] = '\0'; + + return -ECRYPT; +#endif +} + +int kex_validate_algo(const char * algo) +{ + if (algo == NULL) + return -EINVAL; + + /* Use NID validation instead of string array */ + return kex_validate_nid(kex_str_to_nid(algo)); +} + +int crypt_validate_nid(int nid) +{ + const struct nid_map * p; + + if (nid == NID_undef) + return -EINVAL; + + for (p = cipher_nid_map; p->name != NULL; p++) { + if (p->nid == nid) + return 0; + } + + return -ENOTSUP; +} + + +const char * crypt_nid_to_str(uint16_t nid) +{ + const struct nid_map * p; + + for (p = cipher_nid_map; p->name != NULL; p++) { + if (p->nid == nid) + return p->name; + } + + return NULL; +} + +uint16_t crypt_str_to_nid(const char * cipher) +{ + const struct nid_map * p; + + if (cipher == NULL) + return NID_undef; + + /* fast, check if cipher pointer is in the map */ + for (p = cipher_nid_map; p->name != NULL; p++) { + if (cipher == p->name) + return p->nid; + } + + for (p = cipher_nid_map; p->name != NULL; p++) { + if (strcmp(p->name, cipher) == 0) + return p->nid; + } + + return NID_undef; +} + +const char * kex_nid_to_str(uint16_t nid) +{ + const struct nid_map * p; + + for (p = kex_nid_map; p->name != NULL; p++) { + if (p->nid == nid) + return p->name; + } + + return NULL; +} + +uint16_t kex_str_to_nid(const char * algo) +{ + const struct nid_map * p; + + if (algo == NULL) + return NID_undef; + + /* Fast path: check if algo pointer is in the map */ + for (p = kex_nid_map; p->name != NULL; p++) { + if (algo == p->name) + return p->nid; + } + + /* Slow path: string comparison */ + for (p = kex_nid_map; p->name != NULL; p++) { + if (strcmp(p->name, algo) == 0) + return p->nid; + } + + return NID_undef; +} + +int kex_validate_nid(int nid) +{ + const struct nid_map * p; + + if (nid == NID_undef) + return -EINVAL; + + for (p = kex_nid_map; p->name != NULL; p++) { + if (p->nid == nid) + return 0; + } + + return -ENOTSUP; +} + +const char * md_nid_to_str(uint16_t nid) +{ + const struct nid_map * p; + + for (p = md_nid_map; p->name != NULL; p++) { + if (p->nid == nid) + return p->name; + } + + return NULL; +} + +uint16_t md_str_to_nid(const char * kdf) +{ + const struct nid_map * p; + + if (kdf == NULL) + return NID_undef; + + /* Fast path: check if kdf pointer is in the map */ + for (p = md_nid_map; p->name != NULL; p++) { + if (kdf == p->name) + return p->nid; + } + + /* Slow path: string comparison */ + for (p = md_nid_map; p->name != NULL; p++) { + if (strcmp(p->name, kdf) == 0) + return p->nid; + } + + return NID_undef; +} + +int md_validate_nid(int nid) +{ + const struct nid_map * p; + + if (nid == NID_undef) + return -EINVAL; + + for (p = md_nid_map; p->name != NULL; p++) { + if (p->nid == nid) + return 0; + } + + return -ENOTSUP; +} + +/* Hash length now returned by md_digest() */ + int crypt_encrypt(struct crypt_ctx * ctx, buffer_t in, buffer_t * out) @@ -94,7 +550,7 @@ int crypt_encrypt(struct crypt_ctx * ctx, assert(ctx->ctx != NULL); #ifdef HAVE_OPENSSL - return openssl_encrypt(ctx->ctx, ctx->key, in, out); + return openssl_encrypt(ctx->ctx, in, out); #else (void) ctx; (void) in; @@ -112,7 +568,7 @@ int crypt_decrypt(struct crypt_ctx * ctx, assert(ctx->ctx != NULL); #ifdef HAVE_OPENSSL - return openssl_decrypt(ctx->ctx, ctx->key, in, out); + return openssl_decrypt(ctx->ctx, in, out); #else (void) ctx; (void) in; @@ -122,20 +578,21 @@ int crypt_decrypt(struct crypt_ctx * ctx, #endif } -struct crypt_ctx * crypt_create_ctx(const uint8_t * key) +struct crypt_ctx * crypt_create_ctx(struct crypt_sk * sk) { struct crypt_ctx * crypt; + if (crypt_validate_nid(sk->nid) != 0) + return NULL; + crypt = malloc(sizeof(*crypt)); if (crypt == NULL) goto fail_crypt; memset(crypt, 0, sizeof(*crypt)); - if (key != NULL) - memcpy(crypt->key, key, SYMMKEYSZ); #ifdef HAVE_OPENSSL - crypt->ctx=openssl_crypt_create_ctx(); + crypt->ctx = openssl_crypt_create_ctx(sk); if (crypt->ctx == NULL) goto fail_ctx; #endif @@ -204,11 +661,72 @@ int crypt_load_pubkey_str(const char * str, #endif } +int crypt_load_pubkey_file(const char * path, + void ** key) +{ + *key = NULL; + +#ifdef HAVE_OPENSSL + return openssl_load_pubkey_file(path, key); +#else + (void) path; + + return 0; +#endif +} + +int crypt_load_pubkey_file_to_der(const char * path, + buffer_t * buf) +{ + assert(buf != NULL); + +#ifdef HAVE_OPENSSL + return openssl_load_pubkey_file_to_der(path, buf); +#else + (void) path; + + buf->data = NULL; + buf->len = 0; + return 0; +#endif +} + +int crypt_load_pubkey_raw_file(const char * path, + buffer_t * buf) +{ + assert(buf != NULL); + +#ifdef HAVE_OPENSSL + return openssl_load_pubkey_raw_file(path, buf); +#else + (void) path; + + buf->data = NULL; + buf->len = 0; + return 0; +#endif +} + +int crypt_load_privkey_raw_file(const char * path, + void ** key) +{ + *key = NULL; + +#ifdef HAVE_OPENSSL + return openssl_load_privkey_raw_file(path, key); +#else + (void) path; + + return 0; +#endif +} + int crypt_cmp_key(const void * key1, const void * key2) { #ifdef HAVE_OPENSSL - return openssl_cmp_key(key1, key2); + return openssl_cmp_key((const EVP_PKEY *) key1, + (const EVP_PKEY *) key2); #else (void) key1; (void) key2; @@ -223,7 +741,7 @@ void crypt_free_key(void * key) return; #ifdef HAVE_OPENSSL - openssl_free_key(key); + openssl_free_key((EVP_PKEY *) key); #endif } @@ -343,6 +861,19 @@ int crypt_check_crt_name(void * crt, #endif } +int crypt_get_crt_name(void * crt, + char * name) +{ +#ifdef HAVE_OPENSSL + return openssl_get_crt_name(crt, name); +#else + (void) crt; + (void) name; + + return 0; +#endif +} + struct auth_ctx * auth_create_ctx(void) { struct auth_ctx * ctx; @@ -406,13 +937,15 @@ int auth_verify_crt(struct auth_ctx * ctx, } int auth_sign(void * pkp, + int md_nid, buffer_t msg, buffer_t * sig) { #ifdef HAVE_OPENSSL - return openssl_sign(pkp, msg, sig); + return openssl_sign((EVP_PKEY *) pkp, md_nid, msg, sig); #else (void) pkp; + (void) md_nid; (void) msg; (void) sig; @@ -423,16 +956,82 @@ int auth_sign(void * pkp, } int auth_verify_sig(void * pk, + int md_nid, buffer_t msg, buffer_t sig) { #ifdef HAVE_OPENSSL - return openssl_verify_sig(pk, msg, sig); + return openssl_verify_sig((EVP_PKEY *) pk, md_nid, msg, sig); #else (void) pk; + (void) md_nid; (void) msg; (void) sig; return 0; #endif } + +ssize_t md_digest(int md_nid, + buffer_t in, + uint8_t * out) +{ +#ifdef HAVE_OPENSSL + return openssl_md_digest(md_nid, in, out); +#else + (void) md_nid; + (void) in; + (void) out; + + return -1; +#endif +} + +ssize_t md_len(int md_nid) +{ +#ifdef HAVE_OPENSSL + return openssl_md_len(md_nid); +#else + (void) md_nid; + return -1; +#endif +} + +int crypt_secure_malloc_init(size_t max) +{ +#ifdef HAVE_OPENSSL + return openssl_secure_malloc_init(max, SECMEM_GUARD); +#else + return 0; +#endif +} + +void crypt_secure_malloc_fini(void) +{ +#ifdef HAVE_OPENSSL + openssl_secure_malloc_fini(); +#endif +} + +void * crypt_secure_malloc(size_t size) +{ +#ifdef HAVE_OPENSSL + return openssl_secure_malloc(size); +#else + return malloc(size); +#endif +} + +void crypt_secure_free(void * ptr, + size_t size) +{ + if (ptr == NULL) + return; + +#ifdef HAVE_OPENSSL + openssl_secure_free(ptr, size); +#else + memset(ptr, 0, size); + free(ptr); +#endif +} |
