diff --git a/libekmfweb/Makefile b/libekmfweb/Makefile index 1af233de..8e12fb56 100644 --- a/libekmfweb/Makefile +++ b/libekmfweb/Makefile @@ -21,17 +21,31 @@ else INSTALL_TARGETS += skip-libekmfweb-openssl endif -libs = $(rootdir)/libutil/libutil.a +libs = $(rootdir)/libseckey/libseckey.a + +TMPFILE := $(shell mktemp) detect-openssl-version.dep: - echo "#include " > detect-openssl-version.dep - echo "#include " >> detect-openssl-version.dep - echo "#if OPENSSL_VERSION_NUMBER < 0x10101000L" >> detect-openssl-version.dep - echo " #error openssl version 1.1.1 is required" >> detect-openssl-version.dep - echo "#endif" >> detect-openssl-version.dep - echo "static void __attribute__((unused)) test(void) {" >> detect-openssl-version.dep - echo " EVP_PKEY_meth_remove(NULL);" >> detect-openssl-version.dep - echo "}" >> detect-openssl-version.dep + echo "#include " > $(TMPFILE) + echo "#include " >> $(TMPFILE) + echo "#ifndef OPENSSL_VERSION_PREREQ" >> $(TMPFILE) + echo " #if defined(OPENSSL_VERSION_MAJOR) && defined(OPENSSL_VERSION_MINOR)" >> $(TMPFILE) + echo " #define OPENSSL_VERSION_PREREQ(maj, min) \\" >> $(TMPFILE) + echo " ((OPENSSL_VERSION_MAJOR << 16) + \\" >> $(TMPFILE) + echo " OPENSSL_VERSION_MINOR >= ((maj) << 16) + (min))" >> $(TMPFILE) + echo " #else" >> $(TMPFILE) + echo " #define OPENSSL_VERSION_PREREQ(maj, min) \\" >> $(TMPFILE) + echo " (OPENSSL_VERSION_NUMBER >= (((maj) << 28) | \\" >> $(TMPFILE) + echo " ((min) << 20)))" >> $(TMPFILE) + echo " #endif" >> $(TMPFILE) + echo "#endif" >> $(TMPFILE) + echo "#if !OPENSSL_VERSION_PREREQ(1, 1)" >> $(TMPFILE) + echo " #error openssl version 1.1 is required" >> $(TMPFILE) + echo "#endif" >> $(TMPFILE) + echo "static void __attribute__((unused)) test(void) {" >> $(TMPFILE) + echo " EVP_PKEY_meth_remove(NULL);" >> $(TMPFILE) + echo "}" >> $(TMPFILE) + mv $(TMPFILE) $@ check-dep-libekmfweb: detect-openssl-version.dep $(call check_dep, \ @@ -39,7 +53,7 @@ check-dep-libekmfweb: detect-openssl-version.dep "detect-openssl-version.dep", \ "openssl-devel version >= 1.1.1", \ "HAVE_OPENSSL=0", \ - -I. -lcrypto) + -I. -lcrypto -DOPENSSL_SUPPRESS_DEPRECATED) $(call check_dep, \ "libekmfweb", \ "json-c/json.h", \ @@ -73,7 +87,7 @@ libekmfweb.so.$(VERSION): ALL_CFLAGS += -fPIC `curl-config --cflags` libekmfweb.so.$(VERSION): LDLIBS = -ljson-c -lcrypto -lssl `curl-config --libs` -ldl libekmfweb.so.$(VERSION): ALL_LDFLAGS += -shared -Wl,--version-script=libekmfweb.map \ -Wl,-z,defs,-Bsymbolic -Wl,-soname,libekmfweb.so.$(VERM) -libekmfweb.so.$(VERSION): ekmfweb.o utilities.o cca.o +libekmfweb.so.$(VERSION): ekmfweb.o utilities.o cca.o $(libs) $(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@ ln -srf libekmfweb.so.$(VERSION) libekmfweb.so.$(VERM) ln -srf libekmfweb.so.$(VERSION) libekmfweb.so diff --git a/libekmfweb/cca.c b/libekmfweb/cca.c index 95e5f133..7d1606cd 100644 --- a/libekmfweb/cca.c +++ b/libekmfweb/cca.c @@ -14,6 +14,8 @@ #include "lib/zt_common.h" +#include "libseckey/sk_utilities.h" + #include #include #include @@ -31,27 +33,6 @@ #define CCA_KEYWORD_SIZE 8 #define CCA_KEY_ID_SIZE 64 -struct cca_ecc_key_pair_value_struct { - uint8_t curve_type; - uint8_t reserved; - uint16_t curve_length; - uint16_t priv_key_length; - uint16_t public_key_len; -} __packed; - -struct cca_rsa_key_pair_value_struct { - uint16_t modulus_bit_length; - uint16_t modulus_length; - uint16_t public_exp_length; - uint16_t reserved; - uint16_t p_length; - uint16_t q_length; - uint16_t dp_length; - uint16_t dq_length; - uint16_t u_length; - unsigned char public_exponent[3]; -} __packed; - struct cca_ecc_pub_key_value_struct { uint8_t curve_type; uint8_t reserved; @@ -84,76 +65,6 @@ struct cca_token_header { #define CCA_TOKEN_VERS2_AES_DATA 0x04 #define CCA_TOKEN_VERS2_AES_CIPHER 0x05 -struct cca_section_header { - uint8_t section_identifier; - uint8_t section_version; - uint16_t section_length; -} __packed; - -#define CCA_SECTION_ID_RSA_ME_1024_PRIV 0x02 -#define CCA_SECTION_ID_RSA_PUBL 0x04 -#define CCA_SECTION_ID_RSA_CRT_2048_PRIV 0x05 -#define CCA_SECTION_ID_RSA_ME_1024_OPK_PRIV 0x06 -#define CCA_SECTION_ID_RSA_CRT_4096_OPK_PRIV 0x08 -#define CCA_SECTION_ID_RSA_ME_4096_PRIV 0x09 -#define CCA_SECTION_ID_ECC_PRIV 0x20 -#define CCA_SECTION_ID_ECC_PUBL 0x21 -#define CCA_SECTION_ID_RSA_ME_1024_EOPK_PRIV 0x30 -#define CCA_SECTION_ID_RSA_CRT_4096_EOPK_PRIV 0x31 - -struct cca_ecc_pub_key_section { - struct cca_section_header section_header; - uint8_t reserved1[4]; - uint8_t curve_type; - uint8_t reserved2; - uint16_t prime_bits_length; - uint16_t pub_key_length; /* Incl. compression indication byte */ - /* Public key of length pub_key_length */ -} __packed; - -struct cca_rsa_pub_key_section { - struct cca_section_header section_header; - uint16_t reserved1; - uint16_t pub_exp_length; - uint16_t modulus_bits_length; - uint16_t modulus_length; /* if 0 -> see priv key section */ - /* Public exponent of length pub_exp_length */ - /* Modulus of length modulus_length */ -} __packed; - -struct cca_rsa_crt_priv_key_section { - struct cca_section_header section_header; - uint16_t assoc_data_length; - uint16_t payload_length; - uint16_t reserved1; - uint8_t assoc_data_version; - uint8_t key_format; - uint8_t key_source; - uint8_t reserved2; - uint8_t hash_type; - uint8_t hash[32]; - uint8_t reserved3[3]; - uint8_t key_usage; - uint8_t format_restriction; - uint16_t p_length; - uint16_t q_length; - uint16_t dp_length; - uint16_t dq_length; - uint16_t u_length; - uint16_t modulus_length; - uint32_t reserved4; - uint8_t opk[48]; - uint8_t kvp[16]; - uint16_t reserved6; - /* Public modulus in length modulus_length */ - /* Encrypted payload (AESKW-wrapped key material) */ -} __packed; - -#define POINT_CONVERSION_COMPRESSED 0x02 -#define POINT_CONVERSION_UNCOMPRESSED 0x04 -#define POINT_CONVERSION_HYBRID 0x06 -#define POINT_CONVERSION_ODD_EVEN 0x01 - /** * Gets the CCA library function entry points from the library handle */ @@ -164,792 +75,17 @@ static int _cca_get_library_functions(const struct ekmf_cca_lib *cca_lib, return -EINVAL; cca->dll_CSNDPKB = (CSNDPKB_t)dlsym(cca_lib->cca_lib, "CSNDPKB"); - cca->dll_CSNDPKG = (CSNDPKG_t)dlsym(cca_lib->cca_lib, "CSNDPKG"); - cca->dll_CSNDKTC = (CSNDKTC_t)dlsym(cca_lib->cca_lib, "CSNDKTC"); - cca->dll_CSNDDSG = (CSNDDSG_t)dlsym(cca_lib->cca_lib, "CSNDDSG"); cca->dll_CSNBKTB2 = (CSNBKTB2_t)dlsym(cca_lib->cca_lib, "CSNBKTB2"); cca->dll_CSNDEDH = (CSNDEDH_t)dlsym(cca_lib->cca_lib, "CSNDEDH"); cca->dll_CSNDSYI2 = (CSNDSYI2_t)dlsym(cca_lib->cca_lib, "CSNDSYI2"); - if (cca->dll_CSNDPKB == NULL || cca->dll_CSNDPKG == NULL || - cca->dll_CSNDKTC == NULL || cca->dll_CSNDDSG == NULL || - cca->dll_CSNBKTB2 == NULL || cca->dll_CSNDEDH == NULL || - cca->dll_CSNDSYI2 == NULL) + if (cca->dll_CSNDPKB == NULL || cca->dll_CSNBKTB2 == NULL || + cca->dll_CSNDEDH == NULL || cca->dll_CSNDSYI2 == NULL) return -EIO; return 0; } -/** - * Generates an CCA ECC key of the specified curve type and length using the - * CCA host library. - * - * @param cca_lib the CCA library structure - * @param curve_nid the nid specifying the curve. - * @param key_token a buffer to store the generated key token - * @param key_token_length On entry: the size of the buffer - * On return: the size of the key token - * @param verbose if true, verbose messages are printed - * - * @returns a negative errno in case of an error, 0 if success. - */ -int cca_generate_ecc_key_pair(const struct ekmf_cca_lib *cca_lib, - int curve_nid, unsigned char *key_token, - size_t *key_token_length, bool verbose) -{ - long return_code, reason_code, rule_array_count, exit_data_len = 0; - unsigned char transport_key_identifier[CCA_KEY_ID_SIZE] = { 0, }; - unsigned char key_skeleton[CCA_MAX_PKA_KEY_TOKEN_SIZE] = { 0, }; - long key_value_structure_length, private_key_name_length = 0; - unsigned char regeneration_data[CCA_KEY_ID_SIZE] = { 0, }; - struct cca_ecc_key_pair_value_struct key_value_structure; - unsigned char private_key_name[CCA_KEY_ID_SIZE] = { 0, }; - unsigned char rule_array[3 * CCA_KEYWORD_SIZE] = { 0, }; - long regeneration_data_length = 0, key_skeleton_length; - unsigned char *exit_data = NULL; - unsigned char *param2 = NULL; - struct cca_lib cca; - long token_length; - long param1 = 0; - int rc; - - if (cca_lib == NULL || key_token == NULL || key_token_length == NULL) - return -EINVAL; - - rc = _cca_get_library_functions(cca_lib, &cca); - if (rc != 0) { - pr_verbose(verbose, "Failed to get CCA functions from library"); - return rc; - } - - memset(key_token, 0, *key_token_length); - token_length = *key_token_length; - - memset(&key_value_structure, 0, sizeof(key_value_structure)); - if (ecc_is_prime_curve(curve_nid)) { - key_value_structure.curve_type = CCA_PRIME_CURVE; - } else if (ecc_is_brainpool_curve(curve_nid)) { - key_value_structure.curve_type = CCA_BRAINPOOL_CURVE; - } else { - pr_verbose(verbose, "Unsupported curve: %d", curve_nid); - return -EINVAL; - } - key_value_structure.curve_length = ecc_get_curve_prime_bits(curve_nid); - key_value_structure_length = sizeof(key_value_structure); - - rule_array_count = 3; - memcpy(rule_array, "ECC-PAIR", CCA_KEYWORD_SIZE); - memcpy(rule_array + CCA_KEYWORD_SIZE, "KEY-MGMT", CCA_KEYWORD_SIZE); - memcpy(rule_array + 2 * CCA_KEYWORD_SIZE, "ECC-VER1", CCA_KEYWORD_SIZE); - - key_skeleton_length = sizeof(key_skeleton); - - cca.dll_CSNDPKB(&return_code, &reason_code, - &exit_data_len, exit_data, - &rule_array_count, rule_array, - &key_value_structure_length, - (unsigned char *)&key_value_structure, - &private_key_name_length, private_key_name, - ¶m1, param2, ¶m1, param2, - ¶m1, param2, ¶m1, param2, - ¶m1, param2, - &key_skeleton_length, key_skeleton); - if (return_code != 0) { - pr_verbose(verbose, "CCA CSNDPKB (EC KEY TOKEN BUILD) failed: " - "return_code: %ld reason_code: %ld", return_code, - reason_code); - return -EIO; - } - - rule_array_count = 1; - memset(rule_array, 0, sizeof(rule_array)); - memcpy(rule_array, "MASTER ", (size_t)CCA_KEYWORD_SIZE); - - cca.dll_CSNDPKG(&return_code, &reason_code, - NULL, NULL, - &rule_array_count, rule_array, - ®eneration_data_length, regeneration_data, - &key_skeleton_length, key_skeleton, - transport_key_identifier, - &token_length, key_token); - if (return_code != 0) { - pr_verbose(verbose, "CCA CSNDPKG (EC KEY GENERATE) failed: " - "return_code: %ld reason_code: %ld", return_code, - reason_code); - return -EIO; - } - - *key_token_length = token_length; - - return 0; -} - -/** - * Generates an CCA RSA key of the specified key size and optionally the - * specified public exponent using the CCA host library. - * - * @param cca_lib the CCA library structure - * @param modulus_bits the size of the key in bits (512, 1024, 2048, 4096) - * @param pub_exp the public exponent or zero. Possible values are: - * 3, 5, 17, 257, or 65537. Specify zero to choose the - * exponent by random (only possible for modulus_bits - * up to 2048). - * @param key_token a buffer to store the generated key token - * @param key_token_length On entry: the size of the buffer - * On return: the size of the key token - * @param verbose if true, verbose messages are printed - * - * @returns a negative errno in case of an error, 0 if success. - */ -int cca_generate_rsa_key_pair(const struct ekmf_cca_lib *cca_lib, - size_t modulus_bits, unsigned int pub_exp, - unsigned char *key_token, - size_t *key_token_length, bool verbose) -{ - long return_code, reason_code, rule_array_count, exit_data_len = 0; - unsigned char transport_key_identifier[CCA_KEY_ID_SIZE] = { 0, }; - unsigned char key_skeleton[CCA_MAX_PKA_KEY_TOKEN_SIZE] = { 0, }; - long key_value_structure_length, private_key_name_length = 0; - unsigned char regeneration_data[CCA_KEY_ID_SIZE] = { 0, }; - struct cca_rsa_key_pair_value_struct key_value_structure; - unsigned char private_key_name[CCA_KEY_ID_SIZE] = { 0, }; - unsigned char rule_array[2 * CCA_KEYWORD_SIZE] = { 0, }; - long regeneration_data_length = 0, key_skeleton_length; - unsigned char *exit_data = NULL; - unsigned char *param2 = NULL; - struct cca_lib cca; - long token_length; - long param1 = 0; - int rc; - - if (cca_lib == NULL || key_token == NULL || key_token_length == NULL) - return -EINVAL; - - rc = _cca_get_library_functions(cca_lib, &cca); - if (rc != 0) { - pr_verbose(verbose, "Failed to get CCA functions from library"); - return rc; - } - - memset(key_token, 0, *key_token_length); - token_length = *key_token_length; - - memset(&key_value_structure, 0, sizeof(key_value_structure)); - key_value_structure.modulus_bit_length = modulus_bits; - switch (pub_exp) { - case 0: - if (modulus_bits > 2048) { - pr_verbose(verbose, "cannot auto-generate public " - "exponent for keys > 2048"); - return -EINVAL; - } - key_value_structure.public_exp_length = 0; - break; - case 3: - key_value_structure.public_exp_length = 1; - key_value_structure.public_exponent[0] = 3; - break; - case 5: - key_value_structure.public_exp_length = 1; - key_value_structure.public_exponent[0] = 5; - break; - case 17: - key_value_structure.public_exp_length = 1; - key_value_structure.public_exponent[0] = 17; - break; - case 257: - key_value_structure.public_exp_length = 2; - key_value_structure.public_exponent[0] = 0x01; - key_value_structure.public_exponent[0] = 0x01; - break; - case 65537: - key_value_structure.public_exp_length = 3; - key_value_structure.public_exponent[0] = 0x01; - key_value_structure.public_exponent[1] = 0x00; - key_value_structure.public_exponent[2] = 0x01; - break; - default: - pr_verbose(verbose, "Invalid public exponent: %d", pub_exp); - return -EINVAL; - } - - key_value_structure_length = sizeof(key_value_structure) + - key_value_structure.public_exp_length; - - rule_array_count = 2; - memcpy(rule_array, "RSA-AESC", CCA_KEYWORD_SIZE); - memcpy(rule_array + CCA_KEYWORD_SIZE, "KEY-MGMT", CCA_KEYWORD_SIZE); - - key_skeleton_length = sizeof(key_skeleton); - - cca.dll_CSNDPKB(&return_code, &reason_code, - &exit_data_len, exit_data, - &rule_array_count, rule_array, - &key_value_structure_length, - (unsigned char *)&key_value_structure, - &private_key_name_length, private_key_name, - ¶m1, param2, ¶m1, param2, - ¶m1, param2, ¶m1, param2, - ¶m1, param2, - &key_skeleton_length, key_skeleton); - if (return_code != 0) { - pr_verbose(verbose, "CCA CSNDPKB (RSA KEY TOKEN BUILD) failed: " - "return_code: %ld reason_code: %ld", return_code, - reason_code); - return -EIO; - } - - rule_array_count = 1; - memset(rule_array, 0, sizeof(rule_array)); - memcpy(rule_array, "MASTER ", (size_t)CCA_KEYWORD_SIZE); - - cca.dll_CSNDPKG(&return_code, &reason_code, - NULL, NULL, - &rule_array_count, rule_array, - ®eneration_data_length, regeneration_data, - &key_skeleton_length, key_skeleton, - transport_key_identifier, - &token_length, key_token); - if (return_code != 0) { - pr_verbose(verbose, "CCA CSNDPKG (RSA KEY GENERATE) failed: " - "return_code: %ld reason_code: %ld", return_code, - reason_code); - return -EIO; - } - - *key_token_length = token_length; - - return 0; -} - -/** - * Finds a specific section of a CCA internal PKA key token. - */ -static const void *_cca_get_pka_section(const unsigned char *key_token, - size_t key_token_length, - unsigned int section_id, bool verbose) -{ - const struct cca_section_header *section_hdr; - const struct cca_token_header *token_hdr; - size_t ofs; - - if (key_token == NULL) - return NULL; - - if (key_token_length < sizeof(struct cca_token_header)) { - pr_verbose(verbose, "key token length too small"); - return NULL; - } - - token_hdr = (struct cca_token_header *)key_token; - if (token_hdr->token_length > key_token_length) { - pr_verbose(verbose, "key token length too small"); - return NULL; - } - if (token_hdr->token_identifier != CCA_TOKEN_ID_INTERNAL_PKA) { - pr_verbose(verbose, "not an internal PKA token"); - return NULL; - } - if (token_hdr->token_version1 != CCA_TOKEN_VERS1_V0) { - pr_verbose(verbose, "invalid token version"); - return NULL; - } - - ofs = sizeof(struct cca_token_header); - section_hdr = (struct cca_section_header *)&key_token[ofs]; - - while (section_hdr->section_identifier != section_id) { - ofs += section_hdr->section_length; - if (ofs >= token_hdr->token_length) { - pr_verbose(verbose, "section %u not found", section_id); - return NULL; - } - section_hdr = (struct cca_section_header *)&key_token[ofs]; - } - - if (ofs + section_hdr->section_length > token_hdr->token_length) { - pr_verbose(verbose, "section exceed the token length"); - return NULL; - } - - return section_hdr; -} - -/** - * Queries the PKEY type of the key token. - * - * @param key_token the key token containing an CCA ECC key - * @param key_token_length the size of the key token - * @param pkey_type On return: the PKEY type of the key token - * - * @returns a negative errno in case of an error, 0 if success. - */ -int cca_get_key_type(const unsigned char *key_token, size_t key_token_length, - int *pkey_type) -{ - if (key_token == NULL || pkey_type == NULL) - return -EINVAL; - - if (_cca_get_pka_section(key_token, key_token_length, - CCA_SECTION_ID_ECC_PUBL, false) != NULL) - *pkey_type = EVP_PKEY_EC; - else if (_cca_get_pka_section(key_token, key_token_length, - CCA_SECTION_ID_RSA_PUBL, false) != NULL) - *pkey_type = EVP_PKEY_RSA; - else - return -EINVAL; - - return 0; -} - -/** - * Extracts the ECC public key from an CCA internal ECC key token, and returns a - * it a OpenSSL PKEY. - * - * @param key_token the key token containing an CCA ECC key - * @param key_token_length the size of the key token - * @param pkey On return: a PKEY containing the public key - * @param verbose if true, verbose messages are printed - * - * @returns a negative errno in case of an error, 0 if success. - */ -int cca_get_ecc_pub_key_as_pkey(const unsigned char *key_token, - size_t key_token_length, - EVP_PKEY **pkey, bool verbose) -{ - struct cca_ecc_pub_key_section *ecc_pub_section; - const unsigned char *ecc_pub_key, *x, *y; - unsigned char *buf = NULL; - size_t prime_len; - int nid, y_bit = 0; - int rc = 0; - - if (key_token == NULL || pkey == NULL) - return -EINVAL; - - ecc_pub_section = (struct cca_ecc_pub_key_section *) - _cca_get_pka_section(key_token, key_token_length, - CCA_SECTION_ID_ECC_PUBL, verbose); - if (ecc_pub_section == NULL) - return -EINVAL; - if (ecc_pub_section->section_header.section_version != 0x00) { - pr_verbose(verbose, "invalid ECC public key section version"); - return -EINVAL; - } - if (ecc_pub_section->section_header.section_length < - sizeof(struct cca_ecc_pub_key_section)) { - pr_verbose(verbose, "invalid ECC public key section length"); - return -EINVAL; - } - - ecc_pub_key = ((unsigned char *)ecc_pub_section) + - sizeof(struct cca_ecc_pub_key_section); - - if (ecc_pub_section->curve_type == CCA_PRIME_CURVE) - nid = ecc_get_prime_curve_by_prime_bits( - ecc_pub_section->prime_bits_length); - else if (ecc_pub_section->curve_type == CCA_BRAINPOOL_CURVE) - nid = ecc_get_brainpool_curve_by_prime_bits( - ecc_pub_section->prime_bits_length); - else - nid = 0; - if (nid == 0) { - pr_verbose(verbose, "unsupported curve"); - rc = -EIO; - goto out; - } - prime_len = ecc_get_curve_prime_length(nid); - - x = ecc_pub_key + 1; - - /* First byte of public key contains indication of key compression */ - switch (ecc_pub_key[0]) { - case POINT_CONVERSION_COMPRESSED: - case POINT_CONVERSION_COMPRESSED + POINT_CONVERSION_ODD_EVEN: - /* Compressed form, only x is available */ - y_bit = (ecc_pub_key[0] & POINT_CONVERSION_ODD_EVEN) ? 1 : 0; - - buf = malloc(prime_len); - if (buf == NULL) { - pr_verbose(verbose, "malloc failed"); - rc = -ENOMEM; - goto out; - } - - rc = ecc_calculate_y_coordinate(nid, prime_len, x, y_bit, buf); - if (rc != 0) { - pr_verbose(verbose, "ecc_calculate_y_coordinate " - "failed"); - goto out; - } - - y = buf; - break; - - case POINT_CONVERSION_UNCOMPRESSED: - case POINT_CONVERSION_HYBRID: - case POINT_CONVERSION_HYBRID + POINT_CONVERSION_ODD_EVEN: - /* Uncompressed or hybrid, x and y are available */ - y = x + prime_len; - break; - - default: - pr_verbose(verbose, "invalid compression indication"); - rc = -EIO; - goto out; - } - - rc = ecc_pub_key_as_pkey(nid, prime_len, x, y, pkey); - if (rc != 0) { - pr_verbose(verbose, "ecc_pub_key_as_pkey failed"); - goto out; - } - -out: - if (buf != NULL) - free(buf); - - return rc; -} - -/** - * Extracts the ECC public key from an CCA internal ECC key token, and returns a - * JSON object representing the public key as JSON Web Key (JWK, see RFC7517). - * The returned JSON objects must be freed by the caller using json_object_put() - * when no longer needed. - * - * @param key_token the key token containing an CCA ECC key - * @param key_token_length the size of the key token - * qparam jwk the ECC public key as JWT JSON object - * @param verbose if true, verbose messages are printed - * - * @returns a negative errno in case of an error, 0 if success. - */ -int cca_get_ecc_pub_key_as_json_web_key(const unsigned char *key_token, - size_t key_token_length, - json_object **jwk, bool verbose) -{ - const struct cca_ecc_pub_key_section *ecc_pub_section; - const struct cca_section_header *section_hdr; - const struct cca_token_header *token_hdr; - const unsigned char *ecc_pub_key, *x, *y; - json_object *jwk_obj = NULL; - unsigned char *buf = NULL; - size_t ofs, prime_len; - int nid, y_bit = 0; - int rc = 0; - - if (key_token == NULL || jwk == NULL) - return -EINVAL; - - if (key_token_length < sizeof(struct cca_token_header)) { - pr_verbose(verbose, "key token length too small"); - return -EINVAL; - } - - token_hdr = (struct cca_token_header *)key_token; - if (token_hdr->token_length > key_token_length) { - pr_verbose(verbose, "key token length too small"); - return -EINVAL; - } - if (token_hdr->token_identifier != CCA_TOKEN_ID_INTERNAL_PKA) { - pr_verbose(verbose, "not an internal PKA token"); - return -EINVAL; - } - if (token_hdr->token_version1 != CCA_TOKEN_VERS1_V0) { - pr_verbose(verbose, "invalid token version"); - return -EINVAL; - } - - ofs = sizeof(struct cca_token_header); - section_hdr = (struct cca_section_header *)&key_token[ofs]; - - while (section_hdr->section_identifier != CCA_SECTION_ID_ECC_PUBL) { - ofs += section_hdr->section_length; - if (ofs >= token_hdr->token_length) { - pr_verbose(verbose, "no ECC public key section found"); - return -EINVAL; - } - section_hdr = (struct cca_section_header *)&key_token[ofs]; - } - - if (section_hdr->section_version != 0x00) { - pr_verbose(verbose, "invalid ECC public key section version"); - return -EINVAL; - } - if (section_hdr->section_length < - sizeof(struct cca_ecc_pub_key_section)) { - pr_verbose(verbose, "invalid ECC public key section length"); - return -EINVAL; - } - - ecc_pub_section = (struct cca_ecc_pub_key_section *)section_hdr; - ofs += sizeof(struct cca_ecc_pub_key_section); - ecc_pub_key = &key_token[ofs]; - - if (ecc_pub_section->curve_type == CCA_PRIME_CURVE) - nid = ecc_get_prime_curve_by_prime_bits( - ecc_pub_section->prime_bits_length); - else if (ecc_pub_section->curve_type == CCA_BRAINPOOL_CURVE) - nid = ecc_get_brainpool_curve_by_prime_bits( - ecc_pub_section->prime_bits_length); - else - nid = 0; - if (nid == 0) { - pr_verbose(verbose, "unsupported curve"); - rc = -EIO; - goto out; - } - prime_len = ecc_get_curve_prime_length(nid); - - x = ecc_pub_key + 1; - - /* First byte of public key contains indication of key compression */ - switch (ecc_pub_key[0]) { - case POINT_CONVERSION_COMPRESSED: - case POINT_CONVERSION_COMPRESSED + POINT_CONVERSION_ODD_EVEN: - /* Compressed form, only x is available */ - y_bit = (ecc_pub_key[0] & POINT_CONVERSION_ODD_EVEN) ? 1 : 0; - - buf = malloc(prime_len); - if (buf == NULL) { - pr_verbose(verbose, "malloc failed"); - rc = -ENOMEM; - goto out; - } - - rc = ecc_calculate_y_coordinate(nid, prime_len, x, y_bit, buf); - if (rc != 0) { - pr_verbose(verbose, "ecc_calculate_y_coordinate " - "failed"); - goto out; - } - - y = buf; - break; - - case POINT_CONVERSION_UNCOMPRESSED: - case POINT_CONVERSION_HYBRID: - case POINT_CONVERSION_HYBRID + POINT_CONVERSION_ODD_EVEN: - /* Uncompressed or hybrid, x and y are available */ - y = x + prime_len; - break; - - default: - pr_verbose(verbose, "invalid compression indication"); - rc = -EIO; - goto out; - } - - /* construct the JWK */ - jwk_obj = json_object_new_object(); - if (jwk_obj == NULL) { - rc = -ENOMEM; - goto out; - } - - /* - * Note: The order of the fields is important, EKMFWeb expects it in - * exactly this order! - */ - rc = json_object_object_add_ex(jwk_obj, "kty", - json_object_new_string("EC"), 0); - rc |= json_object_object_add_ex(jwk_obj, "crv", json_object_new_string( - ecc_get_curve_id(nid)), 0); - rc |= json_object_object_add_ex(jwk_obj, "x", - json_object_new_base64url(x, prime_len), - 0); - rc |= json_object_object_add_ex(jwk_obj, "y", - json_object_new_base64url(y, prime_len), - 0); - if (rc != 0) { - rc = -EIO; - goto out; - } - - *jwk = jwk_obj; - -out: - if (buf != NULL) - free(buf); - if (rc != 0 && jwk_obj != NULL) - json_object_put(jwk_obj); - return rc; -} - -/** - * Extracts the RSA public key from an CCA internal RSA key token, and returns a - * it a OpenSSL PKEY. - * - * @param key_token the key token containing an CCA RSA key - * @param key_token_length the size of the key token - * @param pkey_type the PKEY type (EVP_PKEY_RSA or EVP_PKEY_RSA_PSS)* - * @param pkey On return: a PKEY containing the public key - * @param verbose if true, verbose messages are printed - * - * @returns a negative errno in case of an error, 0 if success. - */ -int cca_get_rsa_pub_key_as_pkey(const unsigned char *key_token, - size_t key_token_length, - int pkey_type, EVP_PKEY **pkey, bool verbose) -{ - const struct cca_rsa_crt_priv_key_section *rsa_priv_section; - const struct cca_rsa_pub_key_section *rsa_pub_section; - const unsigned char *pub_exp, *modulus; - size_t modulus_length; - int rc = 0; - - if (key_token == NULL || pkey == NULL) - return -EINVAL; - - rsa_pub_section = (struct cca_rsa_pub_key_section *) - _cca_get_pka_section(key_token, key_token_length, - CCA_SECTION_ID_RSA_PUBL, verbose); - if (rsa_pub_section == NULL) - return -EINVAL; - if (rsa_pub_section->section_header.section_version != 0x00) { - pr_verbose(verbose, "invalid RSA public key section version"); - return -EINVAL; - } - if (rsa_pub_section->section_header.section_length < - sizeof(struct cca_ecc_pub_key_section)) { - pr_verbose(verbose, "invalid RSA public key section length"); - return -EINVAL; - } - - pub_exp = ((unsigned char *)rsa_pub_section) + - sizeof(struct cca_rsa_pub_key_section); - modulus = pub_exp + rsa_pub_section->pub_exp_length; - modulus_length = rsa_pub_section->modulus_length; - - /* - * The public key section may have a modulus_length of zero, need to - * get the modulus from the private key section instead. - */ - if (rsa_pub_section->modulus_length == 0) { - rsa_priv_section = (struct cca_rsa_crt_priv_key_section *) - _cca_get_pka_section(key_token, key_token_length, - CCA_SECTION_ID_RSA_CRT_4096_EOPK_PRIV, verbose); - - if (rsa_priv_section == NULL) - return -EINVAL; - if (rsa_priv_section->section_header.section_version != 0x00) { - pr_verbose(verbose, "invalid RSA private key section " - "version"); - return -EINVAL; - } - if (rsa_priv_section->section_header.section_length < - sizeof(struct cca_rsa_crt_priv_key_section)) { - pr_verbose(verbose, "invalid RSA private key section " - "length"); - return -EINVAL; - } - - modulus = ((unsigned char *)rsa_priv_section) + - sizeof(struct cca_rsa_crt_priv_key_section); - modulus_length = rsa_priv_section->modulus_length; - } - - rc = rsa_pub_key_as_pkey(modulus, modulus_length, pub_exp, - rsa_pub_section->pub_exp_length, - pkey_type, pkey); - if (rc != 0) { - pr_verbose(verbose, "rsa_pub_key_as_pkey failed"); - goto out; - } - -out: - return rc; -} - -/** - * Re-enciphers a key token with a new CCA master key. - * - * @param cca_lib the CCA library structure - * @param key_token the key token containing an CCA ECC or RSA key. - * The re-enciphered key token is returned in the same - * buffer. The size of the re-enciphered key token - * remains the same. - * @param key_token_length the size of the key token - * @param to_new If true: the key token is re-enciphered from the - * current to the new master key. - * If false: the key token is re-enciphered from the - * old to the current master key. - * @param verbose if true, verbose messages are printed - * - * @returns a negative errno in case of an error, 0 if success. - * -ENODEV is returned if the master keys are not loaded. - */ -int cca_reencipher_key(const struct ekmf_cca_lib *cca_lib, - const unsigned char *key_token, size_t key_token_length, - bool to_new, bool verbose) -{ - long return_code, reason_code, rule_array_count, exit_data_len = 0; - unsigned char rule_array[2 * CCA_KEYWORD_SIZE] = { 0, }; - unsigned char *exit_data = NULL; - struct cca_lib cca; - long token_length; - int rc, type; - - if (cca_lib == NULL || key_token == NULL) - return -EINVAL; - - rc = _cca_get_library_functions(cca_lib, &cca); - if (rc != 0) { - pr_verbose(verbose, "Failed to get CCA functions from library"); - return rc; - } - - rc = cca_get_key_type(key_token, key_token_length, &type); - if (rc != 0) { - pr_verbose(verbose, "Failed to determine the key token type"); - return rc; - } - - rule_array_count = 2; - switch (type) { - case EVP_PKEY_EC: - memcpy(rule_array, "ECC ", CCA_KEYWORD_SIZE); - break; - case EVP_PKEY_RSA: - case EVP_PKEY_RSA_PSS: - memcpy(rule_array, "RSA ", CCA_KEYWORD_SIZE); - break; - default: - pr_verbose(verbose, "Invalid key token type: %d", type); - return -EINVAL; - } - - if (to_new) - memcpy(rule_array + CCA_KEYWORD_SIZE, "RTNMK ", - CCA_KEYWORD_SIZE); - else - memcpy(rule_array + CCA_KEYWORD_SIZE, "RTCMK ", - CCA_KEYWORD_SIZE); - - token_length = key_token_length; - - cca.dll_CSNDKTC(&return_code, &reason_code, - &exit_data_len, exit_data, - &rule_array_count, rule_array, - &token_length, (unsigned char *)key_token); - - if (return_code != 0) { - pr_verbose(verbose, "CCA CSNDKTC (PKA KEY TOKEN CHANGE) failed:" - " return_code: %ld reason_code: %ld", return_code, - reason_code); - - if (return_code == 12 && reason_code == 764) { - pr_verbose(verbose, "The master keys are not loaded"); - return -ENODEV; - } - - return -EIO; - } - - return 0; -} - /** * Import a CCA key from a JSON object representing a key as JSON Web Key (JWK, * see RFC7517). The JWK can either be an ECC public key (kty=EC), or an @@ -975,6 +111,7 @@ int cca_import_key_from_json_web_key(const struct ekmf_cca_lib *cca_lib, struct cca_ecc_pub_key_value_struct *key_value_struct = NULL; unsigned char private_key_name[CCA_KEY_ID_SIZE] = { 0, }; unsigned char rule_array[1 * CCA_KEYWORD_SIZE] = { 0, }; + const struct sk_ec_curve_info *curve_info; unsigned char *exit_data = NULL; size_t prime_len, q_len, len; unsigned char *param2 = NULL; @@ -1013,20 +150,21 @@ int cca_import_key_from_json_web_key(const struct ekmf_cca_lib *cca_lib, goto out; } - nid = ecc_get_curve_by_id(crv); - if (nid == 0) { + nid = EC_curve_nist2nid(crv); + if (nid == NID_undef) { pr_verbose(verbose, "curve '%s' not supported", crv); rc = -EIO; goto out; } - prime_len = ecc_get_curve_prime_length(nid); - if (prime_len == 0) { - pr_verbose(verbose, "curve %d not supported", nid); - rc = -EIO; + curve_info = SK_UTIL_ec_get_curve_info(nid); + if (curve_info == NULL) { + pr_verbose(verbose, "Unsupported curve: %d", nid); + rc = -EINVAL; goto out; } + prime_len = curve_info->prime_len; q_len = 1 + 2 * prime_len; key_value_struct_length = sizeof(struct cca_ecc_pub_key_value_struct) + q_len; @@ -1039,16 +177,19 @@ int cca_import_key_from_json_web_key(const struct ekmf_cca_lib *cca_lib, } memset(key_value_struct, 0, sizeof(*key_value_struct)); - if (ecc_is_prime_curve(nid)) { + switch (curve_info->type) { + case SK_EC_TYPE_PRIME: key_value_struct->curve_type = CCA_PRIME_CURVE; - } else if (ecc_is_brainpool_curve(nid)) { + break; + case SK_EC_TYPE_BRAINPOOL: key_value_struct->curve_type = CCA_BRAINPOOL_CURVE; - } else { + break; + default: pr_verbose(verbose, "Unsupported curve: %d", nid); rc = -EINVAL; goto out; } - key_value_struct->curve_length = ecc_get_curve_prime_bits(nid); + key_value_struct->curve_length = curve_info->prime_bits; key_value_struct->public_key_len = q_len; q = ((unsigned char *)key_value_struct) + @@ -1375,431 +516,3 @@ int cca_import_external_key(const struct ekmf_cca_lib *cca_lib, return 0; } -static const unsigned char der_DigestInfo_SHA1[] = { - 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, - 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14, }; -static const unsigned char der_DigestInfo_SHA224[] = { - 0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, - 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05, - 0x00, 0x04, 0x1C, }; -static const unsigned char der_DigestInfo_SHA256[] = { - 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, - 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, - 0x00, 0x04, 0x20, }; -static const unsigned char der_DigestInfo_SHA384[] = { - 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, - 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, - 0x00, 0x04, 0x30, }; -static const unsigned char der_DigestInfo_SHA512[] = { - 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, - 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, - 0x00, 0x04, 0x40, }; -static const unsigned char der_DigestInfo_SHA3_224[] = { - 0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, - 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x07, 0x05, - 0x00, 0x04, 0x1C, }; -static const unsigned char der_DigestInfo_SHA3_256[] = { - 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, - 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x08, 0x05, - 0x00, 0x04, 0x20, }; -static const unsigned char der_DigestInfo_SHA3_384[] = { - 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, - 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x09, 0x05, - 0x00, 0x04, 0x30, }; -static const unsigned char der_DigestInfo_SHA3_512[] = { - 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, - 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0a, 0x05, - 0x00, 0x04, 0x40, }; - -struct digest_info { - int digest_nid; - size_t digest_size; - const char *cca_keyword; - const unsigned char *der; - size_t der_size; -}; - -static const struct digest_info digest_list[] = { - { .digest_nid = NID_sha1, .digest_size = SHA_DIGEST_LENGTH, - .cca_keyword = "SHA-1 ", .der = der_DigestInfo_SHA1, - .der_size = sizeof(der_DigestInfo_SHA1), }, - { .digest_nid = NID_sha224, .digest_size = SHA224_DIGEST_LENGTH, - .cca_keyword = "SHA-224 ", .der = der_DigestInfo_SHA224, - .der_size = sizeof(der_DigestInfo_SHA224), }, - { .digest_nid = NID_sha256, .digest_size = SHA256_DIGEST_LENGTH, - .cca_keyword = "SHA-256 ", .der = der_DigestInfo_SHA256, - .der_size = sizeof(der_DigestInfo_SHA256), }, - { .digest_nid = NID_sha384, .digest_size = SHA384_DIGEST_LENGTH, - .cca_keyword = "SHA-384 ", .der = der_DigestInfo_SHA384, - .der_size = sizeof(der_DigestInfo_SHA384), }, - { .digest_nid = NID_sha512, .digest_size = SHA512_DIGEST_LENGTH, - .cca_keyword = "SHA-512 ", .der = der_DigestInfo_SHA512, - .der_size = sizeof(der_DigestInfo_SHA512), }, - { .digest_nid = NID_sha3_224, .digest_size = SHA224_DIGEST_LENGTH, - .cca_keyword = NULL, .der = der_DigestInfo_SHA3_224, - .der_size = sizeof(der_DigestInfo_SHA3_224), }, - { .digest_nid = NID_sha3_256, .digest_size = SHA256_DIGEST_LENGTH, - .cca_keyword = NULL, .der = der_DigestInfo_SHA3_256, - .der_size = sizeof(der_DigestInfo_SHA3_256), }, - { .digest_nid = NID_sha3_384, .digest_size = SHA384_DIGEST_LENGTH, - .cca_keyword = NULL, .der = der_DigestInfo_SHA3_384, - .der_size = sizeof(der_DigestInfo_SHA3_384), }, - { .digest_nid = NID_sha3_512, .digest_size = SHA512_DIGEST_LENGTH, - .cca_keyword = NULL, .der = der_DigestInfo_SHA3_512, - .der_size = sizeof(der_DigestInfo_SHA3_512), }, -}; - -static const int digest_list_num = sizeof(digest_list) / - sizeof(struct digest_info); - -static const struct digest_info *get_digest_info(int digest_nid) -{ - int i; - - for (i = 0; i < digest_list_num; i++) { - if (digest_list[i].digest_nid == digest_nid) - return &digest_list[i]; - } - - return NULL; -} - -struct cca_private_data { - CSNDDSG_t dll_CSNDDSG; - bool verbose; -}; - -/** - * Sign data using RSA. - * - * @param cca_lib the CCA library structure - * @param key_token the RSA key token - * @param key_token_length the length of the key token - * @param sig a buffer to store the signature on return. - * @param siglen on input: the size if the signature buffer - * on return: the size of the signature - * @param tbs the data to be signed. - * @param tbslen the size of the data to be signed - * @param padding_type the OpenSSL padding type (RSA_X931_PADDING or - * RSA_PKCS1_PADDING) - * @param digest_nid the OpenSSL nid of the message digest used to - * produce the data to be signed - * @param verbose if true, verbose messages are printed - * - * @returns a negative errno in case of an error, 0 if success. - */ -int cca_rsa_sign(const struct ekmf_cca_lib *cca_lib, - const unsigned char *key_token, size_t key_token_length, - unsigned char *sig, size_t *siglen, - const unsigned char *tbs, size_t tbslen, - int padding_type, int md_nid, bool verbose) -{ - long return_code, reason_code, rule_array_count, exit_data_len = 0; - long token_length, hash_length, sign_bit_length, sign_length; - unsigned char rule_array[3 * CCA_KEYWORD_SIZE] = { 0, }; - unsigned char *hash = NULL, *buf = NULL; - const struct digest_info *digest; - unsigned char *exit_data = NULL; - struct cca_lib cca; - int rc; - - if (cca_lib == NULL || key_token == NULL || sig == NULL || - siglen == NULL || tbs == NULL) - return -EINVAL; - - rc = _cca_get_library_functions(cca_lib, &cca); - if (rc != 0) { - pr_verbose(verbose, "Failed to get CCA functions from library"); - return rc; - } - - rule_array_count = 3; - memcpy(rule_array, "RSA ", CCA_KEYWORD_SIZE); - memcpy(rule_array + CCA_KEYWORD_SIZE, "HASH ", CCA_KEYWORD_SIZE); - - switch (padding_type) { - case RSA_X931_PADDING: - hash = (unsigned char *)tbs; - hash_length = tbslen; - - memcpy(rule_array + 2 * CCA_KEYWORD_SIZE, "X9.31 ", - CCA_KEYWORD_SIZE); - break; - - case RSA_PKCS1_PADDING: - digest = get_digest_info(md_nid); - if (digest == NULL) { - pr_verbose(verbose, "Invalid digest nid: %d", md_nid); - return -EINVAL; - } - - if (tbslen != digest->digest_size) { - pr_verbose(verbose, "Invalid data length: %lu", tbslen); - return -EINVAL; - } - - hash_length = digest->der_size + tbslen; - buf = (unsigned char *)malloc(hash_length); - if (buf == NULL) { - pr_verbose(verbose, "malloc failed"); - return -ENOMEM; - } - - memcpy(buf, digest->der, digest->der_size); - memcpy(buf + digest->der_size, tbs, tbslen); - hash = buf; - - memcpy(rule_array + 2 * CCA_KEYWORD_SIZE, "PKCS-1.1", - CCA_KEYWORD_SIZE); - break; - - default: - pr_verbose(verbose, "Invalid padding type: %d", padding_type); - return -EINVAL; - } - - token_length = key_token_length; - sign_length = *siglen; - - cca.dll_CSNDDSG(&return_code, &reason_code, - &exit_data_len, exit_data, - &rule_array_count, rule_array, - &token_length, (unsigned char *)key_token, - &hash_length, hash, - &sign_length, &sign_bit_length, sig); - - if (return_code != 0) { - pr_verbose(verbose, "CCA CSNDDSG (DIG. SIGNATURE CREATE, RSA) " - "failed: return_code: %ld reason_code: %ld", - return_code, reason_code); - rc = -EIO; - goto out; - } - - *siglen = sign_length; - rc = 0; - -out: - if (buf != NULL) - free(buf); - - return rc; -} - -/** - * Sign data using RSA-PSS. - * - * @param cca_lib the CCA library structure - * @param key_token the RSA key token - * @param key_token_length the length of the key token - * @param sig a buffer to store the signature on return. - * @param siglen on input: the size if the signature buffer - * on return: the size of the signature - * @param tbs the data to be signed. - * @param tbslen the size of the data to be signed - * @param digest_nid the OpenSSL nid of the message digest used to - * produce the data to be signed - * @param mgf_digest_nid the OpenSSL nid of the mask generation function for - * PSS padding - * @param saltlen the length of the salt for PSS - * @param verbose if true, verbose messages are printed - * - * @returns a negative errno in case of an error, 0 if success. - */ -int cca_rsa_pss_sign(const struct ekmf_cca_lib *cca_lib, - const unsigned char *key_token, size_t key_token_length, - unsigned char *sig, size_t *siglen, - const unsigned char *tbs, size_t tbslen, - int digest_nid, int mgf_digest_nid, int saltlen, - bool verbose) -{ - long return_code, reason_code, rule_array_count, exit_data_len = 0; - unsigned char rule_array[4 * CCA_KEYWORD_SIZE] = { 0, }; - long token_length, hash_length, sign_bit_length, sign_length; - const struct digest_info *digest; - unsigned char *exit_data = NULL; - unsigned char *buf = NULL; - struct cca_lib cca; - uint32_t salt_len; - int rc; - - if (cca_lib == NULL || key_token == NULL || sig == NULL || - siglen == NULL || tbs == NULL) - return -EINVAL; - - rc = _cca_get_library_functions(cca_lib, &cca); - if (rc != 0) { - pr_verbose(verbose, "Failed to get CCA functions from library"); - return rc; - } - - if (mgf_digest_nid != digest_nid) { - pr_verbose(verbose, "Mgf nid must be the same as the message " - "digest nid"); - return -EINVAL; - } - - digest = get_digest_info(digest_nid); - if (digest == NULL || digest->cca_keyword == NULL) { - pr_verbose(verbose, "Invalid mgf nid: %d", digest_nid); - return -EINVAL; - } - - rule_array_count = 4; - memcpy(rule_array, "RSA ", CCA_KEYWORD_SIZE); - memcpy(rule_array + CCA_KEYWORD_SIZE, "PKCS-PSS", CCA_KEYWORD_SIZE); - memcpy(rule_array + 2 * CCA_KEYWORD_SIZE, "HASH ", CCA_KEYWORD_SIZE); - memcpy(rule_array + 3 * CCA_KEYWORD_SIZE, digest->cca_keyword, - CCA_KEYWORD_SIZE); - - hash_length = sizeof(uint32_t) + tbslen; - buf = (unsigned char *)malloc(hash_length); - if (buf == NULL) { - pr_verbose(verbose, "malloc failed"); - return -ENOMEM; - } - - salt_len = saltlen; - memcpy(buf, &salt_len, sizeof(uint32_t)); - memcpy(buf + sizeof(uint32_t), tbs, tbslen); - - token_length = key_token_length; - sign_length = *siglen; - - cca.dll_CSNDDSG(&return_code, &reason_code, - &exit_data_len, exit_data, - &rule_array_count, rule_array, - &token_length, (unsigned char *)key_token, - &hash_length, buf, - &sign_length, &sign_bit_length, sig); - - if (return_code != 0) { - pr_verbose(verbose, "CCA CSNDDSG (DIG. SIGNATURE CREATE, " - "RSA-PSS) failed: return_code: %ld reason_code: %ld", - return_code, reason_code); - rc = -EIO; - goto out; - } - - *siglen = sign_length; - rc = 0; - -out: - free(buf); - - return rc; -} - -/** - * Sign data using ECDSA. - * - * @param cca_lib the CCA library structure - * @param key_token the RSA key token - * @param key_token_length the length of the key token - * @param sig a buffer to store the signature on return. - * @param siglen on input: the size if the signature buffer - * on return: the size of the signature - * @param tbs the data to be signed. - * @param tbslen the size of the data to be signed - * @param digest_nid the OpenSSL nid of the message digest used to - * produce the data to be signed - * @param verbose if true, verbose messages are printed - * - * @returns a negative errno in case of an error, 0 if success. - */ -int cca_ecdsa_sign(const struct ekmf_cca_lib *cca_lib, - const unsigned char *key_token, size_t key_token_length, - unsigned char *sig, size_t *siglen, - const unsigned char *tbs, size_t tbslen, - int UNUSED(digest_nid), bool verbose) -{ - long return_code, reason_code, rule_array_count, exit_data_len = 0; - long token_length, hash_length, sign_bit_length, sign_length; - unsigned char rule_array[2 * CCA_KEYWORD_SIZE] = { 0, }; - unsigned char *exit_data = NULL; - unsigned char *der = NULL; - ECDSA_SIG *ec_sig = NULL; - BIGNUM *bn_r = NULL; - BIGNUM *bn_s = NULL; - struct cca_lib cca; - int rc, der_len; - - if (cca_lib == NULL || key_token == NULL || sig == NULL || - siglen == NULL || tbs == NULL) - return -EINVAL; - - rc = _cca_get_library_functions(cca_lib, &cca); - if (rc != 0) { - pr_verbose(verbose, "Failed to get CCA functions from library"); - return rc; - } - - rule_array_count = 2; - memcpy(rule_array, "ECDSA ", CCA_KEYWORD_SIZE); - memcpy(rule_array + CCA_KEYWORD_SIZE, "HASH ", CCA_KEYWORD_SIZE); - - hash_length = tbslen; - token_length = key_token_length; - sign_length = *siglen; - - cca.dll_CSNDDSG(&return_code, &reason_code, - &exit_data_len, exit_data, - &rule_array_count, rule_array, - &token_length, (unsigned char *)key_token, - &hash_length, (unsigned char *)tbs, - &sign_length, &sign_bit_length, sig); - - if (return_code != 0) { - pr_verbose(verbose, "CCA CSNDDSG (DIG. SIGNATURE CREATE, ECDSA)" - " failed: return_code: %ld reason_code: %ld", - return_code, reason_code); - return -EIO; - } - - ec_sig = ECDSA_SIG_new(); - if (ec_sig == NULL) { - rc = -ENOMEM; - goto out; - } - - bn_r = BN_bin2bn(sig, sign_length / 2, NULL); - bn_s = BN_bin2bn(sig + sign_length / 2, sign_length / 2, NULL); - if (bn_r == NULL || bn_s == NULL) { - rc = -EIO; - goto out; - } - - if (ECDSA_SIG_set0(ec_sig, bn_r, bn_s) != 1) { - rc = -EIO; - goto out; - } - bn_r = NULL; - bn_s = NULL; - - der_len = i2d_ECDSA_SIG(ec_sig, NULL); - if (der_len > (int)*siglen) { - rc = -ERANGE; - goto out; - } - - memset(sig, 0, *siglen); - der = sig; - *siglen = i2d_ECDSA_SIG(ec_sig, &der); - - if (*siglen == 0) { - rc = -EIO; - goto out; - } - - rc = 0; -out: - if (ec_sig != NULL) - ECDSA_SIG_free(ec_sig); - if (bn_r != NULL) - BN_free(bn_r); - if (bn_s != NULL) - BN_free(bn_s); - - return rc; -} - diff --git a/libekmfweb/cca.h b/libekmfweb/cca.h index 10a67fa6..54277a0e 100644 --- a/libekmfweb/cca.h +++ b/libekmfweb/cca.h @@ -19,21 +19,6 @@ #include "ekmfweb/ekmfweb.h" -/* CCA PKA Key Generate function */ -typedef void (*CSNDPKG_t)(long *return_code, - long *reason_code, - long *exit_data_length, - unsigned char *exit_data, - long *rule_array_count, - unsigned char *rule_array, - long *regeneration_data_length, - unsigned char *regeneration_data, - long *skeleton_key_token_length, - unsigned char *skeleton_key_token, - unsigned char *transport_key_identifier, - long *generated_key_identifier_length, - unsigned char *generated_key_identifier); - /* CCA PKA Key Token Build function */ typedef void (*CSNDPKB_t)(long *return_code, long *reason_code, @@ -57,31 +42,6 @@ typedef void (*CSNDPKB_t)(long *return_code, unsigned char *reserved_5, long *token_length, unsigned char *token); -/* CCA PKA Key Token Change function */ -typedef void (*CSNDKTC_t)(long *return_code, - long *reason_code, - long *exit_data_length, - unsigned char *exit_data, - long *rule_array_count, - unsigned char *rule_array, - long *key_identifier_length, - unsigned char *key_identifier); - -/* CCA Digital Signature Generate function */ -typedef void (*CSNDDSG_t)(long *return_code, - long *reason_code, - long *exit_data_length, - unsigned char *exit_data, - long *rule_array_count, - unsigned char *rule_array, - long *PKA_private_key_identifier_length, - unsigned char *PKA_private_key_identifier, - long *hash_length, - unsigned char *hash, - long *signature_field_length, - long *signature_bit_length, - unsigned char *signature_field); - /* CCA Key Token Build2 function */ typedef void (*CSNBKTB2_t)(long *return_code, long *reason_code, @@ -153,9 +113,6 @@ typedef void (*CSNDSYI2_t)(long *return_code, struct cca_lib { CSNDPKB_t dll_CSNDPKB; - CSNDPKG_t dll_CSNDPKG; - CSNDKTC_t dll_CSNDKTC; - CSNDDSG_t dll_CSNDDSG; CSNBKTB2_t dll_CSNBKTB2; CSNDEDH_t dll_CSNDEDH; CSNDSYI2_t dll_CSNDSYI2; @@ -164,34 +121,6 @@ struct cca_lib { #define CCA_MAX_PKA_KEY_TOKEN_SIZE 3500 #define CCA_MAX_SYM_KEY_TOKEN_SIZE 725 -int cca_generate_ecc_key_pair(const struct ekmf_cca_lib *cca_lib, - int curve_nid, unsigned char *key_token, - size_t *key_token_length, bool verbose); - -int cca_generate_rsa_key_pair(const struct ekmf_cca_lib *cca_lib, - size_t modulus_bits, unsigned int pub_exp, - unsigned char *key_token, - size_t *key_token_length, bool verbose); - -int cca_get_key_type(const unsigned char *key_token, size_t key_token_length, - int *pkey_type); - -int cca_reencipher_key(const struct ekmf_cca_lib *cca_lib, - const unsigned char *key_token, size_t key_token_length, - bool to_new, bool verbose); - -int cca_get_ecc_pub_key_as_pkey(const unsigned char *key_token, - size_t key_token_length, - EVP_PKEY **pkey, bool verbose); - -int cca_get_ecc_pub_key_as_json_web_key(const unsigned char *key_token, - size_t key_token_length, - json_object **jwk, bool verbose); - -int cca_get_rsa_pub_key_as_pkey(const unsigned char *key_token, - size_t key_token_length, - int pkey_type, EVP_PKEY **pkey, bool verbose); - int cca_import_key_from_json_web_key(const struct ekmf_cca_lib *cca_lib, json_object *jwk, unsigned char *key_token, size_t *key_token_length, bool verbose); @@ -225,23 +154,4 @@ int cca_import_external_key(const struct ekmf_cca_lib *cca_lib, size_t *imported_key_token_length, bool verbose); -int cca_rsa_sign(const struct ekmf_cca_lib *cca_lib, - const unsigned char *key_token, size_t key_token_length, - unsigned char *sig, size_t *siglen, - const unsigned char *tbs, size_t tbslen, - int padding_type, int digest_nid, bool verbose); - -int cca_rsa_pss_sign(const struct ekmf_cca_lib *cca_lib, - const unsigned char *key_token, size_t key_token_length, - unsigned char *sig, size_t *siglen, - const unsigned char *tbs, size_t tbslen, - int digest_nid, int mgf_digest_nid, int saltlen, - bool verbose); - -int cca_ecdsa_sign(const struct ekmf_cca_lib *cca_lib, - const unsigned char *key_token, size_t key_token_length, - unsigned char *sig, size_t *siglen, - const unsigned char *tbs, size_t tbslen, int digest_nid, - bool verbose); - #endif diff --git a/libekmfweb/ekmfweb.c b/libekmfweb/ekmfweb.c index 1f9ad170..ee25fc08 100644 --- a/libekmfweb/ekmfweb.c +++ b/libekmfweb/ekmfweb.c @@ -31,12 +31,12 @@ #include "lib/zt_common.h" +#include "libseckey/sk_openssl.h" + #include "ekmfweb/ekmfweb.h" #include "utilities.h" #include "cca.h" -#define SERIAL_NUMBER_BIT_SIZE 159 - #define DEFAULT_SESSION_EC_KEY_CURVE NID_secp521r1 #define MAX_KEY_BLOB_SIZE CCA_MAX_PKA_KEY_TOKEN_SIZE @@ -144,19 +144,61 @@ static const char *accepted_content_types[] = { "application/json", "text/x-json", NULL}; -struct private_data { - const struct ekmf_ext_lib *ext_lib; - bool verbose; +struct ext_lib_info { + struct sk_ext_lib ext_lib; + union { + struct sk_ext_cca_lib cca; /* Used if type = EXT_LIB_CCA */ + struct sk_ext_ep11_lib ep11; /* Used if type = EXT_LIB_EP11 */ + }; }; -static int _ekmf_setup_sign_context(const unsigned char *key_blob, - size_t key_blob_size, EVP_PKEY *pkey, - int digest_nid, - struct ekmf_rsa_pss_params *rsa_pss_params, - EVP_MD_CTX **md_ctx, - EVP_PKEY_CTX **pkey_ctx, - struct private_data *private, - bool verbose); +static void _ekmf_copy_ext_lib(const struct ekmf_ext_lib *ekmf_ext_lib, + struct ext_lib_info *ext_lib_info) +{ + switch (ekmf_ext_lib->type) { + case EKMF_EXT_LIB_CCA: + ext_lib_info->ext_lib.type = SK_EXT_LIB_CCA; + ext_lib_info->ext_lib.cca = &ext_lib_info->cca; + ext_lib_info->cca.cca_lib = ekmf_ext_lib->cca->cca_lib; + break; + default: + ext_lib_info->ext_lib.type = 0; + } +} + +static void _ekmf_copy_key_gen_info(const struct ekmf_key_gen_info *ekmf_info, + struct sk_key_gen_info *sk_info) +{ + switch (ekmf_info->type) { + case EKMF_KEY_TYPE_ECC: + sk_info->type = SK_KEY_TYPE_EC; + sk_info->ec.curve_nid = ekmf_info->params.ecc.curve_nid; + break; + case EKMF_KEY_TYPE_RSA: + sk_info->type = SK_KEY_TYPE_RSA; + sk_info->rsa.modulus_bits = ekmf_info->params.rsa.modulus_bits; + sk_info->rsa.pub_exp = ekmf_info->params.rsa.pub_exp; + sk_info->rsa.x9_31 = 0; + break; + default: + sk_info->type = 0; + break; + } +} + +static void _ekmf_copy_pss_params( + const struct ekmf_rsa_pss_params *ekmf_pss_params, + struct sk_rsa_pss_params *rsa_pss_params) +{ + if (ekmf_pss_params != NULL) { + rsa_pss_params->mgf_digest_nid = + ekmf_pss_params->mgf_digest_nid; + rsa_pss_params->salt_len = ekmf_pss_params->salt_len; + } else { + rsa_pss_params->mgf_digest_nid = NID_undef; + rsa_pss_params->salt_len = 0; + } +} /** * Extract the public key from a certificate in PEM format and store it into a @@ -1442,6 +1484,13 @@ int ekmf_get_public_key(const struct ekmf_config *config, CURL **curl_handle, if (config == NULL) return -EINVAL; + rc = SK_OPENSSL_init(verbose); + if (rc != 0) { + pr_verbose(verbose, "Failed to initialize secure key support: " + "%s", strerror(-rc)); + return rc; + } + rc = ekmf_check_login_token(config, &token_valid, &login_token, verbose); if (rc != 0 || !token_valid) { @@ -1509,6 +1558,7 @@ out: free(login_token); if (pkey != NULL) EVP_PKEY_free(pkey); + SK_OPENSSL_term(); return rc; } @@ -1938,53 +1988,26 @@ static int _ekmf_build_signature(unsigned char *key_blob, const struct ekmf_ext_lib *ext_lib, bool verbose) { - struct ekmf_rsa_pss_params rsa_pss_params; + struct sk_rsa_pss_params rsa_pss_params; + struct ext_lib_info ext_lib_info; EVP_PKEY_CTX *pkey_ctx = NULL; - struct private_data private; EVP_MD_CTX *md_ctx = NULL; - bool pkey_meth = false; EVP_PKEY *pkey = NULL; const char *payload; const char *jws_alg; int rc, curve_nid; char *jws = NULL; - int pkey_type; BIO *b; - switch (ext_lib->type) { - case EKMF_EXT_LIB_CCA: - rc = cca_get_key_type(key_blob, key_blob_length, &pkey_type); - if (rc != 0) { - pr_verbose(verbose, "Failed to get the identity key " - "type"); - goto out; - } + _ekmf_copy_ext_lib(ext_lib, &ext_lib_info); - switch (pkey_type) { - case EVP_PKEY_EC: - rc = cca_get_ecc_pub_key_as_pkey(key_blob, - key_blob_length, - &pkey, verbose); - break; - case EVP_PKEY_RSA: - case EVP_PKEY_RSA_PSS: - rc = cca_get_rsa_pub_key_as_pkey(key_blob, - key_blob_length, - use_rsa_pss ? - EVP_PKEY_RSA_PSS : - EVP_PKEY_RSA, - &pkey, verbose); - break; - } - - if (rc != 0) { - pr_verbose(verbose, "Failed to get the identity PKEY"); - goto out; - } - break; - default: - pr_verbose(verbose, "Invalid ext lib type: %d", ext_lib->type); - return -EINVAL; + rc = SK_OPENSSL_get_secure_key_as_pkey(key_blob, key_blob_length, + use_rsa_pss, &pkey, + &ext_lib_info.ext_lib, + verbose); + if (rc != 0) { + pr_verbose(verbose, "Failed to get the identity PKEY"); + goto out; } /* @@ -2002,8 +2025,7 @@ static int _ekmf_build_signature(unsigned char *key_blob, */ switch (EVP_PKEY_id(pkey)) { case EVP_PKEY_EC: - curve_nid = EC_GROUP_get_curve_name(EC_KEY_get0_group( - EVP_PKEY_get0_EC_KEY(pkey))); + curve_nid = SK_OPENSSL_get_curve_from_ec_pkey(pkey); switch (curve_nid) { case NID_secp521r1: digest_nid = NID_sha512; @@ -2069,15 +2091,13 @@ static int _ekmf_build_signature(unsigned char *key_blob, goto out; } - private.ext_lib = ext_lib; - private.verbose = verbose; - - rc = _ekmf_setup_sign_context(key_blob, key_blob_length, pkey, - digest_nid, &rsa_pss_params, &md_ctx, - &pkey_ctx, &private, verbose); - if (rc != 0) + rc = SK_OPENSSL_setup_sign_context(pkey, false, digest_nid, + &rsa_pss_params, &md_ctx, &pkey_ctx, + verbose); + if (rc != 0) { + pr_verbose(verbose, "Failed to setup secure key sign context"); goto out; - pkey_meth = true; + } payload = json_object_to_json_string_ext(payload_obj, JSON_C_TO_STRING_PLAIN | @@ -2111,8 +2131,6 @@ static int _ekmf_build_signature(unsigned char *key_blob, out: if (md_ctx != NULL) EVP_MD_CTX_free(md_ctx); - if (pkey_meth) - cleanup_secure_key_pkey_method(EVP_PKEY_id(pkey)); if (pkey != NULL) EVP_PKEY_free(pkey); if (jws != NULL) @@ -2280,6 +2298,51 @@ out: return rc; } +/* + * Callback function for SK_OPENSSL_get_public_from_secure_key. Construct + * a JSON Web key from a public EC key. + */ +static int _ekmf_pub_key_as_json_web_key(const struct sk_pub_key_info *pub_key, + void *private) +{ + json_object **jwk_ret = private; + json_object *jwk_obj = NULL; + int rc = 0; + + if (pub_key->type != SK_KEY_TYPE_EC) + return -EINVAL; + + /* construct the JWK */ + jwk_obj = json_object_new_object(); + if (jwk_obj == NULL) + return -ENOMEM; + + /* + * Note: The order of the fields is important, EKMFWeb expects it in + * exactly this order! + */ + rc = json_object_object_add_ex(jwk_obj, "kty", + json_object_new_string("EC"), 0); + rc |= json_object_object_add_ex(jwk_obj, "crv", json_object_new_string( + EC_curve_nid2nist(pub_key->ec.curve_nid)), 0); + rc |= json_object_object_add_ex(jwk_obj, "x", + json_object_new_base64url(pub_key->ec.x, + pub_key->ec.prime_len), + 0); + rc |= json_object_object_add_ex(jwk_obj, "y", + json_object_new_base64url(pub_key->ec.y, + pub_key->ec.prime_len), + 0); + if (rc != 0) { + json_object_put(jwk_obj); + return -EIO; + } + + *jwk_ret = jwk_obj; + + return 0; +} + /** * Requests a key to be retrieved from EKMFweb and imported under the current * HSM's master key. @@ -2342,8 +2405,10 @@ int ekmf_retrieve_key(const struct ekmf_config *config, CURL **curl_handle, json_object *resp_sess_jwk_obj = NULL; json_object *req_sess_jwk_obj = NULL; json_object *resp_exp_jwk_obj = NULL; + struct ext_lib_info ext_lib_info; json_object *response_obj = NULL; json_object *request_obj = NULL; + struct sk_key_gen_info gen_info; EVP_PKEY *server_pubkey = NULL; char *escaped_uuid = NULL; char *login_token = NULL; @@ -2357,6 +2422,15 @@ int ekmf_retrieve_key(const struct ekmf_config *config, CURL **curl_handle, key_blob_length == NULL || ext_lib == NULL) return -EINVAL; + _ekmf_copy_ext_lib(ext_lib, &ext_lib_info); + + rc = SK_OPENSSL_init(verbose); + if (rc != 0) { + pr_verbose(verbose, "Failed to initialize secure key support: " + "%s", strerror(-rc)); + return rc; + } + rc = ekmf_check_login_token(config, &token_valid, &login_token, verbose); if (rc != 0 || !token_valid) { @@ -2390,34 +2464,30 @@ int ekmf_retrieve_key(const struct ekmf_config *config, CURL **curl_handle, goto out; } - switch (ext_lib->type) { - case EKMF_EXT_LIB_CCA: - req_sess_ec_key_length = sizeof(req_sess_ec_key); - rc = cca_generate_ecc_key_pair(ext_lib->cca, - sess_ec_curve_nid != 0 ? - sess_ec_curve_nid : - DEFAULT_SESSION_EC_KEY_CURVE, - req_sess_ec_key, - &req_sess_ec_key_length, - verbose); - if (rc != 0) { - pr_verbose(verbose, "Failed to generate a session EC " - "key"); - goto out; - } + gen_info.type = SK_KEY_TYPE_EC; + gen_info.ec.curve_nid = sess_ec_curve_nid != 0 ? sess_ec_curve_nid : + DEFAULT_SESSION_EC_KEY_CURVE; - rc = cca_get_ecc_pub_key_as_json_web_key(req_sess_ec_key, - req_sess_ec_key_length, - &req_sess_jwk_obj, - verbose); - if (rc != 0) { - pr_verbose(verbose, "Failed to generate session JWK"); - goto out; - } - break; - default: - pr_verbose(verbose, "Invalid ext lib type: %d", ext_lib->type); - return -EINVAL; + req_sess_ec_key_length = sizeof(req_sess_ec_key); + rc = SK_OPENSSL_generate_secure_key(req_sess_ec_key, + &req_sess_ec_key_length, + &gen_info, &ext_lib_info.ext_lib, + verbose); + if (rc != 0) { + pr_verbose(verbose, "Failed to generate a session EC " + "key"); + goto out; + } + + rc = SK_OPENSSL_get_public_from_secure_key(req_sess_ec_key, + req_sess_ec_key_length, + _ekmf_pub_key_as_json_web_key, + &req_sess_jwk_obj, + &ext_lib_info.ext_lib, + verbose); + if (rc != 0 || req_sess_jwk_obj == NULL) { + pr_verbose(verbose, "Failed to generate session JWK"); + goto out; } req_timestamp_obj = get_json_timestamp(); @@ -2639,6 +2709,7 @@ out: free(resp_party_info); if (escaped_uuid != NULL) curl_free(escaped_uuid); + SK_OPENSSL_term(); return rc; } @@ -4803,6 +4874,8 @@ int ekmf_generate_identity_key(const struct ekmf_config *config, { unsigned char key_blob[MAX_KEY_BLOB_SIZE]; size_t key_blob_size = sizeof(key_blob); + struct ext_lib_info ext_lib_info; + struct sk_key_gen_info gen_info; int rc; if (config == NULL || info == NULL || ext_lib == NULL) @@ -4810,30 +4883,11 @@ int ekmf_generate_identity_key(const struct ekmf_config *config, if (config->identity_secure_key == NULL) return -EINVAL; - switch (ext_lib->type) { - case EKMF_EXT_LIB_CCA: - switch (info->type) { - case EKMF_KEY_TYPE_ECC: - rc = cca_generate_ecc_key_pair(ext_lib->cca, - info->params.ecc.curve_nid, - key_blob, &key_blob_size, verbose); - break; - case EKMF_KEY_TYPE_RSA: - rc = cca_generate_rsa_key_pair(ext_lib->cca, - info->params.rsa.modulus_bits, - info->params.rsa.pub_exp, - key_blob, &key_blob_size, verbose); - break; - default: - pr_verbose(verbose, "Invalid key type: %d", info->type); - return -EINVAL; - } - break; - default: - pr_verbose(verbose, "Invalid ext lib type: %d", ext_lib->type); - return -EINVAL; - } + _ekmf_copy_ext_lib(ext_lib, &ext_lib_info); + _ekmf_copy_key_gen_info(info, &gen_info); + rc = SK_OPENSSL_generate_secure_key(key_blob, &key_blob_size, &gen_info, + &ext_lib_info.ext_lib, verbose); if (rc != 0) { pr_verbose(verbose, "Failed to generate a key: rc: %d - %s", rc, strerror(-rc)); @@ -4896,6 +4950,7 @@ int ekmf_reencipher_identity_key(const struct ekmf_config *config, { unsigned char key_blob[MAX_KEY_BLOB_SIZE]; size_t key_blob_size = sizeof(key_blob); + struct ext_lib_info ext_lib_info; const char *out_file; int rc; @@ -4904,6 +4959,8 @@ int ekmf_reencipher_identity_key(const struct ekmf_config *config, if (config->identity_secure_key == NULL) return -EINVAL; + _ekmf_copy_ext_lib(ext_lib, &ext_lib_info); + rc = read_key_blob(config->identity_secure_key, key_blob, &key_blob_size); if (rc != 0) { @@ -4913,16 +4970,8 @@ int ekmf_reencipher_identity_key(const struct ekmf_config *config, return rc; } - switch (ext_lib->type) { - case EKMF_EXT_LIB_CCA: - rc = cca_reencipher_key(ext_lib->cca, key_blob, key_blob_size, - to_new, verbose); - break; - default: - pr_verbose(verbose, "Invalid ext lib type: %d", ext_lib->type); - return -EINVAL; - } - + rc = SK_OPENSSL_reencipher_secure_key(key_blob, key_blob_size, to_new, + &ext_lib_info.ext_lib, verbose); if (rc != 0) { pr_verbose(verbose, "Failed to re-encipher the secure identity " "key from file '%s': %s", @@ -4942,217 +4991,6 @@ int ekmf_reencipher_identity_key(const struct ekmf_config *config, return 0; } -/** - * Wrapper for the RSA sign callback to route the call to the selected - * secure key library. - */ -static int _ekmf_rsa_sign(const unsigned char *key_blob, size_t key_blob_length, - unsigned char *sig, size_t *siglen, - const unsigned char *tbs, size_t tbslen, - int padding_type, int md_nid, void *private) -{ - struct private_data *prv = (struct private_data *)private; - - if (prv == NULL || prv->ext_lib == NULL) - return 1; - - switch (prv->ext_lib->type) { - case EKMF_EXT_LIB_CCA: - return cca_rsa_sign(prv->ext_lib->cca, key_blob, - key_blob_length, sig, siglen, tbs, tbslen, - padding_type, md_nid, prv->verbose); - default: - return 1; - } -} - -/** - * Wrapper for the RSA-PSS sign callback to route the call to the selected - * secure key library. - */ -static int _ekmf_rsa_pss_sign(const unsigned char *key_blob, - size_t key_blob_length, unsigned char *sig, - size_t *siglen, const unsigned char *tbs, - size_t tbslen, int md_nid, int mgfmd_nid, - int saltlen, void *private) -{ - struct private_data *prv = (struct private_data *)private; - - if (prv == NULL || prv->ext_lib == NULL) - return 1; - - switch (prv->ext_lib->type) { - case EKMF_EXT_LIB_CCA: - return cca_rsa_pss_sign(prv->ext_lib->cca, key_blob, - key_blob_length, sig, siglen, tbs, - tbslen, md_nid, mgfmd_nid, saltlen, - prv->verbose); - default: - return 1; - } -} - -/** - * Wrapper for the ECDSA sign callback to route the call to the selected - * secure key library. - */ -static int _ekmf_ecdsa_sign(const unsigned char *key_blob, - size_t key_blob_length, unsigned char *sig, - size_t *siglen, const unsigned char *tbs, - size_t tbslen, int md_nid, void *private) -{ - struct private_data *prv = (struct private_data *)private; - - if (prv == NULL || prv->ext_lib == NULL) - return 1; - - switch (prv->ext_lib->type) { - case EKMF_EXT_LIB_CCA: - return cca_ecdsa_sign(prv->ext_lib->cca, key_blob, - key_blob_length, sig, siglen, tbs, tbslen, - md_nid, prv->verbose); - default: - return 1; - } -} - -/** - * Gets the public key from the key blob as a PKEY object. - */ -static int _ekmf_get_pub_key_as_pkey(const unsigned char *key_blob, - size_t key_blob_size, EVP_PKEY **pkey, - bool rsa_pss, - const struct ekmf_ext_lib *ext_lib, - bool verbose) -{ - int rc, pkey_type; - - switch (ext_lib->type) { - case EKMF_EXT_LIB_CCA: - rc = cca_get_key_type(key_blob, key_blob_size, &pkey_type); - if (rc != 0) { - pr_verbose(verbose, "Failed to get the identity key " - "type: %s", strerror(-rc)); - return rc; - } - - switch (pkey_type) { - case EVP_PKEY_EC: - rc = cca_get_ecc_pub_key_as_pkey(key_blob, - key_blob_size, pkey, verbose); - break; - case EVP_PKEY_RSA: - case EVP_PKEY_RSA_PSS: - rc = cca_get_rsa_pub_key_as_pkey(key_blob, - key_blob_size, rsa_pss ? - EVP_PKEY_RSA_PSS : pkey_type, - pkey, verbose); - break; - default: - pr_verbose(verbose, "Invalid identity key type: %d", - pkey_type); - return -EIO; - } - - if (rc != 0) - return rc; - break; - default: - pr_verbose(verbose, "Invalid ext lib type: %d", ext_lib->type); - return -EINVAL; - } - - return 0; -} - -/** - * Setup a signing context for the specified key, digest_nid, and RSA-PSS - * parameters. - */ -static int _ekmf_setup_sign_context(const unsigned char *key_blob, - size_t key_blob_size, EVP_PKEY *pkey, - int digest_nid, - struct ekmf_rsa_pss_params *rsa_pss_params, - EVP_MD_CTX **md_ctx, - EVP_PKEY_CTX **pkey_ctx, - struct private_data *private, - bool verbose) -{ - struct sk_pkey_sign_func sign_func; - EVP_PKEY_CTX *pctx = NULL; - const EVP_MD *md = NULL; - int rc, default_nid; - EVP_MD_CTX *ctx; - - rc = setup_secure_key_pkey_method(EVP_PKEY_id(pkey)); - if (rc != 0) { - pr_verbose(verbose, "Failed to setup secure key PKEY method"); - return rc; - } - - ctx = EVP_MD_CTX_new(); - if (ctx == NULL) { - pr_verbose(verbose, "Failed to allocate the digest context"); - rc = -ENOMEM; - goto out; - } - - if (digest_nid != 0) { - md = EVP_get_digestbynid(digest_nid); - if (md == NULL) { - pr_verbose(verbose, "Requested digest not supported"); - rc = -ENOTSUP; - goto out; - } - - if (EVP_PKEY_get_default_digest_nid(pkey, &default_nid) == 2 && - default_nid == 0) { - pr_verbose(verbose, "The signing algorithm requires " - "there to be no digest"); - md = NULL; - } - } - - rc = EVP_DigestSignInit(ctx, &pctx, md, NULL, pkey); - if (rc != 1) { - pr_verbose(verbose, "Failed to initialize the signing " - "operation"); - rc = -EIO; - goto out; - } - - sign_func.rsa_sign = _ekmf_rsa_sign; - sign_func.rsa_pss_sign = _ekmf_rsa_pss_sign; - sign_func.ecdsa_sign = _ekmf_ecdsa_sign; - - rc = setup_secure_key_pkey_context(pctx, key_blob, key_blob_size, - &sign_func, private); - if (rc != 0) { - pr_verbose(verbose, "Failed to setup the secure key PKEY " - "context: %s", strerror(-rc)); - goto out; - } - - if (EVP_PKEY_id(pkey) == EVP_PKEY_RSA_PSS && rsa_pss_params != NULL) { - rc = setup_rsa_pss_pkey_context(pctx, rsa_pss_params); - if (rc != 0) { - pr_verbose(verbose, "Failed to setup RSA-PSS context"); - goto out; - } - } - - *md_ctx = ctx; - *pkey_ctx = pctx; - -out: - if (rc != 0) { - cleanup_secure_key_pkey_method(EVP_PKEY_id(pkey)); - if (ctx != NULL) - EVP_MD_CTX_free(ctx); - } - return rc; -} - /** * Generate a certificate signing request using the secure identity key (field * identity_secure_key in config structure) with the specified subject name, @@ -5215,15 +5053,10 @@ int ekmf_generate_csr(const struct ekmf_config *config, const char *csr_pem_filename, bool new_hdr, const struct ekmf_ext_lib *ext_lib, bool verbose) { - const STACK_OF(X509_EXTENSION) *cert_exts = NULL; unsigned char key_blob[MAX_KEY_BLOB_SIZE]; size_t key_blob_size = sizeof(key_blob); - X509_NAME *subject_name = NULL; - EVP_PKEY_CTX *pkey_ctx = NULL; - struct private_data private; - EVP_MD_CTX *md_ctx = NULL; - bool pkey_meth = false; - EVP_PKEY *pkey = NULL; + struct sk_rsa_pss_params pss_params; + struct ext_lib_info ext_lib_info; X509_REQ *req = NULL; X509 *cert = NULL; int rc; @@ -5238,6 +5071,15 @@ int ekmf_generate_csr(const struct ekmf_config *config, if (num_extensions != 0 && extensions == NULL) return -EINVAL; + _ekmf_copy_ext_lib(ext_lib, &ext_lib_info); + + rc = SK_OPENSSL_init(verbose); + if (rc != 0) { + pr_verbose(verbose, "Failed to initialize secure key support: " + "%s", strerror(-rc)); + return rc; + } + rc = read_key_blob(config->identity_secure_key, key_blob, &key_blob_size); if (rc != 0) { @@ -5247,30 +5089,6 @@ int ekmf_generate_csr(const struct ekmf_config *config, goto out; } - rc = _ekmf_get_pub_key_as_pkey(key_blob, key_blob_size, &pkey, - rsa_pss_params != NULL, ext_lib, - verbose); - if (rc != 0) { - pr_verbose(verbose, "Failed to get identity key as PKEY from " - "file '%s': %s", config->identity_secure_key, - strerror(-rc)); - goto out; - } - - req = X509_REQ_new(); - if (req == NULL) { - pr_verbose(verbose, "X509_REQ_new failed"); - rc = -ENOMEM; - goto out; - } - - rc = X509_REQ_set_version(req, 0L); - if (rc != 1) { - pr_verbose(verbose, "X509_REQ_set_version failed: rc: %d", rc); - rc = -EIO; - goto out; - } - if (renew_cert_filename != NULL) { rc = read_x509_certificate(renew_cert_filename, &cert); if (rc != 0) { @@ -5279,63 +5097,20 @@ int ekmf_generate_csr(const struct ekmf_config *config, strerror(-rc)); goto out; } - - subject_name = X509_NAME_dup(X509_get_subject_name(cert)); - cert_exts = X509_get0_extensions(cert); } - if (subject_rdns != NULL && num_subject_rdns > 0) { - rc = build_subject_name(&subject_name, subject_rdns, - num_subject_rdns, subject_utf8); - if (rc != 0) { - pr_verbose(verbose, "Failed to parse the subject name " - "RDSn: %s", strerror(-rc)); - goto out; - } - } - if (subject_name == NULL) { - rc = -EINVAL; - pr_verbose(verbose, "Subject name can not be empty"); - goto out; - } + _ekmf_copy_pss_params(rsa_pss_params, &pss_params); - rc = X509_REQ_set_subject_name(req, subject_name); - if (rc != 1) { - rc = -EIO; - pr_verbose(verbose, "Failed to set subject name into request"); - goto out; - } - - rc = build_certificate_extensions(NULL, req, extensions, - num_extensions, cert_exts); + rc = SK_OPENSSL_generate_csr(key_blob, key_blob_size, + subject_rdns, num_subject_rdns, + subject_utf8, cert, + extensions, num_extensions, + digest_nid, &pss_params, &req, + &ext_lib_info.ext_lib, verbose); if (rc != 0) { - pr_verbose(verbose, "Failed to parse the extensions: " - "%s", strerror(-rc)); - goto out; - } - - rc = X509_REQ_set_pubkey(req, pkey); - if (rc != 1) { - pr_verbose(verbose, "Failed to set the public key"); - rc = -EIO; - goto out; - } - - private.ext_lib = ext_lib; - private.verbose = verbose; - - rc = _ekmf_setup_sign_context(key_blob, key_blob_size, pkey, digest_nid, - rsa_pss_params, &md_ctx, &pkey_ctx, - &private, verbose); - if (rc != 0) - goto out; - pkey_meth = true; - - rc = X509_REQ_sign_ctx(req, md_ctx); - if (rc <= 0) { - pr_verbose(verbose, "Failed to perform the signing operation"); - rc = -EIO; + pr_verbose(verbose, "SK_OPENSSL_generate_csr failed " + "'%s': %s", csr_pem_filename, strerror(-rc)); goto out; } @@ -5346,24 +5121,15 @@ int ekmf_generate_csr(const struct ekmf_config *config, goto out; } - if (verbose) { - pr_verbose(verbose, "Certificate Signing Request created:"); - X509_REQ_print_fp(stderr, req); - } + pr_verbose(verbose, "Certificate Signing Request created successfully " + "into '%s'", csr_pem_filename); out: - if (md_ctx != NULL) - EVP_MD_CTX_free(md_ctx); - if (pkey_meth) - cleanup_secure_key_pkey_method(EVP_PKEY_id(pkey)); - if (subject_name != NULL) - X509_NAME_free(subject_name); if (cert != NULL) X509_free(cert); if (req != NULL) X509_REQ_free(req); - if (pkey != NULL) - EVP_PKEY_free(pkey); + SK_OPENSSL_term(); return rc; } @@ -5433,15 +5199,10 @@ int ekmf_generate_ss_cert(const struct ekmf_config *config, const char *cert_pem_filename, const struct ekmf_ext_lib *ext_lib, bool verbose) { - const STACK_OF(X509_EXTENSION) *cert_exts = NULL; unsigned char key_blob[MAX_KEY_BLOB_SIZE]; size_t key_blob_size = sizeof(key_blob); - X509_NAME *subject_name = NULL; - EVP_PKEY_CTX *pkey_ctx = NULL; - struct private_data private; - EVP_MD_CTX *md_ctx = NULL; - bool pkey_meth = false; - EVP_PKEY *pkey = NULL; + struct sk_rsa_pss_params pss_params; + struct ext_lib_info ext_lib_info; X509 *rcert = NULL; X509 *cert = NULL; int rc; @@ -5456,6 +5217,15 @@ int ekmf_generate_ss_cert(const struct ekmf_config *config, if (num_extensions != 0 && extensions == NULL) return -EINVAL; + _ekmf_copy_ext_lib(ext_lib, &ext_lib_info); + + rc = SK_OPENSSL_init(verbose); + if (rc != 0) { + pr_verbose(verbose, "Failed to initialize secure key support: " + "%s", strerror(-rc)); + return rc; + } + rc = read_key_blob(config->identity_secure_key, key_blob, &key_blob_size); if (rc != 0) { @@ -5465,37 +5235,6 @@ int ekmf_generate_ss_cert(const struct ekmf_config *config, goto out; } - rc = _ekmf_get_pub_key_as_pkey(key_blob, key_blob_size, &pkey, - rsa_pss_params != NULL, ext_lib, - verbose); - if (rc != 0) { - pr_verbose(verbose, "Failed to get identity key as PKEY from " - "file '%s': %s", config->identity_secure_key, - strerror(-rc)); - goto out; - } - - cert = X509_new(); - if (cert == NULL) { - pr_verbose(verbose, "X509_new failed"); - rc = -ENOMEM; - goto out; - } - - rc = X509_set_version(cert, 2L); - if (rc != 1) { - pr_verbose(verbose, "X509_set_version failed: rc: %d", rc); - rc = -EIO; - goto out; - } - - rc = generate_x509_serial_number(cert, SERIAL_NUMBER_BIT_SIZE); - if (rc != 0) { - pr_verbose(verbose, "Failed to set the serial number: %s", - strerror(-rc)); - goto out; - } - if (renew_cert_filename != NULL) { rc = read_x509_certificate(renew_cert_filename, &rcert); if (rc != 0) { @@ -5504,83 +5243,20 @@ int ekmf_generate_ss_cert(const struct ekmf_config *config, strerror(-rc)); goto out; } - - subject_name = X509_NAME_dup(X509_get_subject_name(rcert)); - cert_exts = X509_get0_extensions(rcert); } - if (subject_rdns != NULL && num_subject_rdns > 0) { - rc = build_subject_name(&subject_name, subject_rdns, - num_subject_rdns, subject_utf8); - if (rc != 0) { - pr_verbose(verbose, "Failed to parse the subject name " - "RDSn: %s", strerror(-rc)); - goto out; - } - } + _ekmf_copy_pss_params(rsa_pss_params, &pss_params); - if (subject_name == NULL) { - rc = -EINVAL; - pr_verbose(verbose, "Subject name can not be empty"); - goto out; - } - - rc = X509_set_subject_name(cert, subject_name); - if (rc != 1) { - rc = -EIO; - pr_verbose(verbose, "Failed to set subject name into cert"); - goto out; - } - - rc = X509_set_issuer_name(cert, subject_name); - if (rc != 1) { - rc = -EIO; - pr_verbose(verbose, "Failed to set issuer name into cert"); - goto out; - } - - rc = build_certificate_extensions(cert, NULL, extensions, - num_extensions, cert_exts); + rc = SK_OPENSSL_generate_ss_cert(key_blob, key_blob_size, + subject_rdns, num_subject_rdns, + subject_utf8, rcert, + extensions, num_extensions, + validity_days, digest_nid, + &pss_params, &cert, + &ext_lib_info.ext_lib, verbose); if (rc != 0) { - pr_verbose(verbose, "Failed to parse the extensions: " - "%s", strerror(-rc)); - goto out; - } - - if (X509_gmtime_adj(X509_getm_notBefore(cert), 0) == NULL) { - rc = -EIO; - pr_verbose(verbose, "Failed to set notBefore time inti cert"); - goto out; - } - - if (X509_time_adj_ex(X509_getm_notAfter(cert), - validity_days, 0, NULL) == NULL) { - rc = -EIO; - pr_verbose(verbose, "Failed to set notAfter time into cert"); - goto out; - } - - rc = X509_set_pubkey(cert, pkey); - if (rc != 1) { - pr_verbose(verbose, "Failed to set the public key"); - rc = -EIO; - goto out; - } - - private.ext_lib = ext_lib; - private.verbose = verbose; - - rc = _ekmf_setup_sign_context(key_blob, key_blob_size, pkey, digest_nid, - rsa_pss_params, &md_ctx, &pkey_ctx, - &private, verbose); - if (rc != 0) - goto out; - pkey_meth = true; - - rc = X509_sign_ctx(cert, md_ctx); - if (rc <= 0) { - pr_verbose(verbose, "Failed to perform the signing operation"); - rc = -EIO; + pr_verbose(verbose, "SK_OPENSSL_generate_ss_cert failed " + "'%s': %s", cert_pem_filename, strerror(-rc)); goto out; } @@ -5591,24 +5267,15 @@ int ekmf_generate_ss_cert(const struct ekmf_config *config, goto out; } - if (verbose) { - pr_verbose(verbose, "Self-signed Certificate created:"); - X509_print_fp(stderr, cert); - } + pr_verbose(verbose, "Self-signed Certificate created successfully " + "into '%s'", cert_pem_filename); out: - if (md_ctx != NULL) - EVP_MD_CTX_free(md_ctx); - if (pkey_meth) - cleanup_secure_key_pkey_method(EVP_PKEY_id(pkey)); - if (subject_name != NULL) - X509_NAME_free(subject_name); if (cert != NULL) X509_free(cert); if (rcert != NULL) X509_free(rcert); - if (pkey != NULL) - EVP_PKEY_free(pkey); + SK_OPENSSL_term(); return rc; } diff --git a/libekmfweb/utilities.c b/libekmfweb/utilities.c index d0f93678..766e833c 100644 --- a/libekmfweb/utilities.c +++ b/libekmfweb/utilities.c @@ -23,6 +23,9 @@ #include "lib/zt_common.h" +#include "libseckey/sk_openssl.h" +#include "libseckey/sk_utilities.h" + #include "utilities.h" #ifndef JSON_C_TO_STRING_NOSLASHESCAPE @@ -397,6 +400,7 @@ int create_json_web_signature(const char *algorithm, bool b64, const char *kid, bool detached_payload, EVP_MD_CTX *md_ctx, char **jws) { + const struct sk_ec_curve_info *curve_info; unsigned char *signature = NULL; json_object *header_obj = NULL; json_object *crit_obj = NULL; @@ -531,8 +535,13 @@ int create_json_web_signature(const char *algorithm, bool b64, const char *kid, switch (EVP_PKEY_id(pkey)) { case EVP_PKEY_EC: - prime_len = ecc_get_curve_prime_length(EC_GROUP_get_curve_name( - EC_KEY_get0_group(EVP_PKEY_get0_EC_KEY(pkey)))); + curve_info = SK_UTIL_ec_get_curve_info( + SK_OPENSSL_get_curve_from_ec_pkey(pkey)); + if (curve_info == NULL) { + rc = -EINVAL; + goto out; + } + prime_len = curve_info->prime_len; p = signature; if (d2i_ECDSA_SIG(&ec_sig, &p, signature_len) == NULL) { @@ -634,13 +643,12 @@ int verify_json_web_signature(const char *jws, const unsigned char *payload, unsigned char *signature = NULL, *der = NULL, *sig = NULL; json_object *header_obj = NULL, *b64_obj = NULL; int der_len, rc, curve_nid = 0, digest_nid = 0; - struct ekmf_rsa_pss_params rsa_pss_params; + struct sk_rsa_pss_params rsa_pss_params; bool b64 = true, rsa_pss = false; EVP_MD_CTX *md_ctx = NULL; EVP_PKEY_CTX *pctx = NULL; ECDSA_SIG *ec_sig = NULL; char *payload_b64 = NULL; - const EVP_MD *md = NULL; BIGNUM *bn_r = NULL; BIGNUM *bn_s = NULL; const char *alg; @@ -670,8 +678,7 @@ int verify_json_web_signature(const char *jws, const unsigned char *payload, hdr_pld_len = ch - jws; if (EVP_PKEY_id(pkey) == EVP_PKEY_EC) { - curve_nid = EC_GROUP_get_curve_name(EC_KEY_get0_group( - EVP_PKEY_get0_EC_KEY(pkey))); + curve_nid = SK_OPENSSL_get_curve_from_ec_pkey(pkey); } alg = json_get_string(header_obj, "alg"); @@ -735,32 +742,18 @@ int verify_json_web_signature(const char *jws, const unsigned char *payload, goto out; } - md = EVP_get_digestbynid(digest_nid); - if (md == NULL) { - rc = -ENOTSUP; - goto out; - } - - md_ctx = EVP_MD_CTX_new(); - if (md_ctx == NULL) { - rc = -ENOMEM; - goto out; - } - - rc = EVP_DigestVerifyInit(md_ctx, &pctx, md, NULL, pkey); - if (rc != 1) { - rc = -EIO; - goto out; - } - + memset(&rsa_pss_params, 0, sizeof(rsa_pss_params)); if (rsa_pss) { rsa_pss_params.mgf_digest_nid = digest_nid; rsa_pss_params.salt_len = RSA_PSS_SALTLEN_DIGEST; - rc = setup_rsa_pss_pkey_context(pctx, &rsa_pss_params); - if (rc != 0) - goto out; } + rc = SK_OPENSSL_setup_sign_context(pkey, true, digest_nid, + &rsa_pss_params, + &md_ctx, &pctx, false); + if (rc != 0) + goto out; + switch (EVP_PKEY_id(pkey)) { case EVP_PKEY_EC: ec_sig = ECDSA_SIG_new(); @@ -1771,431 +1764,6 @@ char *get_http_header_value(const struct curl_slist *headers, const char *name) return NULL; } -struct ecc_curve_info { - int curve_nid; - enum { - ECC_TYPE_PRIME = 0, - ECC_TYPE_BRAINPOOL = 1, - } type; - size_t prime_bits; - size_t prime_len; - const char *curve_id; -}; - -static const struct ecc_curve_info ecc_curve_list[] = { - { .curve_nid = NID_X9_62_prime192v1, .type = ECC_TYPE_PRIME, - .prime_bits = 192, .prime_len = 24, .curve_id = "P-192" }, - { .curve_nid = NID_secp224r1, .type = ECC_TYPE_PRIME, - .prime_bits = 224, .prime_len = 28, .curve_id = "P-224" }, - { .curve_nid = NID_X9_62_prime256v1, .type = ECC_TYPE_PRIME, - .prime_bits = 256, .prime_len = 32, .curve_id = "P-256" }, - { .curve_nid = NID_secp384r1, .type = ECC_TYPE_PRIME, - .prime_bits = 384, .prime_len = 48, .curve_id = "P-384" }, - { .curve_nid = NID_secp521r1, .type = ECC_TYPE_PRIME, - .prime_bits = 521, .prime_len = 66, .curve_id = "P-521" }, - { .curve_nid = NID_brainpoolP160r1, .type = ECC_TYPE_BRAINPOOL, - .prime_bits = 160, .prime_len = 20, .curve_id = "brainpoolP160r1" }, - { .curve_nid = NID_brainpoolP192r1, .type = ECC_TYPE_BRAINPOOL, - .prime_bits = 192, .prime_len = 24, .curve_id = "brainpoolP192r1" }, - { .curve_nid = NID_brainpoolP224r1, .type = ECC_TYPE_BRAINPOOL, - .prime_bits = 224, .prime_len = 28, .curve_id = "brainpoolP224r1" }, - { .curve_nid = NID_brainpoolP256r1, .type = ECC_TYPE_BRAINPOOL, - .prime_bits = 256, .prime_len = 32, .curve_id = "brainpoolP256r1" }, - { .curve_nid = NID_brainpoolP320r1, .type = ECC_TYPE_BRAINPOOL, - .prime_bits = 320, .prime_len = 40, .curve_id = "brainpoolP320r1" }, - { .curve_nid = NID_brainpoolP384r1, .type = ECC_TYPE_BRAINPOOL, - .prime_bits = 384, .prime_len = 48, .curve_id = "brainpoolP384r1" }, - { .curve_nid = NID_brainpoolP512r1, .type = ECC_TYPE_BRAINPOOL, - .prime_bits = 512, .prime_len = 64, .curve_id = "brainpoolP512r1" }, -}; - -static const int ecc_curve_num = - sizeof(ecc_curve_list) / sizeof(struct ecc_curve_info); - -/** - * Returns the prime bit length of the specified curve, or 0 if the curve - * is not known. - */ -size_t ecc_get_curve_prime_bits(int curve_nid) -{ - int i; - - for (i = 0; i < ecc_curve_num; i++) { - if (ecc_curve_list[i].curve_nid == curve_nid) - return ecc_curve_list[i].prime_bits; - } - return 0; -} - -/** - * Returns the prime length in bytes of the specified curve, or 0 if the curve - * is not known. - */ -size_t ecc_get_curve_prime_length(int curve_nid) -{ - int i; - - for (i = 0; i < ecc_curve_num; i++) { - if (ecc_curve_list[i].curve_nid == curve_nid) - return ecc_curve_list[i].prime_len; - } - return 0; -} - -/** - * Returns the textual curve ID of the specified curve, or NULL if the curve - * is not known. - */ -const char *ecc_get_curve_id(int curve_nid) -{ - int i; - - for (i = 0; i < ecc_curve_num; i++) { - if (ecc_curve_list[i].curve_nid == curve_nid) - return ecc_curve_list[i].curve_id; - } - return NULL; -} - -/** - * Returns true if the specified curve is a Prime curve, false if not, or if - * the curve is not known. - */ -bool ecc_is_prime_curve(int curve_nid) -{ - int i; - - for (i = 0; i < ecc_curve_num; i++) { - if (ecc_curve_list[i].curve_nid == curve_nid) - return ecc_curve_list[i].type == ECC_TYPE_PRIME; - } - return false; -} - -/** - * Returns true if the specified curve is a Brainpool curve, false if not, or if - * the curve is not known. - */ -bool ecc_is_brainpool_curve(int curve_nid) -{ - int i; - - for (i = 0; i < ecc_curve_num; i++) { - if (ecc_curve_list[i].curve_nid == curve_nid) - return ecc_curve_list[i].type == ECC_TYPE_BRAINPOOL; - } - return false; -} - -/** - * Returns the nid of the curve of the specified curve ID, or 0 if the curve - * is not known. - */ -int ecc_get_curve_by_id(const char *curve_id) -{ - int i; - - for (i = 0; i < ecc_curve_num; i++) { - if (strcmp(ecc_curve_list[i].curve_id, curve_id) == 0) - return ecc_curve_list[i].curve_nid; - } - return 0; -} - -/** - * Returns the nid of the Prime curve by its specified prime bit size, or 0 - * if the curve is not knwon. - */ -int ecc_get_prime_curve_by_prime_bits(size_t prime_bits) -{ - int i; - - for (i = 0; i < ecc_curve_num; i++) { - if (ecc_curve_list[i].type == ECC_TYPE_PRIME && - ecc_curve_list[i].prime_bits == prime_bits) - return ecc_curve_list[i].curve_nid; - } - return 0; -} - -/** - * Returns the nid of the Brainpool curve by its specified prime bit size, or 0 - * if the curve is not knwon. - */ -int ecc_get_brainpool_curve_by_prime_bits(size_t prime_bits) -{ - int i; - - for (i = 0; i < ecc_curve_num; i++) { - if (ecc_curve_list[i].type == ECC_TYPE_BRAINPOOL && - ecc_curve_list[i].prime_bits == prime_bits) - return ecc_curve_list[i].curve_nid; - } - return 0; -} - -/** - * Calculates the y coordinate of a point on an EC curve using the x coordinate - * and the y bit. x and y must be supplied by the caller with prime_len bytes. - * On return y contains the calculated y coordinate. - * - * @param nid the OpenSSL nid of the ECC curve used - * @param prime_len the length of the prime in bytes. This is also the - * length of the x and y coordinates. - * @param x the x coordinate as big endian binary number in - * prime_len size - * @param y_bit the y-bit to identify which of the two possible - * values for y should be used - * @param y buffer to store the y coordinate as big endian - * binary number in prime_len size. - * @returns zero for success, a negative errno in case of an error: - * -EINVAL: a function parameter is invalid - * -ENOMEM: failed to allocate memory - * -EIO: OpenSSL failed to calculate the y coordinate - * -ENOENT: OpenSSL does not know/support the curve (nid) - */ -int ecc_calculate_y_coordinate(int nid, size_t prime_len, - const unsigned char *x, int y_bit, - unsigned char *y) -{ - EC_GROUP *group = NULL; - EC_POINT *point = NULL; - BIGNUM *bn_x = NULL; - BIGNUM *bn_y = NULL; - BN_CTX *ctx = NULL; - int rc = 0; - - if (x == NULL || y == NULL) - return -EINVAL; - - bn_x = BN_bin2bn(x, prime_len, NULL); - if (bn_x == NULL) { - rc = -EIO; - goto out; - } - - group = EC_GROUP_new_by_curve_name(nid); - if (group == NULL) { - rc = -ENOENT; - goto out; - } - - point = EC_POINT_new(group); - if (point == NULL) { - rc = -EIO; - goto out; - } - - bn_y = BN_new(); - if (bn_y == NULL) { - rc = -ENOMEM; - goto out; - } - - ctx = BN_CTX_new(); - if (ctx == NULL) { - rc = -ENOMEM; - goto out; - } - - if (!EC_POINT_set_compressed_coordinates(group, point, bn_x, - y_bit, ctx)) { - rc = -EIO; - goto out; - } - - if (!EC_POINT_is_on_curve(group, point, ctx)) { - rc = -EIO; - goto out; - } - - if (!EC_POINT_get_affine_coordinates(group, point, bn_x, bn_y, - ctx)) { - rc = -EIO; - goto out; - } - - BN_bn2binpad(bn_y, y, prime_len); - -out: - if (ctx != NULL) - BN_CTX_free(ctx); - if (point != NULL) - EC_POINT_free(point); - if (group != NULL) - EC_GROUP_free(group); - if (bn_x != NULL) - BN_free(bn_x); - if (bn_y != NULL) - BN_free(bn_y); - - return rc; -} - -/** - * Converts an ECC public key given by the nid and the x and y coordinates into - * an OpenSSL PKEY. - * - * @param nid the OpenSSL nid of the ECC curve used - * @param prime_len the length of the prime in bytes. This is also the - * length of the x and y coordinates. - * @param x the x coordinate as big endian binary number in - * prime_len size - * @param y the y coordinate as big endian binary number in - * prime_len size - * @param pkey On return: A PKEY containing the ECC public key. - * - * @returns zero for success, a negative errno in case of an error: - * -EINVAL: a function parameter is invalid - * -ENOMEM: failed to allocate memory - * -EIO: OpenSSL failed to generate the PKEY - * -ENOENT: OpenSSL does not know/support the curve (nid) - */ -int ecc_pub_key_as_pkey(int nid, size_t prime_len, const unsigned char *x, - const unsigned char *y, EVP_PKEY **pkey) -{ - BIGNUM *bn_x = NULL, *bn_y = NULL; - EC_GROUP *group = NULL; - EC_KEY *ec = NULL; - int rc; - - if (pkey == NULL || x == NULL || y == NULL) - return -EINVAL; - - *pkey = NULL; - - bn_x = BN_bin2bn(x, prime_len, NULL); - bn_y = BN_bin2bn(y, prime_len, NULL); - if (bn_x == NULL || bn_y == NULL) { - rc = -ENOMEM; - goto out; - } - - group = EC_GROUP_new_by_curve_name(nid); - if (group == NULL) { - rc = -ENOENT; - goto out; - } - - ec = EC_KEY_new(); - if (ec == NULL) { - rc = -ENOMEM; - goto out; - } - - rc = EC_KEY_set_group(ec, group); - if (rc != 1) { - rc = -EIO; - goto out; - } - - rc = EC_KEY_set_public_key_affine_coordinates(ec, bn_x, bn_y); - if (rc != 1) { - rc = -EIO; - goto out; - } - - *pkey = EVP_PKEY_new(); - if (*pkey == NULL) { - rc = -ENOMEM; - goto out; - } - - rc = EVP_PKEY_assign_EC_KEY(*pkey, ec); - if (rc != 1) { - rc = -EIO; - goto out; - } - - rc = 0; -out: - if (bn_x != NULL) - BN_free(bn_x); - if (bn_y != NULL) - BN_free(bn_y); - if (group != NULL) - EC_GROUP_free(group); - if (rc != 0 && *pkey != NULL) { - EVP_PKEY_free(*pkey); - *pkey = NULL; - } - return rc; -} - -/** - * Converts an RSA public key given by the modulus and public exponent into - * an OpenSSL PKEY. - * - * @param modulus the modulus as big endian number - * @param modulus_length the length of the modulus in bytes - * @param pub_exp the public exponent as big endian number - * @param pub_exp_length the length of the public exponent in bytes - * @param pkey_type the PKEY type (EVP_PKEY_RSA or EVP_PKEY_RSA_PSS) - * @param pkey On return: A PKEY containing the RSA public key. - * - * @returns zero for success, a negative errno in case of an error: - * -EINVAL: a function parameter is invalid - * -ENOMEM: failed to allocate memory - * -EIO: OpenSSL failed to generate the PKEY - */ -int rsa_pub_key_as_pkey(const unsigned char *modulus, size_t modulus_length, - const unsigned char *pub_exp, size_t pub_exp_length, - int pkey_type, EVP_PKEY **pkey) -{ - BIGNUM *bn_modulus = NULL, *bn_pub_exp = NULL; - RSA *rsa; - int rc; - - if (pkey == NULL || modulus == NULL || pub_exp == NULL) - return -EINVAL; - - if (pkey_type != EVP_PKEY_RSA && pkey_type != EVP_PKEY_RSA_PSS) - return -EINVAL; - - *pkey = NULL; - - bn_modulus = BN_bin2bn(modulus, modulus_length, NULL); - bn_pub_exp = BN_bin2bn(pub_exp, pub_exp_length, NULL); - if (bn_modulus == NULL || bn_pub_exp == NULL) { - rc = -ENOMEM; - goto out; - } - - rsa = RSA_new(); - if (rsa == NULL) { - rc = -ENOMEM; - goto out; - } - - rc = RSA_set0_key(rsa, bn_modulus, bn_pub_exp, NULL); - if (rc != 1) { - rc = -EIO; - goto out; - } - - *pkey = EVP_PKEY_new(); - if (*pkey == NULL) { - rc = -ENOMEM; - goto out; - } - - rc = EVP_PKEY_assign(*pkey, pkey_type, rsa); - if (rc != 1) { - rc = -EIO; - goto out; - } - - rc = 0; - -out: - if (rc != 0 && bn_modulus != NULL) - BN_free(bn_modulus); - if (rc != 0 && bn_pub_exp != NULL) - BN_free(bn_pub_exp); - - return rc; -} - /** * Converts a JSON Web Key (ECC or RSA) into a OpenSSL PKEY * @@ -2209,6 +1777,8 @@ out: int json_web_key_as_pkey(json_object *jwk, int pkey_type, EVP_PKEY **pkey) { unsigned char *x = NULL, *y = NULL, *n = NULL, *e = NULL; + const struct sk_ec_curve_info *curve_info; + struct sk_pub_key_info pub_key = { 0 }; size_t prime_len, len, n_len, e_len; const char *kty, *crv; int nid, rc = 0; @@ -2231,13 +1801,18 @@ int json_web_key_as_pkey(json_object *jwk, int pkey_type, EVP_PKEY **pkey) goto out; } - nid = ecc_get_curve_by_id(crv); - if (nid == 0) { + nid = EC_curve_nist2nid(crv); + if (nid == NID_undef) { rc = -EIO; goto out; } - prime_len = ecc_get_curve_prime_length(nid); + curve_info = SK_UTIL_ec_get_curve_info(nid); + if (curve_info == NULL) { + rc = -EIO; + goto out; + } + prime_len = curve_info->prime_len; if (prime_len == 0) { rc = -EIO; goto out; @@ -2270,9 +1845,11 @@ int json_web_key_as_pkey(json_object *jwk, int pkey_type, EVP_PKEY **pkey) goto out; } - rc = ecc_pub_key_as_pkey(nid, prime_len, x, y, pkey); - if (rc != 0) - goto out; + pub_key.type = SK_KEY_TYPE_EC; + pub_key.ec.curve_nid = nid; + pub_key.ec.prime_len = prime_len; + pub_key.ec.x = x; + pub_key.ec.y = y; } else if (strcmp(kty, "RSA") == 0) { n_len = 0; rc = json_object_get_base64url(jwk, "n", NULL, &n_len); @@ -2304,14 +1881,21 @@ int json_web_key_as_pkey(json_object *jwk, int pkey_type, EVP_PKEY **pkey) if (rc != 0) goto out; - rc = rsa_pub_key_as_pkey(n, n_len, e, e_len, pkey_type, pkey); - if (rc != 0) - goto out; - + pub_key.type = SK_KEY_TYPE_RSA; + pub_key.rsa.modulus = n; + pub_key.rsa.modulus_len = n_len; + pub_key.rsa.pub_exp = e; + pub_key.rsa.pub_exp_len = e_len; } else { return -EIO; } + rc = SK_OPENSSL_get_pkey(NULL, 0, &pub_key, + pkey_type == EVP_PKEY_RSA_PSS, NULL, NULL, + pkey, false); + if (rc != 0) + goto out; + out: if (x != NULL) free(x); @@ -2583,521 +2167,6 @@ int write_public_key(const char *pem_filename, EVP_PKEY *pkey) return 0; } -/* Secure key PKEY context control */ -#define EVP_PKEY_CTRL_SK_KEY_BLOB 0x10000001 -#define EVP_PKEY_CTRL_SK_SIGN_FUNCTIONS 0x10000002 -#define EVP_PKEY_CTRL_SK_PRIVATE_DATA 0x10000003 - -/* Secure key PKEY context data */ -struct sk_pkey_ctx { - rsa_sign_t rsa_sign; - rsa_pss_sign_t rsa_pss_sign; - ecdsa_sign_t ecdsa_sign; - - unsigned char *key_blob; - size_t key_blob_length; - - const EVP_MD *md; - int rsa_padding; - int rsa_pss_saltlen; - const EVP_MD *rsa_pss_mgfmd; - - void *private; -}; - -/** - * Initialize an secure key PKEY context - * - * @param ctx the PKEY context to initialize - * - * @returns 1 for success, 0 in case of an error - */ -static int sk_pkey_meth_init(EVP_PKEY_CTX *ctx) -{ - struct sk_pkey_ctx *sk_ctx; - EVP_PKEY *pkey; - - pkey = EVP_PKEY_CTX_get0_pkey(ctx); - if (pkey == NULL) - return 0; - - sk_ctx = OPENSSL_zalloc(sizeof(struct sk_pkey_ctx)); - if (sk_ctx == NULL) - return 0; - - if (EVP_PKEY_id(pkey) == EVP_PKEY_RSA_PSS) { - sk_ctx->rsa_pss_saltlen = RSA_PSS_SALTLEN_AUTO; - sk_ctx->rsa_padding = RSA_PKCS1_PSS_PADDING; - } - if (EVP_PKEY_id(pkey) == EVP_PKEY_RSA) - sk_ctx->rsa_padding = RSA_PKCS1_PADDING; - - EVP_PKEY_CTX_set_data(ctx, sk_ctx); - - return 1; -} - -/** - * Cleanup an secure key PKEY context - * - * @param ctx the PKEY context to to clean - */ -static void sk_pkey_meth_cleanup(EVP_PKEY_CTX *ctx) -{ - struct sk_pkey_ctx *sk_ctx; - - sk_ctx = EVP_PKEY_CTX_get_data(ctx); - if (sk_ctx != NULL) { - OPENSSL_free(sk_ctx); - EVP_PKEY_CTX_set_data(ctx, NULL); - } -} - -/** - * Copy an secure key PKEY context - * - * @param dst the source PKEY context to copy from - * @param src the destinationPKEY context to copy to - * - * @returns 1 for success, 0 in case of an error - */ -static int sk_pkey_meth_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src) -{ - struct sk_pkey_ctx *sk_ctx_src, *sk_ctx_dst; - - if (sk_pkey_meth_init(dst) != 1) - return 0; - - sk_ctx_src = EVP_PKEY_CTX_get_data(src); - if (sk_ctx_src == NULL) - return 0; - - sk_ctx_dst = EVP_PKEY_CTX_get_data(dst); - if (sk_ctx_dst == NULL) - return 0; - - sk_ctx_dst->rsa_sign = sk_ctx_src->rsa_sign; - sk_ctx_dst->rsa_pss_sign = sk_ctx_src->rsa_pss_sign; - sk_ctx_dst->ecdsa_sign = sk_ctx_src->ecdsa_sign; - sk_ctx_dst->key_blob = sk_ctx_src->key_blob; - sk_ctx_dst->key_blob_length = sk_ctx_src->key_blob_length; - sk_ctx_dst->md = sk_ctx_src->md; - sk_ctx_dst->rsa_pss_saltlen = sk_ctx_src->rsa_pss_saltlen; - sk_ctx_dst->rsa_padding = sk_ctx_src->rsa_padding; - sk_ctx_dst->rsa_pss_mgfmd = sk_ctx_src->rsa_pss_mgfmd; - sk_ctx_dst->private = sk_ctx_src->private; - - return 1; -} - -/** - * Perform a sign operation with the secure key PKEY context. - * The data to be signed has already been hashed. - * - * The key to perform the sign operation with is available in the PKEY context. - * For this secure key case, the pkey as well as the secure key blob is - * available. - * - * @param ctx the PKEY context to sign with - * @param sig the buffer to store the signature - * @param siglen On input: the size of the signature buffer - * On return: the size of the signature - * @param tbs the data to be signed - * @param tbslen the size of the data to be signed - * - * @returns 1 for success, 0 in case of an error - */ -static int sk_pkey_meth_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, - size_t *siglen, const unsigned char *tbs, - size_t tbslen) -{ - int rc, md_type, mgf_md_type, saltlen, max_saltlen, hlen; - struct sk_pkey_ctx *sk_ctx; - EVP_PKEY *pkey; - - sk_ctx = EVP_PKEY_CTX_get_data(ctx); - if (sk_ctx == NULL) - return 0; - - pkey = EVP_PKEY_CTX_get0_pkey(ctx); - if (pkey == NULL) - return 0; - - md_type = sk_ctx->md != NULL ? EVP_MD_type(sk_ctx->md) : NID_sha1; - - switch (EVP_PKEY_id(pkey)) { - case EVP_PKEY_RSA: - if (sk_ctx->rsa_sign == NULL) - return 0; - rc = sk_ctx->rsa_sign(sk_ctx->key_blob, sk_ctx->key_blob_length, - sig, siglen, tbs, tbslen, - sk_ctx->rsa_padding, md_type, - sk_ctx->private); - break; - - case EVP_PKEY_RSA_PSS: - if (sk_ctx->rsa_pss_sign == NULL) - return 0; - - if (sk_ctx->md != NULL) - hlen = EVP_MD_size(sk_ctx->md); - else - hlen = SHA_DIGEST_LENGTH; - - if (sk_ctx->rsa_pss_mgfmd != NULL) { - mgf_md_type = EVP_MD_type(sk_ctx->rsa_pss_mgfmd); - hlen = EVP_MD_size(sk_ctx->rsa_pss_mgfmd); - } else { - mgf_md_type = md_type; - } - - /* - * We should be using RSA_bits(EVP_PKEY_get0_RSA(pkey)) here, - * but EVP_PKEY_get0_RSA(pkey) does not work with PKEY/type - * EVP_PKEY_RSA_PSS on older OpenSSL versions, so we fall back - * on EVP_PKEY_bits in this case. - */ - max_saltlen = (EVP_PKEY_get0_RSA(pkey) != NULL ? - RSA_bits(EVP_PKEY_get0_RSA(pkey)) : - EVP_PKEY_bits(pkey)) / 8 - hlen - 2; - - switch (sk_ctx->rsa_pss_saltlen) { - case RSA_PSS_SALTLEN_DIGEST: - saltlen = hlen; - break; - case RSA_PSS_SALTLEN_AUTO: - case RSA_PSS_SALTLEN_MAX: - saltlen = max_saltlen; - break; - default: - saltlen = sk_ctx->rsa_pss_saltlen; - break; - } - - if (saltlen > max_saltlen || saltlen < 0) - return 0; - - rc = sk_ctx->rsa_pss_sign(sk_ctx->key_blob, - sk_ctx->key_blob_length, - sig, siglen, tbs, tbslen, - md_type, mgf_md_type, saltlen, - sk_ctx->private); - break; - - case EVP_PKEY_EC: - if (sk_ctx->ecdsa_sign == NULL) - return 0; - - rc = sk_ctx->ecdsa_sign(sk_ctx->key_blob, - sk_ctx->key_blob_length, sig, siglen, - tbs, tbslen, md_type, sk_ctx->private); - break; - - default: - rc = -1; - } - - return rc == 0 ? 1 : 0; -} - -/** - * Control options of the secure key PKEY context - * - * Besides some standard controls, the following secure key PKEY context - * specific controls are available: - * EVP_PKEY_CTRL_SK_KEY_BLOB set the secure key blob into the context - * EVP_PKEY_CTRL_SK_SIGN_FUNCTIONS set the sign functions for the context - * EVP_PKEY_CTRL_SK_PRIVATE_DATA set the private data to the context - * - * @param ctx the PKEY context to control - * @param type the control type - * @param p1 an integer option - * @param p2 a pointer option - * - * @returns 1 for success, 0 in case of an error, -2 if the control is not - * supported by the context - */ -static int sk_pkey_meth_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) -{ - struct sk_pkey_sign_func *func; - struct sk_pkey_ctx *sk_ctx; - EVP_PKEY *pkey; - int md_type; - - sk_ctx = EVP_PKEY_CTX_get_data(ctx); - if (sk_ctx == NULL) - return 0; - - pkey = EVP_PKEY_CTX_get0_pkey(ctx); - if (pkey == NULL) - return 0; - - switch (type) { - case EVP_PKEY_CTRL_SK_KEY_BLOB: - sk_ctx->key_blob = p2; - sk_ctx->key_blob_length = p1; - break; - - case EVP_PKEY_CTRL_SK_SIGN_FUNCTIONS: - func = (struct sk_pkey_sign_func *)p2; - sk_ctx->rsa_sign = func->rsa_sign; - sk_ctx->rsa_pss_sign = func->rsa_pss_sign; - sk_ctx->ecdsa_sign = func->ecdsa_sign; - break; - - case EVP_PKEY_CTRL_SK_PRIVATE_DATA: - sk_ctx->private = p2; - break; - - case EVP_PKEY_CTRL_MD: - md_type = EVP_MD_type((const EVP_MD *)p2); - if (md_type != NID_sha1 && - md_type != NID_ecdsa_with_SHA1 && - md_type != NID_sha224 && - md_type != NID_sha256 && - md_type != NID_sha384 && - md_type != NID_sha512 && - md_type != NID_sha3_224 && - md_type != NID_sha3_256 && - md_type != NID_sha3_384 && - md_type != NID_sha3_512) - return 0; - sk_ctx->md = p2; - break; - - case EVP_PKEY_CTRL_GET_MD: - *(const EVP_MD **)p2 = sk_ctx->md; - break; - - case EVP_PKEY_CTRL_RSA_PADDING: - switch (EVP_PKEY_id(pkey)) { - case EVP_PKEY_EC: - return -2; - case EVP_PKEY_RSA: - break; - case EVP_PKEY_RSA_PSS: - if (p1 != RSA_PKCS1_PSS_PADDING) - return -2; - break; - } - sk_ctx->rsa_padding = p1; - break; - - case EVP_PKEY_CTRL_GET_RSA_PADDING: - switch (EVP_PKEY_id(pkey)) { - case EVP_PKEY_EC: - return -1; - case EVP_PKEY_RSA: - case EVP_PKEY_RSA_PSS: - *(int *)p2 = sk_ctx->rsa_padding; - break; - } - break; - - case EVP_PKEY_CTRL_RSA_PSS_SALTLEN: - if (sk_ctx->rsa_padding != RSA_PKCS1_PSS_PADDING) - return -2; - if (p1 < RSA_PSS_SALTLEN_MAX) - return -2; - if (p1 == RSA_PSS_SALTLEN_MAX) - sk_ctx->rsa_pss_saltlen = RSA_PSS_SALTLEN_MAX_SIGN; - else - sk_ctx->rsa_pss_saltlen = p1; - break; - - case EVP_PKEY_CTRL_GET_RSA_PSS_SALTLEN: - if (sk_ctx->rsa_padding != RSA_PKCS1_PSS_PADDING) - return -2; - *(int *)p2 = sk_ctx->rsa_pss_saltlen; - break; - - case EVP_PKEY_CTRL_RSA_MGF1_MD: - if (sk_ctx->rsa_padding != RSA_PKCS1_PSS_PADDING) - return -2; - sk_ctx->rsa_pss_mgfmd = p2; - break; - - case EVP_PKEY_CTRL_GET_RSA_MGF1_MD: - if (sk_ctx->rsa_padding != RSA_PKCS1_PSS_PADDING) - return -2; - *(const EVP_MD **)p2 = sk_ctx->rsa_pss_mgfmd != NULL ? - sk_ctx->rsa_pss_mgfmd : sk_ctx->md; - break; - - case EVP_PKEY_CTRL_DIGESTINIT: - case EVP_PKEY_CTRL_PEER_KEY: - case EVP_PKEY_CTRL_PKCS7_SIGN: - case EVP_PKEY_CTRL_CMS_SIGN: - break; - - default: - return -2; - } - - return 1; -} - -/** - * Sets up a secure key PKEY method to handle PKEY sign operations of the - * specified PKEY id (type) using secure key functions, instead of the default - * ones. - * - * Note: This should be done only right before the sign operation is used, and - * should be cleaned up using cleanup_secure_key_pkey_method() right after the - * sign operation is finished, to not interfere with other PKEY usage. - * - * @param pkey_id the PKEY id (type) to setup special handling - * for. Use EVP_PKEY_id() to get the id of an existing - * pkey. - * - * @returns zero for success, a negative errno in case of an error: - * -ENOMEM: failed to allocate memory - * -EIO: OpenSSL failed to setup the method - */ -int setup_secure_key_pkey_method(int pkey_id) -{ - EVP_PKEY_METHOD *pkey_meth; - - pkey_meth = EVP_PKEY_meth_new(pkey_id, 0); - if (pkey_meth == NULL) - return -ENOMEM; - - EVP_PKEY_meth_set_init(pkey_meth, sk_pkey_meth_init); - EVP_PKEY_meth_set_cleanup(pkey_meth, sk_pkey_meth_cleanup); - EVP_PKEY_meth_set_copy(pkey_meth, sk_pkey_meth_copy); - EVP_PKEY_meth_set_ctrl(pkey_meth, sk_pkey_meth_ctrl, NULL); - EVP_PKEY_meth_set_sign(pkey_meth, NULL, sk_pkey_meth_sign); - - if (EVP_PKEY_meth_add0(pkey_meth) != 1) - return -EIO; - - return 0; -} - -/** - * Cleans up the secure key PKEY method to handle PKEY sign operations of the - * specified PKEY id (type) using secure key functions. - * - * Note: Only call this function of you have previously setup the PKEY method - * using setup_secure_key_pkey_method(). - * - * @param pkey_id the PKEY id (type) to setup special handling - * for. Use EVP_PKEY_id() to get the id of an existing - * pkey. - * - * @returns zero for success, a negative errno in case of an error: - * -ENOENT: method not found - * -EIO: OpenSSL failed to cleanup the method - */ -int cleanup_secure_key_pkey_method(int pkey_id) -{ - const EVP_PKEY_METHOD *pkey_meth; - - pkey_meth = EVP_PKEY_meth_find(pkey_id); - if (pkey_meth == NULL) - return -ENOENT; - - if (EVP_PKEY_meth_remove(pkey_meth) != 1) - return -EIO; - - EVP_PKEY_meth_free((EVP_PKEY_METHOD *)pkey_meth); - - return 0; -} - -/** - * Sets up a secure key PKEY context to handle PKEY sign operations using the - * specified secure key blob, and secure key sign functions. The secure key blob - * must match the PKEY that was used to create the context with. The pkey - * contains the public key parts only, the secure key blob contains the - * private (and possibly public) key parts of the same key. - * - * Note: Only call this function of you have previously setup the PKEY method - * using setup_secure_key_pkey_method(). - * - * @param pkey_ctx the PKEY context to setup special handling for - * @param key_blob the secure key blob to sign with - * @param key_blob_len the size of the key bob in bytes - * @param sign_funcs secure key specific sign functions - * @param private a pointer passed as is to the sign functions - * - * @returns zero for success, a negative errno in case of an error: - * -EINVAL: invalid argument - * -EIO: OpenSSL failed to setup the context - */ -int setup_secure_key_pkey_context(EVP_PKEY_CTX *pkey_ctx, - const unsigned char *key_blob, - size_t key_blob_len, - struct sk_pkey_sign_func *sign_funcs, - void *private) -{ - int rc; - - if (pkey_ctx == NULL || sign_funcs == NULL) - return -EINVAL; - - rc = EVP_PKEY_CTX_ctrl(pkey_ctx, -1, -1, EVP_PKEY_CTRL_SK_KEY_BLOB, - key_blob_len, (void *)key_blob); - if (rc != 1) - return -EIO; - - rc = EVP_PKEY_CTX_ctrl(pkey_ctx, -1, -1, - EVP_PKEY_CTRL_SK_SIGN_FUNCTIONS, - 0, sign_funcs); - if (rc != 1) - return -EIO; - - rc = EVP_PKEY_CTX_ctrl(pkey_ctx, -1, -1, EVP_PKEY_CTRL_SK_PRIVATE_DATA, - 0, private); - if (rc != 1) - return -EIO; - - return 0; -} - -/** - * Sets up a PKEY context with RSA-PSS parameters. - * - * @param pkey_ctx the PKEY context to setup special handling for - * @param rsa_pss_params the RSA-PSS paramaters - * - * @returns zero for success, a negative errno in case of an error: - * -EINVAL: invalid argument - * -EIO: OpenSSL failed to setup the context - */ -int setup_rsa_pss_pkey_context(EVP_PKEY_CTX *pkey_ctx, - struct ekmf_rsa_pss_params *rsa_pss_params) -{ - const EVP_MD *mgf_md; - int rc; - - if (pkey_ctx == NULL || rsa_pss_params == NULL) - return -EINVAL; - - rc = EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, - RSA_PKCS1_PSS_PADDING); - if (rc != 1) - return -EIO; - - rc = EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, - rsa_pss_params->salt_len); - if (rc != 1) - return -EIO; - - if (rsa_pss_params->mgf_digest_nid != 0) { - mgf_md = EVP_get_digestbynid( - rsa_pss_params->mgf_digest_nid); - if (mgf_md == NULL) - return -ENOENT; - - rc = EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, mgf_md); - if (rc != 1) - return -EIO; - } - - return 0; -} - /** * Checks if an exact duplicate of the name entry is part of the name already. */ diff --git a/libekmfweb/utilities.h b/libekmfweb/utilities.h index 2f61c862..f460449b 100644 --- a/libekmfweb/utilities.h +++ b/libekmfweb/utilities.h @@ -81,26 +81,6 @@ void free_key_info(struct ekmf_key_info *key); char *get_http_header_value(const struct curl_slist *headers, const char *name); -size_t ecc_get_curve_prime_bits(int curve_nid); -size_t ecc_get_curve_prime_length(int curve_nid); -const char *ecc_get_curve_id(int curve_nid); -bool ecc_is_prime_curve(int curve_nid); -bool ecc_is_brainpool_curve(int curve_nid); -int ecc_get_curve_by_id(const char *curve_id); -int ecc_get_prime_curve_by_prime_bits(size_t prime_bits); -int ecc_get_brainpool_curve_by_prime_bits(size_t prime_bits); - -int ecc_calculate_y_coordinate(int nid, size_t prime_len, - const unsigned char *x, int y_bit, - unsigned char *y); - -int ecc_pub_key_as_pkey(int nid, size_t prime_len, const unsigned char *x, - const unsigned char *y, EVP_PKEY **pkey); - -int rsa_pub_key_as_pkey(const unsigned char *modulus, size_t modulus_length, - const unsigned char *pub_exp, size_t pub_exp_length, - int pkey_type, EVP_PKEY **pkey); - int json_web_key_as_pkey(json_object *jwk, int pkey_type, EVP_PKEY **pkey); int write_key_blob(const char *filename, unsigned char *key_blob, @@ -119,38 +99,6 @@ int read_public_key(const char *pem_filename, EVP_PKEY **pkey); int write_public_key(const char *pem_filename, EVP_PKEY *pkey); -typedef int (*rsa_sign_t)(const unsigned char *key_blob, size_t key_blob_length, - unsigned char *sig, size_t *siglen, - const unsigned char *tbs, size_t tbslen, - int padding_type, int md_nid, - void *private); -typedef int (*rsa_pss_sign_t)(const unsigned char *key_blob, - size_t key_blob_length, unsigned char *sig, - size_t *siglen, const unsigned char *tbs, - size_t tbslen, int md_nid, int mfgmd_nid, - int saltlen, void *private); -typedef int (*ecdsa_sign_t)(const unsigned char *key_blob, - size_t key_blob_length, unsigned char *sig, - size_t *siglen, const unsigned char *tbs, - size_t tbslen, int md_nid, void *private); - -struct sk_pkey_sign_func { - rsa_sign_t rsa_sign; - rsa_pss_sign_t rsa_pss_sign; - ecdsa_sign_t ecdsa_sign; -}; - -int setup_secure_key_pkey_method(int pkey_id); -int cleanup_secure_key_pkey_method(int pkey_id); -int setup_secure_key_pkey_context(EVP_PKEY_CTX *pkey_ctx, - const unsigned char *key_blob, - size_t key_blob_len, - struct sk_pkey_sign_func *sign_funcs, - void *private); - -int setup_rsa_pss_pkey_context(EVP_PKEY_CTX *pkey_ctx, - struct ekmf_rsa_pss_params *rsa_pss_params); - int build_subject_name(X509_NAME **name, const char *rdns[], size_t num_rdns, bool utf8);