ssl: set engine implicitly when a PKCS#11 URI is provided

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
This commit is contained in:
Anderson Toshiyuki Sasaki 2018-02-19 14:31:06 +01:00 committed by Daniel Stenberg
parent c892795ea3
commit 298d2565e2
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
6 changed files with 109 additions and 1 deletions

View 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

View 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.

View 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");

View 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;

View 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);

View 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",