mirror of
https://github.com/moparisthebest/curl
synced 2024-11-05 00:55:04 -05:00
SSL: support in-memory CA certs for some backends
- New options CURLOPT_CAINFO_BLOB and CURLOPT_PROXY_CAINFO_BLOB to specify in-memory PEM certificates for OpenSSL, Schannel (Windows) and Secure Transport (Apple) SSL backends. Prior to this change PEM certificates could only be imported from a file and not from memory. Co-authored-by: moparisthebest@users.noreply.github.com Ref: https://github.com/curl/curl/pull/4679 Ref: https://github.com/curl/curl/pull/5677 Ref: https://github.com/curl/curl/pull/6109 Closes https://github.com/curl/curl/pull/6662
This commit is contained in:
parent
70cf50fb4a
commit
77fc3859b2
@ -584,8 +584,12 @@ Verify the DOH (DNS-over-HTTPS) SSL certificate's status. See
|
|||||||
\fICURLOPT_DOH_SSL_VERIFYSTATUS(3)\fP
|
\fICURLOPT_DOH_SSL_VERIFYSTATUS(3)\fP
|
||||||
.IP CURLOPT_CAINFO
|
.IP CURLOPT_CAINFO
|
||||||
CA cert bundle. See \fICURLOPT_CAINFO(3)\fP
|
CA cert bundle. See \fICURLOPT_CAINFO(3)\fP
|
||||||
|
.IP CURLOPT_CAINFO_BLOB
|
||||||
|
CA cert bundle memory buffer. See \fICURLOPT_CAINFO_BLOB(3)\fP
|
||||||
.IP CURLOPT_PROXY_CAINFO
|
.IP CURLOPT_PROXY_CAINFO
|
||||||
Proxy CA cert bundle. See \fICURLOPT_PROXY_CAINFO(3)\fP
|
Proxy CA cert bundle. See \fICURLOPT_PROXY_CAINFO(3)\fP
|
||||||
|
.IP CURLOPT_PROXY_CAINFO_BLOB
|
||||||
|
Proxy CA cert bundle memory buffer. See \fICURLOPT_PROXY_CAINFO_BLOB(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
|
.IP CURLOPT_ISSUERCERT_BLOB
|
||||||
|
@ -79,5 +79,5 @@ option is ignored. Schannel support added in libcurl 7.60.
|
|||||||
Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
|
Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
|
||||||
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
|
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
|
||||||
.SH "SEE ALSO"
|
.SH "SEE ALSO"
|
||||||
.BR CURLOPT_CAPATH "(3), "
|
.BR CURLOPT_CAINFO_BLOB "(3), " CURLOPT_CAPATH "(3), "
|
||||||
.BR CURLOPT_SSL_VERIFYPEER "(3), " CURLOPT_SSL_VERIFYHOST "(3), "
|
.BR CURLOPT_SSL_VERIFYPEER "(3), " CURLOPT_SSL_VERIFYHOST "(3), "
|
||||||
|
68
docs/libcurl/opts/CURLOPT_CAINFO_BLOB.3
Normal file
68
docs/libcurl/opts/CURLOPT_CAINFO_BLOB.3
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
.\" **************************************************************************
|
||||||
|
.\" * _ _ ____ _
|
||||||
|
.\" * Project ___| | | | _ \| |
|
||||||
|
.\" * / __| | | | |_) | |
|
||||||
|
.\" * | (__| |_| | _ <| |___
|
||||||
|
.\" * \___|\___/|_| \_\_____|
|
||||||
|
.\" *
|
||||||
|
.\" * Copyright (C) 1998 - 2021, 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.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_CAINFO_BLOB 3 "31 March 2021" "libcurl 7.77.0" "curl_easy_setopt options"
|
||||||
|
.SH NAME
|
||||||
|
CURLOPT_CAINFO_BLOB \- Certificate Authority (CA) bundle in PEM format
|
||||||
|
.SH SYNOPSIS
|
||||||
|
#include <curl/curl.h>
|
||||||
|
|
||||||
|
CURLcode curl_easy_setopt(CURL *handle, CURLOPT_CAINFO_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 PEM encoded content holding
|
||||||
|
one or more certificates to verify the HTTPS server with.
|
||||||
|
|
||||||
|
If \fICURLOPT_SSL_VERIFYPEER(3)\fP is zero and you avoid verifying the
|
||||||
|
server's certificate, \fICURLOPT_CAINFO_BLOB(3)\fP is not needed.
|
||||||
|
|
||||||
|
This option overrides \fICURLOPT_CAINFO(3)\fP.
|
||||||
|
.SH DEFAULT
|
||||||
|
NULL
|
||||||
|
.SH PROTOCOLS
|
||||||
|
All TLS based protocols: HTTPS, FTPS, IMAPS, POP3S, SMTPS etc.
|
||||||
|
.SH EXAMPLE
|
||||||
|
.nf
|
||||||
|
char *strpem; /* strpem must point to a PEM string */
|
||||||
|
CURL *curl = curl_easy_init();
|
||||||
|
if(curl) {
|
||||||
|
struct curl_blob blob;
|
||||||
|
curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
|
||||||
|
blob.data = strpem;
|
||||||
|
blob.len = strlen(strpem);
|
||||||
|
blob.flags = CURL_BLOB_COPY;
|
||||||
|
curl_easy_setopt(curl, CURLOPT_CAINFO_BLOB, &blob);
|
||||||
|
ret = curl_easy_perform(curl);
|
||||||
|
curl_easy_cleanup(curl);
|
||||||
|
}
|
||||||
|
.fi
|
||||||
|
.SH AVAILABILITY
|
||||||
|
Added in 7.77.0.
|
||||||
|
|
||||||
|
This option is supported by the OpenSSL, Secure
|
||||||
|
Transport and Schannel 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_CAINFO "(3), " CURLOPT_CAPATH "(3), "
|
||||||
|
.BR CURLOPT_SSL_VERIFYPEER "(3), " CURLOPT_SSL_VERIFYHOST "(3), "
|
@ -77,7 +77,8 @@ https://curl.se/docs/ssl-compared.html
|
|||||||
Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
|
Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
|
||||||
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
|
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
|
||||||
.SH "SEE ALSO"
|
.SH "SEE ALSO"
|
||||||
.BR CURLOPT_PROXY_CAPATH "(3), "
|
.BR CURLOPT_PROXY_CAINFO_BLOB "(3), " CURLOPT_PROXY_CAPATH "(3), "
|
||||||
.BR CURLOPT_PROXY_SSL_VERIFYPEER "(3), " CURLOPT_PROXY_SSL_VERIFYHOST "(3), "
|
.BR CURLOPT_PROXY_SSL_VERIFYPEER "(3), " CURLOPT_PROXY_SSL_VERIFYHOST "(3), "
|
||||||
|
.BR CURLOPT_CAINFO "(3), " CURLOPT_CAINFO_BLOB "(3), "
|
||||||
.BR CURLOPT_CAPATH "(3), "
|
.BR CURLOPT_CAPATH "(3), "
|
||||||
.BR CURLOPT_SSL_VERIFYPEER "(3), " CURLOPT_SSL_VERIFYHOST "(3), "
|
.BR CURLOPT_SSL_VERIFYPEER "(3), " CURLOPT_SSL_VERIFYHOST "(3), "
|
||||||
|
75
docs/libcurl/opts/CURLOPT_PROXY_CAINFO_BLOB.3
Normal file
75
docs/libcurl/opts/CURLOPT_PROXY_CAINFO_BLOB.3
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
.\" **************************************************************************
|
||||||
|
.\" * _ _ ____ _
|
||||||
|
.\" * Project ___| | | | _ \| |
|
||||||
|
.\" * / __| | | | |_) | |
|
||||||
|
.\" * | (__| |_| | _ <| |___
|
||||||
|
.\" * \___|\___/|_| \_\_____|
|
||||||
|
.\" *
|
||||||
|
.\" * Copyright (C) 1998 - 2021, 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.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_CAINFO_BLOB 3 "31 March 2021" "libcurl 7.77.0" "curl_easy_setopt options"
|
||||||
|
.SH NAME
|
||||||
|
CURLOPT_PROXY_CAINFO_BLOB \- proxy Certificate Authority (CA) bundle in PEM format
|
||||||
|
.SH SYNOPSIS
|
||||||
|
#include <curl/curl.h>
|
||||||
|
|
||||||
|
CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXY_CAINFO_BLOB, struct curl_blob *stblob);
|
||||||
|
.SH DESCRIPTION
|
||||||
|
This option is for connecting to an HTTPS proxy, not an HTTPS server.
|
||||||
|
|
||||||
|
Pass a pointer to a curl_blob structure, which contains information (pointer
|
||||||
|
and size) about a memory block with binary data of PEM encoded content holding
|
||||||
|
one or more certificates to verify the HTTPS proxy with.
|
||||||
|
|
||||||
|
If \fICURLOPT_PROXY_SSL_VERIFYPEER(3)\fP is zero and you avoid verifying the
|
||||||
|
server's certificate, \fICURLOPT_PROXY_CAINFO_BLOB(3)\fP is not needed.
|
||||||
|
|
||||||
|
This option overrides \fICURLOPT_PROXY_CAINFO(3)\fP.
|
||||||
|
.SH DEFAULT
|
||||||
|
NULL
|
||||||
|
.SH PROTOCOLS
|
||||||
|
Used with HTTPS proxy
|
||||||
|
.SH EXAMPLE
|
||||||
|
.nf
|
||||||
|
char *strpem; /* strpem must point to a PEM string */
|
||||||
|
CURL *curl = curl_easy_init();
|
||||||
|
if(curl) {
|
||||||
|
struct curl_blob blob;
|
||||||
|
curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
|
||||||
|
/* using an HTTPS proxy */
|
||||||
|
curl_easy_setopt(curl, CURLOPT_PROXY, "https://localhost:443");
|
||||||
|
blob.data = strpem;
|
||||||
|
blob.len = strlen(strpem);
|
||||||
|
blob.flags = CURL_BLOB_COPY;
|
||||||
|
curl_easy_setopt(curl, CURLOPT_PROXY_CAINFO_BLOB, &blob);
|
||||||
|
ret = curl_easy_perform(curl);
|
||||||
|
curl_easy_cleanup(curl);
|
||||||
|
}
|
||||||
|
.fi
|
||||||
|
.SH AVAILABILITY
|
||||||
|
Added in 7.77.0.
|
||||||
|
|
||||||
|
This option is supported by the OpenSSL, Secure
|
||||||
|
Transport and Schannel 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_PROXY_CAINFO "(3), " CURLOPT_PROXY_CAPATH "(3), "
|
||||||
|
.BR CURLOPT_PROXY_SSL_VERIFYPEER "(3), " CURLOPT_PROXY_SSL_VERIFYHOST "(3), "
|
||||||
|
.BR CURLOPT_CAINFO "(3), " CURLOPT_CAINFO_BLOB "(3), "
|
||||||
|
.BR CURLOPT_CAPATH "(3), "
|
||||||
|
.BR CURLOPT_SSL_VERIFYPEER "(3), " CURLOPT_SSL_VERIFYHOST "(3), "
|
@ -115,6 +115,7 @@ man_MANS = \
|
|||||||
CURLOPT_AUTOREFERER.3 \
|
CURLOPT_AUTOREFERER.3 \
|
||||||
CURLOPT_BUFFERSIZE.3 \
|
CURLOPT_BUFFERSIZE.3 \
|
||||||
CURLOPT_CAINFO.3 \
|
CURLOPT_CAINFO.3 \
|
||||||
|
CURLOPT_CAINFO_BLOB.3 \
|
||||||
CURLOPT_CAPATH.3 \
|
CURLOPT_CAPATH.3 \
|
||||||
CURLOPT_CERTINFO.3 \
|
CURLOPT_CERTINFO.3 \
|
||||||
CURLOPT_CHUNK_BGN_FUNCTION.3 \
|
CURLOPT_CHUNK_BGN_FUNCTION.3 \
|
||||||
@ -267,6 +268,7 @@ man_MANS = \
|
|||||||
CURLOPT_PROXYUSERNAME.3 \
|
CURLOPT_PROXYUSERNAME.3 \
|
||||||
CURLOPT_PROXYUSERPWD.3 \
|
CURLOPT_PROXYUSERPWD.3 \
|
||||||
CURLOPT_PROXY_CAINFO.3 \
|
CURLOPT_PROXY_CAINFO.3 \
|
||||||
|
CURLOPT_PROXY_CAINFO_BLOB.3 \
|
||||||
CURLOPT_PROXY_CAPATH.3 \
|
CURLOPT_PROXY_CAPATH.3 \
|
||||||
CURLOPT_PROXY_CRLFILE.3 \
|
CURLOPT_PROXY_CRLFILE.3 \
|
||||||
CURLOPT_PROXY_KEYPASSWD.3 \
|
CURLOPT_PROXY_KEYPASSWD.3 \
|
||||||
|
@ -374,6 +374,7 @@ CURLOPT_APPEND 7.17.0
|
|||||||
CURLOPT_AUTOREFERER 7.1
|
CURLOPT_AUTOREFERER 7.1
|
||||||
CURLOPT_BUFFERSIZE 7.10
|
CURLOPT_BUFFERSIZE 7.10
|
||||||
CURLOPT_CAINFO 7.4.2
|
CURLOPT_CAINFO 7.4.2
|
||||||
|
CURLOPT_CAINFO_BLOB 7.77.0
|
||||||
CURLOPT_CAPATH 7.9.8
|
CURLOPT_CAPATH 7.9.8
|
||||||
CURLOPT_CERTINFO 7.19.1
|
CURLOPT_CERTINFO 7.19.1
|
||||||
CURLOPT_CHUNK_BGN_FUNCTION 7.21.0
|
CURLOPT_CHUNK_BGN_FUNCTION 7.21.0
|
||||||
@ -543,6 +544,7 @@ CURLOPT_PROXYTYPE 7.10
|
|||||||
CURLOPT_PROXYUSERNAME 7.19.1
|
CURLOPT_PROXYUSERNAME 7.19.1
|
||||||
CURLOPT_PROXYUSERPWD 7.1
|
CURLOPT_PROXYUSERPWD 7.1
|
||||||
CURLOPT_PROXY_CAINFO 7.52.0
|
CURLOPT_PROXY_CAINFO 7.52.0
|
||||||
|
CURLOPT_PROXY_CAINFO_BLOB 7.77.0
|
||||||
CURLOPT_PROXY_CAPATH 7.52.0
|
CURLOPT_PROXY_CAPATH 7.52.0
|
||||||
CURLOPT_PROXY_CRLFILE 7.52.0
|
CURLOPT_PROXY_CRLFILE 7.52.0
|
||||||
CURLOPT_PROXY_ISSUERCERT 7.71.0
|
CURLOPT_PROXY_ISSUERCERT 7.71.0
|
||||||
|
@ -2093,6 +2093,14 @@ typedef enum {
|
|||||||
/* Same as CURLOPT_SSL_VERIFYSTATUS but for DOH (DNS-over-HTTPS) servers. */
|
/* Same as CURLOPT_SSL_VERIFYSTATUS but for DOH (DNS-over-HTTPS) servers. */
|
||||||
CURLOPT(CURLOPT_DOH_SSL_VERIFYSTATUS, CURLOPTTYPE_LONG, 308),
|
CURLOPT(CURLOPT_DOH_SSL_VERIFYSTATUS, CURLOPTTYPE_LONG, 308),
|
||||||
|
|
||||||
|
/* The CA certificates as "blob" used to validate the peer certificate
|
||||||
|
this option is used only if SSL_VERIFYPEER is true */
|
||||||
|
CURLOPT(CURLOPT_CAINFO_BLOB, CURLOPTTYPE_BLOB, 309),
|
||||||
|
|
||||||
|
/* The CA certificates as "blob" used to validate the proxy certificate
|
||||||
|
this option is used only if PROXY_SSL_VERIFYPEER is true */
|
||||||
|
CURLOPT(CURLOPT_PROXY_CAINFO_BLOB, CURLOPTTYPE_BLOB, 310),
|
||||||
|
|
||||||
CURLOPT_LASTENTRY /* the last unused */
|
CURLOPT_LASTENTRY /* the last unused */
|
||||||
} CURLoption;
|
} CURLoption;
|
||||||
|
|
||||||
|
@ -313,6 +313,10 @@ static CURLcode dohprobe(struct Curl_easy *data,
|
|||||||
ERROR_CHECK_SETOPT(CURLOPT_CAINFO,
|
ERROR_CHECK_SETOPT(CURLOPT_CAINFO,
|
||||||
data->set.str[STRING_SSL_CAFILE]);
|
data->set.str[STRING_SSL_CAFILE]);
|
||||||
}
|
}
|
||||||
|
if(data->set.blobs[BLOB_CAINFO]) {
|
||||||
|
ERROR_CHECK_SETOPT(CURLOPT_CAINFO_BLOB,
|
||||||
|
data->set.blobs[BLOB_CAINFO]);
|
||||||
|
}
|
||||||
if(data->set.str[STRING_SSL_CAPATH]) {
|
if(data->set.str[STRING_SSL_CAPATH]) {
|
||||||
ERROR_CHECK_SETOPT(CURLOPT_CAPATH,
|
ERROR_CHECK_SETOPT(CURLOPT_CAPATH,
|
||||||
data->set.str[STRING_SSL_CAPATH]);
|
data->set.str[STRING_SSL_CAPATH]);
|
||||||
|
@ -38,6 +38,7 @@ struct curl_easyoption Curl_easyopts[] = {
|
|||||||
{"AWS_SIGV4", CURLOPT_AWS_SIGV4, CURLOT_STRING, 0},
|
{"AWS_SIGV4", CURLOPT_AWS_SIGV4, CURLOT_STRING, 0},
|
||||||
{"BUFFERSIZE", CURLOPT_BUFFERSIZE, CURLOT_LONG, 0},
|
{"BUFFERSIZE", CURLOPT_BUFFERSIZE, CURLOT_LONG, 0},
|
||||||
{"CAINFO", CURLOPT_CAINFO, CURLOT_STRING, 0},
|
{"CAINFO", CURLOPT_CAINFO, CURLOT_STRING, 0},
|
||||||
|
{"CAINFO_BLOB", CURLOPT_CAINFO_BLOB, CURLOT_BLOB, 0},
|
||||||
{"CAPATH", CURLOPT_CAPATH, CURLOT_STRING, 0},
|
{"CAPATH", CURLOPT_CAPATH, CURLOT_STRING, 0},
|
||||||
{"CERTINFO", CURLOPT_CERTINFO, CURLOT_LONG, 0},
|
{"CERTINFO", CURLOPT_CERTINFO, CURLOT_LONG, 0},
|
||||||
{"CHUNK_BGN_FUNCTION", CURLOPT_CHUNK_BGN_FUNCTION, CURLOT_FUNCTION, 0},
|
{"CHUNK_BGN_FUNCTION", CURLOPT_CHUNK_BGN_FUNCTION, CURLOT_FUNCTION, 0},
|
||||||
@ -205,6 +206,7 @@ struct curl_easyoption Curl_easyopts[] = {
|
|||||||
{"PROXYUSERNAME", CURLOPT_PROXYUSERNAME, CURLOT_STRING, 0},
|
{"PROXYUSERNAME", CURLOPT_PROXYUSERNAME, CURLOT_STRING, 0},
|
||||||
{"PROXYUSERPWD", CURLOPT_PROXYUSERPWD, CURLOT_STRING, 0},
|
{"PROXYUSERPWD", CURLOPT_PROXYUSERPWD, CURLOT_STRING, 0},
|
||||||
{"PROXY_CAINFO", CURLOPT_PROXY_CAINFO, CURLOT_STRING, 0},
|
{"PROXY_CAINFO", CURLOPT_PROXY_CAINFO, CURLOT_STRING, 0},
|
||||||
|
{"PROXY_CAINFO_BLOB", CURLOPT_PROXY_CAINFO_BLOB, CURLOT_BLOB, 0},
|
||||||
{"PROXY_CAPATH", CURLOPT_PROXY_CAPATH, CURLOT_STRING, 0},
|
{"PROXY_CAPATH", CURLOPT_PROXY_CAPATH, CURLOT_STRING, 0},
|
||||||
{"PROXY_CRLFILE", CURLOPT_PROXY_CRLFILE, CURLOT_STRING, 0},
|
{"PROXY_CRLFILE", CURLOPT_PROXY_CRLFILE, CURLOT_STRING, 0},
|
||||||
{"PROXY_ISSUERCERT", CURLOPT_PROXY_ISSUERCERT, CURLOT_STRING, 0},
|
{"PROXY_ISSUERCERT", CURLOPT_PROXY_ISSUERCERT, CURLOT_STRING, 0},
|
||||||
@ -352,6 +354,6 @@ struct curl_easyoption Curl_easyopts[] = {
|
|||||||
*/
|
*/
|
||||||
int Curl_easyopts_check(void)
|
int Curl_easyopts_check(void)
|
||||||
{
|
{
|
||||||
return ((CURLOPT_LASTENTRY%10000) != (308 + 1));
|
return ((CURLOPT_LASTENTRY%10000) != (310 + 1));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
27
lib/setopt.c
27
lib/setopt.c
@ -2041,6 +2041,20 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
|
|||||||
result = Curl_setstropt(&data->set.str[STRING_SSL_CAFILE],
|
result = Curl_setstropt(&data->set.str[STRING_SSL_CAFILE],
|
||||||
va_arg(param, char *));
|
va_arg(param, char *));
|
||||||
break;
|
break;
|
||||||
|
case CURLOPT_CAINFO_BLOB:
|
||||||
|
/*
|
||||||
|
* Blob that holds CA info for SSL connection.
|
||||||
|
* Specify entire PEM of the CA certificate
|
||||||
|
*/
|
||||||
|
#ifdef USE_SSL
|
||||||
|
if(Curl_ssl->supports & SSLSUPP_CAINFO_BLOB)
|
||||||
|
result = Curl_setblobopt(&data->set.blobs[BLOB_CAINFO],
|
||||||
|
va_arg(param, struct curl_blob *));
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
return CURLE_NOT_BUILT_IN;
|
||||||
|
|
||||||
|
break;
|
||||||
#ifndef CURL_DISABLE_PROXY
|
#ifndef CURL_DISABLE_PROXY
|
||||||
case CURLOPT_PROXY_CAINFO:
|
case CURLOPT_PROXY_CAINFO:
|
||||||
/*
|
/*
|
||||||
@ -2050,6 +2064,19 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
|
|||||||
result = Curl_setstropt(&data->set.str[STRING_SSL_CAFILE_PROXY],
|
result = Curl_setstropt(&data->set.str[STRING_SSL_CAFILE_PROXY],
|
||||||
va_arg(param, char *));
|
va_arg(param, char *));
|
||||||
break;
|
break;
|
||||||
|
case CURLOPT_PROXY_CAINFO_BLOB:
|
||||||
|
/*
|
||||||
|
* Blob that holds CA info for SSL connection proxy.
|
||||||
|
* Specify entire PEM of the CA certificate
|
||||||
|
*/
|
||||||
|
#ifdef USE_SSL
|
||||||
|
if(Curl_ssl->supports & SSLSUPP_CAINFO_BLOB)
|
||||||
|
result = Curl_setblobopt(&data->set.blobs[BLOB_CAINFO_PROXY],
|
||||||
|
va_arg(param, struct curl_blob *));
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
return CURLE_NOT_BUILT_IN;
|
||||||
|
break;
|
||||||
#endif
|
#endif
|
||||||
case CURLOPT_CAPATH:
|
case CURLOPT_CAPATH:
|
||||||
/*
|
/*
|
||||||
|
@ -3738,6 +3738,7 @@ static CURLcode create_conn(struct Curl_easy *data,
|
|||||||
data->set.ssl.primary.pinned_key =
|
data->set.ssl.primary.pinned_key =
|
||||||
data->set.str[STRING_SSL_PINNEDPUBLICKEY];
|
data->set.str[STRING_SSL_PINNEDPUBLICKEY];
|
||||||
data->set.ssl.primary.cert_blob = data->set.blobs[BLOB_CERT];
|
data->set.ssl.primary.cert_blob = data->set.blobs[BLOB_CERT];
|
||||||
|
data->set.ssl.primary.ca_info_blob = data->set.blobs[BLOB_CAINFO];
|
||||||
data->set.ssl.primary.curves = data->set.str[STRING_SSL_EC_CURVES];
|
data->set.ssl.primary.curves = data->set.str[STRING_SSL_EC_CURVES];
|
||||||
|
|
||||||
#ifndef CURL_DISABLE_PROXY
|
#ifndef CURL_DISABLE_PROXY
|
||||||
@ -3753,6 +3754,8 @@ static CURLcode create_conn(struct Curl_easy *data,
|
|||||||
data->set.proxy_ssl.primary.pinned_key =
|
data->set.proxy_ssl.primary.pinned_key =
|
||||||
data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY];
|
data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY];
|
||||||
data->set.proxy_ssl.primary.cert_blob = data->set.blobs[BLOB_CERT_PROXY];
|
data->set.proxy_ssl.primary.cert_blob = data->set.blobs[BLOB_CERT_PROXY];
|
||||||
|
data->set.proxy_ssl.primary.ca_info_blob =
|
||||||
|
data->set.blobs[BLOB_CAINFO_PROXY];
|
||||||
data->set.proxy_ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE_PROXY];
|
data->set.proxy_ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE_PROXY];
|
||||||
data->set.proxy_ssl.issuercert = data->set.str[STRING_SSL_ISSUERCERT_PROXY];
|
data->set.proxy_ssl.issuercert = data->set.str[STRING_SSL_ISSUERCERT_PROXY];
|
||||||
data->set.proxy_ssl.cert_type = data->set.str[STRING_CERT_TYPE_PROXY];
|
data->set.proxy_ssl.cert_type = data->set.str[STRING_CERT_TYPE_PROXY];
|
||||||
|
@ -253,6 +253,7 @@ struct ssl_primary_config {
|
|||||||
char *cipher_list13; /* list of TLS 1.3 cipher suites to use */
|
char *cipher_list13; /* list of TLS 1.3 cipher suites to use */
|
||||||
char *pinned_key;
|
char *pinned_key;
|
||||||
struct curl_blob *cert_blob;
|
struct curl_blob *cert_blob;
|
||||||
|
struct curl_blob *ca_info_blob;
|
||||||
char *curves; /* list of curves to use */
|
char *curves; /* list of curves to use */
|
||||||
BIT(verifypeer); /* set TRUE if this is desired */
|
BIT(verifypeer); /* set TRUE if this is desired */
|
||||||
BIT(verifyhost); /* set TRUE if CN/SAN must match hostname */
|
BIT(verifyhost); /* set TRUE if CN/SAN must match hostname */
|
||||||
@ -1604,6 +1605,8 @@ enum dupblob {
|
|||||||
BLOB_KEY_PROXY,
|
BLOB_KEY_PROXY,
|
||||||
BLOB_SSL_ISSUERCERT,
|
BLOB_SSL_ISSUERCERT,
|
||||||
BLOB_SSL_ISSUERCERT_PROXY,
|
BLOB_SSL_ISSUERCERT_PROXY,
|
||||||
|
BLOB_CAINFO,
|
||||||
|
BLOB_CAINFO_PROXY,
|
||||||
BLOB_LAST
|
BLOB_LAST
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2510,6 +2510,67 @@ static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static CURLcode load_cacert_from_memory(SSL_CTX *ctx,
|
||||||
|
const struct curl_blob *ca_info_blob)
|
||||||
|
{
|
||||||
|
/* these need freed at the end */
|
||||||
|
BIO *cbio = NULL;
|
||||||
|
STACK_OF(X509_INFO) *inf = NULL;
|
||||||
|
|
||||||
|
/* everything else is just a reference */
|
||||||
|
int i, count = 0;
|
||||||
|
X509_STORE *cts = NULL;
|
||||||
|
X509_INFO *itmp = NULL;
|
||||||
|
|
||||||
|
if(ca_info_blob->len > (size_t)INT_MAX)
|
||||||
|
return CURLE_SSL_CACERT_BADFILE;
|
||||||
|
|
||||||
|
cts = SSL_CTX_get_cert_store(ctx);
|
||||||
|
if(!cts)
|
||||||
|
return CURLE_OUT_OF_MEMORY;
|
||||||
|
|
||||||
|
cbio = BIO_new_mem_buf(ca_info_blob->data, (int)ca_info_blob->len);
|
||||||
|
if(!cbio)
|
||||||
|
return CURLE_OUT_OF_MEMORY;
|
||||||
|
|
||||||
|
inf = PEM_X509_INFO_read_bio(cbio, NULL, NULL, NULL);
|
||||||
|
if(!inf) {
|
||||||
|
BIO_free(cbio);
|
||||||
|
return CURLE_SSL_CACERT_BADFILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add each entry from PEM file to x509_store */
|
||||||
|
for(i = 0; i < (int)sk_X509_INFO_num(inf); ++i) {
|
||||||
|
itmp = sk_X509_INFO_value(inf, i);
|
||||||
|
if(itmp->x509) {
|
||||||
|
if(X509_STORE_add_cert(cts, itmp->x509)) {
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* set count to 0 to return an error */
|
||||||
|
count = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(itmp->crl) {
|
||||||
|
if(X509_STORE_add_crl(cts, itmp->crl)) {
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* set count to 0 to return an error */
|
||||||
|
count = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sk_X509_INFO_pop_free(inf, X509_INFO_free);
|
||||||
|
BIO_free(cbio);
|
||||||
|
|
||||||
|
/* if we didn't end up importing anything, treat that as an error */
|
||||||
|
return (count > 0 ? CURLE_OK : CURLE_SSL_CACERT_BADFILE);
|
||||||
|
}
|
||||||
|
|
||||||
static CURLcode ossl_connect_step1(struct Curl_easy *data,
|
static CURLcode ossl_connect_step1(struct Curl_easy *data,
|
||||||
struct connectdata *conn, int sockindex)
|
struct connectdata *conn, int sockindex)
|
||||||
{
|
{
|
||||||
@ -2537,8 +2598,11 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
|
|||||||
#endif
|
#endif
|
||||||
char * const ssl_cert = SSL_SET_OPTION(primary.clientcert);
|
char * const ssl_cert = SSL_SET_OPTION(primary.clientcert);
|
||||||
const struct curl_blob *ssl_cert_blob = SSL_SET_OPTION(primary.cert_blob);
|
const struct curl_blob *ssl_cert_blob = SSL_SET_OPTION(primary.cert_blob);
|
||||||
|
const struct curl_blob *ca_info_blob = SSL_CONN_CONFIG(ca_info_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 =
|
||||||
|
/* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
|
||||||
|
(ca_info_blob ? NULL : SSL_CONN_CONFIG(CAfile));
|
||||||
const char * const ssl_capath = SSL_CONN_CONFIG(CApath);
|
const char * const ssl_capath = SSL_CONN_CONFIG(CApath);
|
||||||
const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
|
const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
|
||||||
const char * const ssl_crlfile = SSL_SET_OPTION(CRLfile);
|
const char * const ssl_crlfile = SSL_SET_OPTION(CRLfile);
|
||||||
@ -2962,6 +3026,19 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if(ca_info_blob) {
|
||||||
|
result = load_cacert_from_memory(backend->ctx, ca_info_blob);
|
||||||
|
if(result) {
|
||||||
|
if(result == CURLE_OUT_OF_MEMORY ||
|
||||||
|
(verifypeer && !imported_native_ca)) {
|
||||||
|
failf(data, "error importing CA certificate blob");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
/* Only warning if no certificate verification is required. */
|
||||||
|
infof(data, "error importing CA certificate blob, continuing anyway\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
|
#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
|
||||||
/* OpenSSL 3.0.0 has deprecated SSL_CTX_load_verify_locations */
|
/* OpenSSL 3.0.0 has deprecated SSL_CTX_load_verify_locations */
|
||||||
{
|
{
|
||||||
@ -3018,7 +3095,8 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CURL_CA_FALLBACK
|
#ifdef CURL_CA_FALLBACK
|
||||||
if(verifypeer && !ssl_cafile && !ssl_capath && !imported_native_ca) {
|
if(verifypeer &&
|
||||||
|
!ca_info_blob && !ssl_cafile && !ssl_capath && !imported_native_ca) {
|
||||||
/* verifying the peer without any CA certificates won't
|
/* verifying the peer without any CA certificates won't
|
||||||
work so use openssl's built in default as fallback */
|
work so use openssl's built in default as fallback */
|
||||||
SSL_CTX_set_default_verify_paths(backend->ctx);
|
SSL_CTX_set_default_verify_paths(backend->ctx);
|
||||||
@ -4425,6 +4503,7 @@ const struct Curl_ssl Curl_ssl_openssl = {
|
|||||||
{ CURLSSLBACKEND_OPENSSL, "openssl" }, /* info */
|
{ CURLSSLBACKEND_OPENSSL, "openssl" }, /* info */
|
||||||
|
|
||||||
SSLSUPP_CA_PATH |
|
SSLSUPP_CA_PATH |
|
||||||
|
SSLSUPP_CAINFO_BLOB |
|
||||||
SSLSUPP_CERTINFO |
|
SSLSUPP_CERTINFO |
|
||||||
SSLSUPP_PINNEDPUBKEY |
|
SSLSUPP_PINNEDPUBKEY |
|
||||||
SSLSUPP_SSL_CTX |
|
SSLSUPP_SSL_CTX |
|
||||||
|
@ -473,7 +473,7 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
|
|||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
#ifdef HAS_MANUAL_VERIFY_API
|
#ifdef HAS_MANUAL_VERIFY_API
|
||||||
if(SSL_CONN_CONFIG(CAfile)) {
|
if(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(ca_info_blob)) {
|
||||||
if(curlx_verify_windows_version(6, 1, PLATFORM_WINNT,
|
if(curlx_verify_windows_version(6, 1, PLATFORM_WINNT,
|
||||||
VERSION_GREATER_THAN_EQUAL)) {
|
VERSION_GREATER_THAN_EQUAL)) {
|
||||||
BACKEND->use_manual_cred_validation = true;
|
BACKEND->use_manual_cred_validation = true;
|
||||||
@ -487,7 +487,7 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
|
|||||||
else
|
else
|
||||||
BACKEND->use_manual_cred_validation = false;
|
BACKEND->use_manual_cred_validation = false;
|
||||||
#else
|
#else
|
||||||
if(SSL_CONN_CONFIG(CAfile)) {
|
if(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(ca_info_blob)) {
|
||||||
failf(data, "schannel: CA cert support not built in");
|
failf(data, "schannel: CA cert support not built in");
|
||||||
return CURLE_NOT_BUILT_IN;
|
return CURLE_NOT_BUILT_IN;
|
||||||
}
|
}
|
||||||
@ -2403,6 +2403,9 @@ const struct Curl_ssl Curl_ssl_schannel = {
|
|||||||
{ CURLSSLBACKEND_SCHANNEL, "schannel" }, /* info */
|
{ CURLSSLBACKEND_SCHANNEL, "schannel" }, /* info */
|
||||||
|
|
||||||
SSLSUPP_CERTINFO |
|
SSLSUPP_CERTINFO |
|
||||||
|
#ifdef HAS_MANUAL_VERIFY_API
|
||||||
|
SSLSUPP_CAINFO_BLOB |
|
||||||
|
#endif
|
||||||
SSLSUPP_PINNEDPUBKEY,
|
SSLSUPP_PINNEDPUBKEY,
|
||||||
|
|
||||||
sizeof(struct ssl_backend_data),
|
sizeof(struct ssl_backend_data),
|
||||||
|
@ -77,7 +77,146 @@ static int is_cr_or_lf(char c)
|
|||||||
return c == '\r' || c == '\n';
|
return c == '\r' || c == '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
static CURLcode add_certs_to_store(HCERTSTORE trust_store,
|
/* Search the substring needle,needlelen into string haystack,haystacklen
|
||||||
|
* Strings don't need to be terminated by a '\0'.
|
||||||
|
* Similar of OSX/Linux memmem (not available on Visual Studio).
|
||||||
|
* Return position of beginning of first occurence or NULL if not found
|
||||||
|
*/
|
||||||
|
static const char *c_memmem(const void *haystack, size_t haystacklen,
|
||||||
|
const void *needle, size_t needlelen)
|
||||||
|
{
|
||||||
|
const char *p;
|
||||||
|
char first;
|
||||||
|
const char *str_limit = (const char *)haystack + haystacklen;
|
||||||
|
if(!needlelen || needlelen > haystacklen)
|
||||||
|
return NULL;
|
||||||
|
first = *(const char *)needle;
|
||||||
|
for(p = (const char *)haystack; p <= (str_limit - needlelen); p++)
|
||||||
|
if(((*p) == first) && (memcmp(p, needle, needlelen) == 0))
|
||||||
|
return p;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static CURLcode add_certs_data_to_store(HCERTSTORE trust_store,
|
||||||
|
const char *ca_buffer,
|
||||||
|
size_t ca_buffer_size,
|
||||||
|
const char *ca_file_text,
|
||||||
|
struct Curl_easy *data)
|
||||||
|
{
|
||||||
|
const size_t begin_cert_len = strlen(BEGIN_CERT);
|
||||||
|
const size_t end_cert_len = strlen(END_CERT);
|
||||||
|
CURLcode result = CURLE_OK;
|
||||||
|
int num_certs = 0;
|
||||||
|
bool more_certs = 1;
|
||||||
|
const char *current_ca_file_ptr = ca_buffer;
|
||||||
|
const char *ca_buffer_limit = ca_buffer + ca_buffer_size;
|
||||||
|
|
||||||
|
while(more_certs && (current_ca_file_ptr<ca_buffer_limit)) {
|
||||||
|
const char *begin_cert_ptr = c_memmem(current_ca_file_ptr,
|
||||||
|
ca_buffer_limit-current_ca_file_ptr,
|
||||||
|
BEGIN_CERT,
|
||||||
|
begin_cert_len);
|
||||||
|
if(!begin_cert_ptr || !is_cr_or_lf(begin_cert_ptr[begin_cert_len])) {
|
||||||
|
more_certs = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const char *end_cert_ptr = c_memmem(begin_cert_ptr,
|
||||||
|
ca_buffer_limit-begin_cert_ptr,
|
||||||
|
END_CERT,
|
||||||
|
end_cert_len);
|
||||||
|
if(!end_cert_ptr) {
|
||||||
|
failf(data,
|
||||||
|
"schannel: CA file '%s' is not correctly formatted",
|
||||||
|
ca_file_text);
|
||||||
|
result = CURLE_SSL_CACERT_BADFILE;
|
||||||
|
more_certs = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
CERT_BLOB cert_blob;
|
||||||
|
CERT_CONTEXT *cert_context = NULL;
|
||||||
|
BOOL add_cert_result = FALSE;
|
||||||
|
DWORD actual_content_type = 0;
|
||||||
|
DWORD cert_size = (DWORD)
|
||||||
|
((end_cert_ptr + end_cert_len) - begin_cert_ptr);
|
||||||
|
|
||||||
|
cert_blob.pbData = (BYTE *)begin_cert_ptr;
|
||||||
|
cert_blob.cbData = cert_size;
|
||||||
|
if(!CryptQueryObject(CERT_QUERY_OBJECT_BLOB,
|
||||||
|
&cert_blob,
|
||||||
|
CERT_QUERY_CONTENT_FLAG_CERT,
|
||||||
|
CERT_QUERY_FORMAT_FLAG_ALL,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
&actual_content_type,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
(const void **)&cert_context)) {
|
||||||
|
char buffer[STRERROR_LEN];
|
||||||
|
failf(data,
|
||||||
|
"schannel: failed to extract certificate from CA file "
|
||||||
|
"'%s': %s",
|
||||||
|
ca_file_text,
|
||||||
|
Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
|
||||||
|
result = CURLE_SSL_CACERT_BADFILE;
|
||||||
|
more_certs = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
current_ca_file_ptr = begin_cert_ptr + cert_size;
|
||||||
|
|
||||||
|
/* Sanity check that the cert_context object is the right type */
|
||||||
|
if(CERT_QUERY_CONTENT_CERT != actual_content_type) {
|
||||||
|
failf(data,
|
||||||
|
"schannel: unexpected content type '%d' when extracting "
|
||||||
|
"certificate from CA file '%s'",
|
||||||
|
actual_content_type, ca_file_text);
|
||||||
|
result = CURLE_SSL_CACERT_BADFILE;
|
||||||
|
more_certs = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
add_cert_result =
|
||||||
|
CertAddCertificateContextToStore(trust_store,
|
||||||
|
cert_context,
|
||||||
|
CERT_STORE_ADD_ALWAYS,
|
||||||
|
NULL);
|
||||||
|
CertFreeCertificateContext(cert_context);
|
||||||
|
if(!add_cert_result) {
|
||||||
|
char buffer[STRERROR_LEN];
|
||||||
|
failf(data,
|
||||||
|
"schannel: failed to add certificate from CA file '%s' "
|
||||||
|
"to certificate store: %s",
|
||||||
|
ca_file_text,
|
||||||
|
Curl_winapi_strerror(GetLastError(), buffer,
|
||||||
|
sizeof(buffer)));
|
||||||
|
result = CURLE_SSL_CACERT_BADFILE;
|
||||||
|
more_certs = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
num_certs++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(result == CURLE_OK) {
|
||||||
|
if(!num_certs) {
|
||||||
|
infof(data,
|
||||||
|
"schannel: did not add any certificates from CA file '%s'\n",
|
||||||
|
ca_file_text);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
infof(data,
|
||||||
|
"schannel: added %d certificate(s) from CA file '%s'\n",
|
||||||
|
num_certs, ca_file_text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static CURLcode add_certs_file_to_store(HCERTSTORE trust_store,
|
||||||
const char *ca_file,
|
const char *ca_file,
|
||||||
struct Curl_easy *data)
|
struct Curl_easy *data)
|
||||||
{
|
{
|
||||||
@ -85,13 +224,9 @@ static CURLcode add_certs_to_store(HCERTSTORE trust_store,
|
|||||||
HANDLE ca_file_handle = INVALID_HANDLE_VALUE;
|
HANDLE ca_file_handle = INVALID_HANDLE_VALUE;
|
||||||
LARGE_INTEGER file_size;
|
LARGE_INTEGER file_size;
|
||||||
char *ca_file_buffer = NULL;
|
char *ca_file_buffer = NULL;
|
||||||
char *current_ca_file_ptr = NULL;
|
|
||||||
TCHAR *ca_file_tstr = NULL;
|
TCHAR *ca_file_tstr = NULL;
|
||||||
size_t ca_file_bufsize = 0;
|
size_t ca_file_bufsize = 0;
|
||||||
DWORD total_bytes_read = 0;
|
DWORD total_bytes_read = 0;
|
||||||
bool more_certs = 0;
|
|
||||||
int num_certs = 0;
|
|
||||||
size_t END_CERT_LEN;
|
|
||||||
|
|
||||||
ca_file_tstr = curlx_convert_UTF8_to_tchar((char *)ca_file);
|
ca_file_tstr = curlx_convert_UTF8_to_tchar((char *)ca_file);
|
||||||
if(!ca_file_tstr) {
|
if(!ca_file_tstr) {
|
||||||
@ -181,106 +316,10 @@ static CURLcode add_certs_to_store(HCERTSTORE trust_store,
|
|||||||
if(result != CURLE_OK) {
|
if(result != CURLE_OK) {
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
result = add_certs_data_to_store(trust_store,
|
||||||
END_CERT_LEN = strlen(END_CERT);
|
ca_file_buffer, ca_file_bufsize,
|
||||||
|
|
||||||
more_certs = 1;
|
|
||||||
current_ca_file_ptr = ca_file_buffer;
|
|
||||||
while(more_certs && *current_ca_file_ptr != '\0') {
|
|
||||||
char *begin_cert_ptr = strstr(current_ca_file_ptr, BEGIN_CERT);
|
|
||||||
if(!begin_cert_ptr || !is_cr_or_lf(begin_cert_ptr[strlen(BEGIN_CERT)])) {
|
|
||||||
more_certs = 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
char *end_cert_ptr = strstr(begin_cert_ptr, END_CERT);
|
|
||||||
if(!end_cert_ptr) {
|
|
||||||
failf(data,
|
|
||||||
"schannel: CA file '%s' is not correctly formatted",
|
|
||||||
ca_file);
|
|
||||||
result = CURLE_SSL_CACERT_BADFILE;
|
|
||||||
more_certs = 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
CERT_BLOB cert_blob;
|
|
||||||
CERT_CONTEXT *cert_context = NULL;
|
|
||||||
BOOL add_cert_result = FALSE;
|
|
||||||
DWORD actual_content_type = 0;
|
|
||||||
DWORD cert_size = (DWORD)
|
|
||||||
((end_cert_ptr + END_CERT_LEN) - begin_cert_ptr);
|
|
||||||
|
|
||||||
cert_blob.pbData = (BYTE *)begin_cert_ptr;
|
|
||||||
cert_blob.cbData = cert_size;
|
|
||||||
if(!CryptQueryObject(CERT_QUERY_OBJECT_BLOB,
|
|
||||||
&cert_blob,
|
|
||||||
CERT_QUERY_CONTENT_FLAG_CERT,
|
|
||||||
CERT_QUERY_FORMAT_FLAG_ALL,
|
|
||||||
0,
|
|
||||||
NULL,
|
|
||||||
&actual_content_type,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
(const void **)&cert_context)) {
|
|
||||||
char buffer[STRERROR_LEN];
|
|
||||||
failf(data,
|
|
||||||
"schannel: failed to extract certificate from CA file "
|
|
||||||
"'%s': %s",
|
|
||||||
ca_file,
|
ca_file,
|
||||||
Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
|
data);
|
||||||
result = CURLE_SSL_CACERT_BADFILE;
|
|
||||||
more_certs = 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
current_ca_file_ptr = begin_cert_ptr + cert_size;
|
|
||||||
|
|
||||||
/* Sanity check that the cert_context object is the right type */
|
|
||||||
if(CERT_QUERY_CONTENT_CERT != actual_content_type) {
|
|
||||||
failf(data,
|
|
||||||
"schannel: unexpected content type '%d' when extracting "
|
|
||||||
"certificate from CA file '%s'",
|
|
||||||
actual_content_type, ca_file);
|
|
||||||
result = CURLE_SSL_CACERT_BADFILE;
|
|
||||||
more_certs = 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
add_cert_result =
|
|
||||||
CertAddCertificateContextToStore(trust_store,
|
|
||||||
cert_context,
|
|
||||||
CERT_STORE_ADD_ALWAYS,
|
|
||||||
NULL);
|
|
||||||
CertFreeCertificateContext(cert_context);
|
|
||||||
if(!add_cert_result) {
|
|
||||||
char buffer[STRERROR_LEN];
|
|
||||||
failf(data,
|
|
||||||
"schannel: failed to add certificate from CA file '%s' "
|
|
||||||
"to certificate store: %s",
|
|
||||||
ca_file,
|
|
||||||
Curl_winapi_strerror(GetLastError(), buffer,
|
|
||||||
sizeof(buffer)));
|
|
||||||
result = CURLE_SSL_CACERT_BADFILE;
|
|
||||||
more_certs = 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
num_certs++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(result == CURLE_OK) {
|
|
||||||
if(!num_certs) {
|
|
||||||
infof(data,
|
|
||||||
"schannel: did not add any certificates from CA file '%s'\n",
|
|
||||||
ca_file);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
infof(data,
|
|
||||||
"schannel: added %d certificate(s) from CA file '%s'\n",
|
|
||||||
num_certs, ca_file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
if(ca_file_handle != INVALID_HANDLE_VALUE) {
|
if(ca_file_handle != INVALID_HANDLE_VALUE) {
|
||||||
@ -550,7 +589,8 @@ CURLcode Curl_verify_certificate(struct Curl_easy *data,
|
|||||||
result = CURLE_PEER_FAILED_VERIFICATION;
|
result = CURLE_PEER_FAILED_VERIFICATION;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(result == CURLE_OK && SSL_CONN_CONFIG(CAfile) &&
|
if(result == CURLE_OK &&
|
||||||
|
(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(ca_info_blob)) &&
|
||||||
BACKEND->use_manual_cred_validation) {
|
BACKEND->use_manual_cred_validation) {
|
||||||
/*
|
/*
|
||||||
* Create a chain engine that uses the certificates in the CA file as
|
* Create a chain engine that uses the certificates in the CA file as
|
||||||
@ -576,9 +616,20 @@ CURLcode Curl_verify_certificate(struct Curl_easy *data,
|
|||||||
result = CURLE_SSL_CACERT_BADFILE;
|
result = CURLE_SSL_CACERT_BADFILE;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
result = add_certs_to_store(trust_store, SSL_CONN_CONFIG(CAfile),
|
const struct curl_blob *ca_info_blob = SSL_CONN_CONFIG(ca_info_blob);
|
||||||
|
if(ca_info_blob) {
|
||||||
|
result = add_certs_data_to_store(trust_store,
|
||||||
|
(const char *)ca_info_blob->data,
|
||||||
|
ca_info_blob->len,
|
||||||
|
"(memory blob)",
|
||||||
data);
|
data);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
result = add_certs_file_to_store(trust_store,
|
||||||
|
SSL_CONN_CONFIG(CAfile),
|
||||||
|
data);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(result == CURLE_OK) {
|
if(result == CURLE_OK) {
|
||||||
|
@ -1659,8 +1659,10 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
|
|||||||
curl_socket_t sockfd = conn->sock[sockindex];
|
curl_socket_t sockfd = conn->sock[sockindex];
|
||||||
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 struct curl_blob *ssl_cablob = SSL_CONN_CONFIG(ca_info_blob);
|
||||||
const struct curl_blob *ssl_cablob = NULL;
|
const char * const ssl_cafile =
|
||||||
|
/* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
|
||||||
|
(ssl_cablob ? NULL : SSL_CONN_CONFIG(CAfile));
|
||||||
const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
|
const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
|
||||||
char * const ssl_cert = SSL_SET_OPTION(primary.clientcert);
|
char * const ssl_cert = SSL_SET_OPTION(primary.clientcert);
|
||||||
const struct curl_blob *ssl_cert_blob = SSL_SET_OPTION(primary.cert_blob);
|
const struct curl_blob *ssl_cert_blob = SSL_SET_OPTION(primary.cert_blob);
|
||||||
@ -2007,7 +2009,8 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
|
|||||||
bool is_cert_file = (!is_cert_data) && is_file(ssl_cafile);
|
bool is_cert_file = (!is_cert_data) && is_file(ssl_cafile);
|
||||||
|
|
||||||
if(!(is_cert_file || is_cert_data)) {
|
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 ? ssl_cafile : "(blob memory)");
|
||||||
return CURLE_SSL_CACERT_BADFILE;
|
return CURLE_SSL_CACERT_BADFILE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2084,7 +2087,8 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
|
|||||||
else {
|
else {
|
||||||
CURLcode result;
|
CURLcode result;
|
||||||
ssl_sessionid =
|
ssl_sessionid =
|
||||||
aprintf("%s:%d:%d:%s:%ld", ssl_cafile,
|
aprintf("%s:%d:%d:%s:%ld",
|
||||||
|
ssl_cafile ? ssl_cafile : "(blob memory)",
|
||||||
verifypeer, SSL_CONN_CONFIG(verifyhost), hostname, port);
|
verifypeer, SSL_CONN_CONFIG(verifyhost), hostname, port);
|
||||||
ssl_sessionid_len = strlen(ssl_sessionid);
|
ssl_sessionid_len = strlen(ssl_sessionid);
|
||||||
|
|
||||||
@ -2224,7 +2228,7 @@ static int read_cert(const char *file, unsigned char **out, size_t *outlen)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int append_cert_to_array(struct Curl_easy *data,
|
static int append_cert_to_array(struct Curl_easy *data,
|
||||||
unsigned char *buf, size_t buflen,
|
const unsigned char *buf, size_t buflen,
|
||||||
CFMutableArrayRef array)
|
CFMutableArrayRef array)
|
||||||
{
|
{
|
||||||
CFDataRef certdata = CFDataCreate(kCFAllocatorDefault, buf, buflen);
|
CFDataRef certdata = CFDataCreate(kCFAllocatorDefault, buf, buflen);
|
||||||
@ -2262,18 +2266,14 @@ static int append_cert_to_array(struct Curl_easy *data,
|
|||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static CURLcode verify_cert(const char *cafile, struct Curl_easy *data,
|
static CURLcode verify_cert_buf(struct Curl_easy *data,
|
||||||
|
const unsigned char *certbuf, size_t buflen,
|
||||||
SSLContextRef ctx)
|
SSLContextRef ctx)
|
||||||
{
|
{
|
||||||
int n = 0, rc;
|
int n = 0, rc;
|
||||||
long res;
|
long res;
|
||||||
unsigned char *certbuf, *der;
|
unsigned char *der;
|
||||||
size_t buflen, derlen, offset = 0;
|
size_t derlen, offset = 0;
|
||||||
|
|
||||||
if(read_cert(cafile, &certbuf, &buflen) < 0) {
|
|
||||||
failf(data, "SSL: failed to read or invalid CA certificate");
|
|
||||||
return CURLE_SSL_CACERT_BADFILE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Certbuf now contains the contents of the certificate file, which can be
|
* Certbuf now contains the contents of the certificate file, which can be
|
||||||
@ -2287,7 +2287,6 @@ static CURLcode verify_cert(const char *cafile, struct Curl_easy *data,
|
|||||||
CFMutableArrayRef array = CFArrayCreateMutable(kCFAllocatorDefault, 0,
|
CFMutableArrayRef array = CFArrayCreateMutable(kCFAllocatorDefault, 0,
|
||||||
&kCFTypeArrayCallBacks);
|
&kCFTypeArrayCallBacks);
|
||||||
if(!array) {
|
if(!array) {
|
||||||
free(certbuf);
|
|
||||||
failf(data, "SSL: out of memory creating CA certificate array");
|
failf(data, "SSL: out of memory creating CA certificate array");
|
||||||
return CURLE_OUT_OF_MEMORY;
|
return CURLE_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
@ -2301,7 +2300,6 @@ static CURLcode verify_cert(const char *cafile, struct Curl_easy *data,
|
|||||||
*/
|
*/
|
||||||
res = pem_to_der((const char *)certbuf + offset, &der, &derlen);
|
res = pem_to_der((const char *)certbuf + offset, &der, &derlen);
|
||||||
if(res < 0) {
|
if(res < 0) {
|
||||||
free(certbuf);
|
|
||||||
CFRelease(array);
|
CFRelease(array);
|
||||||
failf(data, "SSL: invalid CA certificate #%d (offset %zu) in bundle",
|
failf(data, "SSL: invalid CA certificate #%d (offset %zu) in bundle",
|
||||||
n, offset);
|
n, offset);
|
||||||
@ -2312,7 +2310,6 @@ static CURLcode verify_cert(const char *cafile, struct Curl_easy *data,
|
|||||||
if(res == 0 && offset == 0) {
|
if(res == 0 && offset == 0) {
|
||||||
/* This is not a PEM file, probably a certificate in DER format. */
|
/* This is not a PEM file, probably a certificate in DER format. */
|
||||||
rc = append_cert_to_array(data, certbuf, buflen, array);
|
rc = append_cert_to_array(data, certbuf, buflen, array);
|
||||||
free(certbuf);
|
|
||||||
if(rc != CURLE_OK) {
|
if(rc != CURLE_OK) {
|
||||||
CFRelease(array);
|
CFRelease(array);
|
||||||
return rc;
|
return rc;
|
||||||
@ -2321,14 +2318,12 @@ static CURLcode verify_cert(const char *cafile, struct Curl_easy *data,
|
|||||||
}
|
}
|
||||||
else if(res == 0) {
|
else if(res == 0) {
|
||||||
/* No more certificates in the bundle. */
|
/* No more certificates in the bundle. */
|
||||||
free(certbuf);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = append_cert_to_array(data, der, derlen, array);
|
rc = append_cert_to_array(data, der, derlen, array);
|
||||||
free(der);
|
free(der);
|
||||||
if(rc != CURLE_OK) {
|
if(rc != CURLE_OK) {
|
||||||
free(certbuf);
|
|
||||||
CFRelease(array);
|
CFRelease(array);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -2385,6 +2380,38 @@ static CURLcode verify_cert(const char *cafile, struct Curl_easy *data,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static CURLcode verify_cert(struct Curl_easy *data, const char *cafile,
|
||||||
|
const struct curl_blob *ca_info_blob,
|
||||||
|
SSLContextRef ctx)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
unsigned char *certbuf;
|
||||||
|
size_t buflen;
|
||||||
|
|
||||||
|
if(ca_info_blob) {
|
||||||
|
certbuf = (unsigned char *)malloc(ca_info_blob->len + 1);
|
||||||
|
if(!certbuf) {
|
||||||
|
return CURLE_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
buflen = ca_info_blob->len;
|
||||||
|
memcpy(certbuf, ca_info_blob->data, ca_info_blob->len);
|
||||||
|
certbuf[ca_info_blob->len]='\0';
|
||||||
|
}
|
||||||
|
else if(cafile) {
|
||||||
|
if(read_cert(cafile, &certbuf, &buflen) < 0) {
|
||||||
|
failf(data, "SSL: failed to read or invalid CA certificate");
|
||||||
|
return CURLE_SSL_CACERT_BADFILE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return CURLE_SSL_CACERT_BADFILE;
|
||||||
|
|
||||||
|
result = verify_cert_buf(data, certbuf, buflen, ctx);
|
||||||
|
free(certbuf);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef SECTRANSP_PINNEDPUBKEY
|
#ifdef SECTRANSP_PINNEDPUBKEY
|
||||||
static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
|
static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
|
||||||
SSLContextRef ctx,
|
SSLContextRef ctx,
|
||||||
@ -2520,8 +2547,10 @@ sectransp_connect_step2(struct Curl_easy *data, struct connectdata *conn,
|
|||||||
/* The below is errSSLServerAuthCompleted; it's not defined in
|
/* The below is errSSLServerAuthCompleted; it's not defined in
|
||||||
Leopard's headers */
|
Leopard's headers */
|
||||||
case -9841:
|
case -9841:
|
||||||
if(SSL_CONN_CONFIG(CAfile) && SSL_CONN_CONFIG(verifypeer)) {
|
if((SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(ca_info_blob)) &&
|
||||||
CURLcode result = verify_cert(SSL_CONN_CONFIG(CAfile), data,
|
SSL_CONN_CONFIG(verifypeer)) {
|
||||||
|
CURLcode result = verify_cert(data, SSL_CONN_CONFIG(CAfile),
|
||||||
|
SSL_CONN_CONFIG(ca_info_blob),
|
||||||
backend->ssl_ctx);
|
backend->ssl_ctx);
|
||||||
if(result)
|
if(result)
|
||||||
return result;
|
return result;
|
||||||
@ -3365,8 +3394,10 @@ static ssize_t sectransp_recv(struct Curl_easy *data,
|
|||||||
/* The below is errSSLPeerAuthCompleted; it's not defined in
|
/* The below is errSSLPeerAuthCompleted; it's not defined in
|
||||||
Leopard's headers */
|
Leopard's headers */
|
||||||
case -9841:
|
case -9841:
|
||||||
if(SSL_CONN_CONFIG(CAfile) && SSL_CONN_CONFIG(verifypeer)) {
|
if((SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(ca_info_blob)) &&
|
||||||
CURLcode result = verify_cert(SSL_CONN_CONFIG(CAfile), data,
|
SSL_CONN_CONFIG(verifypeer)) {
|
||||||
|
CURLcode result = verify_cert(data, SSL_CONN_CONFIG(CAfile),
|
||||||
|
SSL_CONN_CONFIG(ca_info_blob),
|
||||||
backend->ssl_ctx);
|
backend->ssl_ctx);
|
||||||
if(result)
|
if(result)
|
||||||
return result;
|
return result;
|
||||||
@ -3393,6 +3424,7 @@ static void *sectransp_get_internals(struct ssl_connect_data *connssl,
|
|||||||
const struct Curl_ssl Curl_ssl_sectransp = {
|
const struct Curl_ssl Curl_ssl_sectransp = {
|
||||||
{ CURLSSLBACKEND_SECURETRANSPORT, "secure-transport" }, /* info */
|
{ CURLSSLBACKEND_SECURETRANSPORT, "secure-transport" }, /* info */
|
||||||
|
|
||||||
|
SSLSUPP_CAINFO_BLOB |
|
||||||
#ifdef SECTRANSP_PINNEDPUBKEY
|
#ifdef SECTRANSP_PINNEDPUBKEY
|
||||||
SSLSUPP_PINNEDPUBKEY,
|
SSLSUPP_PINNEDPUBKEY,
|
||||||
#else
|
#else
|
||||||
|
@ -135,6 +135,7 @@ Curl_ssl_config_matches(struct ssl_primary_config *data,
|
|||||||
(data->verifyhost == needle->verifyhost) &&
|
(data->verifyhost == needle->verifyhost) &&
|
||||||
(data->verifystatus == needle->verifystatus) &&
|
(data->verifystatus == needle->verifystatus) &&
|
||||||
blobcmp(data->cert_blob, needle->cert_blob) &&
|
blobcmp(data->cert_blob, needle->cert_blob) &&
|
||||||
|
blobcmp(data->ca_info_blob, needle->ca_info_blob) &&
|
||||||
Curl_safe_strcasecompare(data->CApath, needle->CApath) &&
|
Curl_safe_strcasecompare(data->CApath, needle->CApath) &&
|
||||||
Curl_safe_strcasecompare(data->CAfile, needle->CAfile) &&
|
Curl_safe_strcasecompare(data->CAfile, needle->CAfile) &&
|
||||||
Curl_safe_strcasecompare(data->clientcert, needle->clientcert) &&
|
Curl_safe_strcasecompare(data->clientcert, needle->clientcert) &&
|
||||||
@ -161,6 +162,7 @@ Curl_clone_primary_ssl_config(struct ssl_primary_config *source,
|
|||||||
dest->sessionid = source->sessionid;
|
dest->sessionid = source->sessionid;
|
||||||
|
|
||||||
CLONE_BLOB(cert_blob);
|
CLONE_BLOB(cert_blob);
|
||||||
|
CLONE_BLOB(ca_info_blob);
|
||||||
CLONE_STRING(CApath);
|
CLONE_STRING(CApath);
|
||||||
CLONE_STRING(CAfile);
|
CLONE_STRING(CAfile);
|
||||||
CLONE_STRING(clientcert);
|
CLONE_STRING(clientcert);
|
||||||
@ -185,6 +187,7 @@ void Curl_free_primary_ssl_config(struct ssl_primary_config *sslc)
|
|||||||
Curl_safefree(sslc->cipher_list13);
|
Curl_safefree(sslc->cipher_list13);
|
||||||
Curl_safefree(sslc->pinned_key);
|
Curl_safefree(sslc->pinned_key);
|
||||||
Curl_safefree(sslc->cert_blob);
|
Curl_safefree(sslc->cert_blob);
|
||||||
|
Curl_safefree(sslc->ca_info_blob);
|
||||||
Curl_safefree(sslc->curves);
|
Curl_safefree(sslc->curves);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@ struct ssl_connect_data;
|
|||||||
#define SSLSUPP_SSL_CTX (1<<3) /* supports CURLOPT_SSL_CTX */
|
#define SSLSUPP_SSL_CTX (1<<3) /* supports CURLOPT_SSL_CTX */
|
||||||
#define SSLSUPP_HTTPS_PROXY (1<<4) /* supports access via HTTPS proxies */
|
#define SSLSUPP_HTTPS_PROXY (1<<4) /* supports access via HTTPS proxies */
|
||||||
#define SSLSUPP_TLS13_CIPHERSUITES (1<<5) /* supports TLS 1.3 ciphersuites */
|
#define SSLSUPP_TLS13_CIPHERSUITES (1<<5) /* supports TLS 1.3 ciphersuites */
|
||||||
|
#define SSLSUPP_CAINFO_BLOB (1<<6)
|
||||||
|
|
||||||
struct Curl_ssl {
|
struct Curl_ssl {
|
||||||
/*
|
/*
|
||||||
|
@ -1579,6 +1579,10 @@
|
|||||||
d c 00307
|
d c 00307
|
||||||
d CURLOPT_DOH_SSL_VERIFYSTATUS...
|
d CURLOPT_DOH_SSL_VERIFYSTATUS...
|
||||||
d c 00308
|
d c 00308
|
||||||
|
d CURLOPT_CAINFO_BLOB...
|
||||||
|
d c 40309
|
||||||
|
d CURLOPT_PROXY_CAINFO_BLOB...
|
||||||
|
d c 40310
|
||||||
*
|
*
|
||||||
/if not defined(CURL_NO_OLDIES)
|
/if not defined(CURL_NO_OLDIES)
|
||||||
d CURLOPT_FILE c 10001
|
d CURLOPT_FILE c 10001
|
||||||
|
@ -90,7 +90,7 @@ test635 test636 test637 test638 test639 test640 test641 test642 \
|
|||||||
test643 test644 test645 test646 test647 test648 test649 test650 test651 \
|
test643 test644 test645 test646 test647 test648 test649 test650 test651 \
|
||||||
test652 test653 test654 test655 test656 test658 test659 test660 test661 \
|
test652 test653 test654 test655 test656 test658 test659 test660 test661 \
|
||||||
test662 test663 test664 test665 test666 test667 test668 test669 \
|
test662 test663 test664 test665 test666 test667 test668 test669 \
|
||||||
test670 test671 test672 test673 test674 test675 test676 \
|
test670 test671 test672 test673 test674 test675 test676 test678 \
|
||||||
\
|
\
|
||||||
test700 test701 test702 test703 test704 test705 test706 test707 test708 \
|
test700 test701 test702 test703 test704 test705 test706 test707 test708 \
|
||||||
test709 test710 test711 test712 test713 test714 test715 test716 test717 \
|
test709 test710 test711 test712 test713 test714 test715 test716 test717 \
|
||||||
|
59
tests/data/test678
Normal file
59
tests/data/test678
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
<testcase>
|
||||||
|
<info>
|
||||||
|
<keywords>
|
||||||
|
HTTPS
|
||||||
|
HTTP GET
|
||||||
|
PEM certificate
|
||||||
|
</keywords>
|
||||||
|
</info>
|
||||||
|
|
||||||
|
#
|
||||||
|
# Server-side
|
||||||
|
<reply>
|
||||||
|
<data>
|
||||||
|
HTTP/1.1 200 OK
|
||||||
|
Date: Tue, 09 Nov 2010 14:49:00 GMT
|
||||||
|
Server: test-server/fake
|
||||||
|
Content-Length: 7
|
||||||
|
|
||||||
|
MooMoo
|
||||||
|
</data>
|
||||||
|
</reply>
|
||||||
|
|
||||||
|
#
|
||||||
|
# Client-side
|
||||||
|
<client>
|
||||||
|
<features>
|
||||||
|
SSL
|
||||||
|
</features>
|
||||||
|
<server>
|
||||||
|
https Server-localhost-sv.pem
|
||||||
|
</server>
|
||||||
|
<name>
|
||||||
|
HTTPS GET using CURLOPT_CAINFO_BLOB
|
||||||
|
</name>
|
||||||
|
<tool>
|
||||||
|
lib%TESTNUMBER
|
||||||
|
</tool>
|
||||||
|
# provide URL and ca-cert
|
||||||
|
<command>
|
||||||
|
https://localhost:%HTTPSPORT/%TESTNUMBER %SRCDIR/certs/EdelCurlRoot-ca.crt
|
||||||
|
</command>
|
||||||
|
# Ensure that we're running on localhost because we're checking the host name
|
||||||
|
<precheck>
|
||||||
|
./libtest/lib%TESTNUMBER check
|
||||||
|
</precheck>
|
||||||
|
</client>
|
||||||
|
|
||||||
|
#
|
||||||
|
# Verify data after the test has been "shot"
|
||||||
|
<verify>
|
||||||
|
<protocol>
|
||||||
|
GET /%TESTNUMBER HTTP/1.1
|
||||||
|
Host: localhost:%HTTPSPORT
|
||||||
|
User-Agent: CURLOPT_CAINFO_BLOB
|
||||||
|
Accept: */*
|
||||||
|
|
||||||
|
</protocol>
|
||||||
|
</verify>
|
||||||
|
</testcase>
|
@ -48,7 +48,7 @@ noinst_PROGRAMS = chkhostname libauthretry libntlmconnect \
|
|||||||
lib599 \
|
lib599 \
|
||||||
lib643 lib644 lib645 lib650 lib651 lib652 lib653 lib654 lib655 lib658 \
|
lib643 lib644 lib645 lib650 lib651 lib652 lib653 lib654 lib655 lib658 \
|
||||||
lib659 lib661 lib666 lib667 lib668 \
|
lib659 lib661 lib666 lib667 lib668 \
|
||||||
lib670 lib671 lib672 lib673 lib674 lib676 \
|
lib670 lib671 lib672 lib673 lib674 lib676 lib678 \
|
||||||
lib1156 \
|
lib1156 \
|
||||||
lib1500 lib1501 lib1502 lib1503 lib1504 lib1505 lib1506 lib1507 lib1508 \
|
lib1500 lib1501 lib1502 lib1503 lib1504 lib1505 lib1506 lib1507 lib1508 \
|
||||||
lib1509 lib1510 lib1511 lib1512 lib1513 lib1514 lib1515 lib1517 \
|
lib1509 lib1510 lib1511 lib1512 lib1513 lib1514 lib1515 lib1517 \
|
||||||
@ -409,6 +409,10 @@ lib676_SOURCES = lib676.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
|
|||||||
lib676_LDADD = $(TESTUTIL_LIBS)
|
lib676_LDADD = $(TESTUTIL_LIBS)
|
||||||
lib676_CPPFLAGS = $(AM_CPPFLAGS)
|
lib676_CPPFLAGS = $(AM_CPPFLAGS)
|
||||||
|
|
||||||
|
lib678_SOURCES = lib678.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
|
||||||
|
lib678_LDADD = $(TESTUTIL_LIBS)
|
||||||
|
lib678_CPPFLAGS = $(AM_CPPFLAGS)
|
||||||
|
|
||||||
lib1500_SOURCES = lib1500.c $(SUPPORTFILES) $(TESTUTIL)
|
lib1500_SOURCES = lib1500.c $(SUPPORTFILES) $(TESTUTIL)
|
||||||
lib1500_LDADD = $(TESTUTIL_LIBS)
|
lib1500_LDADD = $(TESTUTIL_LIBS)
|
||||||
lib1500_CPPFLAGS = $(AM_CPPFLAGS)
|
lib1500_CPPFLAGS = $(AM_CPPFLAGS)
|
||||||
|
120
tests/libtest/lib678.c
Normal file
120
tests/libtest/lib678.c
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* _ _ ____ _
|
||||||
|
* Project ___| | | | _ \| |
|
||||||
|
* / __| | | | |_) | |
|
||||||
|
* | (__| |_| | _ <| |___
|
||||||
|
* \___|\___/|_| \_\_____|
|
||||||
|
*
|
||||||
|
* Copyright (C) 1998 - 2021, 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.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.
|
||||||
|
*
|
||||||
|
***************************************************************************/
|
||||||
|
#include "test.h"
|
||||||
|
|
||||||
|
#include "testutil.h"
|
||||||
|
#include "warnless.h"
|
||||||
|
#include "memdebug.h"
|
||||||
|
|
||||||
|
static int loadfile(const char *filename, void **filedata, size_t *filesize)
|
||||||
|
{
|
||||||
|
size_t datasize = 0;
|
||||||
|
void *data = NULL;
|
||||||
|
if(filename) {
|
||||||
|
FILE *fInCert = fopen(filename, "rb");
|
||||||
|
|
||||||
|
if(fInCert) {
|
||||||
|
long cert_tell = 0;
|
||||||
|
bool continue_reading = fseek(fInCert, 0, SEEK_END) == 0;
|
||||||
|
if(continue_reading)
|
||||||
|
cert_tell = ftell(fInCert);
|
||||||
|
if(cert_tell < 0)
|
||||||
|
continue_reading = FALSE;
|
||||||
|
else
|
||||||
|
datasize = (size_t)cert_tell;
|
||||||
|
if(continue_reading)
|
||||||
|
continue_reading = fseek(fInCert, 0, SEEK_SET) == 0;
|
||||||
|
if(continue_reading)
|
||||||
|
data = malloc(datasize + 1);
|
||||||
|
if((!data) ||
|
||||||
|
((int)fread(data, datasize, 1, fInCert) != 1))
|
||||||
|
continue_reading = FALSE;
|
||||||
|
fclose(fInCert);
|
||||||
|
if(!continue_reading) {
|
||||||
|
free(data);
|
||||||
|
datasize = 0;
|
||||||
|
data = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*filesize = datasize;
|
||||||
|
*filedata = data;
|
||||||
|
return data ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int test_cert_blob(const char *url, const char *cafile)
|
||||||
|
{
|
||||||
|
CURLcode code = CURLE_OUT_OF_MEMORY;
|
||||||
|
CURL *curl;
|
||||||
|
struct curl_blob blob;
|
||||||
|
size_t certsize;
|
||||||
|
void *certdata;
|
||||||
|
|
||||||
|
curl = curl_easy_init();
|
||||||
|
if(!curl) {
|
||||||
|
fprintf(stderr, "curl_easy_init() failed\n");
|
||||||
|
return CURLE_FAILED_INIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(loadfile(cafile, &certdata, &certsize)) {
|
||||||
|
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_HEADER, 1L);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_URL, url);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_USERAGENT, "CURLOPT_CAINFO_BLOB");
|
||||||
|
curl_easy_setopt(curl, CURLOPT_SSL_OPTIONS,
|
||||||
|
CURLSSLOPT_REVOKE_BEST_EFFORT);
|
||||||
|
|
||||||
|
blob.data = certdata;
|
||||||
|
blob.len = certsize;
|
||||||
|
blob.flags = CURL_BLOB_COPY;
|
||||||
|
curl_easy_setopt(curl, CURLOPT_CAINFO_BLOB, &blob);
|
||||||
|
free(certdata);
|
||||||
|
code = curl_easy_perform(curl);
|
||||||
|
}
|
||||||
|
curl_easy_cleanup(curl);
|
||||||
|
|
||||||
|
return (int)code;
|
||||||
|
}
|
||||||
|
|
||||||
|
int test(char *URL)
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
curl_global_init(CURL_GLOBAL_DEFAULT);
|
||||||
|
if(!strcmp("check", URL)) {
|
||||||
|
CURL *e;
|
||||||
|
CURLcode w = CURLE_OK;
|
||||||
|
struct curl_blob blob = {0};
|
||||||
|
e = curl_easy_init();
|
||||||
|
if(e) {
|
||||||
|
w = curl_easy_setopt(e, CURLOPT_CAINFO_BLOB, &blob);
|
||||||
|
if(w)
|
||||||
|
printf("CURLOPT_CAINFO_BLOB is not supported\n");
|
||||||
|
curl_easy_cleanup(e);
|
||||||
|
}
|
||||||
|
res = (int)w;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
res = test_cert_blob(URL, libtest_arg2);
|
||||||
|
|
||||||
|
curl_global_cleanup();
|
||||||
|
return res;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user