summaryrefslogtreecommitdiff
path: root/src/lib/crypt.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/crypt.c')
-rw-r--r--src/lib/crypt.c647
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
+}