]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
ssl: set engine implicitly when a PKCS#11 URI is provided
authorAnderson Toshiyuki Sasaki <ansasaki@redhat.com>
Mon, 19 Feb 2018 13:31:06 +0000 (14:31 +0100)
committerDaniel Stenberg <daniel@haxx.se>
Wed, 8 Aug 2018 07:46:01 +0000 (09:46 +0200)
This allows the use of PKCS#11 URI for certificates and keys without
setting the corresponding type as "ENG" and the engine as "pkcs11"
explicitly. If a PKCS#11 URI is provided for certificate, key,
proxy_certificate or proxy_key, the corresponding type is set as "ENG"
if not provided and the engine is set to "pkcs11" if not provided.

Acked-by: Nikos Mavrogiannopoulos
Closes #2333

docs/cmdline-opts/cert.d
docs/cmdline-opts/key.d
lib/vtls/openssl.c
src/tool_getparam.c
src/tool_operate.c
tests/unit/unit1394.c

index adf62fc7ab097c1d2d736bf1bff7314abbd74138..510b8333ffaf35fdb9c94f636c4eb2f9e41beeca 100644 (file)
@@ -23,6 +23,13 @@ nickname contains ":", it needs to be preceded by "\\" so that it is not
 recognized as password delimiter.  If the nickname contains "\\", it needs to
 be escaped as "\\\\" so that it is not recognized as an escape character.
 
+If curl is built against OpenSSL library, and the engine pkcs11 is available,
+then a PKCS#11 URI (RFC 7512) can be used to specify a certificate located in
+a PKCS#11 device. A string beginning with "pkcs11:" will be interpreted as a
+PKCS#11 URI. If a PKCS#11 URI is provided, then the --engine option will be set
+as "pkcs11" if none was provided and the --cert-type option will be set as
+"ENG" if none was provided.
+
 (iOS and macOS only) If curl is built against Secure Transport, then the
 certificate string can either be the name of a certificate/private key in the
 system or user keychain, or the path to a PKCS#12-encoded certificate and
index fbf583af0b899fcd457477508471ce791dce8d0f..4877b42386f3a34a4c1167508c1ff67fe3f82b8f 100644 (file)
@@ -7,4 +7,11 @@ Private key file name. Allows you to provide your private key in this separate
 file. For SSH, if not specified, curl tries the following candidates in order:
 '~/.ssh/id_rsa', '~/.ssh/id_dsa', './id_rsa', './id_dsa'.
 
+If curl is built against OpenSSL library, and the engine pkcs11 is available,
+then a PKCS#11 URI (RFC 7512) can be used to specify a private key located in a
+PKCS#11 device. A string beginning with "pkcs11:" will be interpreted as a
+PKCS#11 URI. If a PKCS#11 URI is provided, then the --engine option will be set
+as "pkcs11" if none was provided and the --key-type option will be set as
+"ENG" if none was provided.
+
 If this option is used several times, the last one will be used.
index d5b474771e79aa88d380a8a3f1d5aed9978ac0f4..9ce1ae5ab5e6da9936c87482b716cc56bd23c58f 100644 (file)
@@ -558,8 +558,25 @@ static int ssl_ui_writer(UI *ui, UI_STRING *uis)
   }
   return (UI_method_get_writer(UI_OpenSSL()))(ui, uis);
 }
+
+/*
+ * Check if a given string is a PKCS#11 URI
+ */
+static bool is_pkcs11_uri(const char *string)
+{
+  if(strncasecompare(string, "pkcs11:", 7)) {
+    return TRUE;
+  }
+  else {
+    return FALSE;
+  }
+}
+
 #endif
 
