libseckey: Add a secure key library

The libseckey is a secure key library to perform secure key operations
with OpenSSL. It provides a framework to create OpenSSL PKEYs with a
secure key attached. Such a PKEY contains the public key parts in clear,
but the private key as secure key blob. Only the private key operations
are actually performed with the secure key, public key operations are
performed in software by OpenSSL. It supports CCA and EP11 secure
keys for RSA and ECC crypto operations.

Because many PKEY method related functions are deprecated since OpenSSL
3.0, two versions of the OpenSSL secure key support are needed. One (using
a PKEY method override) for OpenSSL 1.1.1, and another one (using an own
OpenSSL provider) for OpenSSL 3.0 and later. The desired implementation is
selected automatically at compile time, using OpenSSL version defines. The
interface of both implementations is the same, so a user does not need to
care which one is used.

Reviewed-by: Juergen Christ <jchrist@linux.ibm.com>
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
Ingo Franzki
2021-04-08 11:33:53 +02:00
committed by Jan Höppner
parent fff83fc116
commit e70cde2c5d
14 changed files with 11901 additions and 1 deletions

2
.gitignore vendored
View File

@@ -45,6 +45,8 @@ libekmfweb/detect-openssl-version.dep
libekmfweb/libekmfweb.so
libekmfweb/libekmfweb.so.1
libekmfweb/libekmfweb.so.1.0
libseckey/check-dep-libseckey
libseckey/detect-openssl-version.dep
libutil/*_example
libvmcp/vmcp_example
libzds/libzds.a

View File

@@ -3,7 +3,8 @@ ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/ar
# Include common definitions
include common.mak
LIB_DIRS = libvtoc libutil libzds libdasd libvmdump libccw libvmcp libekmfweb
LIB_DIRS = libvtoc libutil libzds libdasd libvmdump libccw libvmcp libekmfweb \
libseckey
TOOL_DIRS = zipl zdump fdasd dasdfmt dasdview tunedasd \
tape390 osasnmpd qetharp ip_watcher qethconf scripts zconf \
vmconvert vmcp man mon_tools dasdinfo vmur cpuplugd ipl_tools \

View File

@@ -374,6 +374,10 @@ $(rootdir)/libekmfweb/libekmfweb.so: $(rootdir)/libekmfweb
$(MAKE) -C $(rootdir)/libekmfweb/ libekmfweb.so
.PHONY: $(rootdir)/libekmfweb
$(rootdir)/libseckey/libseckey.a: $(rootdir)/libseckey
$(MAKE) -C $(rootdir)/libseckey/ libseckey.a
.PHONY: $(rootdir)/libseckey
$(rootdir)/zipl/boot/data.o:
$(MAKE) -C $(rootdir)/zipl/boot/ data.o

View File

@@ -0,0 +1,48 @@
/*
* libseckey - Secure key library
*
* Copyright IBM Corp. 2021
*
* 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 SK_CCA_H
#define SK_CCA_H
#include <stddef.h>
#include <stdbool.h>
#include <openssl/evp.h>
#include "libseckey/sk_openssl.h"
#define CCA_MAX_PKA_KEY_TOKEN_SIZE 3500
int SK_CCA_generate_ec_key_pair(const struct sk_ext_cca_lib *cca_lib,
int curve_nid, unsigned char *key_token,
size_t *key_token_length, bool debug);
int SK_CCA_generate_rsa_key_pair(const struct sk_ext_cca_lib *cca_lib,
size_t modulus_bits, unsigned int pub_exp,
unsigned char *key_token,
size_t *key_token_length, bool debug);
int SK_CCA_get_key_type(const unsigned char *key_token, size_t key_token_length,
int *pkey_type);
int SK_CCA_get_secure_key_as_pkey(const struct sk_ext_cca_lib *cca_lib,
const unsigned char *key_token,
size_t key_token_length,
bool rsa_pss, EVP_PKEY **pkey, bool debug);
int SK_CCA_get_public_from_secure_key(const unsigned char *key_token,
size_t key_token_length,
sk_pub_key_func_t pub_key_cb,
void *private,
bool debug);
int SK_CCA_reencipher_key(const struct sk_ext_cca_lib *cca_lib,
unsigned char *key_token, size_t key_token_length,
bool to_new, bool debug);
#endif

177
include/libseckey/sk_ep11.h Normal file
View File

@@ -0,0 +1,177 @@
/*
* libseckey - Secure key library
*
* Copyright IBM Corp. 2021
*
* 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 SK_EP11_H
#define SK_EP11_H
#include <stddef.h>
#include <stdbool.h>
#include <openssl/evp.h>
#include "libseckey/sk_openssl.h"
#define EP11_MAX_KEY_TOKEN_SIZE 8192
int SK_EP11_generate_ec_key_pair(const struct sk_ext_ep11_lib *ep11_lib,
int curve_nid, unsigned char *key_token,
size_t *key_token_length, bool debug);
int SK_EP11_generate_rsa_key_pair(const struct sk_ext_ep11_lib *ep11_lib,
size_t modulus_bits, unsigned int pub_exp,
bool x9_31, unsigned char *key_token,
size_t *key_token_length, bool debug);
int SK_EP11_get_key_type(const unsigned char *key_token,
size_t key_token_length,
int *pkey_type);
const unsigned char *SK_EP11_get_key_blob(const unsigned char *key_token,
size_t key_token_length);
size_t SK_EP11_get_key_blob_size(const unsigned char *key_token,
size_t key_token_length);
int SK_EP11_get_secure_key_as_pkey(const struct sk_ext_ep11_lib *ep11_lib,
const unsigned char *key_token,
size_t key_token_length,
bool rsa_pss, EVP_PKEY **pkey, bool debug);
int SK_EP11_get_public_from_secure_key(const unsigned char *key_token,
size_t key_token_length,
sk_pub_key_func_t pub_key_cb,
void *private,
bool debug);
int SK_EP11_reencipher_key(const struct sk_ext_ep11_lib *ep11_lib,
unsigned char *key_token, size_t key_token_length,
bool debug);
/* PKCS#11 definitions */
#define CK_PTR *
typedef unsigned char CK_BYTE;
typedef CK_BYTE CK_CHAR;
typedef CK_BYTE CK_UTF8CHAR;
typedef CK_BYTE CK_BBOOL;
typedef unsigned long CK_ULONG;
typedef long CK_LONG;
typedef CK_ULONG CK_FLAGS;
typedef CK_ULONG CK_RV;
typedef CK_ULONG CK_SLOT_ID;
typedef CK_ULONG CK_MECHANISM_TYPE;
typedef CK_ULONG CK_ATTRIBUTE_TYPE;
typedef CK_ULONG CK_OBJECT_CLASS;
typedef CK_ULONG CK_KEY_TYPE;
typedef CK_ULONG CK_RSA_PKCS_OAEP_SOURCE_TYPE;
typedef CK_ULONG CK_RSA_PKCS_MGF_TYPE;
typedef CK_BYTE CK_PTR CK_BYTE_PTR;
typedef CK_CHAR CK_PTR CK_CHAR_PTR;
typedef CK_UTF8CHAR CK_PTR CK_UTF8CHAR_PTR;
typedef CK_ULONG CK_PTR CK_ULONG_PTR;
typedef void CK_PTR CK_VOID_PTR;
typedef CK_SLOT_ID CK_PTR CK_SLOT_ID_PTR;
typedef CK_MECHANISM_TYPE CK_PTR CK_MECHANISM_TYPE_PTR;
typedef CK_RSA_PKCS_MGF_TYPE CK_PTR CK_RSA_PKCS_MGF_TYPE_PTR;
typedef struct CK_MECHANISM {
CK_MECHANISM_TYPE mechanism;
CK_VOID_PTR pParameter;
CK_ULONG ulParameterLen;
} CK_MECHANISM;
typedef CK_MECHANISM CK_PTR CK_MECHANISM_PTR;
typedef struct CK_ATTRIBUTE {
CK_ATTRIBUTE_TYPE type;
CK_VOID_PTR pValue;
CK_ULONG ulValueLen;
} CK_ATTRIBUTE;
typedef CK_ATTRIBUTE CK_PTR CK_ATTRIBUTE_PTR;
typedef struct CK_RSA_PKCS_PSS_PARAMS {
CK_MECHANISM_TYPE hashAlg;
CK_RSA_PKCS_MGF_TYPE mgf;
CK_ULONG sLen;
} CK_RSA_PKCS_PSS_PARAMS;
typedef CK_RSA_PKCS_PSS_PARAMS CK_PTR CK_RSA_PKCS_PSS_PARAMS_PTR;
typedef struct CK_RSA_PKCS_OAEP_PARAMS {
CK_MECHANISM_TYPE hashAlg;
CK_RSA_PKCS_MGF_TYPE mgf;
CK_RSA_PKCS_OAEP_SOURCE_TYPE source;
CK_VOID_PTR pSourceData;
CK_ULONG ulSourceDataLen;
} CK_RSA_PKCS_OAEP_PARAMS;
typedef CK_RSA_PKCS_OAEP_PARAMS CK_PTR CK_RSA_PKCS_OAEP_PARAMS_PTR;
#define CKZ_DATA_SPECIFIED 0x00000001
#define CKG_MGF1_SHA1 0x00000001
#define CKG_MGF1_SHA224 0x00000005
#define CKG_MGF1_SHA256 0x00000002
#define CKG_MGF1_SHA384 0x00000003
#define CKG_MGF1_SHA512 0x00000004
#define CKG_VENDOR_DEFINED 0x80000000UL
#define CKG_IBM_MGF1_SHA3_224 (CKG_VENDOR_DEFINED + 1)
#define CKG_IBM_MGF1_SHA3_256 (CKG_VENDOR_DEFINED + 2)
#define CKG_IBM_MGF1_SHA3_384 (CKG_VENDOR_DEFINED + 3)
#define CKG_IBM_MGF1_SHA3_512 (CKG_VENDOR_DEFINED + 4)
#define CKR_OK 0x00000000
#define CKR_VENDOR_DEFINED 0x80000000
#define CKO_PUBLIC_KEY 0x00000002
#define CKO_PRIVATE_KEY 0x00000003
#define CKK_EC 0x00000003
#define CKM_RSA_PKCS_KEY_PAIR_GEN 0x00000000
#define CKM_RSA_PKCS 0x00000001
#define CKM_RSA_PKCS_OAEP 0x00000009
#define CKM_RSA_X9_31_KEY_PAIR_GEN 0x0000000A
#define CKM_RSA_X9_31 0x0000000B
#define CKM_RSA_PKCS_PSS 0x0000000D
#define CKM_SHA_1 0x00000220
#define CKM_SHA256 0x00000250
#define CKM_SHA224 0x00000255
#define CKM_SHA384 0x00000260
#define CKM_SHA512 0x00000270
#define CKM_SHA512_224 0x00000048
#define CKM_SHA512_256 0x0000004C
#define CKM_EC_KEY_PAIR_GEN 0x00001040
#define CKM_ECDSA 0x00001041
#define CKM_VENDOR_DEFINED 0x80000000
#define CKM_IBM_SHA3_224 (CKM_VENDOR_DEFINED + 0x00010001)
#define CKM_IBM_SHA3_256 (CKM_VENDOR_DEFINED + 0x00010002)
#define CKM_IBM_SHA3_384 (CKM_VENDOR_DEFINED + 0x00010003)
#define CKM_IBM_SHA3_512 (CKM_VENDOR_DEFINED + 0x00010004)
#define CKA_CLASS 0x00000000
#define CKA_KEY_TYPE 0x00000100
#define CKA_SENSITIVE 0x00000103
#define CKA_ENCRYPT 0x00000104
#define CKA_DECRYPT 0x00000105
#define CKA_SIGN 0x00000108
#define CKA_VERIFY 0x0000010A
#define CKA_DERIVE 0x0000010C
#define CKA_DECRYPT 0x00000105
#define CKA_WRAP 0x00000106
#define CKA_UNWRAP 0x00000107
#define CKA_MODULUS_BITS 0x00000121
#define CKA_PUBLIC_EXPONENT 0x00000122
#define CKA_EC_PARAMS 0x00000180
#endif

