[Openvpn-devel,v3,13/18] Add a generic key loading helper function for xkey provider

Message ID 20211214165928.30676-14-selva.nair@gmail.com
State Accepted
Headers show
Series External key provider for use with OpenSSL 3 | expand

Commit Message

Selva Nair Dec. 14, 2021, 5:59 a.m. UTC
From: Selva Nair <selva.nair@gmail.com>

- Load keys by specifying the opaque privtae key handle,
  public key, sign-op and free-op required for loading keys
  from Windows store and pkcs11.

- xkey_load_management_key is refactored to use the new function

- Also make xkey_digest non-static

Used in following commits to load CNG and pkcs11 keys

Signed-off-by: Selva Nair <selva.nair@gmail.com>
---
 src/openvpn/xkey_common.h | 35 +++++++++++++++++++++++++++++++++++
 src/openvpn/xkey_helper.c | 37 +++++++++++++++++++++++++++++++------
 2 files changed, 66 insertions(+), 6 deletions(-)

Comments

Arne Schwabe Jan. 20, 2022, 12:11 a.m. UTC | #1
Am 14.12.21 um 17:59 schrieb selva.nair@gmail.com:
> From: Selva Nair <selva.nair@gmail.com>
> 
> - Load keys by specifying the opaque privtae key handle,
>    public key, sign-op and free-op required for loading keys
>    from Windows store and pkcs11.
> 
> - xkey_load_management_key is refactored to use the new function
> 
> - Also make xkey_digest non-static
> 
> Used in following commits to load CNG and pkcs11 keys
>


Acked-By: Arne Schwabe <arne@rfc2549.org>
Gert Doering Jan. 20, 2022, 5:58 a.m. UTC | #2
I knew fixing that "avaiable" typo would come back and bite me :-)

Client tested with 3.0.1, and glanced at the code a bit.

Fixed a comment typo ("callng free_op").

Your patch has been applied to the master branch.

commit b64c9eb31824dd46c949d071751f8aebc008004c
Author: Selva Nair
Date:   Tue Dec 14 11:59:23 2021 -0500

     Add a generic key loading helper function for xkey provider

     Signed-off-by: Selva Nair <selva.nair@gmail.com>
     Acked-by: Arne Schwabe <arne@rfc2549.org>
     Message-Id: <20211214165928.30676-14-selva.nair@gmail.com>
     URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg23436.html
     Signed-off-by: Gert Doering <gert@greenie.muc.de>


--
kind regards,

Gert Doering

Patch

diff --git a/src/openvpn/xkey_common.h b/src/openvpn/xkey_common.h
index c04c9c5c..e2ddc178 100644
--- a/src/openvpn/xkey_common.h
+++ b/src/openvpn/xkey_common.h
@@ -116,6 +116,41 @@  bool
 encode_pkcs1(unsigned char *enc, size_t *enc_len, const char *mdname,
              const unsigned char *tbs, size_t tbslen);
 
+/**
+ * Compute message digest
+ *
+ * @param src           pointer to message to be hashed
+ * @param srclen        length of data in bytes
+ * @param buf           pointer to output buffer
+ * @param buflen        *buflen = capacity in bytes of output buffer
+ * @param mdname        name of the hash algorithm (SHA256, SHA1 etc.)
+ *
+ * @return              false on error, true  on success
+ *
+ * On successful return *buflen is set to the actual size of the result.
+ * TIP: EVP_MD_MAX_SIZE should be enough capacity of buf for al algorithms.
+ */
+int
+xkey_digest(const unsigned char *src, size_t srclen, unsigned char *buf,
+            size_t *buflen, const char *mdname);
+
+/**
+ * Load a generic external key with custom sign and free ops
+ *
+ * @param libctx    library context in which xkey provider has been loaded
+ * @param handle    an opaque handle to the backend -- passed to alll callbacks
+ * @param pubkey    corresponding pubkey in the default provider's context
+ * @param sign_op   private key signature operation to callback
+ * @param sign_op   private key signature operation to callback
+ *
+ * @returns a new EVP_PKEY in the provider's keymgmt context.
+ * IMPORTANT: a reference to the handle is retained by the provider and
+ * relased by callng free_op. The caller should not free it.
+ */
+EVP_PKEY *
+xkey_load_generic_key(OSSL_LIB_CTX *libctx, void *handle, EVP_PKEY *pubkey,
+                      XKEY_EXTERNAL_SIGN_fn sign_op, XKEY_PRIVKEY_FREE_fn free_op);
+
 #endif /* HAVE_XKEY_PROVIDER */
 
 #endif /* XKEY_COMMON_H_ */
