From 70e07b58a248fefa848c11082e0a0aaa6b064bdc Mon Sep 17 00:00:00 2001 From: geoffrey Date: Fri, 27 Feb 2026 14:30:01 +0100 Subject: [PATCH] Audit ECC key --- audit/fips.c | 515 ++++++++++++++++++++++++----------------------- audit/fips.h | 71 +++++-- certificate.c | 67 +++--- cryptodit | Bin 41672 -> 39256 bytes entropy_ebpf.o | Bin 8152 -> 8024 bytes error.h | 18 +- examples/foo.pem | 9 - 7 files changed, 372 insertions(+), 308 deletions(-) delete mode 100644 examples/foo.pem diff --git a/audit/fips.c b/audit/fips.c index db0816b..367a83d 100644 --- a/audit/fips.c +++ b/audit/fips.c @@ -7,7 +7,7 @@ /* * SSL Format * RSA PUBLIC KEY -> PKCS#1 format - * PUBLIC KEY -> PEM Format + * PUBLIC KEY -> PEM Format (SPKI) */ static int DEBUG = 0; @@ -16,47 +16,54 @@ int fips(const char *pkey, struct audit_fips *st_audit_fips, struct keyinfo *st_ int res; if(type == TYPE_RSA){ - /* If it's a pub key, we are going to analyse it */ if (is_pubkey == 1) res = fips_pubkey_rsa(st_audit_fips, st_keyinfo, pkey); else res = fips_privkey_rsa(st_audit_fips, st_keyinfo, pkey); } - else if (type == TYPE_X509){ - if (openssl_version() == 1) - res = fips_x509_v1(st_audit_fips, st_keyinfo, pkey); - else - res = fips_x509_v3(st_audit_fips, st_keyinfo, pkey); + else if (type == TYPE_ELLIPTIC){ + if (is_pubkey){ + EC_KEY *ec = fips_load_pubkey_ecc(pkey); + if (!ec) + return FIPS_ERR_LOAD_ECC_PUBKEY; + + res = fips_pubkey_ecc(ec, st_audit_fips, st_keyinfo, pkey); + } } + else if (type == TYPE_X509) + res = fips_x509(st_audit_fips, st_keyinfo, pkey); + return res; } + +/********************************************************/ +/* RSA part */ +/********************************************************/ + /* * This function load public RSA key and make an audit on it */ static int fips_pubkey_rsa(struct audit_fips *st_audit_fips, struct keyinfo *st_keyinfo, const char *pkey) { - struct rsa *rsa; - size_t keysize; int res; /* - * Now, we check if the public certificate is compliant with FIPS + * Now, we check if the public key is compliant with FIPS * The program check the length of the key, the exponent */ - if (openssl_version() == 1) - res = loadkeys_rsa_v1(&rsa, pkey, &st_keyinfo->format); - else /* OpenSSL version 3 */ - res = loadkeys_rsa_v3(&rsa, pkey, &st_keyinfo->format); + + RSA *rsa = NULL; + res = loadkeys_rsa(&rsa, pkey, &st_keyinfo->st_rsa.format); - if (res > 0 || rsa == NULL){ + if (res > 0 || !rsa){ printf("Failed to read the public key\n"); - clean_rsa_st(rsa); return res; } + /* We have loaded our RSA key, we can audit it */ audit_rsa_keys(rsa, st_audit_fips, st_keyinfo, pkey); - // Clean - clean_rsa_st(rsa); + // Cleaning + RSA_free(rsa); return 0; } /* @@ -64,106 +71,84 @@ static int fips_pubkey_rsa(struct audit_fips *st_audit_fips, struct keyinfo *st_ */ static int fips_privkey_rsa(struct audit_fips *st_audit_fips, struct keyinfo *st_keyinfo, const char *pkey) { int res; - struct rsa *rsa = NULL; + RSA *rsa = NULL; - if (openssl_version() == 1) - res = load_priv_rsa_keys_v1(&rsa, pkey); - else /* OpenSSL version 3 */ - res = load_priv_rsa_keys_v3(&rsa, pkey); + res = load_priv_rsa_keys(&rsa, pkey); - if (res > 0){ + if (res > 0 || !rsa){ printf("Failed to read the private key\n"); - clean_rsa_st(rsa); return res; } audit_rsa_keys(rsa, st_audit_fips, st_keyinfo, pkey); // Clean - clean_rsa_st(rsa); + RSA_free(rsa); return 0; } /* - * If OpenSSL v3, we need tu use new OpenSSL functions for reading keys + * This function load the RSA key and store to the RSA * object + * Detect and specify the correct RSA format public key */ -static int loadkeys_rsa_v3(struct rsa **rsa, const char *pkey, int *format){ - *rsa = (struct rsa*)malloc(sizeof(struct rsa*)); - - if (*rsa == NULL){ - if (DEBUG) - printf("Cannot malloc the structure\n"); - return COMMON_ERR_MALLOC; - } - - memset(*rsa, 0, sizeof(struct rsa*)); - - (*rsa)->bio = BIO_new(BIO_s_file()); - if (BIO_read_filename((*rsa)->bio, pkey) == 0){ +static int loadkeys_rsa(RSA **rsa, const char *pkey, int *format){ + BIO *bio = BIO_new(BIO_s_file()); + if (BIO_read_filename(bio, pkey) == 0){ printf("Failed to read BIO\n"); return FIPS_ERR_READ_BIO; } - - #if OPENSSL_VERSION_NUMBER > 0x03000000f - (*rsa)->evp = PEM_read_bio_PUBKEY_ex((*rsa)->bio, NULL, NULL, NULL, NULL, NULL); - if ((*rsa)->evp == NULL){ - return FIPS_ERR_LOAD_KEY; - } - //printf("Keysize: %d\n", EVP_PKEY_bits((*rsa)->evp)); - (*rsa)->rsa = EVP_PKEY_get1_RSA((*rsa)->evp); - if ((*rsa)->rsa == NULL){ - return FIPS_ERR_LOAD_RSA_KEY; - } - #endif - - // Get the format of the key - *format = 0; - return 0; -} -static int loadkeys_rsa_v1(struct rsa **rsa, const char *pkey, int *format){ - *rsa = (struct rsa*)malloc(sizeof(struct rsa*)); - - if (*rsa == NULL){ - if (DEBUG) - printf("Cannot malloc the structure\n"); - return COMMON_ERR_MALLOC; - } - memset(*rsa, 0, sizeof(struct rsa*)); - - (*rsa)->bio = BIO_new(BIO_s_file()); - if(BIO_read_filename((*rsa)->bio, pkey) == 0){ - printf("Failed to read BIO\n"); - return FIPS_ERR_READ_BIO; - } - /* * Works with PEM_read_RSAPublicKey, but when we try to read the file * we cannot. This function "block" the access to the file */ - /*rsa->rsa = PEM_read_RSAPublicKey(f, NULL, NULL, NULL); */ + /*rsa = PEM_read_RSAPublicKey(f, NULL, NULL, NULL); */ + #if OPENSSL_VERSION_NUMBER > 0x03000000f + EVP_PKEY *evp = PEM_read_bio_PUBKEY_ex(bio, NULL, NULL, NULL, NULL, NULL); + if (!evp){ + BIO_free(bio); + return FIPS_ERR_LOAD_KEY; + } + + BIO_free(bio); + + //printf("Keysize: %d\n", EVP_PKEY_bits(evp)); + /* EVP_PKEY_get1_RSA is deprecated, need to find another way to get the RSA key */ + *rsa = EVP_PKEY_get1_RSA(evp); + if (!(*rsa)){ + EVP_PKEY_free(evp); + return FIPS_ERR_LOAD_RSA_KEY; + } + EVP_PKEY_free(evp); + *format = 0; + + #else // Deprecated in OpenSSL v3 /* * RSAPublicKey read publickey at the PEM format * RSA_PUBKEY read publickey at the PKCS1 format */ - (*rsa)->rsa = PEM_read_bio_RSAPublicKey((*rsa)->bio, NULL, NULL, NULL); - if ((*rsa)->rsa == NULL){ - //print_error(); + /* In case it's OpenSSL v1, we get the RSA * object from BIO */ + *rsa = PEM_read_bio_RSAPublicKey(bio, NULL, NULL, NULL); + + // If we cannot read it, we try with the PKCS1 format + if (!(*rsa)){ + // print_error(); /* * We need to reset or reseek the BIO, otherwise, we cannot read it * https://docs.openssl.org/3.0/man3/BIO_ctrl/#synopsis */ //BIO_reset((*rsa)->bio); /* Works too */ - BIO_seek((*rsa)->bio, 0); + BIO_seek(bio, 0); - (*rsa)->rsa = PEM_read_bio_RSA_PUBKEY((*rsa)->bio, NULL, NULL,NULL); + *(rsa) = PEM_read_bio_RSA_PUBKEY(bio, NULL, NULL,NULL); - if ((*rsa)->rsa == NULL){ + if (!(*rsa)){ if (DEBUG) printf("Cannot read the SPKI format of the public key\n"); + BIO_free(bio); return FIPS_ERR_LOAD_KEY; } @@ -172,75 +157,54 @@ static int loadkeys_rsa_v1(struct rsa **rsa, const char *pkey, int *format){ else *format = RSA_FORMAT_PKCS1; + BIO_free(bio); + #endif + return 0; } /* - * This function load RSA Private key for OpenSSL v1 + * This function load RSA Private key */ -static int load_priv_rsa_keys_v1(struct rsa **rsa, const char *pkey){ - *rsa = (struct rsa*)malloc(sizeof(struct rsa*)); - - if (*rsa == NULL){ - if (DEBUG) - printf("Cannot malloc the structure\n"); - return COMMON_ERR_MALLOC; - } - - (*rsa)->bio = BIO_new(BIO_s_file()); - if ((*rsa)->bio == NULL){ +static int load_priv_rsa_keys(RSA **rsa, const char *pkey){ + BIO *bio = BIO_new(BIO_s_file()); + if (!bio){ if (DEBUG) printf("Failed to create new BIO\n"); return FIPS_ERR_NEW_BIO; } - if(BIO_read_filename((*rsa)->bio, pkey) == 0){ - printf("Failed to read BIO\n"); - return FIPS_ERR_READ_BIO; - } - - (*rsa)->rsa = PEM_read_bio_RSAPrivateKey((*rsa)->bio, NULL, NULL, NULL); - if ((*rsa)->rsa == NULL){ - if (DEBUG) - printf("Failed to read BIO RSAPrivateKey\n"); - return FIPS_ERR_LOAD_RSA_PRIV_KEY; - } - - return 0; -} -/* - * This function load RSA Private key for OpenSSL v3 - */ -static int load_priv_rsa_keys_v3(struct rsa **rsa, const char *pkey){ - *rsa = (struct rsa*)malloc(sizeof(struct rsa*)); - - if (*rsa == NULL){ - if (DEBUG) - printf("Cannot malloc the structure\n"); - return COMMON_ERR_MALLOC; - } - - (*rsa)->bio = BIO_new(BIO_s_file()); - if ((*rsa)->bio == NULL){ - if (DEBUG) - printf("Failed to create new BIO\n"); - return FIPS_ERR_NEW_BIO; - } - if(BIO_read_filename((*rsa)->bio, pkey) == 0){ + if(BIO_read_filename(bio, pkey) == 0){ printf("Failed to read BIO\n"); + BIO_free(bio); return FIPS_ERR_READ_BIO; } #if OPENSSL_VERSION_NUMBER > 0x03000000f - (*rsa)->evp = PEM_read_bio_PrivateKey_ex((*rsa)->bio, NULL, NULL, NULL, NULL, NULL); + EVP_PKEY *evp = PEM_read_bio_PrivateKey_ex(bio, NULL, NULL, NULL, NULL, NULL); - if ((*rsa)->evp == NULL){ + if (!evp){ if (DEBUG) printf("Failed to read BIO PrivateKey\n"); + BIO_free(bio); return FIPS_ERR_READ_BIO; } - (*rsa)->rsa = EVP_PKEY_get1_RSA((*rsa)->evp); - if ((*rsa)->rsa == NULL) + BIO_free(bio); + + *rsa = EVP_PKEY_get1_RSA(evp); + if (!*rsa){ + EVP_PKEY_free(evp); return FIPS_ERR_LOAD_RSA_KEY; + } + EVP_PKEY_free(evp); + #else /* For OpenSSL v1 */ + *rsa = PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, NULL); + if (!*rsa){ + if (DEBUG) + printf("Failed to read BIO RSAPrivateKey\n"); + BIO_free(bio); + return FIPS_ERR_LOAD_RSA_PRIV_KEY; + } + BIO_free(bio); #endif return 0; @@ -250,32 +214,32 @@ static int load_priv_rsa_keys_v3(struct rsa **rsa, const char *pkey){ * This function audit the RSA keys, both public and private * For the audit, the function check the exponent (modulus) and the key size */ -static void audit_rsa_keys(struct rsa *rsa, struct audit_fips *st_audit_fips, struct keyinfo *st_keyinfo, const char *pkey){ +static void audit_rsa_keys(RSA *rsa, struct audit_fips *st_audit_fips, struct keyinfo *st_keyinfo, const char *pkey){ int res; - st_keyinfo->keysize = RSA_size(rsa->rsa); + st_keyinfo->st_rsa.keysize = RSA_size(rsa); st_keyinfo->algo = ALGO_RSA; // The return value is a const, shouldn't be freed - const BIGNUM *e = RSA_get0_e(rsa->rsa); + const BIGNUM *e = RSA_get0_e(rsa); char *exponent = BN_bn2dec(e); //free(exponent); OPENSSL_free(exponent); /* Exponent has been set up, we can check it */ - res = check_exponent(e, st_audit_fips->audit_exponent.result, &st_keyinfo->exponent); + res = check_exponent(e, st_audit_fips->audit_rsa.audit_exponent.result, &st_keyinfo->st_rsa.exponent); /* * Audit the key size. For a better security, the key size is at least 2048 bits */ - if (st_keyinfo->keysize * 8 < 2048){ - sprintf(st_audit_fips->audit_keysize.result, "The key size is lower than 2048. The key should be at least 2048 bits."); - st_audit_fips->audit_keysize.audit = FALSE; + if (st_keyinfo->st_rsa.keysize * 8 < 2048){ + sprintf(st_audit_fips->audit_rsa.audit_keysize.result, "The key size is lower than 2048. The key should be at least 2048 bits."); + st_audit_fips->audit_rsa.audit_keysize.audit = FALSE; } else{ - sprintf(st_audit_fips->audit_keysize.result, "The key size is upper or equal than 2048. The audit is passed with success."); - st_audit_fips->audit_keysize.audit = TRUE; + sprintf(st_audit_fips->audit_rsa.audit_keysize.result, "The key size is upper or equal than 2048. The audit is passed with success."); + st_audit_fips->audit_rsa.audit_keysize.audit = TRUE; } } @@ -297,12 +261,9 @@ static int check_exponent(const BIGNUM *e, char *buf, unsigned long *exponent){ sprintf(nExponent, "%d", 2); BN_dec2bn(&m, nExponent); - //BN_mod(rem, e, m); ctx = BN_CTX_new(); BN_div(NULL, rem, e, m, ctx); - //r = malloc(4); r = BN_bn2dec(rem); - //printf("%s\n", r); /* * According to the FIPS 186-5, the exponent size must be 2 ** 16 < e < 2 ** 256 @@ -310,7 +271,6 @@ static int check_exponent(const BIGNUM *e, char *buf, unsigned long *exponent){ */ char *exp = BN_bn2dec(e); *exponent = (char2dec(exp[0]) * 10000) + (char2dec(exp[1]) * 1000) + (char2dec(exp[2])* 100) + (char2dec(exp[3]) * 10) + (char2dec(exp[4])); - // printf("Exp: %lu\n", exp); if (strcmp(r, "0") == 0){ strncpy(buf, "The exponent is even, should be odd", BUF_SIZE_AUDIT); @@ -338,136 +298,195 @@ static int check_exponent(const BIGNUM *e, char *buf, unsigned long *exponent){ OPENSSL_free(exp); return 0; } +/********************************************************/ +/* ECC part */ +/********************************************************/ +static int fips_pubkey_ecc(EC_KEY *ec, struct audit_fips *st_audit_fips, struct keyinfo *st_keyinfo, const char *pkey){ + st_keyinfo->algo = ALGO_EC; + memset(&st_keyinfo->s_ecc, 0, sizeof(struct ecc*)); + + st_keyinfo->s_ecc.ec = ec; + + int res = get_domain_parameters(&st_keyinfo->s_ecc); + + if (res != 0) + return res; + + audit_ecc(st_audit_fips, st_keyinfo->s_ecc.nid); + + return 0; +} /* - * This function load X509 certificate for OpenSSL v1 + * This function audit the ECC keys. + * According to the RCC 7748 and NIST recommendation, + * curve schemes: P-521, Curve25519 or Curve448 should be used + * The key length recommended is at least 256 bit. */ -static int fips_x509_v1(struct audit_fips *st_audit_fips, struct keyinfo *st_keyinfo, const char *pkey){ - struct rsa *rsa = (struct rsa*)malloc(sizeof(struct rsa*)); - - if (rsa == NULL){ - if (DEBUG) - printf("Cannot malloc the structure\n"); - return COMMON_ERR_MALLOC; +static void audit_ecc(struct audit_fips *st_audit, const int nid){ + /* + * Recommended curve name (See file /usr/include/openssl/obj_mac): + * NID 716 = secp521r1 + * NID 1034 = X25519 (Curve25519) + * NID 1035 = X448 (Curve448) + */ + if (nid != 716 && nid != 1034 && nid != 1035){ + sprintf(st_audit->audit_ecc.audit_curve.result, "The curve scheme should be P-521, Curve25519 or Curve448."); + st_audit->audit_ecc.audit_curve.audit = FALSE; } - memset(rsa, 0, sizeof(struct rsa*)); + else{ + sprintf(st_audit->audit_ecc.audit_curve.result, "The curve scheme is enough strong and respect NIST recommendation."); + st_audit->audit_ecc.audit_curve.audit = TRUE; + } +} - rsa->bio = BIO_new(BIO_s_file()); - if (BIO_read_filename(rsa->bio, pkey) == 0){ +/* + * This function load the public ECC key and return the key store in the variable EVP_PKEY + */ +static EC_KEY *fips_load_pubkey_ecc(const char *pkey){ + BIO *bio = BIO_new(BIO_s_file()); + if (BIO_read_filename(bio, pkey) == 0){ + printf("Failed to read BIO\n"); + return NULL; + } + EC_KEY *ec = PEM_read_bio_EC_PUBKEY(bio, NULL, NULL, NULL); + + if (!ec){ + if (DEBUG) + printf("Cannot read the ECC Public key\n"); + BIO_free(bio); + return NULL; + } + /* We don't use it anymore, we freeing it */ + BIO_free(bio); + return ec; + +} + +/* + * This function get domain parameters from the ECC key + */ +static int get_domain_parameters(struct ecc *st_ecc){ + EC_GROUP *group = EC_KEY_get0_group(st_ecc->ec); + if(!group){ + if (DEBUG) + printf("Failed to load ECC Group\n"); + EC_KEY_free(st_ecc->ec); + return FIPS_ERR_GET_ECC_GROUP; + } + + // Get cofactor + BIGNUM *b_cofactor = EC_GROUP_get0_cofactor(group); + if(!b_cofactor){ + printf("Cannot get cofactor\n"); + return FIPS_ERR_GET_ECC_DOMAPARAM; + } + st_ecc->cofactor = BN_bn2dec(b_cofactor); + //BN_free(b_cofactor); + + // Get field + #if OPENSSL_VERSION_NUMBER > 0x03000000f + + #endif + + // Get order bit + st_ecc->order_bits = EC_GROUP_order_bits(group); + + // Get order + BIGNUM *b_order = EC_GROUP_get0_order(group); + if(!b_order){ + printf("Cannot get order\n"); + return FIPS_ERR_GET_ECC_DOMAPARAM; + } + st_ecc->order = BN_bn2hex(b_order); + //OPENSSL_free(order); + //BN_free(b_order); + + // Get curve name + st_ecc->nid = EC_GROUP_get_curve_name(group); + st_ecc->curve = OBJ_nid2sn(st_ecc->nid); + //OPENSSL_free(name); /* If I free, the program crash, because it's a const ?? */ + + // Get generator + EC_POINT *g = EC_GROUP_get0_generator(group); + if (!g){ + if (DEBUG) + printf("Failed to get ECC generator\n"); + return FIPS_ERR_GET_ECC_GENERATOR; + } + + st_ecc->g = EC_POINT_point2hex(group, g, POINT_CONVERSION_UNCOMPRESSED, NULL); + /* + * It's cannot mandatory to clean EC_GROUP and EC_POINT and other objects + * We freeing them in certificate.c file. + * Also, for cleaning EC_GROUP and EC_POINT, just freeing EC_KEY is enough + */ + return 0; +} + +/********************************************************/ +/* X.509 part */ +/********************************************************/ + +/* + * This function load X509 certificate + */ +static int fips_x509(struct audit_fips *st_audit_fips, struct keyinfo *st_keyinfo, const char *pkey){ + BIO *bio = BIO_new(BIO_s_file()); + if (!bio){ + printf("Failed to create new BIO\n"); + return FIPS_ERR_NEW_BIO; + } + if (BIO_read_filename(bio, pkey) == 0){ printf("Failed to read BIO\n"); return FIPS_ERR_READ_BIO; } - X509 *x = PEM_read_bio_X509(rsa->bio, NULL, 0, NULL); - if (x == NULL){ + X509 *x = PEM_read_bio_X509(bio, NULL, 0, NULL); + if (!x){ printf("Failed to read the X509 certificate\n"); - clean_rsa_st(rsa); + BIO_free(bio); return FIPS_ERR_LOAD_X509; } + BIO_free(bio); /* We don't need it anymore, we freeing it */ EVP_PKEY *evp = X509_get_pubkey(x); - if (evp == NULL){ + if (!evp){ printf("Failed to get public certificate\n"); X509_free(x); return FIPS_ERR_LOAD_RSA_KEY; } - rsa->rsa = EVP_PKEY_get1_RSA(evp); - if (rsa->rsa == NULL){ - X509_free(x); - EVP_PKEY_free(evp); - return FIPS_ERR_LOAD_RSA_KEY; - } - // We have the RSA key, we can audit it - audit_rsa_keys(rsa, st_audit_fips, st_keyinfo, pkey); + /* Get certificate info, such as issuer, validity, etc. */ X509_free(x); + + /* Key type identification */ + int type = EVP_PKEY_base_id(evp); + + switch (type) { + case EVP_PKEY_RSA: ; + RSA *rsa = EVP_PKEY_get1_RSA(evp); + if (!rsa) + return FIPS_ERR_LOAD_RSA_KEY; + // We have the RSA key, we can audit it + audit_rsa_keys(rsa, st_audit_fips, st_keyinfo, pkey); + RSA_free(rsa); + break; + case EVP_PKEY_EC: ; + /* We free EC_KEY in certificate.c file */ + EC_KEY *ec = EVP_PKEY_get1_EC_KEY(evp); + if (!ec) + return FIPS_ERR_LOAD_ECC_PUBKEY; + int res = fips_pubkey_ecc(ec, st_audit_fips, st_keyinfo, pkey); + break; + default: + break; + } EVP_PKEY_free(evp); - clean_rsa_st(rsa); + return 0; } -/* - * This function load X509 certificate for OpenSSL v3 - */ -static int fips_x509_v3(struct audit_fips *st_audit_fips, struct keyinfo *st_keyinfo, const char *pkey){ - struct rsa *rsa = (struct rsa*)malloc(sizeof(struct rsa*)); - - if (rsa == NULL){ - if (DEBUG) - printf("Cannot malloc the structure\n"); - return COMMON_ERR_MALLOC; - } - memset(rsa, 0, sizeof(struct rsa*)); - - rsa->bio = BIO_new(BIO_s_file()); - if (BIO_read_filename(rsa->bio, pkey) == 0){ - printf("Failed to read BIO\n"); - return FIPS_ERR_READ_BIO; - } - - #if OPENSSL_VERSION_NUMBER > 0x03000000f - rsa->evp = NULL; // Otherwise, I have a seg fault during clean rsa st - - X509 *x = PEM_read_bio_X509(rsa->bio, NULL, 0, NULL); - if (x == NULL){ - printf("Failed to read the X509 certificate\n"); - clean_rsa_st(rsa); - return FIPS_ERR_LOAD_X509; - } - - rsa->evp = X509_get_pubkey(x); - if (rsa->evp == NULL){ - printf("Failed to get public certificate\n"); - X509_free(x); - return FIPS_ERR_LOAD_RSA_KEY; - } - rsa->rsa = EVP_PKEY_get1_RSA(rsa->evp); - if (rsa->rsa == NULL){ - X509_free(x); - return FIPS_ERR_LOAD_RSA_KEY; - } - #endif - - /* - * TODO: Need to identify public-key cryptosystem: RSA or EC - */ - - // We have the RSA key, we can audit it - audit_rsa_keys(rsa, st_audit_fips, st_keyinfo, pkey); - - #if OPENSSL_VERSION_NUMBER > 0x03000000f - X509_free(x); - #endif - clean_rsa_st(rsa); - return 0; -} - -/* - * This function clean the RSA structure - */ -static void clean_rsa_st(struct rsa *rsa){ - if (DEBUG) - printf("\nCleaning RSA\n"); - - if (rsa == NULL) - return; - - if (rsa->bio != NULL) - BIO_free(rsa->bio); - - if (openssl_version() == 3){ - #if OPENSSL_VERSION_NUMBER > 0x03000000f - if (rsa->evp != NULL) - EVP_PKEY_free(rsa->evp); - #endif - } - - if (rsa->rsa != NULL) - RSA_free(rsa->rsa); - - free(rsa); - rsa = NULL; -} /* * Return 1 if the version is upper than 1 and less than 3 diff --git a/audit/fips.h b/audit/fips.h index a8679ef..ef9ae1b 100644 --- a/audit/fips.h +++ b/audit/fips.h @@ -8,8 +8,9 @@ #include #include "audit.h" -#define TYPE_RSA 0x01 -#define TYPE_X509 0x02 +#define TYPE_RSA 0x01 +#define TYPE_ELLIPTIC 0x02 +#define TYPE_X509 0x03 #define RSA_FORMAT_PKCS1 0x1 #define RSA_FORMAT_SPKI 0x2 @@ -19,43 +20,71 @@ #define ALGO_RSA 0x01 #define ALGO_EC 0x02 -struct audit_fips{ +struct audit_fips_ecc{ + struct st_audit audit_curve; +}; + +struct audit_fips_rsa{ struct st_audit audit_keysize; struct st_audit audit_exponent; }; +struct audit_fips{ + struct audit_fips_rsa audit_rsa; + struct audit_fips_ecc audit_ecc; +}; + struct rsa{ - RSA *rsa; - BIO *bio; -#if OPENSSL_VERSION_NUMBER > 0x03000000f + int keysize; + unsigned long exponent; + int format; /* Format of the RSA KEY: PKCS1 or SPKI */ + char *key; + int algo; +}; + +struct ecc{ + //char *prime; + EC_KEY *ec; + char *g; + char *order; + int order_bits; + const char *curve; + int nid; + char *cofactor; +}; + +struct x509{ EVP_PKEY *evp; -#endif + X509_NAME *issuer; + X509_NAME *subject; }; struct keyinfo{ - int keysize; - unsigned long exponent; - int format; - char *key; - int algo; + int algo; /* RSA, ECC */ + + struct x509 st_x509; + struct ecc s_ecc; + struct rsa st_rsa; }; int fips(const char *, struct audit_fips *, struct keyinfo *, const int, const int); /* RSA */ static int fips_pubkey_rsa(struct audit_fips *, struct keyinfo *, const char *); static int fips_privkey_rsa(struct audit_fips *, struct keyinfo *, const char *); -static int loadkeys_rsa_v1(struct rsa **, const char *, int *format); -static int loadkeys_rsa_v3(struct rsa **, const char *, int *format); -static int load_priv_rsa_keys_v1(struct rsa **, const char *); -static int load_priv_rsa_keys_v3(struct rsa **, const char *); -static void audit_rsa_keys(struct rsa *, struct audit_fips *, struct keyinfo *, const char *); +static int loadkeys_rsa(RSA **, const char *, int *format); +static int load_priv_rsa_keys(RSA **, const char *); +static void audit_rsa_keys(RSA *, struct audit_fips *, struct keyinfo *, const char *); +static int check_exponent(const BIGNUM *, char *, unsigned long *); + +/* Elliptic */ +static int fips_pubkey_ecc(EC_KEY *, struct audit_fips *, struct keyinfo *, const char *); +static EC_KEY *fips_load_pubkey_ecc(const char *); +static int get_domain_parameters(struct ecc *); +static void audit_ecc(struct audit_fips *, const int); /* X509 */ -static int fips_x509_v1(struct audit_fips *, struct keyinfo *, const char *); -static int fips_x509_v3(struct audit_fips *, struct keyinfo *, const char *); +static int fips_x509(struct audit_fips *, struct keyinfo *, const char *); -static int check_exponent(const BIGNUM *, char *, unsigned long *); -static void clean_rsa_st(struct rsa *); static int openssl_version(); static void print_error(); diff --git a/certificate.c b/certificate.c index bc50025..9397f09 100644 --- a/certificate.c +++ b/certificate.c @@ -90,37 +90,54 @@ int certificate(char **argv, const int argc){ /*************************/ printf("\nChecking FIPS compliance...\n"); - /*if (type == TYPE_X509){ - printf("Cannot decrypt x509 certifcate, it is not implemented yet\n"); - return 0; - }*/ res = fips(buf_pkey, &st_audit_fips, &st_keyinfo, type, is_pubkey); - if (res < 0){ + if (res > 0){ printf("Error during check FIPS compliance\n"); return -1; } /* Print information regarding the key */ printf("Certificate information:\n"); - printf("\tKey size: %d bytes (%d)\n", st_keyinfo.keysize, (st_keyinfo.keysize * 8)); - printf("\tExponent: %lu\n", st_keyinfo.exponent); - if (st_keyinfo.algo == ALGO_RSA) + if (st_keyinfo.algo == ALGO_RSA){ + printf("\tKey size: %d bytes (%d)\n", st_keyinfo.st_rsa.keysize, (st_keyinfo.st_rsa.keysize * 8)); + printf("\tExponent: %lu\n", st_keyinfo.st_rsa.exponent); printf("\tAlgorithm: RSA\n"); - if (st_keyinfo.algo == ALGO_EC) - printf("\tAlgorithm: Elliptic Curve\n"); + if (st_keyinfo.st_rsa.format == RSA_FORMAT_PKCS1) + printf("\tFormat RSA key: PKCS#1\n"); + if (st_keyinfo.st_rsa.format == RSA_FORMAT_SPKI) + printf("\tFormat RSA key: SPKI (PEM)\n"); - if (st_keyinfo.format == RSA_FORMAT_PKCS1) - printf("\tFormat RSA key: PKCS#1\n"); - if (st_keyinfo.format == RSA_FORMAT_SPKI) - printf("\tFormat RSA key: SPKI\n"); + /* Print the audit result */ + printf("\nExponent result:\n"); + printf("\t%s\n", st_audit_fips.audit_rsa.audit_exponent.result); + printf("Keysize result:\n"); + printf("\t%s\n", st_audit_fips.audit_rsa.audit_keysize.result); + } + if (st_keyinfo.algo == ALGO_EC) { + printf("\tAlgorithm: Elliptic Curve\n"); + printf("\tCurve name: %s\n", st_keyinfo.s_ecc.curve); + printf("\tCofactor: %s\n", st_keyinfo.s_ecc.cofactor); + printf("\tOrder: %s\n", st_keyinfo.s_ecc.order); + printf("\tOrder length: %d\n", st_keyinfo.s_ecc.order_bits); + printf("\tGenerator: %s\n", st_keyinfo.s_ecc.g); + + /* Should I allocate each variables in audit/fips.c and clean it ? */ + + OPENSSL_free(st_keyinfo.s_ecc.cofactor); + /* It's a const char *, I cannot free it */ + //OPENSSL_free(st_keyinfo.s_ecc.curve); + OPENSSL_free(st_keyinfo.s_ecc.order); + OPENSSL_free(st_keyinfo.s_ecc.g); + EC_KEY_free(st_keyinfo.s_ecc.ec); + st_keyinfo.s_ecc.ec = NULL; + + /* Print the audit result */ + printf("\nCurve result: \n"); + printf("\t%s\n", st_audit_fips.audit_ecc.audit_curve.result); + } printf("\n"); - /* Print the audit result */ - printf("Exponent result:\n"); - printf("\t%s\n", st_audit_fips.audit_exponent.result); - printf("Keysize result:\n"); - printf("\t%s\n", st_audit_fips.audit_keysize.result); printf("\n"); @@ -128,14 +145,14 @@ int certificate(char **argv, const int argc){ if (to_stdout){ int len = 0; - st_keyinfo.key = (char *)malloc(st_stat.st_size + 1); + st_keyinfo.st_rsa.key = (char *)malloc(st_stat.st_size + 1); lseek(fd, 0, SEEK_SET); - len = read(fd, st_keyinfo.key, st_stat.st_size); - st_keyinfo.key[len] = '\0'; + len = read(fd, st_keyinfo.st_rsa.key, st_stat.st_size); + st_keyinfo.st_rsa.key[len] = '\0'; - printf("Dump the key:\n%s\n", st_keyinfo.key); + printf("Dump the key:\n%s\n", st_keyinfo.st_rsa.key); - free(st_keyinfo.key); + free(st_keyinfo.st_rsa.key); } close(fd); @@ -153,6 +170,8 @@ static int check_arguments_certificate(char **argv, const int argc, char *buf_pk if (strncmp(argv[i], "-type", l) == 0){ if (strcmp(argv[i + 1], "rsa") == 0) *type = TYPE_RSA; + else if (strcmp(argv[i + 1], "elliptic") == 0) + *type = TYPE_ELLIPTIC; else if (strcmp(argv[i + 1], "x509") == 0) *type = TYPE_X509; else diff --git a/cryptodit b/cryptodit index f1f698583f2ec192481ca89678dd5840fcad445b..50bcaef330bc94bb10e1fa37a2265c00bb8c6944 100755 GIT binary patch literal 39256 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%0A>ku{4x}s#tm($QZ_0tS!d1)IC&F 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 diff --git a/entropy_ebpf.o b/entropy_ebpf.o index 0ee8c9fde2c9139aa6a35841c2785a899de58d38..658f4038aa55036344863975e04f524ab2e35574 100644 GIT binary patch literal 8024 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 vKLMV5=yCGMN7-WN=K?OyyFhQl1m diff --git a/error.h b/error.h index 1771521..610ddee 100644 --- a/error.h +++ b/error.h @@ -4,13 +4,19 @@ /* Define all Common errors */ #define COMMON_ERR_MALLOC 0x100 + /* Define all FIPS errors */ -#define FIPS_ERR_LOAD_KEY 0x200 -#define FIPS_ERR_NEW_BIO 0x201 -#define FIPS_ERR_READ_BIO 0x202 -#define FIPS_ERR_LOAD_RSA_KEY 0x203 -#define FIPS_ERR_LOAD_RSA_PRIV_KEY 0x204 -#define FIPS_ERR_LOAD_X509 0x205 +#define FIPS_ERR_LOAD_KEY 0x200 +#define FIPS_ERR_NEW_BIO 0x201 +#define FIPS_ERR_READ_BIO 0x202 +#define FIPS_ERR_LOAD_RSA_KEY 0x203 +#define FIPS_ERR_LOAD_RSA_PRIV_KEY 0x204 +#define FIPS_ERR_LOAD_X509 0x205 +#define FIPS_ERR_LOAD_ECC_PUBKEY 0x210 +#define FIPS_ERR_LOAD_ECC_PRIVKEY 0x211 +#define FIPS_ERR_GET_ECC_GROUP 0x212 +#define FIPS_ERR_GET_ECC_DOMAPARAM 0x213 +#define FIPS_ERR_GET_ECC_GENERATOR 0x214 #endif diff --git a/examples/foo.pem b/examples/foo.pem deleted file mode 100644 index 0b6ed9b..0000000 --- a/examples/foo.pem +++ /dev/null @@ -1,9 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIBPQIBAAJBAKxX41iNOT0dknOVXnBJ/HJp7Ka4Mu0VKePBIBn2XHFO4f3ZDHXJ -Zt5xb+NJ8nUR640Gjcoc7lOOcw0QmEj1PbMCAwEAAQJBAITEJBDYooqxWFwQarNI -W+DsNvHsntbDYgThh1BY2Lg0EAM9KcJhBDmBF1X12yhMiFlrNbSxV0ZR7/tpMij2 -ycECIQDTvtc9rGQJGhD6GbAlFWP1ukWgwlB1NcC4xMZM+nalIQIhANBc4yVRq3gx -RtgcijG9m++d+IT7ZATHK8+0NlQJkzRTAiEAg5vUcLLbooSfFLQutX3sGWljqZ3d -IFz+olk739C1OcECIQCFVYt9jB+gEFh3XvwIDH/G/F3WK1C7xgCBL588c8whRQIh -AKPuzXozkJrD0K2LHU0GU9bRzl6j6m22+gBG8rDsWUwP ------END RSA PRIVATE KEY-----