View File

@@ -0,0 +1,234 @@
/*
* libseckey - Secure key library
*
* Copyright IBM Corp. 2021
*
* 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 SK_OPENSSL_H
#define SK_OPENSSL_H
#include <stddef.h>
#include <stdbool.h>
#include <openssl/evp.h>
#include <openssl/opensslv.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#ifndef OPENSSL_VERSION_PREREQ
#if defined(OPENSSL_VERSION_MAJOR) && defined(OPENSSL_VERSION_MINOR)
#define OPENSSL_VERSION_PREREQ(maj, min) \
((OPENSSL_VERSION_MAJOR << 16) + \
OPENSSL_VERSION_MINOR >= ((maj) << 16) + (min))
#else
#define OPENSSL_VERSION_PREREQ(maj, min) \
(OPENSSL_VERSION_NUMBER >= (((maj) << 28) | \
((min) << 20)))
#endif
#endif
/**
* External crypto library definitions
*/
struct sk_ext_cca_lib {
void *cca_lib; /* Handle of CCA host library loaded via dlopen */
};
typedef uint64_t target_t;
struct sk_ext_ep11_lib {
void *ep11_lib; /* Handle of EP11 host library loaded via dlopen */
target_t target; /* single or group target handle */
};
enum sk_ext_lib_type {
SK_EXT_LIB_CCA = 1,
SK_EXT_LIB_EP11 = 2,
};
struct sk_ext_lib {
enum sk_ext_lib_type type;
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 */
};
};
/*
* Secure key library initialization and termination functions
*/
int SK_OPENSSL_init(bool debug);
void SK_OPENSSL_term(void);
/*
* Secure key generation and reenciphering definitions and functions
*/
enum sk_key_type {
SK_KEY_TYPE_EC = 1,
SK_KEY_TYPE_RSA = 2,
};
struct sk_key_gen_info {
enum sk_key_type type;
union {
struct {
int curve_nid;
} ec;
struct {
size_t modulus_bits;
unsigned int pub_exp;
bool x9_31;
} rsa;
};
};
int SK_OPENSSL_generate_secure_key(unsigned char *secure_key,
size_t *secure_key_size,
const struct sk_key_gen_info *info,
const struct sk_ext_lib *ext_lib,
bool debug);
int SK_OPENSSL_reencipher_secure_key(unsigned char *secure_key,
size_t secure_key_size, bool to_new,
const struct sk_ext_lib *ext_lib,
bool debug);
/*
* Get an OpenSSL PKEY from a secure key to be used with OpenSSL.
*/
int SK_OPENSSL_get_secure_key_as_pkey(const unsigned char *secure_key,
size_t secure_key_size, bool rsa_pss,
EVP_PKEY **pkey,
const struct sk_ext_lib *ext_lib,
bool debug);
/*
* Get the public key parts from a secure key.
*/
struct sk_pub_key_info {
enum sk_key_type type;
union {
struct {
int curve_nid;
size_t prime_len;
const unsigned char *x;
const unsigned char *y;
} ec;
struct {
size_t modulus_len;
const unsigned char *modulus;
size_t pub_exp_len;
const unsigned char *pub_exp;
} rsa;
};
};
typedef int (*sk_pub_key_func_t)(const struct sk_pub_key_info *pub_key,
void *private);
int SK_OPENSSL_get_public_from_secure_key(const unsigned char *secure_key,
size_t secure_key_size,
sk_pub_key_func_t pub_key_cb,
void *private,
const struct sk_ext_lib *ext_lib,
bool debug);
/*
* Helper functions to setup a secure key sign context and to generate
* certificate signing requests or self signed certificates with the secure key
*/
struct sk_rsa_pss_params {
/*
* salt length in bytes, or OpenSSL constants
* RSA_PSS_SALTLEN_DIGEST (-1), RSA_PSS_SALTLEN_AUTO (-2), or
* RSA_PSS_SALTLEN_MAX(-3)
*/
int salt_len;
/*
* OpenSSl digest nid, or NID_undef to use the same digest algorithm
* as the signature algorithm
*/
int mgf_digest_nid;
};
int SK_OPENSSL_setup_sign_context(EVP_PKEY *pkey, bool verify, int digest_nid,
struct sk_rsa_pss_params *rsa_pss_params,
EVP_MD_CTX **md_ctx, EVP_PKEY_CTX **pkey_ctx,
bool debug);
int SK_OPENSSL_generate_csr(const unsigned char *secure_key,
size_t secure_key_size,
const char *subject_rdns[], size_t num_subject_rdns,
bool subject_utf8, const X509 *renew_cert,
const char *extensions[], size_t num_extensions,
int digest_nid,
struct sk_rsa_pss_params *rsa_pss_params,
X509_REQ **csr,
const struct sk_ext_lib *ext_lib, bool debug);
int SK_OPENSSL_generate_ss_cert(const unsigned char *secure_key,
size_t secure_key_size,
const char *subject_rdns[],
size_t num_subject_rdns, bool subject_utf8,
const X509 *renew_cert,
const char *extensions[], size_t num_extensions,
int validity_days, int digest_nid,
struct sk_rsa_pss_params *rsa_pss_params,
X509 **ss_cert,
const struct sk_ext_lib *ext_lib, bool debug);
/*
* Import secure keys as PKEY, or import clear public keys as PKEY
*/
typedef int (*sk_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, bool debug);
typedef int (*sk_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, bool debug);
typedef int (*sk_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,
bool debug);
typedef int (*sk_rsa_decrypt_t)(const unsigned char *key_blob,
size_t key_blob_length,
unsigned char *to, size_t *tolen,
const unsigned char *from, size_t fromlen,
int padding_type, void *private, bool debug);
typedef int (*sk_rsa_decrypt_oaep_t)(const unsigned char *key_blob,
size_t key_blob_length,
unsigned char *to, size_t *tolen,
const unsigned char *from, size_t fromlen,
int oaep_md_nid, int mgfmd_nid,
unsigned char *label, int label_len,
void *private, bool debug);
struct sk_funcs {
sk_rsa_sign_t rsa_sign;
sk_rsa_pss_sign_t rsa_pss_sign;
sk_ecdsa_sign_t ecdsa_sign;
sk_rsa_decrypt_t rsa_decrypt;
sk_rsa_decrypt_oaep_t rsa_decrypt_oaep;
};
int SK_OPENSSL_get_pkey(const unsigned char *secure_key, size_t secure_key_size,
const struct sk_pub_key_info *pub_key, bool rsa_pss,
const struct sk_funcs *sk_funcs, const void *private,
EVP_PKEY **pkey, bool debug);
int SK_OPENSSL_get_curve_from_ec_pkey(EVP_PKEY *pkey);
#endif

