diff options
author | Selva Nair | 2021-12-14 11:59:24 -0500 |
---|---|---|
committer | Gert Doering | 2022-01-20 17:59:30 +0100 |
commit | 6121001ed82914f336da081bb8aefaeb055450cb (patch) | |
tree | 55237cfd7731bd881468e39c13dab0066dd4e644 /src/openvpn/pkcs11_openssl.c | |
parent | b64c9eb31824dd46c949d071751f8aebc008004c (diff) | |
download | openvpn-6121001ed82914f336da081bb8aefaeb055450cb.zip openvpn-6121001ed82914f336da081bb8aefaeb055450cb.tar.gz |
pkcs11: Interface the xkey provider with pkcs11-helper
- Load the 'private key' handle through the provider and set it in
SSL_CTX
- Add a sign op function to interface provider with pkcs11-helper.
Previously we used its "OpenSSL Session" which internally sets up
callbacks in RSA and EC key methods. Not useful for the provider
interface, so, we directly call the PKCS#11 sign operation
as done with mbedTLS.
- tls_libctx is made global for accessing from pkcs11_openssl.c
Supports ECDSA and RSA_PKCS1_PADDING signatures. PSS support
will be added when pkcs11-helper with our PR for specifying
CK_MECHANISM variable in sign operations is released.
(i.e., next release of pkcs11-helper).
Signed-off-by: Selva Nair <selva.nair@gmail.com>
Acked-by: Arne Schwabe <arne@rfc2549.org>
Message-Id: <20211214165928.30676-15-selva.nair@gmail.com>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg23442.html
Signed-off-by: Gert Doering <gert@greenie.muc.de>
Diffstat (limited to 'src/openvpn/pkcs11_openssl.c')
-rw-r--r-- | src/openvpn/pkcs11_openssl.c | 151 |
1 files changed, 151 insertions, 0 deletions
diff --git a/src/openvpn/pkcs11_openssl.c b/src/openvpn/pkcs11_openssl.c index b29504b..9cf46b2 100644 --- a/src/openvpn/pkcs11_openssl.c +++ b/src/openvpn/pkcs11_openssl.c @@ -39,12 +39,163 @@ #include "errlevel.h" #include "pkcs11_backend.h" #include "ssl_verify.h" +#include "xkey_common.h" #include <pkcs11-helper-1.0/pkcs11h-openssl.h> +#ifdef HAVE_XKEY_PROVIDER +static XKEY_EXTERNAL_SIGN_fn xkey_pkcs11h_sign; + +/** + * Sign op called from xkey provider + * + * We support ECDSA, RSA_NO_PADDING, RSA_PKCS1_PADDING + */ +static int +xkey_pkcs11h_sign(void *handle, unsigned char *sig, + size_t *siglen, const unsigned char *tbs, size_t tbslen, XKEY_SIGALG sigalg) +{ + pkcs11h_certificate_t cert = handle; + CK_MECHANISM mech = {CKM_RSA_PKCS, NULL, 0}; /* default value */ + + unsigned char buf[EVP_MAX_MD_SIZE]; + size_t buflen; + + if (!strcmp(sigalg.op, "DigestSign")) + { + dmsg(D_LOW, "xkey_pkcs11h_sign: computing digest"); + if (xkey_digest(tbs, tbslen, buf, &buflen, sigalg.mdname)) + { + tbs = buf; + tbslen = (size_t) buflen; + sigalg.op = "Sign"; + } + else + { + return 0; + } + } + + if (!strcmp(sigalg.keytype, "EC")) + { + mech.mechanism = CKM_ECDSA; + } + else if (!strcmp(sigalg.keytype, "RSA")) + { + if (!strcmp(sigalg.padmode,"none")) + { + mech.mechanism = CKM_RSA_X_509; + } + else if (!strcmp(sigalg.padmode, "pss")) + { + msg(M_NONFATAL, "PKCS#11: Error: PSS padding is not yet supported."); + return 0; + } + else if (!strcmp(sigalg.padmode, "pkcs1")) + { + /* CMA_RSA_PKCS needs pkcs1 encoded digest */ + + unsigned char enc[EVP_MAX_MD_SIZE + 32]; /* 32 bytes enough for DigestInfo header */ + size_t enc_len = sizeof(enc); + + if (!encode_pkcs1(enc, &enc_len, sigalg.mdname, tbs, tbslen)) + { + return 0; + } + tbs = enc; + tbslen = enc_len; + } + else /* should not happen */ + { + msg(M_WARN, "PKCS#11: Unknown padmode <%s>", sigalg.padmode); + } + } + else + { + ASSERT(0); /* coding error -- we couldnt have created any such key */ + } + + return CKR_OK == pkcs11h_certificate_signAny(cert, mech.mechanism, + tbs, tbslen, sig, siglen); +} + +/* wrapper for handle free */ +static void +xkey_handle_free(void *handle) +{ + pkcs11h_certificate_freeCertificate(handle); +} + + +/** + * Load certificate and public key from pkcs11h to SSL_CTX + * through xkey provider. + * + * @param certificate pkcs11h certificate object + * @param ctx OpenVPN root tls context + * + * @returns 1 on success, 0 on error to match + * other xkey_load_.. routines + */ +static int +xkey_load_from_pkcs11h(pkcs11h_certificate_t certificate, + struct tls_root_ctx *const ctx) +{ + int ret = 0; + + X509 *x509 = pkcs11h_openssl_getX509(certificate); + if (!x509) + { + msg(M_WARN, "PKCS#11: Unable get x509 certificate object"); + return 0; + } + + EVP_PKEY *pubkey = X509_get0_pubkey(x509); + + XKEY_PRIVKEY_FREE_fn *free_op = xkey_handle_free; /* it calls pkcs11h_..._freeCertificate() */ + XKEY_EXTERNAL_SIGN_fn *sign_op = xkey_pkcs11h_sign; + + EVP_PKEY *pkey = xkey_load_generic_key(tls_libctx, certificate, pubkey, sign_op, free_op); + if (!pkey) + { + msg(M_WARN, "PKCS#11: Failed to load private key into xkey provider"); + goto cleanup; + } + /* provider took ownership of the pkcs11h certificate object -- do not free below */ + certificate = NULL; + + if (!SSL_CTX_use_cert_and_key(ctx->ctx, x509, pkey, NULL, 0)) + { + msg(M_WARN, "PKCS#11: Failed to set cert and private key for OpenSSL"); + goto cleanup; + } + ret = 1; + +cleanup: + if (x509) + { + X509_free(x509); + } + if (pkey) + { + EVP_PKEY_free(pkey); + } + if (certificate) + { + pkcs11h_certificate_freeCertificate(certificate); + } + return ret; +} +#endif /* HAVE_XKEY_PROVIDER */ + int pkcs11_init_tls_session(pkcs11h_certificate_t certificate, struct tls_root_ctx *const ssl_ctx) { + +#ifdef HAVE_XKEY_PROVIDER + return (xkey_load_from_pkcs11h(certificate, ssl_ctx) == 0); /* inverts the return value */ +#endif + int ret = 1; X509 *x509 = NULL; |