+static CURLcode Curl_ossl_set_engine(struct Curl_easy *data,
+                                     const char *engine);
+
 static
 int cert_stuff(struct connectdata *conn,
                SSL_CTX* ctx,
@@ -622,6 +639,16 @@ int cert_stuff(struct connectdata *conn,
     case SSL_FILETYPE_ENGINE:
 #if defined(USE_OPENSSL_ENGINE) && defined(ENGINE_CTRL_GET_CMD_FROM_NAME)
       {
+        /* Implicitly use pkcs11 engine if none was provided and the
+         * cert_file is a PKCS#11 URI */
+        if(!data->state.engine) {
+          if(is_pkcs11_uri(cert_file)) {
+            if(Curl_ossl_set_engine(data, "pkcs11") != CURLE_OK) {
+              return 0;
+            }
+          }
+        }
+
         if(data->state.engine) {
           const char *cmd_name = "LOAD_CERT_CTRL";
           struct {
@@ -798,6 +825,17 @@ int cert_stuff(struct connectdata *conn,
 #ifdef USE_OPENSSL_ENGINE
       {                         /* XXXX still needs some work */
         EVP_PKEY *priv_key = NULL;
+
+        /* Implicitly use pkcs11 engine if none was provided and the
+         * key_file is a PKCS#11 URI */
+        if(!data->state.engine) {
+          if(is_pkcs11_uri(key_file)) {
+            if(Curl_ossl_set_engine(data, "pkcs11") != CURLE_OK) {
+              return 0;
+            }
+          }
+        }
+
         if(data->state.engine) {
           UI_METHOD *ui_method =
             UI_create_method((char *)"curl user interface");
index e42a894cbae74dd13fbee89a671cb5405a1e2e0e..1a81c3803e6f848acb1735ccffcdde524f5b157f 100644 (file)
@@ -342,7 +342,7 @@ void parse_cert_parameter(const char *cert_parameter,
    * looks like a RFC7512 PKCS#11 URI which can be used as-is.
    * Also if cert_parameter contains no colon nor backslash, this
    * means no passphrase was given and no characters escaped */
-  if(!strncmp(cert_parameter, "pkcs11:", 7) ||
+  if(curl_strnequal(cert_parameter, "pkcs11:", 7) ||
      !strpbrk(cert_parameter, ":\\")) {
     *certname = strdup(cert_parameter);
     return;
index 26fc251f5d96bdf9b05f0939a7bdd7052c5980d6..25d450c86824d65262984c84613785e3726ebd74 100644 (file)
@@ -113,6 +113,19 @@ static bool is_fatal_error(CURLcode code)
   return FALSE;
 }
 
+/*
+ * Check if a given string is a PKCS#11 URI
+ */
+static bool is_pkcs11_uri(const char *string)
+{
+  if(curl_strnequal(string, "pkcs11:", 7)) {
+    return TRUE;
+  }
+  else {
+    return FALSE;
+  }
+}
+
 #ifdef __VMS
 /*
  * get_vms_file_size does what it takes to get the real size of the file
@@ -1073,6 +1086,46 @@ static CURLcode operate_do(struct GlobalConfig *global,
           my_setopt_str(curl, CURLOPT_PINNEDPUBLICKEY, config->pinnedpubkey);
 
         if(curlinfo->features & CURL_VERSION_SSL) {
+          /* Check if config->cert is a PKCS#11 URI and set the
+           * config->cert_type if necessary */
+          if(config->cert) {
+            if(!config->cert_type) {
+              if(is_pkcs11_uri(config->cert)) {
+                config->cert_type = strdup("ENG");
+              }
+            }
+          }
+
+          /* Check if config->key is a PKCS#11 URI and set the
+           * config->key_type if necessary */
+          if(config->key) {
+            if(!config->key_type) {
+              if(is_pkcs11_uri(config->key)) {
+                config->key_type = strdup("ENG");
+              }
+            }
+          }
+
+          /* Check if config->proxy_cert is a PKCS#11 URI and set the
+           * config->proxy_type if necessary */
+          if(config->proxy_cert) {
+            if(!config->proxy_cert_type) {
+              if(is_pkcs11_uri(config->proxy_cert)) {
+                config->proxy_cert_type = strdup("ENG");
+              }
+            }
+          }
+
+          /* Check if config->proxy_key is a PKCS#11 URI and set the
+           * config->proxy_key_type if necessary */
+          if(config->proxy_key) {
+            if(!config->proxy_key_type) {
+              if(is_pkcs11_uri(config->proxy_key)) {
+                config->proxy_key_type = strdup("ENG");
+              }
+            }
+          }
+
           my_setopt_str(curl, CURLOPT_SSLCERT, config->cert);
           my_setopt_str(curl, CURLOPT_PROXY_SSLCERT, config->proxy_cert);
           my_setopt_str(curl, CURLOPT_SSLCERTTYPE, config->cert_type);
index 667991d1ee020541d96ed021b6411adf9e53e7d1..010f052ecf497a5e9038c91edcfb7d1cd3c40518 100644 (file)
@@ -56,6 +56,9 @@ UNITTEST_START
     "foo:bar\\\\",            "foo",                "bar\\\\",
     "foo:bar:",               "foo",                "bar:",
     "foo\\::bar\\:",          "foo:",               "bar\\:",
+    "pkcs11:foobar",          "pkcs11:foobar",      NULL,
+    "PKCS11:foobar",          "PKCS11:foobar",      NULL,
+    "PkCs11:foobar",          "PkCs11:foobar",      NULL,
 #ifdef WIN32
     "c:\\foo:bar:baz",        "c:\\foo",            "bar:baz",
     "c:\\foo\\:bar:baz",      "c:\\foo:bar",        "baz",