45 #ifndef USE_WINDOWS_SSPI 46 # error "Can't compile SCHANNEL support without SSPI." 75 #if defined(_MSC_VER) && (_MSC_VER >= 1800) && !defined(_USING_V110_SDK71_) 80 #define UNISP_NAME_A "Microsoft Unified Security Protocol Provider" 84 #define UNISP_NAME_W L"Microsoft Unified Security Protocol Provider" 89 #define UNISP_NAME UNISP_NAME_W 91 #define UNISP_NAME UNISP_NAME_A 95 #ifndef SP_PROT_SSL2_CLIENT 96 #define SP_PROT_SSL2_CLIENT 0x00000008 99 #ifndef SP_PROT_SSL3_CLIENT 100 #define SP_PROT_SSL3_CLIENT 0x00000008 103 #ifndef SP_PROT_TLS1_CLIENT 104 #define SP_PROT_TLS1_CLIENT 0x00000080 107 #ifndef SP_PROT_TLS1_0_CLIENT 108 #define SP_PROT_TLS1_0_CLIENT SP_PROT_TLS1_CLIENT 111 #ifndef SP_PROT_TLS1_1_CLIENT 112 #define SP_PROT_TLS1_1_CLIENT 0x00000200 115 #ifndef SP_PROT_TLS1_2_CLIENT 116 #define SP_PROT_TLS1_2_CLIENT 0x00000800 119 #ifndef SECBUFFER_ALERT 120 #define SECBUFFER_ALERT 17 124 #define CURL_SCHANNEL_BUFFER_INIT_SIZE 4096 125 #define CURL_SCHANNEL_BUFFER_FREE_SIZE 1024 133 struct curl_schannel_cred {
134 CredHandle cred_handle;
135 TimeStamp time_stamp;
139 struct curl_schannel_ctxt {
140 CtxtHandle ctxt_handle;
141 TimeStamp time_stamp;
144 struct ssl_backend_data {
145 struct curl_schannel_cred *cred;
146 struct curl_schannel_ctxt *ctxt;
147 SecPkgContext_StreamSizes stream_sizes;
148 size_t encdata_length, decdata_length;
149 size_t encdata_offset, decdata_offset;
150 unsigned char *encdata_buffer, *decdata_buffer;
155 bool encdata_is_incomplete;
156 unsigned long req_flags, ret_flags;
158 bool recv_sspi_close_notify;
159 bool recv_connection_closed;
163 #define BACKEND connssl->backend 172 static void InitSecBuffer(SecBuffer *
buffer,
unsigned long BufType,
173 void *BufDataPtr,
unsigned long BufByteSize)
175 buffer->cbBuffer = BufByteSize;
176 buffer->BufferType = BufType;
177 buffer->pvBuffer = BufDataPtr;
180 static void InitSecBufferDesc(SecBufferDesc *desc, SecBuffer *BufArr,
181 unsigned long NumArrElem)
183 desc->ulVersion = SECBUFFER_VERSION;
184 desc->pBuffers = BufArr;
185 desc->cBuffers = NumArrElem;
189 set_ssl_version_min_max(SCHANNEL_CRED *schannel_cred,
struct connectdata *conn)
194 long i = ssl_version;
196 switch(ssl_version_max) {
198 ssl_version_max = ssl_version << 16;
204 for(; i <= (ssl_version_max >> 16); ++
i) {
207 schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_0_CLIENT;
210 schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_1_CLIENT;
213 schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_2_CLIENT;
216 failf(data,
"Schannel: TLS 1.3 is not yet supported");
224 schannel_connect_step1(
struct connectdata *conn,
int sockindex)
230 SecBufferDesc outbuf_desc;
232 SecBufferDesc inbuf_desc;
234 unsigned char alpn_buffer[128];
236 SCHANNEL_CRED schannel_cred;
237 SECURITY_STATUS sspi_status = SEC_E_OK;
238 struct curl_schannel_cred *old_cred = NULL;
241 struct in6_addr addr6;
248 infof(data,
"schannel: SSL/TLS connection with %s port %hu (step 1/3)\n",
251 if(Curl_verify_windows_version(5, 1, PLATFORM_WINNT,
252 VERSION_LESS_THAN_EQUAL)) {
255 infof(data,
"schannel: WinSSL version is old and may not be able to " 256 "connect to some servers due to lack of SNI, algorithms, etc.\n");
263 !GetProcAddress(GetModuleHandleA(
"ntdll"),
264 "wine_get_version") &&
265 Curl_verify_windows_version(6, 3, PLATFORM_WINNT,
266 VERSION_GREATER_THAN_EQUAL);
268 BACKEND->use_alpn =
false;
271 BACKEND->cred = NULL;
275 Curl_ssl_sessionid_lock(conn);
276 if(!Curl_ssl_getsessionid(conn, (
void **)&old_cred, NULL, sockindex)) {
277 BACKEND->cred = old_cred;
278 infof(data,
"schannel: re-using existing credential handle\n");
281 BACKEND->cred->refcount++;
282 infof(data,
"schannel: incremented credential handle refcount = %d\n",
283 BACKEND->cred->refcount);
285 Curl_ssl_sessionid_unlock(conn);
290 memset(&schannel_cred, 0,
sizeof(schannel_cred));
291 schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
297 schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION |
298 SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
299 SCH_CRED_IGNORE_REVOCATION_OFFLINE;
301 schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION;
304 schannel_cred.dwFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
305 SCH_CRED_IGNORE_REVOCATION_OFFLINE;
307 schannel_cred.dwFlags |= SCH_CRED_REVOCATION_CHECK_CHAIN;
310 infof(data,
"schannel: disabled server certificate revocation " 313 infof(data,
"schannel: checking server certificate revocation\n");
316 schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION |
317 SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
318 SCH_CRED_IGNORE_REVOCATION_OFFLINE;
319 infof(data,
"schannel: disabled server certificate revocation checks\n");
323 schannel_cred.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK;
324 infof(data,
"schannel: verifyhost setting prevents Schannel from " 325 "comparing the supplied target name with the subject " 326 "names in server certificates.\n");
332 schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_0_CLIENT |
333 SP_PROT_TLS1_1_CLIENT |
334 SP_PROT_TLS1_2_CLIENT;
341 result = set_ssl_version_min_max(&schannel_cred, conn);
347 schannel_cred.grbitEnabledProtocols = SP_PROT_SSL3_CLIENT;
350 schannel_cred.grbitEnabledProtocols = SP_PROT_SSL2_CLIENT;
353 failf(data,
"Unrecognized parameter passed via CURLOPT_SSLVERSION");
358 BACKEND->cred = (
struct curl_schannel_cred *)
359 malloc(
sizeof(
struct curl_schannel_cred));
361 failf(data,
"schannel: unable to allocate memory");
364 memset(BACKEND->cred, 0,
sizeof(
struct curl_schannel_cred));
365 BACKEND->cred->refcount = 1;
370 s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *)UNISP_NAME,
371 SECPKG_CRED_OUTBOUND, NULL,
372 &schannel_cred, NULL, NULL,
373 &BACKEND->cred->cred_handle,
374 &BACKEND->cred->time_stamp);
376 if(sspi_status != SEC_E_OK) {
377 if(sspi_status == SEC_E_WRONG_PRINCIPAL)
378 failf(data,
"schannel: SNI or certificate check failed: %s",
379 Curl_sspi_strerror(conn, sspi_status));
381 failf(data,
"schannel: AcquireCredentialsHandle failed: %s",
382 Curl_sspi_strerror(conn, sspi_status));
394 infof(data,
"schannel: using IP address, SNI is not supported by OS.\n");
398 if(BACKEND->use_alpn) {
400 int list_start_index = 0;
401 unsigned int *extension_len = NULL;
402 unsigned short* list_len = NULL;
406 extension_len = (
unsigned int *)(&alpn_buffer[cur]);
407 cur +=
sizeof(
unsigned int);
411 *(
unsigned int *)&alpn_buffer[cur] =
412 SecApplicationProtocolNegotiationExt_ALPN;
413 cur +=
sizeof(
unsigned int);
417 list_len = (
unsigned short*)(&alpn_buffer[cur]);
418 cur +=
sizeof(
unsigned short);
420 list_start_index = cur;
424 memcpy(&alpn_buffer[cur], NGHTTP2_PROTO_ALPN, NGHTTP2_PROTO_ALPN_LEN);
425 cur += NGHTTP2_PROTO_ALPN_LEN;
426 infof(data,
"schannel: ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID);
436 *extension_len = *list_len +
sizeof(
unsigned int) +
sizeof(
unsigned short);
438 InitSecBuffer(&inbuf, SECBUFFER_APPLICATION_PROTOCOLS, alpn_buffer, cur);
439 InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
443 InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0);
444 InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
447 InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0);
448 InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
452 InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
453 InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
456 BACKEND->req_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
457 ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY |
461 BACKEND->ctxt = (
struct curl_schannel_ctxt *)
462 malloc(
sizeof(
struct curl_schannel_ctxt));
464 failf(data,
"schannel: unable to allocate memory");
467 memset(BACKEND->ctxt, 0,
sizeof(
struct curl_schannel_ctxt));
469 host_name = Curl_convert_UTF8_to_tchar(hostname);
480 sspi_status = s_pSecFn->InitializeSecurityContext(
481 &BACKEND->cred->cred_handle, NULL, host_name, BACKEND->req_flags, 0, 0,
482 (BACKEND->use_alpn ? &inbuf_desc : NULL),
483 0, &BACKEND->ctxt->ctxt_handle,
484 &outbuf_desc, &BACKEND->ret_flags, &BACKEND->ctxt->time_stamp);
486 Curl_unicodefree(host_name);
488 if(sspi_status != SEC_I_CONTINUE_NEEDED) {
489 if(sspi_status == SEC_E_WRONG_PRINCIPAL)
490 failf(data,
"schannel: SNI or certificate check failed: %s",
491 Curl_sspi_strerror(conn, sspi_status));
493 failf(data,
"schannel: initial InitializeSecurityContext failed: %s",
494 Curl_sspi_strerror(conn, sspi_status));
499 infof(data,
"schannel: sending initial handshake data: " 500 "sending %lu bytes...\n", outbuf.cbBuffer);
504 outbuf.cbBuffer, &written);
505 s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
506 if((result !=
CURLE_OK) || (outbuf.cbBuffer != (
size_t) written)) {
507 failf(data,
"schannel: failed to send initial handshake data: " 508 "sent %zd of %lu bytes", written, outbuf.cbBuffer);
512 infof(data,
"schannel: sent initial handshake data: " 513 "sent %zd bytes\n", written);
515 BACKEND->recv_unrecoverable_err =
CURLE_OK;
516 BACKEND->recv_sspi_close_notify =
false;
517 BACKEND->recv_connection_closed =
false;
518 BACKEND->encdata_is_incomplete =
false;
527 schannel_connect_step2(
struct connectdata *conn,
int sockindex)
530 ssize_t nread = -1, written = -1;
533 unsigned char *reallocated_buffer;
534 size_t reallocated_length;
536 SecBufferDesc outbuf_desc;
538 SecBufferDesc inbuf_desc;
539 SECURITY_STATUS sspi_status = SEC_E_OK;
548 infof(data,
"schannel: SSL/TLS connection with %s port %hu (step 2/3)\n",
551 if(!BACKEND->cred || !BACKEND->ctxt)
555 if(BACKEND->decdata_buffer == NULL) {
556 BACKEND->decdata_offset = 0;
557 BACKEND->decdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
558 BACKEND->decdata_buffer =
malloc(BACKEND->decdata_length);
559 if(BACKEND->decdata_buffer == NULL) {
560 failf(data,
"schannel: unable to allocate memory");
566 if(BACKEND->encdata_buffer == NULL) {
567 BACKEND->encdata_is_incomplete =
false;
568 BACKEND->encdata_offset = 0;
569 BACKEND->encdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
570 BACKEND->encdata_buffer =
malloc(BACKEND->encdata_length);
571 if(BACKEND->encdata_buffer == NULL) {
572 failf(data,
"schannel: unable to allocate memory");
578 if(BACKEND->encdata_length - BACKEND->encdata_offset <
579 CURL_SCHANNEL_BUFFER_FREE_SIZE) {
581 reallocated_length = BACKEND->encdata_offset +
582 CURL_SCHANNEL_BUFFER_FREE_SIZE;
583 reallocated_buffer =
realloc(BACKEND->encdata_buffer,
586 if(reallocated_buffer == NULL) {
587 failf(data,
"schannel: unable to re-allocate memory");
591 BACKEND->encdata_buffer = reallocated_buffer;
592 BACKEND->encdata_length = reallocated_length;
600 (
char *) (BACKEND->encdata_buffer +
601 BACKEND->encdata_offset),
602 BACKEND->encdata_length -
603 BACKEND->encdata_offset,
608 infof(data,
"schannel: failed to receive handshake, " 612 else if((result !=
CURLE_OK) || (nread == 0)) {
613 failf(data,
"schannel: failed to receive handshake, " 614 "SSL/TLS connection failed");
619 BACKEND->encdata_offset += nread;
620 BACKEND->encdata_is_incomplete =
false;
621 infof(data,
"schannel: encrypted data got %zd\n", nread);
624 infof(data,
"schannel: encrypted data buffer: offset %zu length %zu\n",
625 BACKEND->encdata_offset, BACKEND->encdata_length);
628 InitSecBuffer(&inbuf[0], SECBUFFER_TOKEN,
malloc(BACKEND->encdata_offset),
630 InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
631 InitSecBufferDesc(&inbuf_desc, inbuf, 2);
634 InitSecBuffer(&outbuf[0], SECBUFFER_TOKEN, NULL, 0);
635 InitSecBuffer(&outbuf[1], SECBUFFER_ALERT, NULL, 0);
636 InitSecBuffer(&outbuf[2], SECBUFFER_EMPTY, NULL, 0);
637 InitSecBufferDesc(&outbuf_desc, outbuf, 3);
639 if(inbuf[0].pvBuffer == NULL) {
640 failf(data,
"schannel: unable to allocate memory");
645 memcpy(inbuf[0].pvBuffer, BACKEND->encdata_buffer,
646 BACKEND->encdata_offset);
648 host_name = Curl_convert_UTF8_to_tchar(hostname);
654 sspi_status = s_pSecFn->InitializeSecurityContext(
655 &BACKEND->cred->cred_handle, &BACKEND->ctxt->ctxt_handle,
656 host_name, BACKEND->req_flags, 0, 0, &inbuf_desc, 0, NULL,
657 &outbuf_desc, &BACKEND->ret_flags, &BACKEND->ctxt->time_stamp);
659 Curl_unicodefree(host_name);
665 if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
666 BACKEND->encdata_is_incomplete =
true;
668 infof(data,
"schannel: received incomplete message, need more data\n");
675 if(sspi_status == SEC_I_INCOMPLETE_CREDENTIALS &&
676 !(BACKEND->req_flags & ISC_REQ_USE_SUPPLIED_CREDS)) {
677 BACKEND->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS;
679 infof(data,
"schannel: a client certificate has been requested\n");
684 if(sspi_status == SEC_I_CONTINUE_NEEDED || sspi_status == SEC_E_OK) {
685 for(i = 0; i < 3; i++) {
687 if(outbuf[i].BufferType == SECBUFFER_TOKEN && outbuf[i].cbBuffer > 0) {
688 infof(data,
"schannel: sending next handshake data: " 689 "sending %lu bytes...\n", outbuf[i].cbBuffer);
693 outbuf[i].pvBuffer, outbuf[i].cbBuffer,
696 (outbuf[i].cbBuffer != (
size_t) written)) {
697 failf(data,
"schannel: failed to send next handshake data: " 698 "sent %zd of %lu bytes", written, outbuf[i].cbBuffer);
704 if(outbuf[i].pvBuffer != NULL) {
705 s_pSecFn->FreeContextBuffer(outbuf[i].pvBuffer);
710 if(sspi_status == SEC_E_WRONG_PRINCIPAL)
711 failf(data,
"schannel: SNI or certificate check failed: %s",
712 Curl_sspi_strerror(conn, sspi_status));
714 failf(data,
"schannel: next InitializeSecurityContext failed: %s",
715 Curl_sspi_strerror(conn, sspi_status));
716 return sspi_status == SEC_E_UNTRUSTED_ROOT ?
721 if(inbuf[1].BufferType == SECBUFFER_EXTRA && inbuf[1].cbBuffer > 0) {
722 infof(data,
"schannel: encrypted data length: %lu\n", inbuf[1].cbBuffer);
735 if(BACKEND->encdata_offset > inbuf[1].cbBuffer) {
736 memmove(BACKEND->encdata_buffer,
737 (BACKEND->encdata_buffer + BACKEND->encdata_offset) -
738 inbuf[1].cbBuffer, inbuf[1].cbBuffer);
739 BACKEND->encdata_offset = inbuf[1].cbBuffer;
740 if(sspi_status == SEC_I_CONTINUE_NEEDED) {
747 BACKEND->encdata_offset = 0;
753 if(sspi_status == SEC_I_CONTINUE_NEEDED) {
759 if(sspi_status == SEC_E_OK) {
761 infof(data,
"schannel: SSL/TLS handshake complete\n");
768 return verify_certificate(conn, sockindex);
775 schannel_connect_step3(
struct connectdata *conn,
int sockindex)
780 SECURITY_STATUS sspi_status = SEC_E_OK;
781 CERT_CONTEXT *ccert_context = NULL;
782 #ifndef CURL_DISABLE_VERBOSE_STRINGS 787 SecPkgContext_ApplicationProtocol alpn_result;
792 infof(data,
"schannel: SSL/TLS connection with %s port %hu (step 3/3)\n",
799 if(BACKEND->ret_flags != BACKEND->req_flags) {
800 if(!(BACKEND->ret_flags & ISC_RET_SEQUENCE_DETECT))
801 failf(data,
"schannel: failed to setup sequence detection");
802 if(!(BACKEND->ret_flags & ISC_RET_REPLAY_DETECT))
803 failf(data,
"schannel: failed to setup replay detection");
804 if(!(BACKEND->ret_flags & ISC_RET_CONFIDENTIALITY))
805 failf(data,
"schannel: failed to setup confidentiality");
806 if(!(BACKEND->ret_flags & ISC_RET_ALLOCATED_MEMORY))
807 failf(data,
"schannel: failed to setup memory allocation");
808 if(!(BACKEND->ret_flags & ISC_RET_STREAM))
809 failf(data,
"schannel: failed to setup stream orientation");
814 if(BACKEND->use_alpn) {
815 sspi_status = s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
816 SECPKG_ATTR_APPLICATION_PROTOCOL, &alpn_result);
818 if(sspi_status != SEC_E_OK) {
819 failf(data,
"schannel: failed to retrieve ALPN result");
823 if(alpn_result.ProtoNegoStatus ==
824 SecApplicationProtocolNegotiationStatus_Success) {
826 infof(data,
"schannel: ALPN, server accepted to use %.*s\n",
827 alpn_result.ProtocolIdSize, alpn_result.ProtocolId);
830 if(alpn_result.ProtocolIdSize == NGHTTP2_PROTO_VERSION_ID_LEN &&
831 !memcmp(NGHTTP2_PROTO_VERSION_ID, alpn_result.ProtocolId,
832 NGHTTP2_PROTO_VERSION_ID_LEN)) {
844 infof(data,
"ALPN, server did not agree to a protocol\n");
851 struct curl_schannel_cred *old_cred = NULL;
853 Curl_ssl_sessionid_lock(conn);
854 incache = !(Curl_ssl_getsessionid(conn, (
void **)&old_cred, NULL,
857 if(old_cred != BACKEND->cred) {
858 infof(data,
"schannel: old credential handle is stale, removing\n");
860 Curl_ssl_delsessionid(conn, (
void *)old_cred);
865 result = Curl_ssl_addsessionid(conn, (
void *)BACKEND->cred,
866 sizeof(
struct curl_schannel_cred),
869 Curl_ssl_sessionid_unlock(conn);
870 failf(data,
"schannel: failed to store credential handle");
875 BACKEND->cred->refcount++;
876 infof(data,
"schannel: stored credential handle in session cache\n");
879 Curl_ssl_sessionid_unlock(conn);
883 sspi_status = s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
884 SECPKG_ATTR_REMOTE_CERT_CONTEXT, &ccert_context);
886 if((sspi_status != SEC_E_OK) || (ccert_context == NULL)) {
887 failf(data,
"schannel: failed to retrieve remote cert context");
891 result = Curl_ssl_init_certinfo(data, 1);
893 if(((ccert_context->dwCertEncodingType & X509_ASN_ENCODING) != 0) &&
894 (ccert_context->cbCertEncoded > 0)) {
896 const char *beg = (
const char *) ccert_context->pbCertEncoded;
897 const char *end = beg + ccert_context->cbCertEncoded;
898 result = Curl_extract_certinfo(conn, 0, beg, end);
901 CertFreeCertificateContext(ccert_context);
912 schannel_connect_common(
struct connectdata *conn,
int sockindex,
913 bool nonblocking,
bool *done)
934 failf(data,
"SSL/TLS connection timeout");
938 result = schannel_connect_step1(conn, sockindex);
952 failf(data,
"SSL/TLS connection timeout");
966 nonblocking ? 0 : timeout_ms);
969 failf(data,
"select/poll on SSL/TLS socket, errno: %d",
SOCKERRNO);
979 failf(data,
"SSL/TLS connection timeout");
993 result = schannel_connect_step2(conn, sockindex);
994 if(result || (nonblocking &&
1003 result = schannel_connect_step3(conn, sockindex);
1010 conn->
recv[sockindex] = schannel_recv;
1011 conn->
send[sockindex] = schannel_send;
1024 schannel_send(
struct connectdata *conn,
int sockindex,
1028 size_t data_len = 0;
1029 unsigned char *data = NULL;
1031 SecBuffer outbuf[4];
1032 SecBufferDesc outbuf_desc;
1033 SECURITY_STATUS sspi_status = SEC_E_OK;
1037 if(BACKEND->stream_sizes.cbMaximumMessage == 0) {
1038 sspi_status = s_pSecFn->QueryContextAttributes(
1039 &BACKEND->ctxt->ctxt_handle,
1040 SECPKG_ATTR_STREAM_SIZES,
1041 &BACKEND->stream_sizes);
1042 if(sspi_status != SEC_E_OK) {
1049 if(len > BACKEND->stream_sizes.cbMaximumMessage) {
1050 len = BACKEND->stream_sizes.cbMaximumMessage;
1054 data_len = BACKEND->stream_sizes.cbHeader + len +
1055 BACKEND->stream_sizes.cbTrailer;
1056 data = (
unsigned char *)
malloc(data_len);
1063 InitSecBuffer(&outbuf[0], SECBUFFER_STREAM_HEADER,
1064 data, BACKEND->stream_sizes.cbHeader);
1065 InitSecBuffer(&outbuf[1], SECBUFFER_DATA,
1066 data + BACKEND->stream_sizes.cbHeader,
curlx_uztoul(len));
1067 InitSecBuffer(&outbuf[2], SECBUFFER_STREAM_TRAILER,
1068 data + BACKEND->stream_sizes.cbHeader + len,
1069 BACKEND->stream_sizes.cbTrailer);
1070 InitSecBuffer(&outbuf[3], SECBUFFER_EMPTY, NULL, 0);
1071 InitSecBufferDesc(&outbuf_desc, outbuf, 4);
1074 memcpy(outbuf[1].pvBuffer, buf, len);
1077 sspi_status = s_pSecFn->EncryptMessage(&BACKEND->ctxt->ctxt_handle, 0,
1081 if(sspi_status == SEC_E_OK) {
1085 len = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer;
1104 while(len > (
size_t)written) {
1114 failf(conn->
data,
"schannel: timed out sending data " 1115 "(bytes sent: %zd)", written);
1129 else if(0 == what) {
1130 failf(conn->
data,
"schannel: timed out sending data " 1131 "(bytes sent: %zd)", written);
1139 len - written, &this_write);
1148 written += this_write;
1151 else if(sspi_status == SEC_E_INSUFFICIENT_MEMORY) {
1160 if(len == (
size_t)written)
1163 written = outbuf[1].cbBuffer;
1169 schannel_recv(
struct connectdata *conn,
int sockindex,
1170 char *buf,
size_t len,
CURLcode *err)
1176 unsigned char *reallocated_buffer;
1177 size_t reallocated_length;
1180 SecBufferDesc inbuf_desc;
1181 SECURITY_STATUS sspi_status = SEC_E_OK;
1184 size_t min_encdata_length = len + CURL_SCHANNEL_BUFFER_FREE_SIZE;
1196 infof(data,
"schannel: client wants to read %zu bytes\n", len);
1199 if(len && len <= BACKEND->decdata_offset) {
1200 infof(data,
"schannel: enough decrypted data is already available\n");
1203 else if(BACKEND->recv_unrecoverable_err) {
1204 *err = BACKEND->recv_unrecoverable_err;
1205 infof(data,
"schannel: an unrecoverable error occurred in a prior call\n");
1208 else if(BACKEND->recv_sspi_close_notify) {
1210 infof(data,
"schannel: server indicated shutdown in a prior call\n");
1220 else if(!BACKEND->recv_connection_closed) {
1222 size = BACKEND->encdata_length - BACKEND->encdata_offset;
1223 if(size < CURL_SCHANNEL_BUFFER_FREE_SIZE ||
1224 BACKEND->encdata_length < min_encdata_length) {
1225 reallocated_length = BACKEND->encdata_offset +
1226 CURL_SCHANNEL_BUFFER_FREE_SIZE;
1227 if(reallocated_length < min_encdata_length) {
1228 reallocated_length = min_encdata_length;
1230 reallocated_buffer =
realloc(BACKEND->encdata_buffer,
1231 reallocated_length);
1232 if(reallocated_buffer == NULL) {
1234 failf(data,
"schannel: unable to re-allocate memory");
1238 BACKEND->encdata_buffer = reallocated_buffer;
1239 BACKEND->encdata_length = reallocated_length;
1240 size = BACKEND->encdata_length - BACKEND->encdata_offset;
1241 infof(data,
"schannel: encdata_buffer resized %zu\n",
1242 BACKEND->encdata_length);
1245 infof(data,
"schannel: encrypted data buffer: offset %zu length %zu\n",
1246 BACKEND->encdata_offset, BACKEND->encdata_length);
1250 (
char *)(BACKEND->encdata_buffer +
1251 BACKEND->encdata_offset),
1256 infof(data,
"schannel: Curl_read_plain returned CURLE_AGAIN\n");
1258 infof(data,
"schannel: Curl_read_plain returned CURLE_RECV_ERROR\n");
1260 infof(data,
"schannel: Curl_read_plain returned error %d\n", *err);
1262 else if(nread == 0) {
1263 BACKEND->recv_connection_closed =
true;
1264 infof(data,
"schannel: server closed the connection\n");
1266 else if(nread > 0) {
1267 BACKEND->encdata_offset += (
size_t)nread;
1268 BACKEND->encdata_is_incomplete =
false;
1269 infof(data,
"schannel: encrypted data got %zd\n", nread);
1273 infof(data,
"schannel: encrypted data buffer: offset %zu length %zu\n",
1274 BACKEND->encdata_offset, BACKEND->encdata_length);
1277 while(BACKEND->encdata_offset > 0 && sspi_status == SEC_E_OK &&
1278 (!len || BACKEND->decdata_offset < len ||
1279 BACKEND->recv_connection_closed)) {
1281 InitSecBuffer(&inbuf[0], SECBUFFER_DATA, BACKEND->encdata_buffer,
1285 InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
1286 InitSecBuffer(&inbuf[2], SECBUFFER_EMPTY, NULL, 0);
1287 InitSecBuffer(&inbuf[3], SECBUFFER_EMPTY, NULL, 0);
1288 InitSecBufferDesc(&inbuf_desc, inbuf, 4);
1292 sspi_status = s_pSecFn->DecryptMessage(&BACKEND->ctxt->ctxt_handle,
1293 &inbuf_desc, 0, NULL);
1297 if(sspi_status == SEC_E_OK || sspi_status == SEC_I_RENEGOTIATE ||
1298 sspi_status == SEC_I_CONTEXT_EXPIRED) {
1301 if(inbuf[1].BufferType == SECBUFFER_DATA) {
1302 infof(data,
"schannel: decrypted data length: %lu\n",
1306 size = inbuf[1].cbBuffer > CURL_SCHANNEL_BUFFER_FREE_SIZE ?
1307 inbuf[1].cbBuffer : CURL_SCHANNEL_BUFFER_FREE_SIZE;
1308 if(BACKEND->decdata_length - BACKEND->decdata_offset < size ||
1309 BACKEND->decdata_length < len) {
1311 reallocated_length = BACKEND->decdata_offset +
size;
1313 if(reallocated_length < len) {
1314 reallocated_length =
len;
1316 reallocated_buffer =
realloc(BACKEND->decdata_buffer,
1317 reallocated_length);
1318 if(reallocated_buffer == NULL) {
1320 failf(data,
"schannel: unable to re-allocate memory");
1323 BACKEND->decdata_buffer = reallocated_buffer;
1324 BACKEND->decdata_length = reallocated_length;
1328 size = inbuf[1].cbBuffer;
1330 memcpy(BACKEND->decdata_buffer + BACKEND->decdata_offset,
1331 inbuf[1].pvBuffer, size);
1332 BACKEND->decdata_offset +=
size;
1335 infof(data,
"schannel: decrypted data added: %zu\n", size);
1336 infof(data,
"schannel: decrypted data cached: offset %zu length %zu\n",
1337 BACKEND->decdata_offset, BACKEND->decdata_length);
1341 if(inbuf[3].BufferType == SECBUFFER_EXTRA && inbuf[3].cbBuffer > 0) {
1342 infof(data,
"schannel: encrypted data length: %lu\n",
1348 if(BACKEND->encdata_offset > inbuf[3].cbBuffer) {
1351 memmove(BACKEND->encdata_buffer,
1352 (BACKEND->encdata_buffer + BACKEND->encdata_offset) -
1353 inbuf[3].cbBuffer, inbuf[3].cbBuffer);
1354 BACKEND->encdata_offset = inbuf[3].cbBuffer;
1357 infof(data,
"schannel: encrypted data cached: offset %zu length %zu\n",
1358 BACKEND->encdata_offset, BACKEND->encdata_length);
1362 BACKEND->encdata_offset = 0;
1366 if(sspi_status == SEC_I_RENEGOTIATE) {
1367 infof(data,
"schannel: remote party requests renegotiation\n");
1369 infof(data,
"schannel: can't renogotiate, an error is pending\n");
1372 if(BACKEND->encdata_offset) {
1374 infof(data,
"schannel: can't renogotiate, " 1375 "encrypted data available\n");
1379 infof(data,
"schannel: renegotiating SSL/TLS connection\n");
1382 *err = schannel_connect_common(conn, sockindex,
FALSE, &done);
1384 infof(data,
"schannel: renegotiation failed\n");
1388 sspi_status = SEC_E_OK;
1389 infof(data,
"schannel: SSL/TLS connection renegotiated\n");
1393 else if(sspi_status == SEC_I_CONTEXT_EXPIRED) {
1396 BACKEND->recv_sspi_close_notify =
true;
1397 if(!BACKEND->recv_connection_closed) {
1398 BACKEND->recv_connection_closed =
true;
1399 infof(data,
"schannel: server closed the connection\n");
1404 else if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
1405 BACKEND->encdata_is_incomplete =
true;
1408 infof(data,
"schannel: failed to decrypt data, need more data\n");
1413 infof(data,
"schannel: failed to read data from server: %s\n",
1414 Curl_sspi_strerror(conn, sspi_status));
1419 infof(data,
"schannel: encrypted data buffer: offset %zu length %zu\n",
1420 BACKEND->encdata_offset, BACKEND->encdata_length);
1422 infof(data,
"schannel: decrypted data buffer: offset %zu length %zu\n",
1423 BACKEND->decdata_offset, BACKEND->decdata_length);
1427 infof(data,
"schannel: schannel_recv cleanup\n");
1437 if(len && !BACKEND->decdata_offset && BACKEND->recv_connection_closed &&
1438 !BACKEND->recv_sspi_close_notify) {
1439 bool isWin2k = Curl_verify_windows_version(5, 0, PLATFORM_WINNT,
1442 if(isWin2k && sspi_status == SEC_E_OK)
1443 BACKEND->recv_sspi_close_notify =
true;
1446 infof(data,
"schannel: server closed abruptly (missing close_notify)\n");
1452 BACKEND->recv_unrecoverable_err = *err;
1454 size = len < BACKEND->decdata_offset ? len : BACKEND->decdata_offset;
1456 memcpy(buf, BACKEND->decdata_buffer, size);
1457 memmove(BACKEND->decdata_buffer, BACKEND->decdata_buffer + size,
1458 BACKEND->decdata_offset - size);
1459 BACKEND->decdata_offset -=
size;
1461 infof(data,
"schannel: decrypted data returned %zu\n", size);
1462 infof(data,
"schannel: decrypted data buffer: offset %zu length %zu\n",
1463 BACKEND->decdata_offset, BACKEND->decdata_length);
1468 if(!*err && !BACKEND->recv_connection_closed)
1477 return *err ? -1 : 0;
1481 int sockindex,
bool *done)
1483 return schannel_connect_common(conn, sockindex,
TRUE, done);
1491 result = schannel_connect_common(conn, sockindex,
FALSE, &done);
1500 static bool Curl_schannel_data_pending(
const struct connectdata *conn,
1506 return (BACKEND->decdata_offset > 0 ||
1507 (BACKEND->encdata_offset > 0 && !BACKEND->encdata_is_incomplete));
1512 static void Curl_schannel_close(
struct connectdata *conn,
int sockindex)
1514 if(conn->
ssl[sockindex].
use)
1519 static void Curl_schannel_session_free(
void *
ptr)
1522 struct curl_schannel_cred *cred =
ptr;
1525 if(cred->refcount == 0) {
1526 s_pSecFn->FreeCredentialsHandle(&cred->cred_handle);
1531 static int Curl_schannel_shutdown(
struct connectdata *conn,
int sockindex)
1541 infof(data,
"schannel: shutting down SSL/TLS connection with %s port %hu\n",
1544 if(BACKEND->cred && BACKEND->ctxt) {
1545 SecBufferDesc BuffDesc;
1547 SECURITY_STATUS sspi_status;
1549 SecBufferDesc outbuf_desc;
1552 DWORD dwshut = SCHANNEL_SHUTDOWN;
1554 InitSecBuffer(&Buffer, SECBUFFER_TOKEN, &dwshut,
sizeof(dwshut));
1555 InitSecBufferDesc(&BuffDesc, &Buffer, 1);
1557 sspi_status = s_pSecFn->ApplyControlToken(&BACKEND->ctxt->ctxt_handle,
1560 if(sspi_status != SEC_E_OK)
1561 failf(data,
"schannel: ApplyControlToken failure: %s",
1562 Curl_sspi_strerror(conn, sspi_status));
1564 host_name = Curl_convert_UTF8_to_tchar(hostname);
1569 InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
1570 InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
1572 sspi_status = s_pSecFn->InitializeSecurityContext(
1573 &BACKEND->cred->cred_handle,
1574 &BACKEND->ctxt->ctxt_handle,
1581 &BACKEND->ctxt->ctxt_handle,
1583 &BACKEND->ret_flags,
1584 &BACKEND->ctxt->time_stamp);
1586 Curl_unicodefree(host_name);
1588 if((sspi_status == SEC_E_OK) || (sspi_status == SEC_I_CONTEXT_EXPIRED)) {
1592 outbuf.cbBuffer, &written);
1594 s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
1595 if((result !=
CURLE_OK) || (outbuf.cbBuffer != (
size_t) written)) {
1596 infof(data,
"schannel: failed to send close msg: %s" 1604 infof(data,
"schannel: clear security context handle\n");
1605 s_pSecFn->DeleteSecurityContext(&BACKEND->ctxt->ctxt_handle);
1611 Curl_ssl_sessionid_lock(conn);
1612 Curl_schannel_session_free(BACKEND->cred);
1613 Curl_ssl_sessionid_unlock(conn);
1614 BACKEND->cred = NULL;
1618 if(BACKEND->encdata_buffer != NULL) {
1620 BACKEND->encdata_length = 0;
1621 BACKEND->encdata_offset = 0;
1622 BACKEND->encdata_is_incomplete =
false;
1626 if(BACKEND->decdata_buffer != NULL) {
1628 BACKEND->decdata_length = 0;
1629 BACKEND->decdata_offset = 0;
1635 static int Curl_schannel_init(
void)
1637 return (Curl_sspi_global_init() ==
CURLE_OK ? 1 : 0);
1640 static void Curl_schannel_cleanup(
void)
1642 Curl_sspi_global_cleanup();
1645 static size_t Curl_schannel_version(
char *
buffer,
size_t size)
1647 size =
snprintf(buffer, size,
"WinSSL");
1653 unsigned char *entropy,
size_t length)
1655 HCRYPTPROV hCryptProv = 0;
1659 if(!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL,
1660 CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
1663 if(!CryptGenRandom(hCryptProv, (DWORD)length, entropy)) {
1664 CryptReleaseContext(hCryptProv, 0UL);
1668 CryptReleaseContext(hCryptProv, 0UL);
1675 SECURITY_STATUS status;
1679 CERT_CONTEXT *pCertContextServer = NULL;
1680 const CERT_CHAIN_CONTEXT *pChainContext = NULL;
1685 status = s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
1686 SECPKG_ATTR_REMOTE_CERT_CONTEXT,
1687 &pCertContextServer);
1689 if((status != SEC_E_OK) || (pCertContextServer == NULL)) {
1690 failf(data,
"schannel: Failed to read remote certificate context: %s",
1691 Curl_sspi_strerror(conn, status));
1696 CERT_CHAIN_PARA ChainPara;
1697 memset(&ChainPara, 0,
sizeof(ChainPara));
1698 ChainPara.cbSize =
sizeof(ChainPara);
1700 if(!CertGetCertificateChain(NULL,
1703 pCertContextServer->hCertStore,
1706 CERT_CHAIN_REVOCATION_CHECK_CHAIN),
1709 failf(data,
"schannel: CertGetCertificateChain failed: %s",
1710 Curl_sspi_strerror(conn, GetLastError()));
1711 pChainContext = NULL;
1716 CERT_SIMPLE_CHAIN *pSimpleChain = pChainContext->rgpChain[0];
1717 DWORD dwTrustErrorMask = ~(DWORD)(CERT_TRUST_IS_NOT_TIME_NESTED);
1718 dwTrustErrorMask &= pSimpleChain->TrustStatus.dwErrorStatus;
1719 if(dwTrustErrorMask) {
1720 if(dwTrustErrorMask & CERT_TRUST_IS_REVOKED)
1721 failf(data,
"schannel: CertGetCertificateChain trust error" 1722 " CERT_TRUST_IS_REVOKED");
1723 else if(dwTrustErrorMask & CERT_TRUST_IS_PARTIAL_CHAIN)
1724 failf(data,
"schannel: CertGetCertificateChain trust error" 1725 " CERT_TRUST_IS_PARTIAL_CHAIN");
1726 else if(dwTrustErrorMask & CERT_TRUST_IS_UNTRUSTED_ROOT)
1727 failf(data,
"schannel: CertGetCertificateChain trust error" 1728 " CERT_TRUST_IS_UNTRUSTED_ROOT");
1729 else if(dwTrustErrorMask & CERT_TRUST_IS_NOT_TIME_VALID)
1730 failf(data,
"schannel: CertGetCertificateChain trust error" 1731 " CERT_TRUST_IS_NOT_TIME_VALID");
1733 failf(data,
"schannel: CertGetCertificateChain error mask: 0x%08x",
1742 TCHAR cert_hostname_buff[256];
1753 len = CertGetNameString(pCertContextServer,
1755 CERT_NAME_DISABLE_IE4_UTF8_FLAG,
1760 const char *cert_hostname;
1766 cert_hostname = Curl_convert_tchar_to_UTF8(cert_hostname_buff);
1767 if(!cert_hostname) {
1776 "schannel: connection hostname (%s) validated " 1777 "against certificate name (%s)\n",
1784 "schannel: connection hostname (%s) " 1785 "does not match certificate name (%s)",
1790 Curl_unicodefree(cert_hostname);
1795 "schannel: CertGetNameString did not provide any " 1796 "certificate name information");
1803 CertFreeCertificateChain(pChainContext);
1805 if(pCertContextServer)
1806 CertFreeCertificateContext(pCertContextServer);
1816 return &BACKEND->ctxt->ctxt_handle;
1819 const struct Curl_ssl Curl_ssl_schannel = {
1828 sizeof(
struct ssl_backend_data),
1831 Curl_schannel_cleanup,
1832 Curl_schannel_version,
1834 Curl_schannel_shutdown,
1835 Curl_schannel_data_pending,
1836 Curl_schannel_random,
1838 Curl_schannel_connect,
1839 Curl_schannel_connect_nonblocking,
1840 Curl_schannel_get_internals,
1841 Curl_schannel_close,
1843 Curl_schannel_session_free,
struct ssl_connect_data ssl[2]
ssize_t( Curl_recv)(struct connectdata *conn, int sockindex, char *buf, size_t len, CURLcode *err)
#define SSL_CONN_CONFIG(var)
CURLcode Curl_write_plain(struct connectdata *conn, curl_socket_t sockfd, const void *mem, size_t len, ssize_t *written)
#define SSL_SET_OPTION(var)
ssl_connect_state connecting_state
UNITTEST_START char * ptr
#define realloc(ptr, size)
UNITTEST_START int result
struct ssl_config_data ssl
struct proxy_info http_proxy
CURLcode Curl_read_plain(curl_socket_t sockfd, char *buf, size_t bytesfromsocket, ssize_t *n)
ssl_connection_state state
memcpy(filename, filename1, strlen(filename1))
#define Curl_ssl_shutdown(x, y)
unsigned long curlx_uztoul(size_t uznum)
int Curl_none_check_cxn(struct connectdata *conn)
#define ALPN_HTTP_1_1_LENGTH
time_t Curl_timeleft(struct Curl_easy *data, struct curltime *nowp, bool duringconnect)
curl_easy_setopt expects a curl_off_t argument for this option curl_easy_setopt expects a curl_write_callback argument for this option curl_easy_setopt expects a curl_ioctl_callback argument for this option curl_easy_setopt expects a curl_opensocket_callback argument for this option curl_easy_setopt expects a curl_debug_callback argument for this option curl_easy_setopt expects a curl_conv_callback argument for this option curl_easy_setopt expects a private data pointer as argument for this option curl_easy_setopt expects a FILE *argument for this option curl_easy_setopt expects a struct curl_httppost *argument for this option curl_easy_setopt expects a struct curl_slist *argument for this option curl_easy_getinfo expects a pointer to char *for this info curl_easy_getinfo expects a pointer to double for this info curl_easy_getinfo expects a pointer to struct curl_tlssessioninfo *for this info curl_easy_getinfo expects a pointer to curl_socket_t for this info size_t
bool Curl_none_false_start(void)
bool Curl_none_cert_status_request(void)
#define SOCKET_WRITABLE(x, z)
ssize_t( Curl_send)(struct connectdata *conn, int sockindex, const void *buf, size_t len, CURLcode *err)
int Curl_inet_pton(int af, const char *src, void *dst)
CURLcode Curl_none_md5sum(unsigned char *input, size_t inputlen, unsigned char *md5sum, size_t md5len)
#define Curl_safefree(ptr)
int Curl_socket_check(curl_socket_t readfd0, curl_socket_t readfd1, curl_socket_t writefd, time_t timeout_ms)
unsigned short curlx_uitous(unsigned int uinum)
CURLcode Curl_none_set_engine(struct Curl_easy *data, const char *engine)
int Curl_cert_hostcheck(const char *match_pattern, const char *hostname)
struct ssl_primary_config ssl_config
struct curl_slist * Curl_none_engines_list(struct Curl_easy *data)
#define CURL_HTTP_VERSION_2
CURL_EXTERN const char * curl_easy_strerror(CURLcode)
CURLcode Curl_none_set_engine_default(struct Curl_easy *data)
void Curl_none_close_all(struct Curl_easy *data)