View File

@@ -0,0 +1,89 @@
/*
* libseckey - Secure key library
*
* Copyright IBM Corp. 2021
*
* 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 SK_UTILITIES_H
#define SK_UTILITIES_H
#include <stddef.h>
#include <stdbool.h>
#include <openssl/x509.h>
#include <openssl/obj_mac.h>
#include <openssl/evp.h>
#include "libseckey/sk_openssl.h"
void SK_UTIL_warnx(const char *func, const char *fmt, ...);
#define sk_debug(debug, fmt...) \
do { \
if (debug) \
SK_UTIL_warnx(__func__, fmt); \
} while (0)
/* EC curve information definitions and functions */
struct sk_ec_curve_info {
int curve_nid;
enum {
SK_EC_TYPE_PRIME = 0,
SK_EC_TYPE_BRAINPOOL = 1,
} type;
size_t prime_bits;
size_t prime_len;
const unsigned char *der; /* DER encoded OID */
size_t der_size;
};
const struct sk_ec_curve_info *SK_UTIL_ec_get_curve_info(int curve_nid);
int SK_UTIL_ec_get_prime_curve_by_prime_bits(size_t prime_bits);
int SK_UTIL_ec_get_brainpool_curve_by_prime_bits(size_t prime_bits);
int SK_UTIL_ec_calculate_y_coordinate(int nid, size_t prime_len,
const unsigned char *x, int y_bit,
unsigned char *y);
/* Digest information definitions and functions */
struct sk_digest_info {
int digest_nid;
size_t digest_size;
const char *cca_keyword;
const unsigned char *der; /* DER encoded SEQ of OID and OCT-STRING */
size_t der_size;
unsigned long pkcs11_mech;
unsigned long pkcs11_mgf;
unsigned char x9_31_md; /* X9.31 digest identifier */
};
const struct sk_digest_info *SK_UTIL_get_digest_info(int digest_nid);
/* Helper functions for certificate and CSR handling */
int SK_UTIL_build_subject_name(X509_NAME **name, const char *rdns[],
size_t num_rdns, bool utf8);
int SK_UTIL_build_certificate_extensions(X509 *cert, X509_REQ *req,
const char *exts[], size_t num_exts,
const STACK_OF(X509_EXTENSION)
*addl_exts);
int SK_UTIL_generate_x509_serial_number(X509 *cert, size_t sn_bit_size);
int SK_UTIL_build_ecdsa_signature(const unsigned char *raw_sig,
size_t raw_sig_len,
unsigned char *sig, size_t *sig_len);
/* Functions to read and write keys, certificates, requests, etc. */
int SK_UTIL_read_x509_certificate(const char *pem_filename, X509 **cert);
int SK_UTIL_write_x509_certificate(const char *pem_filename, X509 *cert);
int SK_UTIL_write_x509_request(const char *pem_filename, X509_REQ *req,
bool new_hdr);
int SK_UTIL_read_key_blob(const char *filename, unsigned char *key_blob,
size_t *key_blob_len);
int SK_UTIL_write_key_blob(const char *filename, unsigned char *key_blob,
size_t key_blob_len);
int SK_UTIL_read_public_key(const char *pem_filename, EVP_PKEY **pkey);
int SK_UTIL_write_public_key(const char *pem_filename, EVP_PKEY *pkey);
#endif

