mirror of
https://github.com/moparisthebest/curl
synced 2024-08-13 17:03:50 -04:00
setopt: support certificate options in memory with struct curl_blob
This change introduces a generic way to provide binary data in setopt options, called BLOBs. This change introduces these new setopts: CURLOPT_ISSUERCERT_BLOB, CURLOPT_PROXY_SSLCERT_BLOB, CURLOPT_PROXY_SSLKEY_BLOB, CURLOPT_SSLCERT_BLOB and CURLOPT_SSLKEY_BLOB. Reviewed-by: Daniel Stenberg Closes #5357
This commit is contained in:
parent
8df455479f
commit
cac5374298
@ -506,16 +506,24 @@ Sets the interval at which connection upkeep are performed. See
|
|||||||
.SH SSL and SECURITY OPTIONS
|
.SH SSL and SECURITY OPTIONS
|
||||||
.IP CURLOPT_SSLCERT
|
.IP CURLOPT_SSLCERT
|
||||||
Client cert. See \fICURLOPT_SSLCERT(3)\fP
|
Client cert. See \fICURLOPT_SSLCERT(3)\fP
|
||||||
|
.IP CURLOPT_SSLCERT_BLOB
|
||||||
|
Client cert memory buffer. See \fICURLOPT_SSLCERT_BLOB(3)\fP
|
||||||
.IP CURLOPT_PROXY_SSLCERT
|
.IP CURLOPT_PROXY_SSLCERT
|
||||||
Proxy client cert. See \fICURLOPT_PROXY_SSLCERT(3)\fP
|
Proxy client cert. See \fICURLOPT_PROXY_SSLCERT(3)\fP
|
||||||
|
.IP CURLOPT_PROXY_SSLCERT_BLOB
|
||||||
|
Proxy client cert memory buffer. See \fICURLOPT_PROXY_SSLCERT_BLOB(3)\fP
|
||||||
.IP CURLOPT_SSLCERTTYPE
|
.IP CURLOPT_SSLCERTTYPE
|
||||||
Client cert type. See \fICURLOPT_SSLCERTTYPE(3)\fP
|
Client cert type. See \fICURLOPT_SSLCERTTYPE(3)\fP
|
||||||
.IP CURLOPT_PROXY_SSLCERTTYPE
|
.IP CURLOPT_PROXY_SSLCERTTYPE
|
||||||
Proxy client cert type. See \fICURLOPT_PROXY_SSLCERTTYPE(3)\fP
|
Proxy client cert type. See \fICURLOPT_PROXY_SSLCERTTYPE(3)\fP
|
||||||
.IP CURLOPT_SSLKEY
|
.IP CURLOPT_SSLKEY
|
||||||
Client key. See \fICURLOPT_SSLKEY(3)\fP
|
Client key. See \fICURLOPT_SSLKEY(3)\fP
|
||||||
|
.IP CURLOPT_SSLKEY_BLOB
|
||||||
|
Client key memory buffer. See \fICURLOPT_SSLKEY_BLOB(3)\fP
|
||||||
.IP CURLOPT_PROXY_SSLKEY
|
.IP CURLOPT_PROXY_SSLKEY
|
||||||
Proxy client key. See \fICURLOPT_PROXY_SSLKEY(3)\fP
|
Proxy client key. See \fICURLOPT_PROXY_SSLKEY(3)\fP
|
||||||
|
.IP CURLOPT_PROXY_SSLKEY_BLOB
|
||||||
|
Proxy client key. See \fICURLOPT_PROXY_SSLKEY_BLOB(3)\fP
|
||||||
.IP CURLOPT_SSLKEYTYPE
|
.IP CURLOPT_SSLKEYTYPE
|
||||||
Client key type. See \fICURLOPT_SSLKEYTYPE(3)\fP
|
Client key type. See \fICURLOPT_SSLKEYTYPE(3)\fP
|
||||||
.IP CURLOPT_PROXY_SSLKEYTYPE
|
.IP CURLOPT_PROXY_SSLKEYTYPE
|
||||||
@ -554,6 +562,8 @@ CA cert bundle. See \fICURLOPT_CAINFO(3)\fP
|
|||||||
Proxy CA cert bundle. See \fICURLOPT_PROXY_CAINFO(3)\fP
|
Proxy CA cert bundle. See \fICURLOPT_PROXY_CAINFO(3)\fP
|
||||||
.IP CURLOPT_ISSUERCERT
|
.IP CURLOPT_ISSUERCERT
|
||||||
Issuer certificate. See \fICURLOPT_ISSUERCERT(3)\fP
|
Issuer certificate. See \fICURLOPT_ISSUERCERT(3)\fP
|
||||||
|
.IP CURLOPT_ISSUERCERT_BLOB
|
||||||
|
Issuer certificate memory buffer. See \fICURLOPT_ISSUERCERT_BLOB(3)\fP
|
||||||
.IP CURLOPT_CAPATH
|
.IP CURLOPT_CAPATH
|
||||||
Path to CA cert bundle. See \fICURLOPT_CAPATH(3)\fP
|
Path to CA cert bundle. See \fICURLOPT_CAPATH(3)\fP
|
||||||
.IP CURLOPT_PROXY_CAPATH
|
.IP CURLOPT_PROXY_CAPATH
|
||||||
|
79
docs/libcurl/opts/CURLOPT_ISSUERCERT_BLOB.3
Normal file
79
docs/libcurl/opts/CURLOPT_ISSUERCERT_BLOB.3
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
.\" **************************************************************************
|
||||||
|
.\" * _ _ ____ _
|
||||||
|
.\" * Project ___| | | | _ \| |
|
||||||
|
.\" * / __| | | | |_) | |
|
||||||
|
.\" * | (__| |_| | _ <| |___
|
||||||
|
.\" * \___|\___/|_| \_\_____|
|
||||||
|
.\" *
|
||||||
|
.\" * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
|
.\" *
|
||||||
|
.\" * This software is licensed as described in the file COPYING, which
|
||||||
|
.\" * you should have received as part of this distribution. The terms
|
||||||
|
.\" * are also available at https://curl.haxx.se/docs/copyright.html.
|
||||||
|
.\" *
|
||||||
|
.\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||||
|
.\" * copies of the Software, and permit persons to whom the Software is
|
||||||
|
.\" * furnished to do so, under the terms of the COPYING file.
|
||||||
|
.\" *
|
||||||
|
.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||||
|
.\" * KIND, either express or implied.
|
||||||
|
.\" *
|
||||||
|
.\" **************************************************************************
|
||||||
|
.\"
|
||||||
|
.TH CURLOPT_ISSUERCERT_BLOB 3 "24 Jun 2020" "libcurl 7.71.0" "curl_easy_setopt options"
|
||||||
|
.SH NAME
|
||||||
|
CURLOPT_ISSUERCERT_BLOB \- issuer SSL certificate from memory blob
|
||||||
|
.SH SYNOPSIS
|
||||||
|
#include <curl/curl.h>
|
||||||
|
|
||||||
|
CURLcode curl_easy_setopt(CURL *handle, CURLOPT_ISSUERCERT_BLOB, struct curl_blob *stblob);
|
||||||
|
.SH DESCRIPTION
|
||||||
|
Pass a pointer to a curl_blob structure, which contains information (pointer
|
||||||
|
and size) about a memory block with binary data of a CA certificate in PEM
|
||||||
|
format. If the option is set, an additional check against the peer certificate
|
||||||
|
is performed to verify the issuer is indeed the one associated with the
|
||||||
|
certificate provided by the option. This additional check is useful in
|
||||||
|
multi-level PKI where one needs to enforce that the peer certificate is from a
|
||||||
|
specific branch of the tree.
|
||||||
|
|
||||||
|
This option should be used in combination with the
|
||||||
|
\fICURLOPT_SSL_VERIFYPEER(3)\fP option. Otherwise, the result of the check is
|
||||||
|
not considered as failure.
|
||||||
|
|
||||||
|
A specific error code (CURLE_SSL_ISSUER_ERROR) is defined with the option,
|
||||||
|
which is returned if the setup of the SSL/TLS session has failed due to a
|
||||||
|
mismatch with the issuer of peer certificate (\fICURLOPT_SSL_VERIFYPEER(3)\fP
|
||||||
|
has to be set too for the check to fail).
|
||||||
|
|
||||||
|
If the blob is initialized with the flags member of struct curl_blob set to
|
||||||
|
CURL_BLOB_COPY, the application does not have to keep the buffer around after
|
||||||
|
setting this.
|
||||||
|
|
||||||
|
This option is an alternative to \fICURLOPT_ISSUERCERT(3)\fP which instead
|
||||||
|
expects a file name as input.
|
||||||
|
.SH DEFAULT
|
||||||
|
NULL
|
||||||
|
.SH PROTOCOLS
|
||||||
|
All TLS-based protocols
|
||||||
|
.SH EXAMPLE
|
||||||
|
.nf
|
||||||
|
CURL *curl = curl_easy_init();
|
||||||
|
if(curl) {
|
||||||
|
struct curl_blob blob;
|
||||||
|
curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
|
||||||
|
blob.data = certificateData;
|
||||||
|
blob.len = filesize;
|
||||||
|
blob.flags = CURL_BLOB_COPY;
|
||||||
|
curl_easy_setopt(curl, CURLOPT_ISSUERCERT_BLOB, &blob);
|
||||||
|
ret = curl_easy_perform(curl);
|
||||||
|
curl_easy_cleanup(curl);
|
||||||
|
}
|
||||||
|
.fi
|
||||||
|
.SH AVAILABILITY
|
||||||
|
Added in libcurl 7.71.0. This option is supported by the OpenSSL backends.
|
||||||
|
.SH RETURN VALUE
|
||||||
|
Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
|
||||||
|
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
|
||||||
|
.SH "SEE ALSO"
|
||||||
|
.BR CURLOPT_ISSUERCERT "(3),"
|
||||||
|
.BR CURLOPT_CRLFILE "(3), " CURLOPT_SSL_VERIFYPEER "(3), "
|
72
docs/libcurl/opts/CURLOPT_PROXY_SSLCERT_BLOB.3
Normal file
72
docs/libcurl/opts/CURLOPT_PROXY_SSLCERT_BLOB.3
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
.\" **************************************************************************
|
||||||
|
.\" * _ _ ____ _
|
||||||
|
.\" * Project ___| | | | _ \| |
|
||||||
|
.\" * / __| | | | |_) | |
|
||||||
|
.\" * | (__| |_| | _ <| |___
|
||||||
|
.\" * \___|\___/|_| \_\_____|
|
||||||
|
.\" *
|
||||||
|
.\" * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
|
.\" *
|
||||||
|
.\" * This software is licensed as described in the file COPYING, which
|
||||||
|
.\" * you should have received as part of this distribution. The terms
|
||||||
|
.\" * are also available at https://curl.haxx.se/docs/copyright.html.
|
||||||
|
.\" *
|
||||||
|
.\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||||
|
.\" * copies of the Software, and permit persons to whom the Software is
|
||||||
|
.\" * furnished to do so, under the terms of the COPYING file.
|
||||||
|
.\" *
|
||||||
|
.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||||
|
.\" * KIND, either express or implied.
|
||||||
|
.\" *
|
||||||
|
.\" **************************************************************************
|
||||||
|
.\"
|
||||||
|
.TH CURLOPT_PROXY_SSLCERT_BLOB 3 "24 Jun 2020" "libcurl 7.71.0" "curl_easy_setopt options"
|
||||||
|
.SH NAME
|
||||||
|
CURLOPT_PROXY_SSLCERT_BLOB \- SSL proxy client certificate from memory blob
|
||||||
|
.SH SYNOPSIS
|
||||||
|
#include <curl/curl.h>
|
||||||
|
|
||||||
|
CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXY_SSLCERT_BLOB, struct curl_blob *blob);
|
||||||
|
.SH DESCRIPTION
|
||||||
|
Pass a pointer to a curl_blob structure, which contains information (pointer
|
||||||
|
and size) about a memory block with binary data of the certificate used to
|
||||||
|
connect to the HTTPS proxy. The format must be "P12" on Secure Transport or
|
||||||
|
Schannel. The format must be "P12" or "PEM" on OpenSSL. The string "P12" or
|
||||||
|
"PEM" must be specified with \fICURLOPT_PROXY_SSLCERTTYPE(3)\fP.
|
||||||
|
|
||||||
|
If the blob is initialized with the flags member of struct curl_blob set to
|
||||||
|
CURL_BLOB_COPY, the application does not have to keep the buffer around after
|
||||||
|
setting this.
|
||||||
|
|
||||||
|
This option is an alternative to \fICURLOPT_PROXY_SSLCERT(3)\fP which instead
|
||||||
|
expects a file name as input.
|
||||||
|
.SH DEFAULT
|
||||||
|
NULL
|
||||||
|
.SH PROTOCOLS
|
||||||
|
All TLS based protocols: HTTPS, FTPS, IMAPS, POP3S, SMTPS etc.
|
||||||
|
.SH EXAMPLE
|
||||||
|
.nf
|
||||||
|
CURL *curl = curl_easy_init();
|
||||||
|
if(curl) {
|
||||||
|
struct curl_blob blob;
|
||||||
|
blob.data = certificateData;
|
||||||
|
blob.len = filesize;
|
||||||
|
blob.flags = CURL_BLOB_COPY;
|
||||||
|
curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
|
||||||
|
curl_easy_setopt(curl, CURLOPT_PROXY, "https://proxy");
|
||||||
|
curl_easy_setopt(curl, CURLOPT_PROXY_SSLKEY, "key.pem");
|
||||||
|
curl_easy_setopt(curl, CURLOPT_PROXY_KEYPASSWD, "s3cret");
|
||||||
|
curl_easy_setopt(curl, CURLOPT_PROXY_SSLCERT_BLOB, &blob);
|
||||||
|
ret = curl_easy_perform(curl);
|
||||||
|
curl_easy_cleanup(curl);
|
||||||
|
}
|
||||||
|
.fi
|
||||||
|
.SH AVAILABILITY
|
||||||
|
Added in libcurl 7.71.0. This option is supported by the OpenSSL, Secure
|
||||||
|
Transport and Schannel backends.
|
||||||
|
.SH RETURN VALUE
|
||||||
|
Returns CURLE_OK if TLS enabled, CURLE_UNKNOWN_OPTION if not, or
|
||||||
|
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
|
||||||
|
.SH "SEE ALSO"
|
||||||
|
.BR CURLOPT_PROXY_SSLCERTTYPE "(3), " CURLOPT_PROXY_SSLKEY "(3), "
|
||||||
|
.BR CURLOPT_PROXY_SSLCERT "(3), "
|
73
docs/libcurl/opts/CURLOPT_PROXY_SSLKEY_BLOB.3
Normal file
73
docs/libcurl/opts/CURLOPT_PROXY_SSLKEY_BLOB.3
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
.\" **************************************************************************
|
||||||
|
.\" * _ _ ____ _
|
||||||
|
.\" * Project ___| | | | _ \| |
|
||||||
|
.\" * / __| | | | |_) | |
|
||||||
|
.\" * | (__| |_| | _ <| |___
|
||||||
|
.\" * \___|\___/|_| \_\_____|
|
||||||
|
.\" *
|
||||||
|
.\" * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
|
.\" *
|
||||||
|
.\" * This software is licensed as described in the file COPYING, which
|
||||||
|
.\" * you should have received as part of this distribution. The terms
|
||||||
|
.\" * are also available at https://curl.haxx.se/docs/copyright.html.
|
||||||
|
.\" *
|
||||||
|
.\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||||
|
.\" * copies of the Software, and permit persons to whom the Software is
|
||||||
|
.\" * furnished to do so, under the terms of the COPYING file.
|
||||||
|
.\" *
|
||||||
|
.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||||
|
.\" * KIND, either express or implied.
|
||||||
|
.\" *
|
||||||
|
.\" **************************************************************************
|
||||||
|
.\"
|
||||||
|
.TH CURLOPT_PROXY_SSLKEY_BLOB 3 "24 Jun 2020" "libcurl 7.71.0" "curl_easy_setopt options"
|
||||||
|
.SH NAME
|
||||||
|
CURLOPT_PROXY_SSLKEY_BLOB \- private key for proxy cert from memory blob
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.nf
|
||||||
|
#include <curl/curl.h>
|
||||||
|
|
||||||
|
CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXY_SSLKEY_BLOB,
|
||||||
|
struct curl_blob *blob);
|
||||||
|
.fi
|
||||||
|
.SH DESCRIPTION
|
||||||
|
Pass a pointer to a curl_blob structure that contains information (pointer and
|
||||||
|
size) about the private key for connecting to the HTTPS proxy. Compatible with
|
||||||
|
OpenSSL. The format (like "PEM") must be specified with
|
||||||
|
\fICURLOPT_PROXY_SSLKEYTYPE(3)\fP.
|
||||||
|
|
||||||
|
If the blob is initialized with the flags member of struct curl_blob set to
|
||||||
|
CURL_BLOB_COPY, the application does not have to keep the buffer around after
|
||||||
|
setting this.
|
||||||
|
.SH DEFAULT
|
||||||
|
NULL
|
||||||
|
.SH PROTOCOLS
|
||||||
|
All TLS based protocols: HTTPS, FTPS, IMAPS, POP3S, SMTPS etc.
|
||||||
|
.SH EXAMPLE
|
||||||
|
.nf
|
||||||
|
CURL *curl = curl_easy_init();
|
||||||
|
if(curl) {
|
||||||
|
struct curl_blob blob;
|
||||||
|
curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
|
||||||
|
curl_easy_setopt(curl, CURLOPT_PROXY, "https://proxy");
|
||||||
|
blob.data = certificateData;
|
||||||
|
blob.len = filesize;
|
||||||
|
blob.flags = CURL_BLOB_COPY;
|
||||||
|
curl_easy_setopt(curl, CURLOPT_PROXY_SSLCERT_BLOB, &blob);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_PROXY_SSLCERTTYPE, "PEM");
|
||||||
|
|
||||||
|
blob.data = privateKeyData;
|
||||||
|
blob.len = privateKeySize;
|
||||||
|
curl_easy_setopt(curl, CURLOPT_PROXY_SSLKEY_BLOB, &blob);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_PROXY_KEYPASSWD, "s3cret");
|
||||||
|
ret = curl_easy_perform(curl);
|
||||||
|
curl_easy_cleanup(curl);
|
||||||
|
}
|
||||||
|
.fi
|
||||||
|
.SH AVAILABILITY
|
||||||
|
Added in libcurl 7.71.0. This option is supported by the OpenSSL backends.
|
||||||
|
.SH RETURN VALUE
|
||||||
|
Returns CURLE_OK if TLS enabled, CURLE_UNKNOWN_OPTION if not, or
|
||||||
|
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
|
||||||
|
.SH "SEE ALSO"
|
||||||
|
.BR CURLOPT_SSLKEYTYPE "(3), " CURLOPT_SSLKEY "(3), "
|
@ -38,15 +38,17 @@ you wish to authenticate with as it is named in the security database. If you
|
|||||||
want to use a file from the current directory, please precede it with "./"
|
want to use a file from the current directory, please precede it with "./"
|
||||||
prefix, in order to avoid confusion with a nickname.
|
prefix, in order to avoid confusion with a nickname.
|
||||||
|
|
||||||
(Schannel only) Client certificates must be specified by a path expression to
|
(Schannel only) Client certificates can be specified by a path expression to
|
||||||
a certificate store. (Loading PFX is not supported; you can import it to a
|
a certificate store. (You can import PFX to a store first). You can use
|
||||||
store first). You can use "<store location>\\<store name>\\<thumbprint>" to
|
"<store location>\\<store name>\\<thumbprint>" to refer to a certificate
|
||||||
refer to a certificate in the system certificates store, for example,
|
in the system certificates store, for example,
|
||||||
"CurrentUser\\MY\\934a7ac6f8a5d579285a74fa61e19f23ddfe8d7a". Thumbprint is
|
"CurrentUser\\MY\\934a7ac6f8a5d579285a74fa61e19f23ddfe8d7a". Thumbprint is
|
||||||
usually a SHA-1 hex string which you can see in certificate details. Following
|
usually a SHA-1 hex string which you can see in certificate details. Following
|
||||||
store locations are supported: CurrentUser, LocalMachine, CurrentService,
|
store locations are supported: CurrentUser, LocalMachine, CurrentService,
|
||||||
Services, CurrentUserGroupPolicy, LocalMachineGroupPolicy,
|
Services, CurrentUserGroupPolicy, LocalMachineGroupPolicy,
|
||||||
LocalMachineEnterprise.
|
LocalMachineEnterprise.
|
||||||
|
Schannel also support P12 certificate file, with the string "P12" specified
|
||||||
|
with \fICURLOPT_SSLCERTTYPE(3)\fP.
|
||||||
|
|
||||||
When using a client certificate, you most likely also need to provide a
|
When using a client certificate, you most likely also need to provide a
|
||||||
private key with \fICURLOPT_SSLKEY(3)\fP.
|
private key with \fICURLOPT_SSLKEY(3)\fP.
|
||||||
|
69
docs/libcurl/opts/CURLOPT_SSLCERT_BLOB.3
Normal file
69
docs/libcurl/opts/CURLOPT_SSLCERT_BLOB.3
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
.\" **************************************************************************
|
||||||
|
.\" * _ _ ____ _
|
||||||
|
.\" * Project ___| | | | _ \| |
|
||||||
|
.\" * / __| | | | |_) | |
|
||||||
|
.\" * | (__| |_| | _ <| |___
|
||||||
|
.\" * \___|\___/|_| \_\_____|
|
||||||
|
.\" *
|
||||||
|
.\" * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
|
.\" *
|
||||||
|
.\" * This software is licensed as described in the file COPYING, which
|
||||||
|
.\" * you should have received as part of this distribution. The terms
|
||||||
|
.\" * are also available at https://curl.haxx.se/docs/copyright.html.
|
||||||
|
.\" *
|
||||||
|
.\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||||
|
.\" * copies of the Software, and permit persons to whom the Software is
|
||||||
|
.\" * furnished to do so, under the terms of the COPYING file.
|
||||||
|
.\" *
|
||||||
|
.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||||
|
.\" * KIND, either express or implied.
|
||||||
|
.\" *
|
||||||
|
.\" **************************************************************************
|
||||||
|
.\"
|
||||||
|
.TH CURLOPT_SSLCERT_BLOB 3 "24 Jun 2020" "libcurl 7.71.0" "curl_easy_setopt options"
|
||||||
|
.SH NAME
|
||||||
|
CURLOPT_SSLCERT_BLOB \- SSL client certificate from memory blob
|
||||||
|
.SH SYNOPSIS
|
||||||
|
#include <curl/curl.h>
|
||||||
|
|
||||||
|
CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSLCERT_BLOB, struct curl_blob *stblob);
|
||||||
|
.SH DESCRIPTION
|
||||||
|
Pass a pointer to a curl_blob structure, which contains (pointer and size) a
|
||||||
|
client certificate. The format must be "P12" on Secure Transport or
|
||||||
|
Schannel. The format must be "P12" or "PEM" on OpenSSL. The string "P12" or
|
||||||
|
"PEM" must be specified with \fICURLOPT_SSLCERTTYPE(3)\fP.
|
||||||
|
|
||||||
|
If the blob is initialized with the flags member of struct curl_blob set to
|
||||||
|
CURL_BLOB_COPY, the application does not have to keep the buffer around after
|
||||||
|
setting this.
|
||||||
|
|
||||||
|
This option is an alternative to \fICURLOPT_SSLCERT(3)\fP which instead
|
||||||
|
expects a file name as input.
|
||||||
|
.SH DEFAULT
|
||||||
|
NULL
|
||||||
|
.SH PROTOCOLS
|
||||||
|
All TLS based protocols: HTTPS, FTPS, IMAPS, POP3S, SMTPS etc.
|
||||||
|
.SH EXAMPLE
|
||||||
|
.nf
|
||||||
|
CURL *curl = curl_easy_init();
|
||||||
|
if(curl) {
|
||||||
|
struct curl_blob stblob;
|
||||||
|
stblob.data = certificateData;
|
||||||
|
stblob.len = filesize;
|
||||||
|
stblob.flags = CURL_BLOB_COPY;
|
||||||
|
curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
|
||||||
|
curl_easy_setopt(curl, CURLOPT_SSLCERT_BLOB, &stblob);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, "P12");
|
||||||
|
curl_easy_setopt(curl, CURLOPT_KEYPASSWD, "s3cret");
|
||||||
|
ret = curl_easy_perform(curl);
|
||||||
|
curl_easy_cleanup(curl);
|
||||||
|
}
|
||||||
|
.fi
|
||||||
|
.SH AVAILABILITY
|
||||||
|
Added in libcurl 7.71.0. This option is supported by the OpenSSL, Secure
|
||||||
|
Transport and Schannel backends.
|
||||||
|
.SH RETURN VALUE
|
||||||
|
Returns CURLE_OK if TLS enabled, CURLE_UNKNOWN_OPTION if not, or
|
||||||
|
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
|
||||||
|
.SH "SEE ALSO"
|
||||||
|
.BR CURLOPT_SSLCERTTYPE "(3), " CURLOPT_SSLKEY "(3), "
|
75
docs/libcurl/opts/CURLOPT_SSLKEY_BLOB.3
Normal file
75
docs/libcurl/opts/CURLOPT_SSLKEY_BLOB.3
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
.\" **************************************************************************
|
||||||
|
.\" * _ _ ____ _
|
||||||
|
.\" * Project ___| | | | _ \| |
|
||||||
|
.\" * / __| | | | |_) | |
|
||||||
|
.\" * | (__| |_| | _ <| |___
|
||||||
|
.\" * \___|\___/|_| \_\_____|
|
||||||
|
.\" *
|
||||||
|
.\" * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
|
.\" *
|
||||||
|
.\" * This software is licensed as described in the file COPYING, which
|
||||||
|
.\" * you should have received as part of this distribution. The terms
|
||||||
|
.\" * are also available at https://curl.haxx.se/docs/copyright.html.
|
||||||
|
.\" *
|
||||||
|
.\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||||
|
.\" * copies of the Software, and permit persons to whom the Software is
|
||||||
|
.\" * furnished to do so, under the terms of the COPYING file.
|
||||||
|
.\" *
|
||||||
|
.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||||
|
.\" * KIND, either express or implied.
|
||||||
|
.\" *
|
||||||
|
.\" **************************************************************************
|
||||||
|
.\"
|
||||||
|
.TH CURLOPT_SSLKEY_BLOB 3 "24 Jun 2020" "libcurl 7.71.0" "curl_easy_setopt options"
|
||||||
|
.SH NAME
|
||||||
|
CURLOPT_SSLKEY_BLOB \- private key for client cert from memory blob
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.nf
|
||||||
|
#include <curl/curl.h>
|
||||||
|
|
||||||
|
CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSLKEY_BLOB,
|
||||||
|
struct curl_blob *blob);
|
||||||
|
.fi
|
||||||
|
.SH DESCRIPTION
|
||||||
|
Pass a pointer to a curl_blob structure, which contains information (pointer
|
||||||
|
and size) for a private key. Compatible with OpenSSL. The format (like "PEM")
|
||||||
|
must be specified with \fICURLOPT_SSLKEYTYPE(3)\fP.
|
||||||
|
|
||||||
|
If the blob is initialized with the flags member of struct curl_blob set to
|
||||||
|
CURL_BLOB_COPY, the application does not have to keep the buffer around after
|
||||||
|
setting this.
|
||||||
|
|
||||||
|
This option is an alternative to \fICURLOPT_SSLKEY(3)\fP which instead expects
|
||||||
|
a file name as input.
|
||||||
|
.SH DEFAULT
|
||||||
|
NULL
|
||||||
|
.SH PROTOCOLS
|
||||||
|
All TLS based protocols: HTTPS, FTPS, IMAPS, POP3S, SMTPS etc.
|
||||||
|
.SH EXAMPLE
|
||||||
|
.nf
|
||||||
|
CURL *curl = curl_easy_init();
|
||||||
|
if(curl) {
|
||||||
|
struct curl_blob blob;
|
||||||
|
curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
|
||||||
|
blob.data = certificateData;
|
||||||
|
blob.len = filesize;
|
||||||
|
blob.flags = CURL_BLOB_COPY;
|
||||||
|
curl_easy_setopt(curl, CURLOPT_SSLCERT_BLOB, &blob);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, "PEM");
|
||||||
|
|
||||||
|
blob.data = privateKeyData;
|
||||||
|
blob.len = privateKeySize;
|
||||||
|
curl_easy_setopt(curl, CURLOPT_SSLKEY_BLOB, &blob);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_KEYPASSWD, "s3cret");
|
||||||
|
curl_easy_setopt(curl, CURLOPT_SSLKEYTYPE, "PEM");
|
||||||
|
ret = curl_easy_perform(curl);
|
||||||
|
curl_easy_cleanup(curl);
|
||||||
|
}
|
||||||
|
.fi
|
||||||
|
.SH AVAILABILITY
|
||||||
|
Added in libcurl 7.71.0. This option is supported by the OpenSSL backends.
|
||||||
|
.SH RETURN VALUE
|
||||||
|
Returns CURLE_OK if TLS enabled, CURLE_UNKNOWN_OPTION if not, or
|
||||||
|
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
|
||||||
|
.SH "SEE ALSO"
|
||||||
|
.BR CURLOPT_SSLKEYTYPE "(3), " CURLOPT_SSLKEY "(3), "
|
@ -198,6 +198,7 @@ man_MANS = \
|
|||||||
CURLOPT_IOCTLFUNCTION.3 \
|
CURLOPT_IOCTLFUNCTION.3 \
|
||||||
CURLOPT_IPRESOLVE.3 \
|
CURLOPT_IPRESOLVE.3 \
|
||||||
CURLOPT_ISSUERCERT.3 \
|
CURLOPT_ISSUERCERT.3 \
|
||||||
|
CURLOPT_ISSUERCERT_BLOB.3 \
|
||||||
CURLOPT_KEEP_SENDING_ON_ERROR.3 \
|
CURLOPT_KEEP_SENDING_ON_ERROR.3 \
|
||||||
CURLOPT_KEYPASSWD.3 \
|
CURLOPT_KEYPASSWD.3 \
|
||||||
CURLOPT_KRBLEVEL.3 \
|
CURLOPT_KRBLEVEL.3 \
|
||||||
@ -260,8 +261,10 @@ man_MANS = \
|
|||||||
CURLOPT_PROXY_PINNEDPUBLICKEY.3 \
|
CURLOPT_PROXY_PINNEDPUBLICKEY.3 \
|
||||||
CURLOPT_PROXY_SERVICE_NAME.3 \
|
CURLOPT_PROXY_SERVICE_NAME.3 \
|
||||||
CURLOPT_PROXY_SSLCERT.3 \
|
CURLOPT_PROXY_SSLCERT.3 \
|
||||||
|
CURLOPT_PROXY_SSLCERT_BLOB.3 \
|
||||||
CURLOPT_PROXY_SSLCERTTYPE.3 \
|
CURLOPT_PROXY_SSLCERTTYPE.3 \
|
||||||
CURLOPT_PROXY_SSLKEY.3 \
|
CURLOPT_PROXY_SSLKEY.3 \
|
||||||
|
CURLOPT_PROXY_SSLKEY_BLOB.3 \
|
||||||
CURLOPT_PROXY_SSLKEYTYPE.3 \
|
CURLOPT_PROXY_SSLKEYTYPE.3 \
|
||||||
CURLOPT_PROXY_SSLVERSION.3 \
|
CURLOPT_PROXY_SSLVERSION.3 \
|
||||||
CURLOPT_PROXY_SSL_CIPHER_LIST.3 \
|
CURLOPT_PROXY_SSL_CIPHER_LIST.3 \
|
||||||
@ -313,10 +316,12 @@ man_MANS = \
|
|||||||
CURLOPT_SSH_PRIVATE_KEYFILE.3 \
|
CURLOPT_SSH_PRIVATE_KEYFILE.3 \
|
||||||
CURLOPT_SSH_PUBLIC_KEYFILE.3 \
|
CURLOPT_SSH_PUBLIC_KEYFILE.3 \
|
||||||
CURLOPT_SSLCERT.3 \
|
CURLOPT_SSLCERT.3 \
|
||||||
|
CURLOPT_SSLCERT_BLOB.3 \
|
||||||
CURLOPT_SSLCERTTYPE.3 \
|
CURLOPT_SSLCERTTYPE.3 \
|
||||||
CURLOPT_SSLENGINE.3 \
|
CURLOPT_SSLENGINE.3 \
|
||||||
CURLOPT_SSLENGINE_DEFAULT.3 \
|
CURLOPT_SSLENGINE_DEFAULT.3 \
|
||||||
CURLOPT_SSLKEY.3 \
|
CURLOPT_SSLKEY.3 \
|
||||||
|
CURLOPT_SSLKEY_BLOB.3 \
|
||||||
CURLOPT_SSLKEYTYPE.3 \
|
CURLOPT_SSLKEYTYPE.3 \
|
||||||
CURLOPT_SSLVERSION.3 \
|
CURLOPT_SSLVERSION.3 \
|
||||||
CURLOPT_SSL_CIPHER_LIST.3 \
|
CURLOPT_SSL_CIPHER_LIST.3 \
|
||||||
|
@ -347,6 +347,7 @@ CURLM_RECURSIVE_API_CALL 7.59.0
|
|||||||
CURLM_UNKNOWN_OPTION 7.15.4
|
CURLM_UNKNOWN_OPTION 7.15.4
|
||||||
CURLM_WAKEUP_FAILURE 7.68.0
|
CURLM_WAKEUP_FAILURE 7.68.0
|
||||||
CURLOPT 7.69.0
|
CURLOPT 7.69.0
|
||||||
|
CURLOPTTYPE_BLOB 7.71.0
|
||||||
CURLOPTTYPE_FUNCTIONPOINT 7.1
|
CURLOPTTYPE_FUNCTIONPOINT 7.1
|
||||||
CURLOPTTYPE_LONG 7.1
|
CURLOPTTYPE_LONG 7.1
|
||||||
CURLOPTTYPE_OBJECTPOINT 7.1
|
CURLOPTTYPE_OBJECTPOINT 7.1
|
||||||
@ -459,6 +460,7 @@ CURLOPT_IOCTLDATA 7.12.3
|
|||||||
CURLOPT_IOCTLFUNCTION 7.12.3
|
CURLOPT_IOCTLFUNCTION 7.12.3
|
||||||
CURLOPT_IPRESOLVE 7.10.8
|
CURLOPT_IPRESOLVE 7.10.8
|
||||||
CURLOPT_ISSUERCERT 7.19.0
|
CURLOPT_ISSUERCERT 7.19.0
|
||||||
|
CURLOPT_ISSUERCERT_BLOB 7.71.0
|
||||||
CURLOPT_KEEP_SENDING_ON_ERROR 7.51.0
|
CURLOPT_KEEP_SENDING_ON_ERROR 7.51.0
|
||||||
CURLOPT_KEYPASSWD 7.17.0
|
CURLOPT_KEYPASSWD 7.17.0
|
||||||
CURLOPT_KRB4LEVEL 7.3 7.17.0
|
CURLOPT_KRB4LEVEL 7.3 7.17.0
|
||||||
@ -528,8 +530,10 @@ CURLOPT_PROXY_KEYPASSWD 7.52.0
|
|||||||
CURLOPT_PROXY_PINNEDPUBLICKEY 7.52.0
|
CURLOPT_PROXY_PINNEDPUBLICKEY 7.52.0
|
||||||
CURLOPT_PROXY_SERVICE_NAME 7.43.0
|
CURLOPT_PROXY_SERVICE_NAME 7.43.0
|
||||||
CURLOPT_PROXY_SSLCERT 7.52.0
|
CURLOPT_PROXY_SSLCERT 7.52.0
|
||||||
|
CURLOPT_PROXY_SSLCERT_BLOB 7.71.0
|
||||||
CURLOPT_PROXY_SSLCERTTYPE 7.52.0
|
CURLOPT_PROXY_SSLCERTTYPE 7.52.0
|
||||||
CURLOPT_PROXY_SSLKEY 7.52.0
|
CURLOPT_PROXY_SSLKEY 7.52.0
|
||||||
|
CURLOPT_PROXY_SSLKEY_BLOB 7.71.0
|
||||||
CURLOPT_PROXY_SSLKEYTYPE 7.52.0
|
CURLOPT_PROXY_SSLKEYTYPE 7.52.0
|
||||||
CURLOPT_PROXY_SSLVERSION 7.52.0
|
CURLOPT_PROXY_SSLVERSION 7.52.0
|
||||||
CURLOPT_PROXY_SSL_CIPHER_LIST 7.52.0
|
CURLOPT_PROXY_SSL_CIPHER_LIST 7.52.0
|
||||||
@ -591,11 +595,13 @@ CURLOPT_SSH_KNOWNHOSTS 7.19.6
|
|||||||
CURLOPT_SSH_PRIVATE_KEYFILE 7.16.1
|
CURLOPT_SSH_PRIVATE_KEYFILE 7.16.1
|
||||||
CURLOPT_SSH_PUBLIC_KEYFILE 7.16.1
|
CURLOPT_SSH_PUBLIC_KEYFILE 7.16.1
|
||||||
CURLOPT_SSLCERT 7.1
|
CURLOPT_SSLCERT 7.1
|
||||||
|
CURLOPT_SSLCERT_BLOB 7.71.0
|
||||||
CURLOPT_SSLCERTPASSWD 7.1.1 7.17.0
|
CURLOPT_SSLCERTPASSWD 7.1.1 7.17.0
|
||||||
CURLOPT_SSLCERTTYPE 7.9.3
|
CURLOPT_SSLCERTTYPE 7.9.3
|
||||||
CURLOPT_SSLENGINE 7.9.3
|
CURLOPT_SSLENGINE 7.9.3
|
||||||
CURLOPT_SSLENGINE_DEFAULT 7.9.3
|
CURLOPT_SSLENGINE_DEFAULT 7.9.3
|
||||||
CURLOPT_SSLKEY 7.9.3
|
CURLOPT_SSLKEY 7.9.3
|
||||||
|
CURLOPT_SSLKEY_BLOB 7.71.0
|
||||||
CURLOPT_SSLKEYPASSWD 7.9.3 7.17.0
|
CURLOPT_SSLKEYPASSWD 7.9.3 7.17.0
|
||||||
CURLOPT_SSLKEYTYPE 7.9.3
|
CURLOPT_SSLKEYTYPE 7.9.3
|
||||||
CURLOPT_SSLVERSION 7.1
|
CURLOPT_SSLVERSION 7.1
|
||||||
|
@ -950,6 +950,7 @@ typedef enum {
|
|||||||
#define CURLOPTTYPE_OBJECTPOINT 10000
|
#define CURLOPTTYPE_OBJECTPOINT 10000
|
||||||
#define CURLOPTTYPE_FUNCTIONPOINT 20000
|
#define CURLOPTTYPE_FUNCTIONPOINT 20000
|
||||||
#define CURLOPTTYPE_OFF_T 30000
|
#define CURLOPTTYPE_OFF_T 30000
|
||||||
|
#define CURLOPTTYPE_BLOB 40000
|
||||||
|
|
||||||
/* *STRINGPOINT is an alias for OBJECTPOINT to allow tools to extract the
|
/* *STRINGPOINT is an alias for OBJECTPOINT to allow tools to extract the
|
||||||
string options from the header file */
|
string options from the header file */
|
||||||
@ -1959,6 +1960,13 @@ typedef enum {
|
|||||||
/* allow RCPT TO command to fail for some recipients */
|
/* allow RCPT TO command to fail for some recipients */
|
||||||
CURLOPT(CURLOPT_MAIL_RCPT_ALLLOWFAILS, CURLOPTTYPE_LONG, 290),
|
CURLOPT(CURLOPT_MAIL_RCPT_ALLLOWFAILS, CURLOPTTYPE_LONG, 290),
|
||||||
|
|
||||||
|
/* the private SSL-certificate as a "blob" */
|
||||||
|
CURLOPT(CURLOPT_SSLCERT_BLOB, CURLOPTTYPE_BLOB, 291),
|
||||||
|
CURLOPT(CURLOPT_SSLKEY_BLOB, CURLOPTTYPE_BLOB, 292),
|
||||||
|
CURLOPT(CURLOPT_PROXY_SSLCERT_BLOB, CURLOPTTYPE_BLOB, 293),
|
||||||
|
CURLOPT(CURLOPT_PROXY_SSLKEY_BLOB, CURLOPTTYPE_BLOB, 294),
|
||||||
|
CURLOPT(CURLOPT_ISSUERCERT_BLOB, CURLOPTTYPE_BLOB, 295),
|
||||||
|
|
||||||
CURLOPT_LASTENTRY /* the last unused */
|
CURLOPT_LASTENTRY /* the last unused */
|
||||||
} CURLoption;
|
} CURLoption;
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
@ -25,6 +25,17 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Flag bits in the curl_blob struct: */
|
||||||
|
#define CURL_BLOB_COPY 1 /* tell libcurl to copy the data */
|
||||||
|
#define CURL_BLOB_NOCOPY 0 /* tell libcurl to NOT copy the data */
|
||||||
|
|
||||||
|
struct curl_blob {
|
||||||
|
void *data;
|
||||||
|
size_t len;
|
||||||
|
unsigned int flags; /* bit 0 is defined, the rest are reserved and should be
|
||||||
|
left zeroes */
|
||||||
|
};
|
||||||
|
|
||||||
CURL_EXTERN CURL *curl_easy_init(void);
|
CURL_EXTERN CURL *curl_easy_init(void);
|
||||||
CURL_EXTERN CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...);
|
CURL_EXTERN CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...);
|
||||||
CURL_EXTERN CURLcode curl_easy_perform(CURL *curl);
|
CURL_EXTERN CURLcode curl_easy_perform(CURL *curl);
|
||||||
|
11
lib/easy.c
11
lib/easy.c
@ -764,6 +764,7 @@ static CURLcode dupset(struct Curl_easy *dst, struct Curl_easy *src)
|
|||||||
{
|
{
|
||||||
CURLcode result = CURLE_OK;
|
CURLcode result = CURLE_OK;
|
||||||
enum dupstring i;
|
enum dupstring i;
|
||||||
|
enum dupblob j;
|
||||||
|
|
||||||
/* Copy src->set into dst->set first, then deal with the strings
|
/* Copy src->set into dst->set first, then deal with the strings
|
||||||
afterwards */
|
afterwards */
|
||||||
@ -780,6 +781,16 @@ static CURLcode dupset(struct Curl_easy *dst, struct Curl_easy *src)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* clear all blob pointers first */
|
||||||
|
memset(dst->set.blobs, 0, BLOB_LAST * sizeof(struct curl_blob *));
|
||||||
|
/* duplicate all blobs */
|
||||||
|
for(j = (enum dupblob)0; j < BLOB_LAST; j++) {
|
||||||
|
result = Curl_setblobopt(&dst->set.blobs[j], src->set.blobs[j]);
|
||||||
|
/* Curl_setstropt return CURLE_BAD_FUNCTION_ARGUMENT with blob */
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/* duplicate memory areas pointed to */
|
/* duplicate memory areas pointed to */
|
||||||
i = STRING_COPYPOSTFIELDS;
|
i = STRING_COPYPOSTFIELDS;
|
||||||
if(src->set.postfieldsize && src->set.str[i]) {
|
if(src->set.postfieldsize && src->set.str[i]) {
|
||||||
|
66
lib/setopt.c
66
lib/setopt.c
@ -77,6 +77,37 @@ CURLcode Curl_setstropt(char **charp, const char *s)
|
|||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CURLcode Curl_setblobopt(struct curl_blob **blobp,
|
||||||
|
const struct curl_blob *blob)
|
||||||
|
{
|
||||||
|
/* free the previous storage at `blobp' and replace by a dynamic storage
|
||||||
|
copy of blob. If CURL_BLOB_COPY is set, the data is copied. */
|
||||||
|
|
||||||
|
Curl_safefree(*blobp);
|
||||||
|
|
||||||
|
if(blob) {
|
||||||
|
struct curl_blob *nblob;
|
||||||
|
if(blob->len > CURL_MAX_INPUT_LENGTH)
|
||||||
|
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||||
|
nblob = (struct curl_blob *)
|
||||||
|
malloc(sizeof(struct curl_blob) +
|
||||||
|
((blob->flags & CURL_BLOB_COPY) ? blob->len : 0));
|
||||||
|
if(!nblob)
|
||||||
|
return CURLE_OUT_OF_MEMORY;
|
||||||
|
*nblob = *blob;
|
||||||
|
if(blob->flags & CURL_BLOB_COPY) {
|
||||||
|
/* put the data after the blob struct in memory */
|
||||||
|
nblob->data = (char *)nblob + sizeof(struct curl_blob);
|
||||||
|
memcpy(nblob->data, blob->data, blob->len);
|
||||||
|
}
|
||||||
|
|
||||||
|
*blobp = nblob;
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
static CURLcode setstropt_userpwd(char *option, char **userp, char **passwdp)
|
static CURLcode setstropt_userpwd(char *option, char **userp, char **passwdp)
|
||||||
{
|
{
|
||||||
CURLcode result = CURLE_OK;
|
CURLcode result = CURLE_OK;
|
||||||
@ -1606,6 +1637,13 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
|
|||||||
result = Curl_setstropt(&data->set.str[STRING_CERT_ORIG],
|
result = Curl_setstropt(&data->set.str[STRING_CERT_ORIG],
|
||||||
va_arg(param, char *));
|
va_arg(param, char *));
|
||||||
break;
|
break;
|
||||||
|
case CURLOPT_SSLCERT_BLOB:
|
||||||
|
/*
|
||||||
|
* Blob that holds file name of the SSL certificate to use
|
||||||
|
*/
|
||||||
|
result = Curl_setblobopt(&data->set.blobs[BLOB_CERT_ORIG],
|
||||||
|
va_arg(param, struct curl_blob *));
|
||||||
|
break;
|
||||||
#ifndef CURL_DISABLE_PROXY
|
#ifndef CURL_DISABLE_PROXY
|
||||||
case CURLOPT_PROXY_SSLCERT:
|
case CURLOPT_PROXY_SSLCERT:
|
||||||
/*
|
/*
|
||||||
@ -1614,6 +1652,13 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
|
|||||||
result = Curl_setstropt(&data->set.str[STRING_CERT_PROXY],
|
result = Curl_setstropt(&data->set.str[STRING_CERT_PROXY],
|
||||||
va_arg(param, char *));
|
va_arg(param, char *));
|
||||||
break;
|
break;
|
||||||
|
case CURLOPT_PROXY_SSLCERT_BLOB:
|
||||||
|
/*
|
||||||
|
* Blob that holds file name of the SSL certificate to use for proxy
|
||||||
|
*/
|
||||||
|
result = Curl_setblobopt(&data->set.blobs[BLOB_CERT_PROXY],
|
||||||
|
va_arg(param, struct curl_blob *));
|
||||||
|
break;
|
||||||
#endif
|
#endif
|
||||||
case CURLOPT_SSLCERTTYPE:
|
case CURLOPT_SSLCERTTYPE:
|
||||||
/*
|
/*
|
||||||
@ -1638,6 +1683,13 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
|
|||||||
result = Curl_setstropt(&data->set.str[STRING_KEY_ORIG],
|
result = Curl_setstropt(&data->set.str[STRING_KEY_ORIG],
|
||||||
va_arg(param, char *));
|
va_arg(param, char *));
|
||||||
break;
|
break;
|
||||||
|
case CURLOPT_SSLKEY_BLOB:
|
||||||
|
/*
|
||||||
|
* Blob that holds file name of the SSL key to use
|
||||||
|
*/
|
||||||
|
result = Curl_setblobopt(&data->set.blobs[BLOB_KEY_ORIG],
|
||||||
|
va_arg(param, struct curl_blob *));
|
||||||
|
break;
|
||||||
#ifndef CURL_DISABLE_PROXY
|
#ifndef CURL_DISABLE_PROXY
|
||||||
case CURLOPT_PROXY_SSLKEY:
|
case CURLOPT_PROXY_SSLKEY:
|
||||||
/*
|
/*
|
||||||
@ -1646,6 +1698,13 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
|
|||||||
result = Curl_setstropt(&data->set.str[STRING_KEY_PROXY],
|
result = Curl_setstropt(&data->set.str[STRING_KEY_PROXY],
|
||||||
va_arg(param, char *));
|
va_arg(param, char *));
|
||||||
break;
|
break;
|
||||||
|
case CURLOPT_PROXY_SSLKEY_BLOB:
|
||||||
|
/*
|
||||||
|
* Blob that holds file name of the SSL key to use for proxy
|
||||||
|
*/
|
||||||
|
result = Curl_setblobopt(&data->set.blobs[BLOB_KEY_PROXY],
|
||||||
|
va_arg(param, struct curl_blob *));
|
||||||
|
break;
|
||||||
#endif
|
#endif
|
||||||
case CURLOPT_SSLKEYTYPE:
|
case CURLOPT_SSLKEYTYPE:
|
||||||
/*
|
/*
|
||||||
@ -1970,6 +2029,13 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
|
|||||||
result = Curl_setstropt(&data->set.str[STRING_SSL_ISSUERCERT_ORIG],
|
result = Curl_setstropt(&data->set.str[STRING_SSL_ISSUERCERT_ORIG],
|
||||||
va_arg(param, char *));
|
va_arg(param, char *));
|
||||||
break;
|
break;
|
||||||
|
case CURLOPT_ISSUERCERT_BLOB:
|
||||||
|
/*
|
||||||
|
* Blob that holds Issuer certificate to check certificates issuer
|
||||||
|
*/
|
||||||
|
result = Curl_setblobopt(&data->set.blobs[BLOB_SSL_ISSUERCERT_ORIG],
|
||||||
|
va_arg(param, struct curl_blob *));
|
||||||
|
break;
|
||||||
#ifndef CURL_DISABLE_TELNET
|
#ifndef CURL_DISABLE_TELNET
|
||||||
case CURLOPT_TELNETOPTIONS:
|
case CURLOPT_TELNETOPTIONS:
|
||||||
/*
|
/*
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
@ -23,6 +23,8 @@
|
|||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
CURLcode Curl_setstropt(char **charp, const char *s);
|
CURLcode Curl_setstropt(char **charp, const char *s);
|
||||||
|
CURLcode Curl_setblobopt(struct curl_blob **blobp,
|
||||||
|
const struct curl_blob *blob);
|
||||||
CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list arg);
|
CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list arg);
|
||||||
|
|
||||||
#endif /* HEADER_CURL_SETOPT_H */
|
#endif /* HEADER_CURL_SETOPT_H */
|
||||||
|
12
lib/url.c
12
lib/url.c
@ -281,10 +281,16 @@ void Curl_freeset(struct Curl_easy *data)
|
|||||||
{
|
{
|
||||||
/* Free all dynamic strings stored in the data->set substructure. */
|
/* Free all dynamic strings stored in the data->set substructure. */
|
||||||
enum dupstring i;
|
enum dupstring i;
|
||||||
|
enum dupblob j;
|
||||||
|
|
||||||
for(i = (enum dupstring)0; i < STRING_LAST; i++) {
|
for(i = (enum dupstring)0; i < STRING_LAST; i++) {
|
||||||
Curl_safefree(data->set.str[i]);
|
Curl_safefree(data->set.str[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for(j = (enum dupblob)0; j < BLOB_LAST; j++) {
|
||||||
|
Curl_safefree(data->set.blobs[j]);
|
||||||
|
}
|
||||||
|
|
||||||
if(data->change.referer_alloc) {
|
if(data->change.referer_alloc) {
|
||||||
Curl_safefree(data->change.referer);
|
Curl_safefree(data->change.referer);
|
||||||
data->change.referer_alloc = FALSE;
|
data->change.referer_alloc = FALSE;
|
||||||
@ -3617,6 +3623,12 @@ static CURLcode create_conn(struct Curl_easy *data,
|
|||||||
data->set.proxy_ssl.password = data->set.str[STRING_TLSAUTH_PASSWORD_PROXY];
|
data->set.proxy_ssl.password = data->set.str[STRING_TLSAUTH_PASSWORD_PROXY];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
data->set.ssl.cert_blob = data->set.blobs[BLOB_CERT_ORIG];
|
||||||
|
data->set.proxy_ssl.cert_blob = data->set.blobs[BLOB_CERT_PROXY];
|
||||||
|
data->set.ssl.key_blob = data->set.blobs[BLOB_KEY_ORIG];
|
||||||
|
data->set.proxy_ssl.key_blob = data->set.blobs[BLOB_KEY_PROXY];
|
||||||
|
data->set.ssl.issuercert_blob = data->set.blobs[BLOB_SSL_ISSUERCERT_ORIG];
|
||||||
|
|
||||||
if(!Curl_clone_primary_ssl_config(&data->set.ssl.primary,
|
if(!Curl_clone_primary_ssl_config(&data->set.ssl.primary,
|
||||||
&conn->ssl_config)) {
|
&conn->ssl_config)) {
|
||||||
result = CURLE_OUT_OF_MEMORY;
|
result = CURLE_OUT_OF_MEMORY;
|
||||||
|
@ -240,11 +240,14 @@ struct ssl_config_data {
|
|||||||
long certverifyresult; /* result from the certificate verification */
|
long certverifyresult; /* result from the certificate verification */
|
||||||
char *CRLfile; /* CRL to check certificate revocation */
|
char *CRLfile; /* CRL to check certificate revocation */
|
||||||
char *issuercert;/* optional issuer certificate filename */
|
char *issuercert;/* optional issuer certificate filename */
|
||||||
|
struct curl_blob *issuercert_blob;
|
||||||
curl_ssl_ctx_callback fsslctx; /* function to initialize ssl ctx */
|
curl_ssl_ctx_callback fsslctx; /* function to initialize ssl ctx */
|
||||||
void *fsslctxp; /* parameter for call back */
|
void *fsslctxp; /* parameter for call back */
|
||||||
char *cert; /* client certificate file name */
|
char *cert; /* client certificate file name */
|
||||||
|
struct curl_blob *cert_blob;
|
||||||
char *cert_type; /* format for certificate (default: PEM)*/
|
char *cert_type; /* format for certificate (default: PEM)*/
|
||||||
char *key; /* private key file name */
|
char *key; /* private key file name */
|
||||||
|
struct curl_blob *key_blob;
|
||||||
char *key_type; /* format for private key (default: PEM) */
|
char *key_type; /* format for private key (default: PEM) */
|
||||||
char *key_passwd; /* plain text private key password */
|
char *key_passwd; /* plain text private key password */
|
||||||
#ifdef USE_TLS_SRP
|
#ifdef USE_TLS_SRP
|
||||||
@ -1580,6 +1583,15 @@ enum dupstring {
|
|||||||
STRING_LAST /* not used, just an end-of-list marker */
|
STRING_LAST /* not used, just an end-of-list marker */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum dupblob {
|
||||||
|
BLOB_CERT_ORIG,
|
||||||
|
BLOB_CERT_PROXY,
|
||||||
|
BLOB_KEY_ORIG,
|
||||||
|
BLOB_KEY_PROXY,
|
||||||
|
BLOB_SSL_ISSUERCERT_ORIG,
|
||||||
|
BLOB_LAST
|
||||||
|
};
|
||||||
|
|
||||||
/* callback that gets called when this easy handle is completed within a multi
|
/* callback that gets called when this easy handle is completed within a multi
|
||||||
handle. Only used for internally created transfers, like for example
|
handle. Only used for internally created transfers, like for example
|
||||||
DoH. */
|
DoH. */
|
||||||
@ -1711,6 +1723,7 @@ struct UserDefined {
|
|||||||
long new_directory_perms; /* Permissions to use when creating remote dirs */
|
long new_directory_perms; /* Permissions to use when creating remote dirs */
|
||||||
long ssh_auth_types; /* allowed SSH auth types */
|
long ssh_auth_types; /* allowed SSH auth types */
|
||||||
char *str[STRING_LAST]; /* array of strings, pointing to allocated memory */
|
char *str[STRING_LAST]; /* array of strings, pointing to allocated memory */
|
||||||
|
struct curl_blob *blobs[BLOB_LAST];
|
||||||
unsigned int scope_id; /* Scope id for IPv6 */
|
unsigned int scope_id; /* Scope id for IPv6 */
|
||||||
long allowed_protocols;
|
long allowed_protocols;
|
||||||
long redir_protocols;
|
long redir_protocols;
|
||||||
|
@ -621,12 +621,136 @@ static bool is_pkcs11_uri(const char *string)
|
|||||||
static CURLcode Curl_ossl_set_engine(struct Curl_easy *data,
|
static CURLcode Curl_ossl_set_engine(struct Curl_easy *data,
|
||||||
const char *engine);
|
const char *engine);
|
||||||
|
|
||||||
|
static int
|
||||||
|
SSL_CTX_use_certificate_bio(SSL_CTX *ctx, BIO *in, int type,
|
||||||
|
const char *key_passwd)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
X509 *x = NULL;
|
||||||
|
|
||||||
|
if(type == SSL_FILETYPE_ASN1) {
|
||||||
|
/* j = ERR_R_ASN1_LIB; */
|
||||||
|
x = d2i_X509_bio(in, NULL);
|
||||||
|
}
|
||||||
|
else if(type == SSL_FILETYPE_PEM) {
|
||||||
|
/* ERR_R_PEM_LIB; */
|
||||||
|
x = PEM_read_bio_X509(in, NULL,
|
||||||
|
passwd_callback, (void *)key_passwd);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ret = 0;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(x == NULL) {
|
||||||
|
ret = 0;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = SSL_CTX_use_certificate(ctx, x);
|
||||||
|
end:
|
||||||
|
X509_free(x);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
SSL_CTX_use_PrivateKey_bio(SSL_CTX *ctx, BIO* in, int type,
|
||||||
|
const char *key_passwd)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
EVP_PKEY *pkey = NULL;
|
||||||
|
|
||||||
|
if(type == SSL_FILETYPE_PEM)
|
||||||
|
pkey = PEM_read_bio_PrivateKey(in, NULL, passwd_callback,
|
||||||
|
(void *)key_passwd);
|
||||||
|
else if(type == SSL_FILETYPE_ASN1)
|
||||||
|
pkey = d2i_PrivateKey_bio(in, NULL);
|
||||||
|
else {
|
||||||
|
ret = 0;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
if(pkey == NULL) {
|
||||||
|
ret = 0;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
ret = SSL_CTX_use_PrivateKey(ctx, pkey);
|
||||||
|
EVP_PKEY_free(pkey);
|
||||||
|
end:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
SSL_CTX_use_certificate_chain_bio(SSL_CTX *ctx, BIO* in,
|
||||||
|
const char *key_passwd)
|
||||||
|
{
|
||||||
|
/* SSL_CTX_add1_chain_cert introduced in OpenSSL 1.0.2 */
|
||||||
|
#if (OPENSSL_VERSION_NUMBER >= 0x1000200fL) /* 1.0.2 or later */
|
||||||
|
int ret = 0;
|
||||||
|
X509 *x = NULL;
|
||||||
|
void *passwd_callback_userdata = (void *)key_passwd;
|
||||||
|
|
||||||
|
ERR_clear_error();
|
||||||
|
|
||||||
|
x = PEM_read_bio_X509_AUX(in, NULL,
|
||||||
|
passwd_callback, (void *)key_passwd);
|
||||||
|
|
||||||
|
if(x == NULL) {
|
||||||
|
ret = 0;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = SSL_CTX_use_certificate(ctx, x);
|
||||||
|
|
||||||
|
if(ERR_peek_error() != 0)
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
if(ret) {
|
||||||
|
X509 *ca;
|
||||||
|
unsigned long err;
|
||||||
|
|
||||||
|
if(!SSL_CTX_clear_chain_certs(ctx)) {
|
||||||
|
ret = 0;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
while((ca = PEM_read_bio_X509(in, NULL, passwd_callback,
|
||||||
|
passwd_callback_userdata))
|
||||||
|
!= NULL) {
|
||||||
|
|
||||||
|
if(!SSL_CTX_add0_chain_cert(ctx, ca)) {
|
||||||
|
X509_free(ca);
|
||||||
|
ret = 0;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = ERR_peek_last_error();
|
||||||
|
if((ERR_GET_LIB(err) == ERR_LIB_PEM) &&
|
||||||
|
(ERR_GET_REASON(err) == PEM_R_NO_START_LINE))
|
||||||
|
ERR_clear_error();
|
||||||
|
else
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
end:
|
||||||
|
X509_free(x);
|
||||||
|
return ret;
|
||||||
|
#else
|
||||||
|
(void)ctx; /* unused */
|
||||||
|
(void)in; /* unused */
|
||||||
|
(void)key_passwd; /* unused */
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
int cert_stuff(struct connectdata *conn,
|
int cert_stuff(struct connectdata *conn,
|
||||||
SSL_CTX* ctx,
|
SSL_CTX* ctx,
|
||||||
char *cert_file,
|
char *cert_file,
|
||||||
|
BIO *cert_bio,
|
||||||
const char *cert_type,
|
const char *cert_type,
|
||||||
char *key_file,
|
char *key_file,
|
||||||
|
BIO* key_bio,
|
||||||
const char *key_type,
|
const char *key_type,
|
||||||
char *key_passwd)
|
char *key_passwd)
|
||||||
{
|
{
|
||||||
@ -636,10 +760,11 @@ int cert_stuff(struct connectdata *conn,
|
|||||||
|
|
||||||
int file_type = do_file_type(cert_type);
|
int file_type = do_file_type(cert_type);
|
||||||
|
|
||||||
if(cert_file || (file_type == SSL_FILETYPE_ENGINE)) {
|
if(cert_file || cert_bio || (file_type == SSL_FILETYPE_ENGINE)) {
|
||||||
SSL *ssl;
|
SSL *ssl;
|
||||||
X509 *x509;
|
X509 *x509;
|
||||||
int cert_done = 0;
|
int cert_done = 0;
|
||||||
|
int cert_use_result;
|
||||||
|
|
||||||
if(key_passwd) {
|
if(key_passwd) {
|
||||||
/* set the password in the callback userdata */
|
/* set the password in the callback userdata */
|
||||||
@ -652,8 +777,10 @@ int cert_stuff(struct connectdata *conn,
|
|||||||
switch(file_type) {
|
switch(file_type) {
|
||||||
case SSL_FILETYPE_PEM:
|
case SSL_FILETYPE_PEM:
|
||||||
/* SSL_CTX_use_certificate_chain_file() only works on PEM files */
|
/* SSL_CTX_use_certificate_chain_file() only works on PEM files */
|
||||||
if(SSL_CTX_use_certificate_chain_file(ctx,
|
cert_use_result = cert_bio ?
|
||||||
cert_file) != 1) {
|
SSL_CTX_use_certificate_chain_bio(ctx, cert_bio, key_passwd) :
|
||||||
|
SSL_CTX_use_certificate_chain_file(ctx, cert_file);
|
||||||
|
if(cert_use_result != 1) {
|
||||||
failf(data,
|
failf(data,
|
||||||
"could not load PEM client certificate, " OSSL_PACKAGE
|
"could not load PEM client certificate, " OSSL_PACKAGE
|
||||||
" error %s, "
|
" error %s, "
|
||||||
@ -668,9 +795,12 @@ int cert_stuff(struct connectdata *conn,
|
|||||||
/* SSL_CTX_use_certificate_file() works with either PEM or ASN1, but
|
/* SSL_CTX_use_certificate_file() works with either PEM or ASN1, but
|
||||||
we use the case above for PEM so this can only be performed with
|
we use the case above for PEM so this can only be performed with
|
||||||
ASN1 files. */
|
ASN1 files. */
|
||||||
if(SSL_CTX_use_certificate_file(ctx,
|
|
||||||
cert_file,
|
cert_use_result = cert_bio ?
|
||||||
file_type) != 1) {
|
SSL_CTX_use_certificate_bio(ctx, cert_bio,
|
||||||
|
file_type, key_passwd) :
|
||||||
|
SSL_CTX_use_certificate_file(ctx, cert_file, file_type);
|
||||||
|
if(cert_use_result != 1) {
|
||||||
failf(data,
|
failf(data,
|
||||||
"could not load ASN1 client certificate, " OSSL_PACKAGE
|
"could not load ASN1 client certificate, " OSSL_PACKAGE
|
||||||
" error %s, "
|
" error %s, "
|
||||||
@ -750,27 +880,31 @@ int cert_stuff(struct connectdata *conn,
|
|||||||
PKCS12 *p12 = NULL;
|
PKCS12 *p12 = NULL;
|
||||||
EVP_PKEY *pri;
|
EVP_PKEY *pri;
|
||||||
STACK_OF(X509) *ca = NULL;
|
STACK_OF(X509) *ca = NULL;
|
||||||
|
if(!cert_bio) {
|
||||||
|
fp = BIO_new(BIO_s_file());
|
||||||
|
if(fp == NULL) {
|
||||||
|
failf(data,
|
||||||
|
"BIO_new return NULL, " OSSL_PACKAGE
|
||||||
|
" error %s",
|
||||||
|
ossl_strerror(ERR_get_error(), error_buffer,
|
||||||
|
sizeof(error_buffer)) );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
fp = BIO_new(BIO_s_file());
|
if(BIO_read_filename(fp, cert_file) <= 0) {
|
||||||
if(fp == NULL) {
|
failf(data, "could not open PKCS12 file '%s'", cert_file);
|
||||||
failf(data,
|
BIO_free(fp);
|
||||||
"BIO_new return NULL, " OSSL_PACKAGE
|
return 0;
|
||||||
" error %s",
|
}
|
||||||
ossl_strerror(ERR_get_error(), error_buffer,
|
|
||||||
sizeof(error_buffer)) );
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(BIO_read_filename(fp, cert_file) <= 0) {
|
p12 = d2i_PKCS12_bio(cert_bio ? cert_bio : fp, NULL);
|
||||||
failf(data, "could not open PKCS12 file '%s'", cert_file);
|
if(fp)
|
||||||
BIO_free(fp);
|
BIO_free(fp);
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
p12 = d2i_PKCS12_bio(fp, NULL);
|
|
||||||
BIO_free(fp);
|
|
||||||
|
|
||||||
if(!p12) {
|
if(!p12) {
|
||||||
failf(data, "error reading PKCS12 file '%s'", cert_file);
|
failf(data, "error reading PKCS12 file '%s'",
|
||||||
|
cert_bio ? "(memory blob)" : cert_file);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -851,8 +985,10 @@ int cert_stuff(struct connectdata *conn,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!key_file)
|
if((!key_file) && (!key_bio)) {
|
||||||
key_file = cert_file;
|
key_file = cert_file;
|
||||||
|
key_bio = cert_bio;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
file_type = do_file_type(key_type);
|
file_type = do_file_type(key_type);
|
||||||
|
|
||||||
@ -862,9 +998,12 @@ int cert_stuff(struct connectdata *conn,
|
|||||||
break;
|
break;
|
||||||
/* FALLTHROUGH */
|
/* FALLTHROUGH */
|
||||||
case SSL_FILETYPE_ASN1:
|
case SSL_FILETYPE_ASN1:
|
||||||
if(SSL_CTX_use_PrivateKey_file(ctx, key_file, file_type) != 1) {
|
cert_use_result = key_bio ?
|
||||||
|
SSL_CTX_use_PrivateKey_bio(ctx, key_bio, file_type, key_passwd) :
|
||||||
|
SSL_CTX_use_PrivateKey_file(ctx, key_file, file_type);
|
||||||
|
if(cert_use_result != 1) {
|
||||||
failf(data, "unable to set private key file: '%s' type %s",
|
failf(data, "unable to set private key file: '%s' type %s",
|
||||||
key_file, key_type?key_type:"PEM");
|
key_file?key_file:"(memory blob)", key_type?key_type:"PEM");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -2418,6 +2557,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
|
|||||||
const enum CURL_TLSAUTH ssl_authtype = SSL_SET_OPTION(authtype);
|
const enum CURL_TLSAUTH ssl_authtype = SSL_SET_OPTION(authtype);
|
||||||
#endif
|
#endif
|
||||||
char * const ssl_cert = SSL_SET_OPTION(cert);
|
char * const ssl_cert = SSL_SET_OPTION(cert);
|
||||||
|
const struct curl_blob *ssl_cert_blob = SSL_SET_OPTION(cert_blob);
|
||||||
const char * const ssl_cert_type = SSL_SET_OPTION(cert_type);
|
const char * const ssl_cert_type = SSL_SET_OPTION(cert_type);
|
||||||
const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile);
|
const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile);
|
||||||
const char * const ssl_capath = SSL_CONN_CONFIG(CApath);
|
const char * const ssl_capath = SSL_CONN_CONFIG(CApath);
|
||||||
@ -2662,10 +2802,33 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(ssl_cert || ssl_cert_type) {
|
if(ssl_cert || ssl_cert_blob || ssl_cert_type) {
|
||||||
if(!cert_stuff(conn, backend->ctx, ssl_cert, ssl_cert_type,
|
BIO *ssl_cert_bio = NULL;
|
||||||
SSL_SET_OPTION(key), SSL_SET_OPTION(key_type),
|
BIO *ssl_key_bio = NULL;
|
||||||
SSL_SET_OPTION(key_passwd))) {
|
int result_cert_stuff;
|
||||||
|
if(ssl_cert_blob) {
|
||||||
|
/* the typecast of blob->len is fine since it is guaranteed to never be
|
||||||
|
larger than CURL_MAX_INPUT_LENGTH */
|
||||||
|
ssl_cert_bio = BIO_new_mem_buf(ssl_cert_blob->data,
|
||||||
|
(int)ssl_cert_blob->len);
|
||||||
|
if(!ssl_cert_bio)
|
||||||
|
return CURLE_SSL_CERTPROBLEM;
|
||||||
|
}
|
||||||
|
if(SSL_SET_OPTION(key_blob)) {
|
||||||
|
ssl_key_bio = BIO_new_mem_buf(SSL_SET_OPTION(key_blob)->data,
|
||||||
|
(int)SSL_SET_OPTION(key_blob)->len);
|
||||||
|
if(!ssl_key_bio)
|
||||||
|
return CURLE_SSL_CERTPROBLEM;
|
||||||
|
}
|
||||||
|
result_cert_stuff = cert_stuff(conn, backend->ctx,
|
||||||
|
ssl_cert, ssl_cert_bio, ssl_cert_type,
|
||||||
|
SSL_SET_OPTION(key), ssl_key_bio,
|
||||||
|
SSL_SET_OPTION(key_type), SSL_SET_OPTION(key_passwd));
|
||||||
|
if(ssl_cert_bio)
|
||||||
|
BIO_free(ssl_cert_bio);
|
||||||
|
if(ssl_key_bio)
|
||||||
|
BIO_free(ssl_key_bio);
|
||||||
|
if(!result_cert_stuff) {
|
||||||
/* failf() is already done in cert_stuff() */
|
/* failf() is already done in cert_stuff() */
|
||||||
return CURLE_SSL_CERTPROBLEM;
|
return CURLE_SSL_CERTPROBLEM;
|
||||||
}
|
}
|
||||||
@ -3714,27 +3877,32 @@ static CURLcode servercert(struct connectdata *conn,
|
|||||||
deallocating the certificate. */
|
deallocating the certificate. */
|
||||||
|
|
||||||
/* e.g. match issuer name with provided issuer certificate */
|
/* e.g. match issuer name with provided issuer certificate */
|
||||||
if(SSL_SET_OPTION(issuercert)) {
|
if(SSL_SET_OPTION(issuercert) || SSL_SET_OPTION(issuercert_blob)) {
|
||||||
fp = BIO_new(BIO_s_file());
|
if(SSL_SET_OPTION(issuercert_blob))
|
||||||
if(fp == NULL) {
|
fp = BIO_new_mem_buf(SSL_SET_OPTION(issuercert_blob)->data,
|
||||||
failf(data,
|
(int)SSL_SET_OPTION(issuercert_blob)->len);
|
||||||
"BIO_new return NULL, " OSSL_PACKAGE
|
else {
|
||||||
" error %s",
|
fp = BIO_new(BIO_s_file());
|
||||||
ossl_strerror(ERR_get_error(), error_buffer,
|
if(fp == NULL) {
|
||||||
sizeof(error_buffer)) );
|
failf(data,
|
||||||
X509_free(backend->server_cert);
|
"BIO_new return NULL, " OSSL_PACKAGE
|
||||||
backend->server_cert = NULL;
|
" error %s",
|
||||||
return CURLE_OUT_OF_MEMORY;
|
ossl_strerror(ERR_get_error(), error_buffer,
|
||||||
}
|
sizeof(error_buffer)) );
|
||||||
|
X509_free(backend->server_cert);
|
||||||
|
backend->server_cert = NULL;
|
||||||
|
return CURLE_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
if(BIO_read_filename(fp, SSL_SET_OPTION(issuercert)) <= 0) {
|
if(BIO_read_filename(fp, SSL_SET_OPTION(issuercert)) <= 0) {
|
||||||
if(strict)
|
if(strict)
|
||||||
failf(data, "SSL: Unable to open issuer cert (%s)",
|
failf(data, "SSL: Unable to open issuer cert (%s)",
|
||||||
SSL_SET_OPTION(issuercert));
|
SSL_SET_OPTION(issuercert));
|
||||||
BIO_free(fp);
|
BIO_free(fp);
|
||||||
X509_free(backend->server_cert);
|
X509_free(backend->server_cert);
|
||||||
backend->server_cert = NULL;
|
backend->server_cert = NULL;
|
||||||
return CURLE_SSL_ISSUER_ERROR;
|
return CURLE_SSL_ISSUER_ERROR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
issuer = PEM_read_bio_X509(fp, NULL, ZERO_NULL, NULL);
|
issuer = PEM_read_bio_X509(fp, NULL, ZERO_NULL, NULL);
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
|
|
||||||
#include "schannel.h"
|
#include "schannel.h"
|
||||||
#include "vtls.h"
|
#include "vtls.h"
|
||||||
|
#include "strcase.h"
|
||||||
#include "sendf.h"
|
#include "sendf.h"
|
||||||
#include "connect.h" /* for the connect timeout */
|
#include "connect.h" /* for the connect timeout */
|
||||||
#include "strerror.h"
|
#include "strerror.h"
|
||||||
@ -583,94 +584,122 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
|
|||||||
|
|
||||||
#ifdef HAS_CLIENT_CERT_PATH
|
#ifdef HAS_CLIENT_CERT_PATH
|
||||||
/* client certificate */
|
/* client certificate */
|
||||||
if(data->set.ssl.cert) {
|
if(data->set.ssl.cert || data->set.ssl.cert_blob) {
|
||||||
DWORD cert_store_name;
|
DWORD cert_store_name = 0;
|
||||||
TCHAR *cert_store_path = NULL;
|
TCHAR *cert_store_path = NULL;
|
||||||
TCHAR *cert_thumbprint_str;
|
TCHAR *cert_thumbprint_str = NULL;
|
||||||
CRYPT_HASH_BLOB cert_thumbprint;
|
CRYPT_HASH_BLOB cert_thumbprint;
|
||||||
BYTE cert_thumbprint_data[CERT_THUMBPRINT_DATA_LEN];
|
BYTE cert_thumbprint_data[CERT_THUMBPRINT_DATA_LEN];
|
||||||
HCERTSTORE cert_store;
|
HCERTSTORE cert_store = NULL;
|
||||||
FILE *fInCert = NULL;
|
FILE *fInCert = NULL;
|
||||||
|
void *certdata = NULL;
|
||||||
|
size_t certsize = 0;
|
||||||
|
bool blob = data->set.ssl.cert_blob != NULL;
|
||||||
|
TCHAR *cert_path = NULL;
|
||||||
|
if(blob) {
|
||||||
|
certdata = data->set.ssl.cert_blob->data;
|
||||||
|
certsize = data->set.ssl.cert_blob->len;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cert_path = curlx_convert_UTF8_to_tchar(data->set.ssl.cert);
|
||||||
|
if(!cert_path)
|
||||||
|
return CURLE_OUT_OF_MEMORY;
|
||||||
|
|
||||||
TCHAR *cert_path = curlx_convert_UTF8_to_tchar(data->set.ssl.cert);
|
result = get_cert_location(cert_path, &cert_store_name,
|
||||||
if(!cert_path)
|
&cert_store_path, &cert_thumbprint_str);
|
||||||
return CURLE_OUT_OF_MEMORY;
|
|
||||||
|
|
||||||
result = get_cert_location(cert_path, &cert_store_name,
|
if(result && (data->set.ssl.cert[0]!='\0'))
|
||||||
&cert_store_path, &cert_thumbprint_str);
|
fInCert = fopen(data->set.ssl.cert, "rb");
|
||||||
if((result != CURLE_OK) && (data->set.ssl.cert[0]!='\0'))
|
|
||||||
fInCert = fopen(data->set.ssl.cert, "rb");
|
|
||||||
|
|
||||||
if((result != CURLE_OK) && (fInCert == NULL)) {
|
if(result && !fInCert) {
|
||||||
failf(data, "schannel: Failed to get certificate location"
|
failf(data, "schannel: Failed to get certificate location"
|
||||||
" or file for %s",
|
" or file for %s",
|
||||||
data->set.ssl.cert);
|
data->set.ssl.cert);
|
||||||
curlx_unicodefree(cert_path);
|
curlx_unicodefree(cert_path);
|
||||||
return result;
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(fInCert) {
|
if((fInCert || blob) && (data->set.ssl.cert_type) &&
|
||||||
|
(!strcasecompare(data->set.ssl.cert_type, "P12"))) {
|
||||||
|
failf(data, "schannel: certificate format compatibility error "
|
||||||
|
" for %s",
|
||||||
|
blob ? "(memory blob)" : data->set.ssl.cert);
|
||||||
|
curlx_unicodefree(cert_path);
|
||||||
|
return CURLE_SSL_CERTPROBLEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(fInCert || blob) {
|
||||||
/* Reading a .P12 or .pfx file, like the example at bottom of
|
/* Reading a .P12 or .pfx file, like the example at bottom of
|
||||||
https://social.msdn.microsoft.com/Forums/windowsdesktop/
|
https://social.msdn.microsoft.com/Forums/windowsdesktop/
|
||||||
en-US/3e7bc95f-b21a-4bcd-bd2c-7f996718cae5
|
en-US/3e7bc95f-b21a-4bcd-bd2c-7f996718cae5
|
||||||
*/
|
*/
|
||||||
void *certdata = NULL;
|
|
||||||
long filesize = 0;
|
|
||||||
CRYPT_DATA_BLOB datablob;
|
CRYPT_DATA_BLOB datablob;
|
||||||
WCHAR* pszPassword;
|
WCHAR* pszPassword;
|
||||||
size_t pwd_len = 0;
|
size_t pwd_len = 0;
|
||||||
int str_w_len = 0;
|
int str_w_len = 0;
|
||||||
int continue_reading = fseek(fInCert, 0, SEEK_END) == 0;
|
const char *cert_showfilename_error = blob ?
|
||||||
if(continue_reading)
|
"(memory blob)" : data->set.ssl.cert;
|
||||||
filesize = ftell(fInCert);
|
|
||||||
if(filesize < 0)
|
|
||||||
continue_reading = 0;
|
|
||||||
if(continue_reading)
|
|
||||||
continue_reading = fseek(fInCert, 0, SEEK_SET) == 0;
|
|
||||||
if(continue_reading)
|
|
||||||
certdata = malloc(((size_t)filesize) + 1);
|
|
||||||
if((certdata == NULL) ||
|
|
||||||
((int) fread(certdata, (size_t)filesize, 1, fInCert) != 1))
|
|
||||||
continue_reading = 0;
|
|
||||||
fclose(fInCert);
|
|
||||||
curlx_unicodefree(cert_path);
|
curlx_unicodefree(cert_path);
|
||||||
|
if(fInCert) {
|
||||||
if(!continue_reading) {
|
long cert_tell = 0;
|
||||||
failf(data, "schannel: Failed to read cert file %s",
|
bool continue_reading = fseek(fInCert, 0, SEEK_END) == 0;
|
||||||
|
if(continue_reading)
|
||||||
|
cert_tell = ftell(fInCert);
|
||||||
|
if(cert_tell < 0)
|
||||||
|
continue_reading = FALSE;
|
||||||
|
else
|
||||||
|
certsize = (size_t)cert_tell;
|
||||||
|
if(continue_reading)
|
||||||
|
continue_reading = fseek(fInCert, 0, SEEK_SET) == 0;
|
||||||
|
if(continue_reading)
|
||||||
|
certdata = malloc(certsize + 1);
|
||||||
|
if((!certdata) ||
|
||||||
|
((int) fread(certdata, certsize, 1, fInCert) != 1))
|
||||||
|
continue_reading = FALSE;
|
||||||
|
fclose(fInCert);
|
||||||
|
if(!continue_reading) {
|
||||||
|
failf(data, "schannel: Failed to read cert file %s",
|
||||||
data->set.ssl.cert);
|
data->set.ssl.cert);
|
||||||
free(certdata);
|
free(certdata);
|
||||||
return CURLE_SSL_CERTPROBLEM;
|
return CURLE_SSL_CERTPROBLEM;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Convert key-pair data to the in-memory certificate store */
|
/* Convert key-pair data to the in-memory certificate store */
|
||||||
datablob.pbData = (BYTE*)certdata;
|
datablob.pbData = (BYTE*)certdata;
|
||||||
datablob.cbData = (DWORD)filesize;
|
datablob.cbData = (DWORD)certsize;
|
||||||
|
|
||||||
if(data->set.ssl.key_passwd != NULL)
|
if(data->set.ssl.key_passwd != NULL)
|
||||||
pwd_len = strlen(data->set.ssl.key_passwd);
|
pwd_len = strlen(data->set.ssl.key_passwd);
|
||||||
pszPassword = (WCHAR*)malloc(sizeof(WCHAR)*(pwd_len + 1));
|
pszPassword = (WCHAR*)malloc(sizeof(WCHAR)*(pwd_len + 1));
|
||||||
if(pwd_len > 0)
|
if(pszPassword) {
|
||||||
str_w_len =
|
if(pwd_len > 0)
|
||||||
MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
|
str_w_len = MultiByteToWideChar(CP_UTF8,
|
||||||
data->set.ssl.key_passwd, (int)pwd_len,
|
MB_ERR_INVALID_CHARS,
|
||||||
pszPassword, (int)(pwd_len + 1));
|
data->set.ssl.key_passwd, (int)pwd_len,
|
||||||
|
pszPassword, (int)(pwd_len + 1));
|
||||||
|
|
||||||
if((str_w_len >= 0) && (str_w_len <= (int)pwd_len))
|
if((str_w_len >= 0) && (str_w_len <= (int)pwd_len))
|
||||||
pszPassword[str_w_len] = 0;
|
pszPassword[str_w_len] = 0;
|
||||||
else
|
else
|
||||||
pszPassword[0] = 0;
|
pszPassword[0] = 0;
|
||||||
|
|
||||||
cert_store = PFXImportCertStore(&datablob, pszPassword, 0);
|
cert_store = PFXImportCertStore(&datablob, pszPassword, 0);
|
||||||
free(pszPassword);
|
free(pszPassword);
|
||||||
free(certdata);
|
}
|
||||||
|
if(!blob)
|
||||||
|
free(certdata);
|
||||||
if(cert_store == NULL) {
|
if(cert_store == NULL) {
|
||||||
DWORD errorcode = GetLastError();
|
DWORD errorcode = GetLastError();
|
||||||
if(errorcode == ERROR_INVALID_PASSWORD)
|
if(errorcode == ERROR_INVALID_PASSWORD)
|
||||||
failf(data, "schannel: Failed to import cert file %s, "
|
failf(data, "schannel: Failed to import cert file %s, "
|
||||||
"password is bad", data->set.ssl.cert);
|
"password is bad",
|
||||||
|
cert_showfilename_error);
|
||||||
else
|
else
|
||||||
failf(data, "schannel: Failed to import cert file %s, "
|
failf(data, "schannel: Failed to import cert file %s, "
|
||||||
"last error is 0x%x", data->set.ssl.cert, errorcode);
|
"last error is 0x%x",
|
||||||
|
cert_showfilename_error, errorcode);
|
||||||
return CURLE_SSL_CERTPROBLEM;
|
return CURLE_SSL_CERTPROBLEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -681,7 +710,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
|
|||||||
if(client_certs[0] == NULL) {
|
if(client_certs[0] == NULL) {
|
||||||
failf(data, "schannel: Failed to get certificate from file %s"
|
failf(data, "schannel: Failed to get certificate from file %s"
|
||||||
", last error is 0x%x",
|
", last error is 0x%x",
|
||||||
data->set.ssl.cert, GetLastError());
|
cert_showfilename_error, GetLastError());
|
||||||
CertCloseStore(cert_store, 0);
|
CertCloseStore(cert_store, 0);
|
||||||
return CURLE_SSL_CERTPROBLEM;
|
return CURLE_SSL_CERTPROBLEM;
|
||||||
}
|
}
|
||||||
|
@ -1126,12 +1126,12 @@ static OSStatus CopyIdentityWithLabel(char *label,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static OSStatus CopyIdentityFromPKCS12File(const char *cPath,
|
static OSStatus CopyIdentityFromPKCS12File(const char *cPath,
|
||||||
|
const struct curl_blob *blob,
|
||||||
const char *cPassword,
|
const char *cPassword,
|
||||||
SecIdentityRef *out_cert_and_key)
|
SecIdentityRef *out_cert_and_key)
|
||||||
{
|
{
|
||||||
OSStatus status = errSecItemNotFound;
|
OSStatus status = errSecItemNotFound;
|
||||||
CFURLRef pkcs_url = CFURLCreateFromFileSystemRepresentation(NULL,
|
CFURLRef pkcs_url = NULL;
|
||||||
(const UInt8 *)cPath, strlen(cPath), false);
|
|
||||||
CFStringRef password = cPassword ? CFStringCreateWithCString(NULL,
|
CFStringRef password = cPassword ? CFStringCreateWithCString(NULL,
|
||||||
cPassword, kCFStringEncodingUTF8) : NULL;
|
cPassword, kCFStringEncodingUTF8) : NULL;
|
||||||
CFDataRef pkcs_data = NULL;
|
CFDataRef pkcs_data = NULL;
|
||||||
@ -1140,8 +1140,26 @@ static OSStatus CopyIdentityFromPKCS12File(const char *cPath,
|
|||||||
/* These constants are documented as having first appeared in 10.6 but they
|
/* These constants are documented as having first appeared in 10.6 but they
|
||||||
raise linker errors when used on that cat for some reason. */
|
raise linker errors when used on that cat for some reason. */
|
||||||
#if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS
|
#if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS
|
||||||
if(CFURLCreateDataAndPropertiesFromResource(NULL, pkcs_url, &pkcs_data,
|
bool resource_imported;
|
||||||
NULL, NULL, &status)) {
|
|
||||||
|
if(blob) {
|
||||||
|
pkcs_data = CFDataCreate(kCFAllocatorDefault,
|
||||||
|
(const unsigned char *)blob->data, blob->len);
|
||||||
|
status = (pkcs_data != NULL) ? errSecSuccess : errSecAllocate;
|
||||||
|
resource_imported = (pkcs_data != NULL);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pkcs_url =
|
||||||
|
CFURLCreateFromFileSystemRepresentation(NULL,
|
||||||
|
(const UInt8 *)cPath,
|
||||||
|
strlen(cPath), false);
|
||||||
|
resource_imported =
|
||||||
|
CFURLCreateDataAndPropertiesFromResource(NULL,
|
||||||
|
pkcs_url, &pkcs_data,
|
||||||
|
NULL, NULL, &status);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(resource_imported) {
|
||||||
CFArrayRef items = NULL;
|
CFArrayRef items = NULL;
|
||||||
|
|
||||||
/* On iOS SecPKCS12Import will never add the client certificate to the
|
/* On iOS SecPKCS12Import will never add the client certificate to the
|
||||||
@ -1219,7 +1237,8 @@ static OSStatus CopyIdentityFromPKCS12File(const char *cPath,
|
|||||||
#endif /* CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS */
|
#endif /* CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS */
|
||||||
if(password)
|
if(password)
|
||||||
CFRelease(password);
|
CFRelease(password);
|
||||||
CFRelease(pkcs_url);
|
if(pkcs_url)
|
||||||
|
CFRelease(pkcs_url);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1376,8 +1395,10 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn,
|
|||||||
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
|
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
|
||||||
struct ssl_backend_data *backend = connssl->backend;
|
struct ssl_backend_data *backend = connssl->backend;
|
||||||
const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile);
|
const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile);
|
||||||
|
const struct curl_blob *ssl_cablob = NULL;
|
||||||
const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
|
const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
|
||||||
char * const ssl_cert = SSL_SET_OPTION(cert);
|
char * const ssl_cert = SSL_SET_OPTION(cert);
|
||||||
|
const struct curl_blob *ssl_cert_blob = SSL_SET_OPTION(cert_blob);
|
||||||
const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
|
const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
|
||||||
conn->host.name;
|
conn->host.name;
|
||||||
const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port;
|
const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port;
|
||||||
@ -1612,15 +1633,16 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn,
|
|||||||
"Transport. The private key must be in the Keychain.\n");
|
"Transport. The private key must be in the Keychain.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ssl_cert) {
|
if(ssl_cert || ssl_cert_blob) {
|
||||||
|
bool is_cert_data = ssl_cert_blob != NULL;
|
||||||
|
bool is_cert_file = (!is_cert_data) && is_file(ssl_cert);
|
||||||
SecIdentityRef cert_and_key = NULL;
|
SecIdentityRef cert_and_key = NULL;
|
||||||
bool is_cert_file = is_file(ssl_cert);
|
|
||||||
|
|
||||||
/* User wants to authenticate with a client cert. Look for it:
|
/* User wants to authenticate with a client cert. Look for it:
|
||||||
If we detect that this is a file on disk, then let's load it.
|
If we detect that this is a file on disk, then let's load it.
|
||||||
Otherwise, assume that the user wants to use an identity loaded
|
Otherwise, assume that the user wants to use an identity loaded
|
||||||
from the Keychain. */
|
from the Keychain. */
|
||||||
if(is_cert_file) {
|
if(is_cert_file || is_cert_data) {
|
||||||
if(!SSL_SET_OPTION(cert_type))
|
if(!SSL_SET_OPTION(cert_type))
|
||||||
infof(data, "WARNING: SSL: Certificate type not set, assuming "
|
infof(data, "WARNING: SSL: Certificate type not set, assuming "
|
||||||
"PKCS#12 format.\n");
|
"PKCS#12 format.\n");
|
||||||
@ -1629,7 +1651,7 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn,
|
|||||||
infof(data, "WARNING: SSL: The Security framework only supports "
|
infof(data, "WARNING: SSL: The Security framework only supports "
|
||||||
"loading identities that are in PKCS#12 format.\n");
|
"loading identities that are in PKCS#12 format.\n");
|
||||||
|
|
||||||
err = CopyIdentityFromPKCS12File(ssl_cert,
|
err = CopyIdentityFromPKCS12File(ssl_cert, ssl_cert_blob,
|
||||||
SSL_SET_OPTION(key_passwd), &cert_and_key);
|
SSL_SET_OPTION(key_passwd), &cert_and_key);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -1669,27 +1691,30 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn,
|
|||||||
CFRelease(cert_and_key);
|
CFRelease(cert_and_key);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
const char *cert_showfilename_error =
|
||||||
|
is_cert_data ? "(memory blob)" : ssl_cert;
|
||||||
|
|
||||||
switch(err) {
|
switch(err) {
|
||||||
case errSecAuthFailed: case -25264: /* errSecPkcs12VerifyFailure */
|
case errSecAuthFailed: case -25264: /* errSecPkcs12VerifyFailure */
|
||||||
failf(data, "SSL: Incorrect password for the certificate \"%s\" "
|
failf(data, "SSL: Incorrect password for the certificate \"%s\" "
|
||||||
"and its private key.", ssl_cert);
|
"and its private key.", cert_showfilename_error);
|
||||||
break;
|
break;
|
||||||
case -26275: /* errSecDecode */ case -25257: /* errSecUnknownFormat */
|
case -26275: /* errSecDecode */ case -25257: /* errSecUnknownFormat */
|
||||||
failf(data, "SSL: Couldn't make sense of the data in the "
|
failf(data, "SSL: Couldn't make sense of the data in the "
|
||||||
"certificate \"%s\" and its private key.",
|
"certificate \"%s\" and its private key.",
|
||||||
ssl_cert);
|
cert_showfilename_error);
|
||||||
break;
|
break;
|
||||||
case -25260: /* errSecPassphraseRequired */
|
case -25260: /* errSecPassphraseRequired */
|
||||||
failf(data, "SSL The certificate \"%s\" requires a password.",
|
failf(data, "SSL The certificate \"%s\" requires a password.",
|
||||||
ssl_cert);
|
cert_showfilename_error);
|
||||||
break;
|
break;
|
||||||
case errSecItemNotFound:
|
case errSecItemNotFound:
|
||||||
failf(data, "SSL: Can't find the certificate \"%s\" and its private "
|
failf(data, "SSL: Can't find the certificate \"%s\" and its private "
|
||||||
"key in the Keychain.", ssl_cert);
|
"key in the Keychain.", cert_showfilename_error);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
failf(data, "SSL: Can't load the certificate \"%s\" and its private "
|
failf(data, "SSL: Can't load the certificate \"%s\" and its private "
|
||||||
"key: OSStatus %d", ssl_cert, err);
|
"key: OSStatus %d", cert_showfilename_error, err);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return CURLE_SSL_CERTPROBLEM;
|
return CURLE_SSL_CERTPROBLEM;
|
||||||
@ -1721,7 +1746,8 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn,
|
|||||||
#else
|
#else
|
||||||
if(SSLSetSessionOption != NULL) {
|
if(SSLSetSessionOption != NULL) {
|
||||||
#endif /* CURL_BUILD_MAC */
|
#endif /* CURL_BUILD_MAC */
|
||||||
bool break_on_auth = !conn->ssl_config.verifypeer || ssl_cafile;
|
bool break_on_auth = !conn->ssl_config.verifypeer ||
|
||||||
|
ssl_cafile || ssl_cablob;
|
||||||
err = SSLSetSessionOption(backend->ssl_ctx,
|
err = SSLSetSessionOption(backend->ssl_ctx,
|
||||||
kSSLSessionOptionBreakOnServerAuth,
|
kSSLSessionOptionBreakOnServerAuth,
|
||||||
break_on_auth);
|
break_on_auth);
|
||||||
@ -1749,10 +1775,11 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn,
|
|||||||
}
|
}
|
||||||
#endif /* CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS */
|
#endif /* CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS */
|
||||||
|
|
||||||
if(ssl_cafile && verifypeer) {
|
if((ssl_cafile || ssl_cablob) && verifypeer) {
|
||||||
bool is_cert_file = is_file(ssl_cafile);
|
bool is_cert_data = ssl_cablob != NULL;
|
||||||
|
bool is_cert_file = (!is_cert_data) && is_file(ssl_cafile);
|
||||||
|
|
||||||
if(!is_cert_file) {
|
if(!(is_cert_file || is_cert_data)) {
|
||||||
failf(data, "SSL: can't load CA certificate file %s", ssl_cafile);
|
failf(data, "SSL: can't load CA certificate file %s", ssl_cafile);
|
||||||
return CURLE_SSL_CACERT_BADFILE;
|
return CURLE_SSL_CACERT_BADFILE;
|
||||||
}
|
}
|
||||||
|
@ -1556,11 +1556,90 @@ static CURLcode single_transfer(struct GlobalConfig *global,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* In debug build of curl tool, using
|
||||||
|
* --cert loadmem=<filename>:<password> --cert-type p12
|
||||||
|
* must do the same thing than classic:
|
||||||
|
* --cert <filename>:<password> --cert-type p12
|
||||||
|
* but is designed to test blob */
|
||||||
|
#if defined(CURLDEBUG) || defined(DEBUGBUILD)
|
||||||
|
if(config->cert && (strlen(config->cert) > 8) &&
|
||||||
|
(memcmp(config->cert, "loadmem=",8) == 0)) {
|
||||||
|
FILE *fInCert = fopen(config->cert + 8, "rb");
|
||||||
|
void *certdata = NULL;
|
||||||
|
long filesize = 0;
|
||||||
|
bool continue_reading = fInCert != NULL;
|
||||||
|
if(continue_reading)
|
||||||
|
continue_reading = fseek(fInCert, 0, SEEK_END) == 0;
|
||||||
|
if(continue_reading)
|
||||||
|
filesize = ftell(fInCert);
|
||||||
|
if(filesize < 0)
|
||||||
|
continue_reading = FALSE;
|
||||||
|
if(continue_reading)
|
||||||
|
continue_reading = fseek(fInCert, 0, SEEK_SET) == 0;
|
||||||
|
if(continue_reading)
|
||||||
|
certdata = malloc(((size_t)filesize) + 1);
|
||||||
|
if((!certdata) ||
|
||||||
|
((int)fread(certdata, (size_t)filesize, 1, fInCert) != 1))
|
||||||
|
continue_reading = FALSE;
|
||||||
|
if(fInCert)
|
||||||
|
fclose(fInCert);
|
||||||
|
if((filesize > 0) && continue_reading) {
|
||||||
|
struct curl_blob structblob;
|
||||||
|
structblob.data = certdata;
|
||||||
|
structblob.len = (size_t)filesize;
|
||||||
|
structblob.flags = CURL_BLOB_COPY;
|
||||||
|
my_setopt_str(curl, CURLOPT_SSLCERT_BLOB, &structblob);
|
||||||
|
/* if test run well, we are sure we don't reuse
|
||||||
|
* original mem pointer */
|
||||||
|
memset(certdata, 0, (size_t)filesize);
|
||||||
|
}
|
||||||
|
free(certdata);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
my_setopt_str(curl, CURLOPT_SSLCERT, config->cert);
|
my_setopt_str(curl, CURLOPT_SSLCERT, config->cert);
|
||||||
my_setopt_str(curl, CURLOPT_PROXY_SSLCERT, config->proxy_cert);
|
my_setopt_str(curl, CURLOPT_PROXY_SSLCERT, config->proxy_cert);
|
||||||
my_setopt_str(curl, CURLOPT_SSLCERTTYPE, config->cert_type);
|
my_setopt_str(curl, CURLOPT_SSLCERTTYPE, config->cert_type);
|
||||||
my_setopt_str(curl, CURLOPT_PROXY_SSLCERTTYPE,
|
my_setopt_str(curl, CURLOPT_PROXY_SSLCERTTYPE,
|
||||||
config->proxy_cert_type);
|
config->proxy_cert_type);
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(CURLDEBUG) || defined(DEBUGBUILD)
|
||||||
|
if(config->key && (strlen(config->key) > 8) &&
|
||||||
|
(memcmp(config->key, "loadmem=",8) == 0)) {
|
||||||
|
FILE *fInCert = fopen(config->key + 8, "rb");
|
||||||
|
void *certdata = NULL;
|
||||||
|
long filesize = 0;
|
||||||
|
bool continue_reading = fInCert != NULL;
|
||||||
|
if(continue_reading)
|
||||||
|
continue_reading = fseek(fInCert, 0, SEEK_END) == 0;
|
||||||
|
if(continue_reading)
|
||||||
|
filesize = ftell(fInCert);
|
||||||
|
if(filesize < 0)
|
||||||
|
continue_reading = FALSE;
|
||||||
|
if(continue_reading)
|
||||||
|
continue_reading = fseek(fInCert, 0, SEEK_SET) == 0;
|
||||||
|
if(continue_reading)
|
||||||
|
certdata = malloc(((size_t)filesize) + 1);
|
||||||
|
if((!certdata) ||
|
||||||
|
((int)fread(certdata, (size_t)filesize, 1, fInCert) != 1))
|
||||||
|
continue_reading = FALSE;
|
||||||
|
if(fInCert)
|
||||||
|
fclose(fInCert);
|
||||||
|
if((filesize > 0) && continue_reading) {
|
||||||
|
struct curl_blob structblob;
|
||||||
|
structblob.data = certdata;
|
||||||
|
structblob.len = (size_t)filesize;
|
||||||
|
structblob.flags = CURL_BLOB_COPY;
|
||||||
|
my_setopt_str(curl, CURLOPT_SSLKEY_BLOB, &structblob);
|
||||||
|
/* if test run well, we are sure we don't reuse
|
||||||
|
* original mem pointer */
|
||||||
|
memset(certdata, 0, (size_t)filesize);
|
||||||
|
}
|
||||||
|
free(certdata);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
my_setopt_str(curl, CURLOPT_SSLKEY, config->key);
|
my_setopt_str(curl, CURLOPT_SSLKEY, config->key);
|
||||||
my_setopt_str(curl, CURLOPT_PROXY_SSLKEY, config->proxy_key);
|
my_setopt_str(curl, CURLOPT_PROXY_SSLKEY, config->proxy_key);
|
||||||
my_setopt_str(curl, CURLOPT_SSLKEYTYPE, config->key_type);
|
my_setopt_str(curl, CURLOPT_SSLKEYTYPE, config->key_type);
|
||||||
|
@ -683,7 +683,7 @@ CURLcode tool_setopt(CURL *curl, bool str, struct GlobalConfig *config,
|
|||||||
ret = curl_easy_setopt(curl, tag, pval);
|
ret = curl_easy_setopt(curl, tag, pval);
|
||||||
|
|
||||||
}
|
}
|
||||||
else {
|
else if(tag < CURLOPTTYPE_BLOB) {
|
||||||
/* Value is expected to be curl_off_t */
|
/* Value is expected to be curl_off_t */
|
||||||
curl_off_t oval = va_arg(arg, curl_off_t);
|
curl_off_t oval = va_arg(arg, curl_off_t);
|
||||||
msnprintf(buf, sizeof(buf),
|
msnprintf(buf, sizeof(buf),
|
||||||
@ -694,6 +694,20 @@ CURLcode tool_setopt(CURL *curl, bool str, struct GlobalConfig *config,
|
|||||||
if(!oval)
|
if(!oval)
|
||||||
skip = TRUE;
|
skip = TRUE;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
/* Value is a blob */
|
||||||
|
void *pblob = va_arg(arg, void *);
|
||||||
|
|
||||||
|
/* blobs are never printable */
|
||||||
|
if(pblob) {
|
||||||
|
value = "blobpointer";
|
||||||
|
remark = TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
skip = TRUE;
|
||||||
|
|
||||||
|
ret = curl_easy_setopt(curl, tag, pblob);
|
||||||
|
}
|
||||||
|
|
||||||
va_end(arg);
|
va_end(arg);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user