mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
libekmfweb: Generate certificate or CSR with identity key
To identify the client with EKMF Web, an X.509 certificate must be generated using the identity key, and must be made known to EKMF Web. Either a self signed certificate can be generated, or a certificate signing request (CSR) that is then passed to a certificate authority (CA) to have a certificate issued. The certificate is then used to register the client with EKMF Web, so that EKMF Web knows the public part of the client's identity key. Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com> Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
committed by
Jan Höppner
parent
1cdfb4946e
commit
8137128a96
@@ -208,4 +208,140 @@ int ekmf_reencipher_identity_key(const struct ekmf_config *config,
|
||||
const struct ekmf_ext_lib *ext_lib,
|
||||
bool verbose);
|
||||
|
||||
struct ekmf_rsa_pss_params {
|
||||
int salt_len; /* salt length in bytes, or OpenSSL constants
|
||||
RSA_PSS_SALTLEN_DIGEST (-1),
|
||||
RSA_PSS_SALTLEN_AUTO (-2), or
|
||||
RSA_PSS_SALTLEN_MAX(-3) */
|
||||
int mgf_digest_nid; /* OpenSSl digest nid, or zero to use the same
|
||||
digest algorithm as the signature algorithm */
|
||||
};
|
||||
|
||||
/**
|
||||
* Generate a certificate signing request using the secure identity key (field
|
||||
* identity_secure_key in config structure) with the specified subject name,
|
||||
* certificate extensions (if any), and writes the CSR to the specified file
|
||||
* in PEM format.
|
||||
*
|
||||
* To renew an existing certificate, specify renew_cert = true. In this case
|
||||
* the existing certificate (field sign_certificate in config struct) is read,
|
||||
* and the subject name is extracted from it. Any specified subject name RDNs
|
||||
* are added to the CSR. Also, the extensions are taken from the existing
|
||||
* certificate, and any specified extensions are added to the CSR.
|
||||
*
|
||||
* The CSR is signed using the secure identity key (field identity_secure_key in
|
||||
* config structure) with an signing algorithm matching the identity key (ECDSA,
|
||||
* RSA-PKCS, or RSA-PSS if rsa_pss is true), and the specified digest. If the
|
||||
* digest nid is zero, then a default digest is used.
|
||||
*
|
||||
* @param config the configuration structure. Only field
|
||||
* identity_secure_key must be specified, all others
|
||||
* are optional.
|
||||
* @param subject_rdns an array of strings, each string representing an
|
||||
* RDN in the form '[+]type=value'. If the type is
|
||||
* prepended with a '+', then this RDN is added to the
|
||||
* previous one.
|
||||
* @param num_subject_rdns number of RDN elements in the array.
|
||||
* @param subject_utf8 if true, RDNs of type MBSTRING_UTF8 are created,
|
||||
* otherwise type is MBSTRING_ASC is used.
|
||||
* @param renew_cert_filename if not NULL, specifies the file name of a PEM file
|
||||
* containing an existing certificate that is renewed
|
||||
* @param extensions an array of strings, each string representing an
|
||||
* certificate extension in the form 'type=value'.
|
||||
* @param num_extensions number of extension elements in the array.
|
||||
* @param digest_nid the OpenSSL digest nid to use with the signature
|
||||
* algorithm, or 0 to use the default
|
||||
* @param rsa_pss_params if not NULL and the identity key is an RSA key, then
|
||||
* the CSR is signed with RSA-PSS using the specified
|
||||
* PSS parameters. Ignored if the identity key is an EC
|
||||
* key
|
||||
* @param csr_pem_filename the name of the PEM file to which the CSR is written
|
||||
* @param new_hdr if true, output "NEW" in the PEM header lines
|
||||
* @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:
|
||||
* -EINVAL: invalid parameter
|
||||
* -ENOMEM: Failed to allocate memory
|
||||
* -EBADMSG: an RDN or extension is not formatted correctly
|
||||
* -EIO: OpenSSL failed to create the CSR
|
||||
* -EEXIST: if one of the RDN name entries or extensions to add is a
|
||||
* duplicate
|
||||
* -ENOTSUP: the specified digest is not supported
|
||||
* any other errno from file I/O routines
|
||||
*/
|
||||
int ekmf_generate_csr(const struct ekmf_config *config,
|
||||
const char *subject_rdns[], size_t num_subject_rdns,
|
||||
bool subject_utf8, const char *renew_cert_filename,
|
||||
const char *extensions[], size_t num_extensions,
|
||||
int digest_nid,
|
||||
struct ekmf_rsa_pss_params *rsa_pss_params,
|
||||
const char *csr_pem_filename, bool new_hdr,
|
||||
const struct ekmf_ext_lib *ext_lib, bool verbose);
|
||||
|
||||
/**
|
||||
* Generate a self signed certificate using the secure identity key (field
|
||||
* identity_secure_key in config structure) with the specified subject name,
|
||||
* certificate extensions (if any), and writes the certificate the specified
|
||||
* file in PEM format.
|
||||
*
|
||||
* To renew an existing certificate, specify renew_cert = true. In this case
|
||||
* the existing certificate (field sign_certificate in config struct) is read,
|
||||
* and the subject name is extracted from it. Any specified subject name RDNs
|
||||
* are added to the certificate. Also, the extensions are taken from the
|
||||
* existing certificate, and any specified extensions are added to the new
|
||||
* certificate.
|
||||
*
|
||||
* The certificate is signed using the secure identity key (field
|
||||
* identity_secure_key in config structure) with an signing algorithm matching
|
||||
* the identity key (ECDSA, RSA-PKCS, or RSA-PSS if rsa_pss is true), and the
|
||||
* specified digest. If the digest nid is zero, then a default digest is used.
|
||||
*
|
||||
* @param config the configuration structure. Only field
|
||||
* identity_secure_key must be specified, all others
|
||||
* are optional.
|
||||
* @param subject_rdns an array of strings, each string representing an
|
||||
* RDN in the form '[+]type=value'. If the type is
|
||||
* prepended with a '+', then this RDN is added to the
|
||||
* previous one.
|
||||
* @param num_subject_rdns number of RDN elements in the array.
|
||||
* @param subject_utf8 if true, RDNs of type MBSTRING_UTF8 are created,
|
||||
* otherwise type is MBSTRING_ASC is used.
|
||||
* @param renew_cert_filename if not NULL, specifies the file name of a PEM file
|
||||
* containing an existing certificate that is renewed
|
||||
* @param extensions an array of strings, each string representing an
|
||||
* certificate extension in the form 'type=value'.
|
||||
* @param num_extensions number of extension elements in the array.
|
||||
* @param validity_days number if day from the current date how long the
|
||||
* certificate is valid.
|
||||
* @param digest_nid the OpenSSL digest nid to use with the signature
|
||||
* algorithm, or 0 to use the default
|
||||
* @param rsa_pss_params if not NULL and the identity key is an RSA key, then
|
||||
* the certificate is signed with RSA-PSS using the
|
||||
* specified PSS parameters. Ignored if the identity
|
||||
* key is an EC key
|
||||
* @param cert_pem_filename the name of the PEM file to which the Certificate
|
||||
* is written
|
||||
* @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.
|
||||
* -EINVAL: invalid parameter
|
||||
* -ENOMEM: Failed to allocate memory
|
||||
* -EBADMSG: an RDN or extension is not formatted correctly
|
||||
* -EIO: OpenSSL failed to create the certificate
|
||||
* -EEXIST: if one of the RDN name entries or extensions to add is a
|
||||
* duplicate
|
||||
* -ENOTSUP: the specified digest is not supported
|
||||
* any other errno from file I/O routines
|
||||
*/
|
||||
int ekmf_generate_ss_cert(const struct ekmf_config *config,
|
||||
const char *subject_rdns[], size_t num_subject_rdns,
|
||||
bool subject_utf8, const char *renew_cert_filename,
|
||||
const char *extensions[], size_t num_extensions,
|
||||
int validity_days, int digest_nid,
|
||||
struct ekmf_rsa_pss_params *rsa_pss_params,
|
||||
const char *cert_pem_filename,
|
||||
const struct ekmf_ext_lib *ext_lib, bool verbose);
|
||||
|
||||
#endif
|
||||
|
||||
+1
-1
@@ -61,7 +61,7 @@ skip-libekmfweb-curl:
|
||||
all: $(BUILD_TARGETS)
|
||||
|
||||
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
|
||||
utilities.o: check-dep-libekmfweb utilities.c utilities.h $(rootdir)include/ekmfweb/ekmfweb.h
|
||||
cca.o: check-dep-libekmfweb cca.c cca.h utilities.h $(rootdir)include/ekmfweb/ekmfweb.h
|
||||
|
||||
libekmfweb.so: ALL_CFLAGS += -fPIC
|
||||
|
||||
+682
-1
@@ -14,6 +14,10 @@
|
||||
|
||||
#include "lib/zt_common.h"
|
||||
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/ecdsa.h>
|
||||
|
||||
#include "cca.h"
|
||||
#include "utilities.h"
|
||||
|
||||
@@ -90,6 +94,59 @@ struct cca_section_header {
|
||||
#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
|
||||
*/
|
||||
@@ -102,9 +159,10 @@ static int _cca_get_library_functions(const struct ekmf_cca_lib *cca_lib,
|
||||
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");
|
||||
|
||||
if (cca->dll_CSNDPKB == NULL || cca->dll_CSNDPKG == NULL ||
|
||||
cca->dll_CSNDKTC == NULL)
|
||||
cca->dll_CSNDKTC == NULL || cca->dll_CSNDDSG == NULL)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
@@ -432,6 +490,201 @@ int cca_get_key_type(const unsigned char *key_token, size_t key_token_length,
|
||||
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 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.
|
||||
*
|
||||
@@ -519,3 +772,431 @@ int cca_reencipher_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;
|
||||
}
|
||||
|
||||
@@ -65,10 +65,26 @@ typedef void (*CSNDKTC_t)(long *return_code,
|
||||
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);
|
||||
|
||||
struct cca_lib {
|
||||
CSNDPKB_t dll_CSNDPKB;
|
||||
CSNDPKG_t dll_CSNDPKG;
|
||||
CSNDKTC_t dll_CSNDKTC;
|
||||
CSNDDSG_t dll_CSNDDSG;
|
||||
};
|
||||
|
||||
#define CCA_MAX_PKA_KEY_TOKEN_SIZE 3500
|
||||
@@ -89,4 +105,31 @@ 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_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_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
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/rsa.h>
|
||||
|
||||
#include <json-c/json.h>
|
||||
#ifndef JSON_C_TO_STRING_NOSLASHESCAPE
|
||||
@@ -33,6 +34,8 @@
|
||||
#include "utilities.h"
|
||||
#include "cca.h"
|
||||
|
||||
#define SERIAL_NUMBER_BIT_SIZE 159
|
||||
|
||||
#define MAX_KEY_BLOB_SIZE CCA_MAX_PKA_KEY_TOKEN_SIZE
|
||||
|
||||
#define pr_verbose(verbose, fmt...) do { \
|
||||
@@ -1295,6 +1298,682 @@ int ekmf_reencipher_identity_key(const struct ekmf_config *config,
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct private_data {
|
||||
const struct ekmf_ext_lib *ext_lib;
|
||||
bool verbose;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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,
|
||||
* certificate extensions (if any), and writes the CSR to the specified file
|
||||
* in PEM format.
|
||||
*
|
||||
* To renew an existing certificate, specify renew_cert = true. In this case
|
||||
* the existing certificate (field sign_certificate in config struct) is read,
|
||||
* and the subject name is extracted from it. Any specified subject name RDNs
|
||||
* are added to the CSR. Also, the extensions are taken from the existing
|
||||
* certificate, and any specified extensions are added to the CSR.
|
||||
*
|
||||
* The CSR is signed using the secure identity key (field identity_secure_key in
|
||||
* config structure) with an signing algorithm matching the identity key (ECDSA,
|
||||
* RSA-PKCS, or RSA-PSS if rsa_pss is true), and the specified digest. If the
|
||||
* digest nid is zero, then a default digest is used.
|
||||
*
|
||||
* @param config the configuration structure. Only field
|
||||
* identity_secure_key must be specified, all others
|
||||
* are optional.
|
||||
* @param subject_rdns an array of strings, each string representing an
|
||||
* RDN in the form '[+]type=value'. If the type is
|
||||
* prepended with a '+', then this RDN is added to the
|
||||
* previous one.
|
||||
* @param num_subject_rdns number of RDN elements in the array.
|
||||
* @param subject_utf8 if true, RDNs of type MBSTRING_UTF8 are created,
|
||||
* otherwise type is MBSTRING_ASC is used.
|
||||
* @param renew_cert_filename if not NULL, specifies the file name of a PEM file
|
||||
* containing an existing certificate that is renewed
|
||||
* @param extensions an array of strings, each string representing an
|
||||
* certificate extension in the form 'type=value'.
|
||||
* @param num_extensions number of extension elements in the array.
|
||||
* @param digest_nid the OpenSSL digest nid to use with the signature
|
||||
* algorithm, or 0 to use the default
|
||||
* @param rsa_pss_params if not NULL and the identity key is an RSA key, then
|
||||
* the CSR is signed with RSA-PSS using the specified
|
||||
* PSS parameters. Ignored if the identity key is an EC
|
||||
* key
|
||||
* @param csr_pem_filename the name of the PEM file to which the CSR is written
|
||||
* @param new_hdr if true, output "NEW" in the PEM header lines
|
||||
* @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:
|
||||
* -EINVAL: invalid parameter
|
||||
* -ENOMEM: Failed to allocate memory
|
||||
* -EBADMSG: an RDN or extension is not formatted correctly
|
||||
* -EIO: OpenSSL failed to create the CSR
|
||||
* -EEXIST: if one of the RDN name entries or extensions to add is a
|
||||
* duplicate
|
||||
* -ENOTSUP: the specified digest is not supported
|
||||
* any other errno from file I/O routines
|
||||
*/
|
||||
int ekmf_generate_csr(const struct ekmf_config *config,
|
||||
const char *subject_rdns[], size_t num_subject_rdns,
|
||||
bool subject_utf8, const char *renew_cert_filename,
|
||||
const char *extensions[], size_t num_extensions,
|
||||
int digest_nid,
|
||||
struct ekmf_rsa_pss_params *rsa_pss_params,
|
||||
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;
|
||||
X509_REQ *req = NULL;
|
||||
X509 *cert = NULL;
|
||||
int rc;
|
||||
|
||||
if (config == NULL || ext_lib == NULL || csr_pem_filename == NULL)
|
||||
return -EINVAL;
|
||||
if (config->identity_secure_key == NULL)
|
||||
return -EINVAL;
|
||||
if (renew_cert_filename == NULL &&
|
||||
(subject_rdns == NULL || num_subject_rdns == 0))
|
||||
return -EINVAL;
|
||||
if (num_extensions != 0 && extensions == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
rc = read_key_blob(config->identity_secure_key, key_blob,
|
||||
&key_blob_size);
|
||||
if (rc != 0) {
|
||||
pr_verbose(verbose, "Failed to read identity key from file "
|
||||
"'%s': %s", config->identity_secure_key,
|
||||
strerror(-rc));
|
||||
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) {
|
||||
pr_verbose(verbose, "Failed to open renew cert file "
|
||||
"'%s': %s", renew_cert_filename,
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
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;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = write_x509_request(csr_pem_filename, req, new_hdr);
|
||||
if (rc != 0) {
|
||||
pr_verbose(verbose, "Failed to write CSR to file "
|
||||
"'%s': %s", csr_pem_filename, strerror(-rc));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
pr_verbose(verbose, "Certificate Signing Request created:");
|
||||
X509_REQ_print_fp(stderr, req);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a self signed certificate using the secure identity key (field
|
||||
* identity_secure_key in config structure) with the specified subject name,
|
||||
* certificate extensions (if any), and writes the certificate the specified
|
||||
* file in PEM format.
|
||||
*
|
||||
* To renew an existing certificate, specify renew_cert = true. In this case
|
||||
* the existing certificate (field sign_certificate in config struct) is read,
|
||||
* and the subject name is extracted from it. Any specified subject name RDNs
|
||||
* are added to the certificate. Also, the extensions are taken from the
|
||||
* existing certificate, and any specified extensions are added to the new
|
||||
* certificate.
|
||||
*
|
||||
* The certificate is signed using the secure identity key (field
|
||||
* identity_secure_key in config structure) with an signing algorithm matching
|
||||
* the identity key (ECDSA, RSA-PKCS, or RSA-PSS if rsa_pss is true), and the
|
||||
* specified digest. If the digest nid is zero, then a default digest is used.
|
||||
*
|
||||
* @param config the configuration structure. Only field
|
||||
* identity_secure_key must be specified, all others
|
||||
* are optional.
|
||||
* @param subject_rdns an array of strings, each string representing an
|
||||
* RDN in the form '[+]type=value'. If the type is
|
||||
* prepended with a '+', then this RDN is added to the
|
||||
* previous one.
|
||||
* @param num_subject_rdns number of RDN elements in the array.
|
||||
* @param subject_utf8 if true, RDNs of type MBSTRING_UTF8 are created,
|
||||
* otherwise type is MBSTRING_ASC is used.
|
||||
* @param renew_cert_filename if not NULL, specifies the file name of a PEM file
|
||||
* containing an existing certificate that is renewed
|
||||
* @param extensions an array of strings, each string representing an
|
||||
* certificate extension in the form 'type=value'.
|
||||
* @param num_extensions number of extension elements in the array.
|
||||
* @param validity_days number if day from the current date how long the
|
||||
* certificate is valid.
|
||||
* @param digest_nid the OpenSSL digest nid to use with the signature
|
||||
* algorithm, or 0 to use the default
|
||||
* @param rsa_pss_params if not NULL and the identity key is an RSA key, then
|
||||
* the certificate is signed with RSA-PSS using the
|
||||
* specified PSS parameters. Ignored if the identity
|
||||
* key is an EC key
|
||||
* @param cert_pem_filename the name of the PEM file to which the Certificate
|
||||
* is written
|
||||
* @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.
|
||||
* -EINVAL: invalid parameter
|
||||
* -ENOMEM: Failed to allocate memory
|
||||
* -EBADMSG: an RDN or extension is not formatted correctly
|
||||
* -EIO: OpenSSL failed to create the certificate
|
||||
* -EEXIST: if one of the RDN name entries or extensions to add is a
|
||||
* duplicate
|
||||
* -ENOTSUP: the specified digest is not supported
|
||||
* any other errno from file I/O routines
|
||||
*/
|
||||
int ekmf_generate_ss_cert(const struct ekmf_config *config,
|
||||
const char *subject_rdns[], size_t num_subject_rdns,
|
||||
bool subject_utf8, const char *renew_cert_filename,
|
||||
const char *extensions[], size_t num_extensions,
|
||||
int validity_days, int digest_nid,
|
||||
struct ekmf_rsa_pss_params *rsa_pss_params,
|
||||
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;
|
||||
X509 *rcert = NULL;
|
||||
X509 *cert = NULL;
|
||||
int rc;
|
||||
|
||||
if (config == NULL || ext_lib == NULL || cert_pem_filename == NULL)
|
||||
return -EINVAL;
|
||||
if (config->identity_secure_key == NULL)
|
||||
return -EINVAL;
|
||||
if (renew_cert_filename == NULL &&
|
||||
(subject_rdns == NULL || num_subject_rdns == 0))
|
||||
return -EINVAL;
|
||||
if (num_extensions != 0 && extensions == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
rc = read_key_blob(config->identity_secure_key, key_blob,
|
||||
&key_blob_size);
|
||||
if (rc != 0) {
|
||||
pr_verbose(verbose, "Failed to read identity key from file "
|
||||
"'%s': %s", config->identity_secure_key,
|
||||
strerror(-rc));
|
||||
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) {
|
||||
pr_verbose(verbose, "Failed to open renew cert file "
|
||||
"'%s': %s", renew_cert_filename,
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
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;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = write_x509_certificate(cert_pem_filename, cert);
|
||||
if (rc != 0) {
|
||||
pr_verbose(verbose, "Failed to write Certificate to file "
|
||||
"'%s': %s", cert_pem_filename, strerror(-rc));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
pr_verbose(verbose, "Self-signed Certificate created:");
|
||||
X509_print_fp(stderr, cert);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Library constructor
|
||||
*/
|
||||
|
||||
@@ -5,5 +5,7 @@ LIBEKMFWEB_1.0 {
|
||||
ekmf_check_login_token;
|
||||
ekmf_generate_identity_key;
|
||||
ekmf_reencipher_identity_key;
|
||||
ekmf_generate_csr;
|
||||
ekmf_generate_ss_cert;
|
||||
local: *;
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -15,9 +15,12 @@
|
||||
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/obj_mac.h>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#include <json-c/json.h>
|
||||
|
||||
#include "ekmfweb/ekmfweb.h"
|
||||
|
||||
int decode_base64url(unsigned char *output, size_t *outlen,
|
||||
const char *input, size_t inlen);
|
||||
|
||||
@@ -37,6 +40,17 @@ 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 write_key_blob(const char *filename, unsigned char *key_blob,
|
||||
size_t key_blob_len);
|
||||
|
||||
@@ -45,4 +59,49 @@ int read_key_blob(const char *filename, unsigned char *key_blob,
|
||||
|
||||
int read_x509_certificate(const char *pem_filename, X509 **cert);
|
||||
|
||||
int write_x509_certificate(const char *pem_filename, X509 *cert);
|
||||
|
||||
int write_x509_request(const char *pem_filename, X509_REQ *req, bool new_hdr);
|
||||
|
||||
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);
|
||||
|
||||
int build_certificate_extensions(X509 *cert, X509_REQ *req,
|
||||
const char *exts[], size_t num_exts,
|
||||
const STACK_OF(X509_EXTENSION) *addl_exts);
|
||||
|
||||
int generate_x509_serial_number(X509 *cert, size_t sn_bit_size);
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user