68
libseckey/Makefile Normal file
View File

@@ -0,0 +1,68 @@
include ../common.mak
lib = libseckey.a
ifneq (${HAVE_OPENSSL},0)
BUILD_TARGETS = $(lib)
else
BUILD_TARGETS = skip-libseckey
endif
TMPFILE := $(shell mktemp)
detect-openssl-version.dep:
echo "#include <openssl/opensslv.h>" > $(TMPFILE)
echo "#include <openssl/evp.h>" >> $(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-libseckey: detect-openssl-version.dep
$(call check_dep, \
"libseckey", \
"detect-openssl-version.dep", \
"openssl-devel version >= 1.1.1", \
"HAVE_OPENSSL=0", \
-I. -lcrypto -DOPENSSL_SUPPRESS_DEPRECATED)
touch check-dep-libseckey
objects = sk_openssl.o sk_pkeymeth.o sk_provider.o sk_utilities.o sk_cca.o sk_ep11.o
headers = $(rootdir)include/libseckey/sk_openssl.h $(rootdir)include/libseckey/sk_utilities.h \
$(rootdir)include/libseckey/sk_cca.h $(rootdir)include/libseckey/sk_ep11.h
ALL_CFLAGS += -fPIC
$(lib): $(objects)
sk_openssl.o: check-dep-libseckey sk_openssl.c $(headers)
sk_pkeymeth.o: check-dep-libseckey sk_pkeymeth.c $(headers)
sk_provider.o: check-dep-libseckey sk_provider.c $(headers)
sk_cca.o: check-dep-libseckey sk_cca.c $(headers)
sk_ep11.o: check-dep-libseckey sk_ep11.c $(headers)
all: $(BUILD_TARGETS)
skip-libseckey:
echo " SKIP libseckey due to HAVE_OPENSSL=0"
install: all
clean:
rm -f *.o $(lib) detect-openssl-version.dep check-dep-libseckey
.PHONY: all install clean skip-libseckey

1580
libseckey/sk_cca.c Normal file

File diff suppressed because it is too large Load Diff

1555
libseckey/sk_ep11.c Normal file

File diff suppressed because it is too large Load Diff

894
libseckey/sk_openssl.c Normal file
View File

@@ -0,0 +1,894 @@
/*
* libseckey - Secure key library
*
* Copyright IBM Corp. 2021
*
* 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 <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdbool.h>
#include <stdarg.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/sha.h>
#include <openssl/bn.h>
#include <openssl/ec.h>
#include <openssl/rsa.h>
#include <openssl/x509v3.h>
#include "lib/zt_common.h"
#include "libseckey/sk_openssl.h"
#include "libseckey/sk_utilities.h"
#include "libseckey/sk_cca.h"
#include "libseckey/sk_ep11.h"
#define SERIAL_NUMBER_BIT_SIZE 159
int sk_openssl_get_pkey_ec(const unsigned char *secure_key,
size_t secure_key_size, int nid, size_t prime_len,
const unsigned char *x, const unsigned char *y,
const struct sk_funcs *sk_funcs, const void *private,
EVP_PKEY **pkey, bool debug);
int sk_openssl_get_pkey_rsa(const unsigned char *secure_key,
size_t secure_key_size,
const unsigned char *modulus, size_t modulus_length,
const unsigned char *pub_exp, size_t pub_exp_length,
int pkey_type, const struct sk_funcs *sk_funcs,
const void *private, EVP_PKEY **pkey, bool debug);
/**
* Generate a secure key using the specified secure key crypto library.
*
* @param secure_key A buffer where the secure key is stored to. If NULL,
* the required buffer size is returned in
* secure_key_size (size query).
* @param secure_key_size On entry, the size of the buffer specified with
* secure_key (ignored if secure_key is NULL),
* on exit the size of the secure key.
* @param info key generation info, such as key type (EC or RSA)
* and key parameters.
* @param ext_lib External secure key crypto library to use
* @param debug if true, debug messages are printed
*
* @returns a negative errno in case of an error, 0 if success.
*/
int SK_OPENSSL_generate_secure_key(unsigned char *secure_key,
size_t *secure_key_size,
const struct sk_key_gen_info *info,
const struct sk_ext_lib *ext_lib, bool debug)
{
int rc;
if (info == NULL || ext_lib == NULL || secure_key_size == NULL)
return -EINVAL;
sk_debug(debug, "ext-lib type: %d key type: %d", ext_lib->type,
info->type);
switch (ext_lib->type) {
case SK_EXT_LIB_CCA:
switch (info->type) {
case SK_KEY_TYPE_EC:
rc = SK_CCA_generate_ec_key_pair(ext_lib->cca,
info->ec.curve_nid,
secure_key, secure_key_size,
debug);
break;
case SK_KEY_TYPE_RSA:
rc = SK_CCA_generate_rsa_key_pair(ext_lib->cca,
info->rsa.modulus_bits,
info->rsa.pub_exp,
secure_key, secure_key_size,
debug);
break;
default:
sk_debug(debug, "ERROR: Invalid key type: %d",
info->type);
return -EINVAL;
}
break;
case SK_EXT_LIB_EP11:
switch (info->type) {
case SK_KEY_TYPE_EC:
rc = SK_EP11_generate_ec_key_pair(ext_lib->ep11,
info->ec.curve_nid,
secure_key, secure_key_size,
debug);
break;
case SK_KEY_TYPE_RSA:
rc = SK_EP11_generate_rsa_key_pair(ext_lib->ep11,
info->rsa.modulus_bits,
info->rsa.pub_exp,
info->rsa.x9_31,
secure_key, secure_key_size,
debug);
break;
default:
sk_debug(debug, "ERROR: Invalid key type: %d",
info->type);
return -EINVAL;
}
break;
default:
sk_debug(debug, "ERROR: Invalid ext-lib type: %d",
ext_lib->type);
return -EINVAL;
}
if (rc != 0) {
sk_debug(debug, "ERROR: Failed to generate a key: rc: %d - %s",
rc, strerror(-rc));
return rc;
}
return 0;
}
/**
* Reenciphers a secure key with a new master key using the specified secure
* key crypto library.
*
* @param secure_key the key token containing an secure key
* @param secure_key_size the size of the key token
* @param to_new if true, reencipher with the MK in then NEW register
* @param ext_lib External secure key crypto library to use
* @param debug if true, debug messages are printed
*
* @returns a negative errno in case of an error, 0 if success.
*/
int SK_OPENSSL_reencipher_secure_key(unsigned char *secure_key,
size_t secure_key_size, bool to_new,
const struct sk_ext_lib *ext_lib,
bool debug)
{
int rc;
if (ext_lib == NULL || secure_key == NULL)
return -EINVAL;
sk_debug(debug, "ext-lib type: %d to_new: %d", ext_lib->type, to_new);
switch (ext_lib->type) {
case SK_EXT_LIB_CCA:
rc = SK_CCA_reencipher_key(ext_lib->cca, secure_key,
secure_key_size, to_new, debug);
break;
case SK_EXT_LIB_EP11:
rc = SK_EP11_reencipher_key(ext_lib->ep11, secure_key,
secure_key_size, debug);
break;
default:
sk_debug(debug, "ERROR: Invalid ext lib type: %d",
ext_lib->type);
return -EINVAL;
}
if (rc != 0) {
sk_debug(debug,
"ERROR: Failed to reencipher a key: rc: %d - %s",
rc, strerror(-rc));
return rc;
}
return 0;
}
/**
* Extracts the public key from a secure key, and returns it as OpenSSL PKEY.
*
* @param secure_key the key token containing an secure key
* @param secure_key_size the size of the key token
* @param rsa_pss if the secure key is a RSA key, return a PKEY of
* type EVP_PKEY_RSA_PSS
* @param pkey On return: a PKEY containing the public key
* @param ext_lib External secure key crypto library to use
* @param debug if true, debug messages are printed
*
* @returns a negative errno in case of an error, 0 if success.
*/
int SK_OPENSSL_get_secure_key_as_pkey(const unsigned char *secure_key,
size_t secure_key_size, bool rsa_pss,
EVP_PKEY **pkey,
const struct sk_ext_lib *ext_lib,
bool debug)
{
int rc;
if (ext_lib == NULL || secure_key == NULL || pkey == NULL)
return -EINVAL;
sk_debug(debug, "ext-lib type: %d rsa_pss: %d", ext_lib->type, rsa_pss);
switch (ext_lib->type) {
case SK_EXT_LIB_CCA:
rc = SK_CCA_get_secure_key_as_pkey(ext_lib->cca, secure_key,
secure_key_size, rsa_pss,
pkey, debug);
break;
case SK_EXT_LIB_EP11:
rc = SK_EP11_get_secure_key_as_pkey(ext_lib->ep11, secure_key,
secure_key_size, rsa_pss,
pkey, debug);
break;
default:
sk_debug(debug, "ERROR: Invalid ext lib type: %d",
ext_lib->type);
return -EINVAL;
}
if (rc != 0) {
sk_debug(debug, "ERROR: Failed to get PKEY: rc: %d - %s",
rc, strerror(-rc));
return rc;
}
sk_debug(debug, "pkey: %p", *pkey);
return 0;
}
/**
* Extracts the public key from a secure key, and calls the specified callback
* function with the public key information.
*
* @param secure_key the key token containing an secure key
* @param secure_key_size the size of the key token
* @param pub_key_cb the callback function to call with the public key
* @param private a private pointer passed as is to the callback
* @param ext_lib External secure key crypto library to use
* @param debug if true, debug messages are printed
*
* @returns a negative errno in case of an error, 0 if success.
*/
int SK_OPENSSL_get_public_from_secure_key(const unsigned char *secure_key,
size_t secure_key_size,
sk_pub_key_func_t pub_key_cb,
void *private,
const struct sk_ext_lib *ext_lib,
bool debug)
{
int rc;
if (ext_lib == NULL || secure_key == NULL || pub_key_cb == NULL)
return -EINVAL;
sk_debug(debug, "ext-lib type: %d", ext_lib->type);
switch (ext_lib->type) {
case SK_EXT_LIB_CCA:
rc = SK_CCA_get_public_from_secure_key(secure_key,
secure_key_size,
pub_key_cb, private,
debug);
break;
case SK_EXT_LIB_EP11:
rc = SK_EP11_get_public_from_secure_key(secure_key,
secure_key_size,
pub_key_cb, private,
debug);
break;
default:
sk_debug(debug, "ERROR: Invalid ext lib type: %d",
ext_lib->type);
return -EINVAL;
}
if (rc != 0) {
sk_debug(debug, "ERROR: Failed to get PKEY: rc: %d - %s",
rc, strerror(-rc));
return rc;
}
return 0;
}
/**
* Converts a key given by the public key infos into an OpenSSL PKEY and
* attaches the secure key together with secure key functions and private
* pointer to it. If no secure key is provided, a public key only PKEY is
* returned.
*
* @param secure_key the secure key blob.
* If NULL, a clear key PKEY is created.
* @param secure_key_size the size of the secure key blob (ignored if
* secure_key is NULL)
* @param pub_key the public key info
* @param rsa_pss For RSA public keys: create a RSA-PSS type PKEY
* @param sk_funcs the secure key functions to operate with the key.
* Ignored if secure_key is NULL, required otherwise.
* @param private a private pointer that is passed to the secure key
* functions (can be NULL)
* @param pkey On return: A PKEY containing the EC public key.
* @param debug true to enable internal debugging
*
* @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 SK_OPENSSL_get_pkey(const unsigned char *secure_key, size_t secure_key_size,
const struct sk_pub_key_info *pub_key, bool rsa_pss,
const struct sk_funcs *sk_funcs, const void *private,
EVP_PKEY **pkey, bool debug)
{
int rc;
if (pub_key == NULL)
return -EINVAL;
sk_debug(debug, "key type: %d", pub_key->type);
switch (pub_key->type) {
case SK_KEY_TYPE_EC:
rc = sk_openssl_get_pkey_ec(secure_key, secure_key_size,
pub_key->ec.curve_nid,
pub_key->ec.prime_len,
pub_key->ec.x, pub_key->ec.y,
sk_funcs, private,
pkey, debug);
if (rc != 0) {
sk_debug(debug,
"ERROR: SK_OPENSSL_get_pkey_ec failed");
return rc;
}
break;
case SK_KEY_TYPE_RSA:
rc = sk_openssl_get_pkey_rsa(secure_key, secure_key_size,
pub_key->rsa.modulus,
pub_key->rsa.modulus_len,
pub_key->rsa.pub_exp,
pub_key->rsa.pub_exp_len,
rsa_pss ? EVP_PKEY_RSA_PSS :
EVP_PKEY_RSA,
sk_funcs, private,
pkey, debug);
if (rc != 0) {
sk_debug(debug,
"ERROR: SK_OPENSSL_get_pkey_rsa failed");
return rc;
}
break;
default:
sk_debug(debug, "ERROR: Invalid key type: %d",
pub_key->type);
return -EINVAL;
}
sk_debug(debug, "pkey: %p", pkey);
return 0;
}
/**
* Sets up a digest sign context with the specified PKEY.
*
* @param pkey the PKEY to use
* @param verify if true a verify context is created, otherwise a
* sign context
* @param digest_nid the NID of the digest algorithm to use. If
* NID_undef, then the PKEY's default digest is used.
* @param rsa_pss_params RSA-PSS parameters (if PKEY is a RSA-PSS key)
* @param md_ctx On return: the MD context that was set up
* @param pkey_ctx On return: the PKEY context that was set up.
* Note: The PKEY context value returned must not be
* freed by the application, it will be freed
* automatically when the MD context is freed.
* @param debug if true, debug messages are printed
*
* @returns a negative errno in case of an error, 0 if success.
*/
int SK_OPENSSL_setup_sign_context(EVP_PKEY *pkey, bool verify, int digest_nid,
struct sk_rsa_pss_params *rsa_pss_params,
EVP_MD_CTX **md_ctx, EVP_PKEY_CTX **pkey_ctx,
bool debug)
{
EVP_PKEY_CTX *pctx = NULL;
const EVP_MD *md = NULL;
int rc, default_nid;
EVP_MD_CTX *ctx;
sk_debug(debug, "pkey: %p verify: %d digest_nid: %d", pkey, verify,
digest_nid);
ctx = EVP_MD_CTX_new();
if (ctx == NULL) {
sk_debug(debug, "ERROR: Failed to allocate the digest context");
rc = -ENOMEM;
goto out;
}
if (digest_nid != NID_undef) {
md = EVP_get_digestbynid(digest_nid);
if (md == NULL) {
sk_debug(debug,
"ERROR: Requested digest not supported");
rc = -ENOTSUP;
goto out;
}
if (EVP_PKEY_get_default_digest_nid(pkey, &default_nid) == 2 &&
default_nid == 0) {
sk_debug(debug, "ERROR: The signing algorithm requires "
"there to be no digest");
md = NULL;
}
}
if (verify)
rc = EVP_DigestVerifyInit(ctx, &pctx, md, NULL, pkey);
else
rc = EVP_DigestSignInit(ctx, &pctx, md, NULL, pkey);
if (rc != 1) {
sk_debug(debug, "ERROR: Failed to initialize the signing "
"operation");
rc = -EIO;
goto out;
}
if (EVP_PKEY_id(pkey) == EVP_PKEY_RSA_PSS && rsa_pss_params != NULL) {
sk_debug(debug, "RSA-PSS: saltlen: %d mgf_digest_nid: %d",
rsa_pss_params->salt_len,
rsa_pss_params->mgf_digest_nid);
rc = EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING);
if (rc != 1) {
sk_debug(debug,
"ERROR: Failed to set the PSS padding mode");
rc = -EIO;
goto out;
}
rc = EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx,
rsa_pss_params->salt_len);
if (rc != 1) {
sk_debug(debug,
"ERROR: Failed to set the PSS salt length");
rc = -EIO;
goto out;
}
if (rsa_pss_params->mgf_digest_nid != 0) {
md = EVP_get_digestbynid(
rsa_pss_params->mgf_digest_nid);
if (md == NULL) {
sk_debug(debug,
"ERROR: Requested MGF digest not "
"supported");
rc = -ENOENT;
goto out;
}
rc = EVP_PKEY_CTX_set_rsa_mgf1_md(pctx, md);
if (rc != 1) {
sk_debug(debug,
"ERROR: Failed to set the MGF md");
rc = -EIO;
goto out;
}
}
}
rc = 0;
*md_ctx = ctx;
*pkey_ctx = pctx;
out:
if (rc != 0 && ctx != NULL)
EVP_MD_CTX_free(ctx);
return rc;
}
/**
* Generate a certificate signing request using the secure key 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 the existing certificate file with
* renew_cert_filename, 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 key with an signing algorithm matching
* the secure key type (ECDSA, RSA-PKCS, or RSA-PSS if rsa_pss_params is not
* NULL), and the specified digest. If the digest nid is NID_undef, then a
* default digest is used.
*
* @param secure_key the key token containing an secure key
* @param secure_key_size the size of the key token
* @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 if not NULL, specifies the 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 NID_undef to use the default
* @param rsa_pss_params if not NULL and the secure key is an RSA key, then
* the CSR is signed with RSA-PSS using the specified
* PSS parameters. Ignored if the secure key is an EC
* key
* @param csr On return: the generated CSR. Must be freed by the
* caller using X509_REQ_free.
* @param ext_lib External secure key crypto library to use
* @param debug if true, debug 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 SK_OPENSSL_generate_csr(const unsigned char *secure_key,
size_t secure_key_size,
const char *subject_rdns[], size_t num_subject_rdns,
bool subject_utf8, const X509 *renew_cert,
const char *extensions[], size_t num_extensions,
int digest_nid,
struct sk_rsa_pss_params *rsa_pss_params,
X509_REQ **csr,
const struct sk_ext_lib *ext_lib, bool debug)
{
const STACK_OF(X509_EXTENSION) *cert_exts = NULL;
X509_NAME *subject_name = NULL;
EVP_PKEY_CTX *pkey_ctx = NULL;
EVP_MD_CTX *md_ctx = NULL;
EVP_PKEY *pkey = NULL;
X509_REQ *req = NULL;
int rc;
if (secure_key == NULL || ext_lib == NULL || csr == NULL)
return -EINVAL;
if (renew_cert == NULL &&
(subject_rdns == NULL || num_subject_rdns == 0))
return -EINVAL;
if (num_extensions != 0 && extensions == NULL)
return -EINVAL;
rc = SK_OPENSSL_get_secure_key_as_pkey(secure_key, secure_key_size,
rsa_pss_params != NULL, &pkey,
ext_lib, debug);
if (rc != 0) {
sk_debug(debug,
"ERROR: SK_OPENSSL_get_secure_key_as_pkey failed");
goto out;
}
req = X509_REQ_new();
if (req == NULL) {
sk_debug(debug, "ERROR: X509_REQ_new failed");
rc = -ENOMEM;
goto out;
}
rc = X509_REQ_set_version(req, 0L);
if (rc != 1) {
sk_debug(debug, "ERROR: X509_REQ_set_version failed: rc: %d",
rc);
rc = -EIO;
goto out;
}
if (renew_cert != NULL) {
subject_name = X509_NAME_dup(X509_get_subject_name(renew_cert));
cert_exts = X509_get0_extensions(renew_cert);
}
if (subject_rdns != NULL && num_subject_rdns > 0) {
rc = SK_UTIL_build_subject_name(&subject_name, subject_rdns,
num_subject_rdns, subject_utf8);
if (rc != 0) {
sk_debug(debug, "ERROR: Failed to parse the subject "
"name RDNs: %s", strerror(-rc));
goto out;
}
}
if (subject_name == NULL) {
rc = -EINVAL;
sk_debug(debug, "ERROR: Subject name can not be empty");
goto out;
}
rc = X509_REQ_set_subject_name(req, subject_name);
if (rc != 1) {
rc = -EIO;
sk_debug(debug,
"ERROR: Failed to set subject name into request");
goto out;
}
rc = SK_UTIL_build_certificate_extensions(NULL, req, extensions,
num_extensions, cert_exts);
if (rc != 0) {
sk_debug(debug, "ERROR: Failed to parse the extensions: "
"%s", strerror(-rc));
goto out;
}
rc = X509_REQ_set_pubkey(req, pkey);
if (rc != 1) {
sk_debug(debug, "ERROR: Failed to set the public key");
rc = -EIO;
goto out;
}
rc = SK_OPENSSL_setup_sign_context(pkey, false, digest_nid,
rsa_pss_params, &md_ctx, &pkey_ctx,
debug);
if (rc != 0) {
sk_debug(debug, "ERROR: SK_OPENSSL_setup_sign_context failed");
goto out;
}
rc = X509_REQ_sign_ctx(req, md_ctx);
if (rc <= 0) {
sk_debug(debug,
"ERROR: Failed to perform the signing operation");
rc = -EIO;
goto out;
}
if (debug) {
sk_debug(debug, "Certificate Signing Request created:");
X509_REQ_print_fp(stderr, req);
}
*csr = req;
req = NULL;
rc = 0;
out:
if (md_ctx != NULL)
EVP_MD_CTX_free(md_ctx);
if (subject_name != NULL)
X509_NAME_free(subject_name);
if (req != NULL)
X509_REQ_free(req);
if (pkey != NULL)
EVP_PKEY_free(pkey);
return rc;
}
/**
* Generate a self signed certificate using the secure key with the
* specified subject name, certificate extensions (if any), and writes the
* certificate to the specified file in PEM format.
*
* To renew an existing certificate, specify the existing certificate file with
* renew_cert_filename, 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 certificate.
*
* The certificate is signed using the secure key with an signing algorithm
* matching the secure key type (ECDSA, RSA-PKCS, or RSA-PSS if rsa_pss_params
* is not NULL), and the specified digest. If the digest nid is NID_undef, then
* a default digest is used.
*
* @param secure_key the key token containing an secure key
* @param secure_key_size the size of the key token
* @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 if not NULL, specifies 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 NID_undef to use the default
* @param rsa_pss_params if not NULL and the secure key is an RSA key, then
* the certificate is signed with RSA-PSS using the
* specified PSS parameters. Ignored if the secure
* key is an EC key
* @param ss_cert On return: The generated self signed certificate.
* Must be freed by the caller using X509_free.
* @param ext_lib External secure key crypto library to use
* @param debug if true, debug 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 SK_OPENSSL_generate_ss_cert(const unsigned char *secure_key,
size_t secure_key_size,
const char *subject_rdns[],
size_t num_subject_rdns, bool subject_utf8,
const X509 *renew_cert,
const char *extensions[], size_t num_extensions,
int validity_days, int digest_nid,
struct sk_rsa_pss_params *rsa_pss_params,
X509 **ss_cert,
const struct sk_ext_lib *ext_lib, bool debug)
{
const STACK_OF(X509_EXTENSION) *cert_exts = NULL;
X509_NAME *subject_name = NULL;
EVP_PKEY_CTX *pkey_ctx = NULL;
EVP_MD_CTX *md_ctx = NULL;
EVP_PKEY *pkey = NULL;
X509 *cert = NULL;
int rc;
if (ext_lib == NULL || ss_cert == NULL)
return -EINVAL;
if (secure_key == NULL)
return -EINVAL;
if (renew_cert == NULL &&
(subject_rdns == NULL || num_subject_rdns == 0))
return -EINVAL;
if (num_extensions != 0 && extensions == NULL)
return -EINVAL;
rc = SK_OPENSSL_get_secure_key_as_pkey(secure_key, secure_key_size,
rsa_pss_params != NULL, &pkey,
ext_lib, debug);
if (rc != 0) {
sk_debug(debug,
"ERROR: SK_OPENSSL_get_secure_key_as_pkey failed");
goto out;
}
cert = X509_new();
if (cert == NULL) {
sk_debug(debug, "ERROR: X509_new failed");
rc = -ENOMEM;
goto out;
}
rc = X509_set_version(cert, 2L);
if (rc != 1) {
sk_debug(debug, "ERROR: X509_set_version failed: rc: %d", rc);
rc = -EIO;
goto out;
}
rc = SK_UTIL_generate_x509_serial_number(cert, SERIAL_NUMBER_BIT_SIZE);
if (rc != 0) {
sk_debug(debug, "ERROR: Failed to set the serial number: %s",
strerror(-rc));
goto out;
}
if (renew_cert != NULL) {
subject_name = X509_NAME_dup(X509_get_subject_name(renew_cert));
cert_exts = X509_get0_extensions(renew_cert);
}
if (subject_rdns != NULL && num_subject_rdns > 0) {
rc = SK_UTIL_build_subject_name(&subject_name, subject_rdns,
num_subject_rdns, subject_utf8);
if (rc != 0) {
sk_debug(debug, "ERROR: Failed to parse the subject "
"name RDNs: %s", strerror(-rc));
goto out;
}
}
if (subject_name == NULL) {
rc = -EINVAL;
sk_debug(debug, "ERROR: Subject name can not be empty");
goto out;
}
rc = X509_set_subject_name(cert, subject_name);
if (rc != 1) {
rc = -EIO;
sk_debug(debug, "ERROR: Failed to set subject name into cert");
goto out;
}
rc = X509_set_issuer_name(cert, subject_name);
if (rc != 1) {
rc = -EIO;
sk_debug(debug, "ERROR: Failed to set issuer name into cert");
goto out;
}
rc = SK_UTIL_build_certificate_extensions(cert, NULL, extensions,
num_extensions, cert_exts);
if (rc != 0) {
sk_debug(debug, "ERROR: Failed to parse the extensions: "
"%s", strerror(-rc));
goto out;
}
if (X509_gmtime_adj(X509_getm_notBefore(cert), 0) == NULL) {
rc = -EIO;
sk_debug(debug,
"ERROR: 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;
sk_debug(debug, "ERROR: Failed to set notAfter time into cert");
goto out;
}
rc = X509_set_pubkey(cert, pkey);
if (rc != 1) {
sk_debug(debug, "ERROR: Failed to set the public key");
rc = -EIO;
goto out;
}
rc = SK_OPENSSL_setup_sign_context(pkey, false, digest_nid,
rsa_pss_params, &md_ctx, &pkey_ctx,
debug);
if (rc != 0) {
sk_debug(debug, "ERROR: SK_OPENSSL_setup_sign_context failed");
goto out;
}
rc = X509_sign_ctx(cert, md_ctx);
if (rc <= 0) {
sk_debug(debug,
"ERROR: Failed to perform the signing operation");
rc = -EIO;
goto out;
}
if (debug) {
sk_debug(debug, "Self-signed Certificate created:");
X509_print_fp(stderr, cert);
}
*ss_cert = cert;
cert = NULL;
rc = 0;
out:
if (md_ctx != NULL)
EVP_MD_CTX_free(md_ctx);
if (subject_name != NULL)
X509_NAME_free(subject_name);
if (cert != NULL)
X509_free(cert);
if (pkey != NULL)
EVP_PKEY_free(pkey);
return rc;
}

1111
libseckey/sk_pkeymeth.c Normal file

File diff suppressed because it is too large Load Diff

5079
libseckey/sk_provider.c Normal file

File diff suppressed because it is too large Load Diff

1058
libseckey/sk_utilities.c Normal file

File diff suppressed because it is too large Load Diff