diff --git a/src/openvpn/xkey_helper.c b/src/openvpn/xkey_helper.c
index d09ad635..19de64ff 100644
--- a/src/openvpn/xkey_helper.c
+++ b/src/openvpn/xkey_helper.c
@@ -50,8 +50,18 @@  static const char *const props = XKEY_PROV_PROPS;
 
 XKEY_EXTERNAL_SIGN_fn xkey_management_sign;
 
+static void
+print_openssl_errors()
+{
+    unsigned long e;
+    while ((e = ERR_get_error()))
+    {
+        msg(M_WARN, "OpenSSL error %lu: %s\n", e, ERR_error_string(e, NULL));
+    }
+}
+
 /** helper to compute digest */
-static int
+int
 xkey_digest(const unsigned char *src, size_t srclen, unsigned char *buf,
             size_t *buflen, const char *mdname)
 {
@@ -85,24 +95,38 @@  xkey_digest(const unsigned char *src, size_t srclen, unsigned char *buf,
 EVP_PKEY *
 xkey_load_management_key(OSSL_LIB_CTX *libctx, EVP_PKEY *pubkey)
 {
-    EVP_PKEY *pkey = NULL;
     ASSERT(pubkey);
 
-    /* Management interface doesnt require any handle to be
+    /* Management interface doesn't require any handle to be
      * stored in the key. We use a dummy pointer as we do need a
      * non-NULL value to indicate private key is avaialble.
      */
     void *dummy = & "dummy";
 
-    const char *origin = "management";
     XKEY_EXTERNAL_SIGN_fn *sign_op = xkey_management_sign;
 
+    return xkey_load_generic_key(libctx, dummy, pubkey, sign_op, NULL);
+}
+
+/**
+ * Load a generic key into the xkey provider.
+ * Returns an EVP_PKEY object attached to xkey provider.
+ * Caller must free it when no longer needed.
+ */
+EVP_PKEY *
+xkey_load_generic_key(OSSL_LIB_CTX *libctx, void *handle, EVP_PKEY *pubkey,
+                      XKEY_EXTERNAL_SIGN_fn sign_op, XKEY_PRIVKEY_FREE_fn free_op)
+{
+    EVP_PKEY *pkey = NULL;
+    const char *origin = "external";
+
     /* UTF8 string pointers in here are only read from, so cast is safe */
     OSSL_PARAM params[] = {
         {"xkey-origin", OSSL_PARAM_UTF8_STRING, (char *) origin, 0, 0},
         {"pubkey", OSSL_PARAM_OCTET_STRING, &pubkey, sizeof(pubkey), 0},
-        {"handle", OSSL_PARAM_OCTET_PTR, &dummy, sizeof(dummy), 0},
+        {"handle", OSSL_PARAM_OCTET_PTR, &handle, sizeof(handle), 0},
         {"sign_op", OSSL_PARAM_OCTET_PTR, (void **) &sign_op, sizeof(sign_op), 0},
+        {"free_op", OSSL_PARAM_OCTET_PTR, (void **) &free_op, sizeof(free_op), 0},
         {NULL, 0, NULL, 0, 0}};
 
     /* Do not use EVP_PKEY_new_from_pkey as that will take keymgmt from pubkey */
@@ -111,7 +135,8 @@  xkey_load_management_key(OSSL_LIB_CTX *libctx, EVP_PKEY *pubkey)
         || EVP_PKEY_fromdata_init(ctx) != 1
         || EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_KEYPAIR, params) != 1)
     {
-        msg(M_NONFATAL, "Error loading key into ovpn.xkey provider");
+        print_openssl_errors();
+        msg(M_FATAL, "OpenSSL error: failed to load key into ovpn.xkey provider");
     }
     if (ctx)
     {