diff --git a/include/ekmfweb/ekmfweb.h b/include/ekmfweb/ekmfweb.h index 9a3b4342..d2a649ff 100644 --- a/include/ekmfweb/ekmfweb.h +++ b/include/ekmfweb/ekmfweb.h @@ -48,6 +48,25 @@ struct ekmf_config { /** File name of the login token (JSON Web Token) used for the last * login. */ const char *login_token; + /** File name of a file containing the client identity secure key blob. + * This key represents the client identity against EKMFWeb. Some + * requests sent to EKMFWeb are signed with this (secure) key */ + const char *identity_secure_key; +}; + +struct ekmf_cca_lib { + void *cca_lib; /* Handle of CCA host library loaded via dlopen */ +}; + +enum ekmf_ext_lib_type { + EKMF_EXT_LIB_CCA = 1, +}; + +struct ekmf_ext_lib { + enum ekmf_ext_lib_type type; + union { + struct ekmf_cca_lib *cca; /* Used if type = EKMF_EXT_LIB_CCA */ + }; }; /** @@ -112,4 +131,43 @@ int ekmf_print_certificates(const char *cert_pem, bool verbose); int ekmf_check_login_token(const struct ekmf_config *config, bool *valid, char **login_token, bool verbose); +enum ekmf_key_type { + EKMF_KEY_TYPE_ECC = 1, + EKMF_KEY_TYPE_RSA = 2, +}; + +struct ekmf_key_gen_info { + enum ekmf_key_type type; + union { + struct { + int curve_nid; + } ecc; + struct { + size_t modulus_bits; + unsigned int pub_exp; + } rsa; + } params; +}; + +/** + * Generate a secure identity key used to identify the client to EKMFWeb. + * The secure key blob is stored in a file specified in field + * identity_secure_key of the config structure. If an secure key already exists + * at that location, it is overwritten. + * + * @param config the configuration structure. Only field + * identity_secure_key must be specified, all others + * are optional. + * @param info key generation info, such as key type (ECC or RSA) + * and key parameters. + * @param ext_lib External secure key crypto library to use + * @param verbose if true, verbose messages are printed + * + * @returns a negative errno in case of an error, 0 if success. + */ +int ekmf_generate_identity_key(const struct ekmf_config *config, + const struct ekmf_key_gen_info *info, + const struct ekmf_ext_lib *ext_lib, + bool verbose); + #endif diff --git a/libekmfweb/Makefile b/libekmfweb/Makefile index e4aafd45..ab54fea6 100644 --- a/libekmfweb/Makefile +++ b/libekmfweb/Makefile @@ -60,14 +60,15 @@ skip-libekmfweb-curl: all: $(BUILD_TARGETS) -ekmfweb.o: check-dep-libekmfweb ekmfweb.c utilities.h $(rootdir)include/ekmfweb/ekmfweb.h +ekmfweb.o: check-dep-libekmfweb ekmfweb.c utilities.h cca.h $(rootdir)include/ekmfweb/ekmfweb.h utilities.o: check-dep-libekmfweb utilities.c utilities.h +cca.o: check-dep-libekmfweb cca.c cca.h utilities.h $(rootdir)include/ekmfweb/ekmfweb.h libekmfweb.so: ALL_CFLAGS += -fPIC -libekmfweb.so: LDLIBS = -ljson-c -lcrypto -lssl -lcurl -shared +libekmfweb.so: LDLIBS = -ljson-c -lcrypto -lssl -lcurl -ldl -shared libekmfweb.so: LDFLAGS = -shared -Wl,--version-script=libekmfweb.map \ -Wl,-z,defs,-Bsymbolic -libekmfweb.so: ekmfweb.o utilities.o +libekmfweb.so: ekmfweb.o utilities.o cca.o $(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@ install-libekmfweb.so: libekmfweb.so diff --git a/libekmfweb/cca.c b/libekmfweb/cca.c new file mode 100644 index 00000000..92d2b90a --- /dev/null +++ b/libekmfweb/cca.c @@ -0,0 +1,312 @@ +/* + * libekmfweb - EKMFWeb client library + * + * Copyright IBM Corp. 2020 + * + * s390-tools is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ +#include +#include +#include +#include +#include + +#include "lib/zt_common.h" + +#include "cca.h" +#include "utilities.h" + +#define pr_verbose(verbose, fmt...) do { \ + if (verbose) \ + warnx(fmt); \ + } while (0) + +/* Internal CCA definitions */ + +#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; + +#define CCA_PRIME_CURVE 0x00 +#define CCA_BRAINPOOL_CURVE 0x01 + +/** + * Gets the CCA library function entry points from the library handle + */ +static int _cca_get_library_functions(const struct ekmf_cca_lib *cca_lib, + struct cca_lib *cca) +{ + if (cca_lib == NULL || cca == NULL) + return -EINVAL; + + cca->dll_CSNDPKB = (CSNDPKB_t)dlsym(cca_lib->cca_lib, "CSNDPKB"); + cca->dll_CSNDPKG = (CSNDPKG_t)dlsym(cca_lib->cca_lib, "CSNDPKG"); + + if (cca->dll_CSNDPKB == NULL || cca->dll_CSNDPKG == 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; +} diff --git a/libekmfweb/cca.h b/libekmfweb/cca.h new file mode 100644 index 00000000..d36d58a9 --- /dev/null +++ b/libekmfweb/cca.h @@ -0,0 +1,72 @@ +/* + * libekmfweb - EKMFWeb client library + * + * Copyright IBM Corp. 2020 + * + * s390-tools is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef CCA_H +#define CCA_H + +#include +#include + +#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, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *key_values_structure_length, + unsigned char *key_values_structure, + long *key_name_ln, + unsigned char *key_name, + long *reserved_1_length, + unsigned char *reserved_1, + long *reserved_2_length, + unsigned char *reserved_2, + long *reserved_3_length, + unsigned char *reserved_3, + long *reserved_4_length, + unsigned char *reserved_4, + long *reserved_5_length, + unsigned char *reserved_5, + long *token_length, unsigned char *token); + +struct cca_lib { + CSNDPKB_t dll_CSNDPKB; + CSNDPKG_t dll_CSNDPKG; +}; + +#define CCA_MAX_PKA_KEY_TOKEN_SIZE 3500 + +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); + +#endif diff --git a/libekmfweb/ekmfweb.c b/libekmfweb/ekmfweb.c index 33b51d79..e51d84a3 100644 --- a/libekmfweb/ekmfweb.c +++ b/libekmfweb/ekmfweb.c @@ -31,6 +31,9 @@ #include "ekmfweb/ekmfweb.h" #include "utilities.h" +#include "cca.h" + +#define MAX_KEY_BLOB_SIZE CCA_MAX_PKA_KEY_TOKEN_SIZE #define pr_verbose(verbose, fmt...) do { \ if (verbose) \ @@ -1131,6 +1134,81 @@ out: return rc; } +/** + * Generate a secure identity key used to identify the client to EKMFWeb. + * The secure key blob is stored in a file specified in field + * identity_secure_key of the config structure. If an secure key already exists + * at that location, it is overwritten. + * + * @param config the configuration structure. Only field + * identity_secure_key must be specified, all others + * are optional. + * @param info key generation info, such as key type (ECC or RSA) + * and key parameters. + * @param ext_lib External secure key crypto library to use + * @param verbose if true, verbose messages are printed + * + * @returns a negative errno in case of an error, 0 if success. + */ +int ekmf_generate_identity_key(const struct ekmf_config *config, + const struct ekmf_key_gen_info *info, + const struct ekmf_ext_lib *ext_lib, bool verbose) +{ + unsigned char key_blob[MAX_KEY_BLOB_SIZE]; + size_t key_blob_size = sizeof(key_blob); + int rc; + + if (config == NULL || info == NULL || ext_lib == NULL) + return -EINVAL; + 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; + } + + if (rc != 0) { + pr_verbose(verbose, "Failed to generate a key: rc: %d - %s", + rc, strerror(-rc)); + return rc; + } + + rc = write_key_blob(config->identity_secure_key, key_blob, + key_blob_size); + if (rc != 0) { + pr_verbose(verbose, "Failed to write the key to file '%s' " + "rc: %d - %s", config->identity_secure_key, rc, + strerror(-rc)); + return rc; + } + + pr_verbose(verbose, "Secure identity key generated (%lu bytes) " + "and written to file '%s'", key_blob_size, + config->identity_secure_key); + + return 0; +} + /** * Library constructor */ diff --git a/libekmfweb/libekmfweb.map b/libekmfweb/libekmfweb.map index b2bbcf6e..0ec852ef 100644 --- a/libekmfweb/libekmfweb.map +++ b/libekmfweb/libekmfweb.map @@ -3,5 +3,6 @@ LIBEKMFWEB_1.0 { ekmf_get_server_cert_chain; ekmf_print_certificates; ekmf_check_login_token; + ekmf_generate_identity_key; local: *; }; diff --git a/libekmfweb/utilities.c b/libekmfweb/utilities.c index 3ec907ca..528f3a4a 100644 --- a/libekmfweb/utilities.c +++ b/libekmfweb/utilities.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -358,6 +359,260 @@ out: return rc; } +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; +} + +/** + * Write a secure key blob to the specified file. + * + * @param filename the name of the file to write to + * @param key_blob the key blob to write + * @param key_blob_len the size of the key blob in bytes + * + * @returns zero for success, a negative errno in case of an error: + * -EINVAL: invalid parameter + * -EIO: error during writing out the key blob + * any other errno as returned by fopen + */ +int write_key_blob(const char *filename, unsigned char *key_blob, + size_t key_blob_len) +{ + size_t count; + FILE *fp; + + if (filename == NULL || key_blob == NULL || key_blob_len == 0) + return -EINVAL; + + fp = fopen(filename, "w"); + if (fp == NULL) + return -errno; + + count = fwrite(key_blob, 1, key_blob_len, fp); + if (count != key_blob_len) { + fclose(fp); + return -EIO; + } + + fclose(fp); + return 0; +} + +/** + * Read a secure key blob from the specified file. + * + * @param filename the name of the file to write to + * @param key_blob a buffer to read the key blob to. If NULL, then + * only the size of the key blob is returned in + * key_blob_len. + * @param key_blob_len On entry: the size of the buffer in bytes + * On return: the size of the key blob read + * + * @returns zero for success, a negative errno in case of an error: + * -EINVAL: invalid parameter + * -ERANGE: The supplied buffer is too short. key_blob_len is set to + * the required size. + * -EIO: error during reading in the key blob + * any other errno as returned by stat or fopen + */ +int read_key_blob(const char *filename, unsigned char *key_blob, + size_t *key_blob_len) +{ + size_t count, size; + struct stat sb; + FILE *fp; + + if (filename == NULL || key_blob_len == NULL) + return -EINVAL; + + if (stat(filename, &sb)) + return -errno; + size = sb.st_size; + + if (key_blob == NULL) { + *key_blob_len = size; + return 0; + } + + if (size > *key_blob_len) { + *key_blob_len = size; + return -ERANGE; + } + + fp = fopen(filename, "r"); + if (fp == NULL) + return -errno; + + count = fread(key_blob, 1, size, fp); + if (count != size) { + fclose(fp); + return -EIO; + } + + *key_blob_len = size; + fclose(fp); + return 0; +} + /** * Reads a X.509 certificate from the specified PEM file. * diff --git a/libekmfweb/utilities.h b/libekmfweb/utilities.h index 41b4f913..1bff2de3 100644 --- a/libekmfweb/utilities.h +++ b/libekmfweb/utilities.h @@ -14,6 +14,7 @@ #include #include +#include #include @@ -27,6 +28,21 @@ int parse_json_web_token(const char *token, json_object **header_obj, json_object **payload_obj, unsigned char **signature, size_t *signature_len); +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 write_key_blob(const char *filename, unsigned char *key_blob, + size_t key_blob_len); + +int read_key_blob(const char *filename, unsigned char *key_blob, + size_t *key_blob_len); + int read_x509_certificate(const char *pem_filename, X509 **cert); #endif