Loading docs/HTTP2.md +2 −1 Original line number Diff line number Diff line Loading @@ -7,7 +7,7 @@ HTTP/2 with curl Build prerequisites ------------------- - nghttp2 - OpenSSL, NSS, GnutTLS or PolarSSL with a new enough version - OpenSSL, NSS, GnutTLS, PolarSSL or SChannel with a new enough version [nghttp2](https://nghttp2.org/) ------------------------------- Loading Loading @@ -58,6 +58,7 @@ provide the necessary TLS features. Right now we support: - NSS: ALPN and NPN - GnuTLS: ALPN - PolarSSL: ALPN - SChannel: ALPN Multiplexing ------------ Loading lib/vtls/schannel.c +105 −1 Original line number Diff line number Diff line Loading @@ -61,6 +61,12 @@ /* The last #include file should be: */ #include "memdebug.h" /* ALPN requires version 8.1 of the Windows SDK, which was shipped with Visual Studio 2013, aka _MSC_VER 1800*/ #if defined(_MSC_VER) && (_MSC_VER >= 1800) # define HAS_ALPN 1 #endif /* Uncomment to force verbose output * #define infof(x, y, ...) printf(y, __VA_ARGS__) * #define failf(x, y, ...) printf(y, __VA_ARGS__) Loading Loading @@ -97,6 +103,11 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) struct ssl_connect_data *connssl = &conn->ssl[sockindex]; SecBuffer outbuf; SecBufferDesc outbuf_desc; SecBuffer inbuf; SecBufferDesc inbuf_desc; #ifdef HAS_ALPN unsigned char alpn_buffer[128]; #endif SCHANNEL_CRED schannel_cred; SECURITY_STATUS sspi_status = SEC_E_OK; struct curl_schannel_cred *old_cred = NULL; Loading Loading @@ -219,6 +230,60 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) infof(data, "schannel: using IP address, SNI is not supported by OS.\n"); } #ifdef HAS_ALPN if(data->set.ssl_enable_alpn) { int cur = 0; int list_start_index = 0; unsigned int* extension_len = NULL; unsigned short* list_len = NULL; /* The first four bytes will be an unsigned int indicating number of bytes of data in the rest of the the buffer. */ extension_len = (unsigned int*)(&alpn_buffer[cur]); cur += sizeof(unsigned int); /* The next four bytes are an indicator that this buffer will contain ALPN data, as opposed to NPN, for example. */ *(unsigned int*)&alpn_buffer[cur] = SecApplicationProtocolNegotiationExt_ALPN; cur += sizeof(unsigned int); /* The next two bytes will be an unsigned short indicating the number of bytes used to list the preferred protocols. */ list_len = (unsigned short*)(&alpn_buffer[cur]); cur += sizeof(unsigned short); list_start_index = cur; #ifdef USE_NGHTTP2 if(data->set.httpversion >= CURL_HTTP_VERSION_2) { memcpy(&alpn_buffer[cur], NGHTTP2_PROTO_ALPN, NGHTTP2_PROTO_ALPN_LEN); cur += NGHTTP2_PROTO_ALPN_LEN; infof(data, "schannel: ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID); } #endif alpn_buffer[cur++] = ALPN_HTTP_1_1_LENGTH; memcpy(&alpn_buffer[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH); cur += ALPN_HTTP_1_1_LENGTH; infof(data, "schannel: ALPN, offering %s\n", ALPN_HTTP_1_1); *list_len = cur - list_start_index; *extension_len = *list_len + sizeof(unsigned int) + sizeof(unsigned short); InitSecBuffer(&inbuf, SECBUFFER_APPLICATION_PROTOCOLS, alpn_buffer, cur); InitSecBufferDesc(&inbuf_desc, &inbuf, 1); } else { InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0); InitSecBufferDesc(&inbuf_desc, &inbuf, 1); } #else /* HAS_ALPN */ InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0); InitSecBufferDesc(&inbuf_desc, &inbuf, 1); #endif /* setup output buffer */ InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0); InitSecBufferDesc(&outbuf_desc, &outbuf, 1); Loading @@ -245,7 +310,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) sspi_status = s_pSecFn->InitializeSecurityContext( &connssl->cred->cred_handle, NULL, host_name, connssl->req_flags, 0, 0, NULL, 0, &connssl->ctxt->ctxt_handle, connssl->req_flags, 0, 0, &inbuf_desc, 0, &connssl->ctxt->ctxt_handle, &outbuf_desc, &connssl->ret_flags, &connssl->ctxt->time_stamp); Curl_unicodefree(host_name); Loading Loading @@ -535,6 +600,10 @@ schannel_connect_step3(struct connectdata *conn, int sockindex) struct SessionHandle *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; struct curl_schannel_cred *old_cred = NULL; #ifdef HAS_ALPN SECURITY_STATUS sspi_status = SEC_E_OK; SecPkgContext_ApplicationProtocol alpn_result; #endif bool incache; DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); Loading @@ -560,6 +629,41 @@ schannel_connect_step3(struct connectdata *conn, int sockindex) return CURLE_SSL_CONNECT_ERROR; } #ifdef HAS_ALPN if(data->set.ssl_enable_alpn) { sspi_status = s_pSecFn->QueryContextAttributes(&connssl->ctxt->ctxt_handle, SECPKG_ATTR_APPLICATION_PROTOCOL, &alpn_result); if(sspi_status != SEC_E_OK) { failf(data, "schannel: failed to retrieve ALPN result"); return CURLE_SSL_CONNECT_ERROR; } if(alpn_result.ProtoNegoStatus == SecApplicationProtocolNegotiationStatus_Success) { infof(data, "schannel: ALPN, server accepted to use %.*s\n", alpn_result.ProtocolIdSize, alpn_result.ProtocolId); #ifdef USE_NGHTTP2 if(alpn_result.ProtocolIdSize == NGHTTP2_PROTO_VERSION_ID_LEN && !memcmp(NGHTTP2_PROTO_VERSION_ID, alpn_result.ProtocolId, NGHTTP2_PROTO_VERSION_ID_LEN)) { conn->negnpn = CURL_HTTP_VERSION_2; } else #endif if(alpn_result.ProtocolIdSize == ALPN_HTTP_1_1_LENGTH && !memcmp(ALPN_HTTP_1_1, alpn_result.ProtocolId, ALPN_HTTP_1_1_LENGTH)) { conn->negnpn = CURL_HTTP_VERSION_1_1; } } else infof(data, "ALPN, server did not agree to a protocol\n"); } #endif /* increment the reference counter of the credential/session handle */ if(connssl->cred && connssl->ctxt) { connssl->cred->refcount++; Loading Loading
docs/HTTP2.md +2 −1 Original line number Diff line number Diff line Loading @@ -7,7 +7,7 @@ HTTP/2 with curl Build prerequisites ------------------- - nghttp2 - OpenSSL, NSS, GnutTLS or PolarSSL with a new enough version - OpenSSL, NSS, GnutTLS, PolarSSL or SChannel with a new enough version [nghttp2](https://nghttp2.org/) ------------------------------- Loading Loading @@ -58,6 +58,7 @@ provide the necessary TLS features. Right now we support: - NSS: ALPN and NPN - GnuTLS: ALPN - PolarSSL: ALPN - SChannel: ALPN Multiplexing ------------ Loading
lib/vtls/schannel.c +105 −1 Original line number Diff line number Diff line Loading @@ -61,6 +61,12 @@ /* The last #include file should be: */ #include "memdebug.h" /* ALPN requires version 8.1 of the Windows SDK, which was shipped with Visual Studio 2013, aka _MSC_VER 1800*/ #if defined(_MSC_VER) && (_MSC_VER >= 1800) # define HAS_ALPN 1 #endif /* Uncomment to force verbose output * #define infof(x, y, ...) printf(y, __VA_ARGS__) * #define failf(x, y, ...) printf(y, __VA_ARGS__) Loading Loading @@ -97,6 +103,11 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) struct ssl_connect_data *connssl = &conn->ssl[sockindex]; SecBuffer outbuf; SecBufferDesc outbuf_desc; SecBuffer inbuf; SecBufferDesc inbuf_desc; #ifdef HAS_ALPN unsigned char alpn_buffer[128]; #endif SCHANNEL_CRED schannel_cred; SECURITY_STATUS sspi_status = SEC_E_OK; struct curl_schannel_cred *old_cred = NULL; Loading Loading @@ -219,6 +230,60 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) infof(data, "schannel: using IP address, SNI is not supported by OS.\n"); } #ifdef HAS_ALPN if(data->set.ssl_enable_alpn) { int cur = 0; int list_start_index = 0; unsigned int* extension_len = NULL; unsigned short* list_len = NULL; /* The first four bytes will be an unsigned int indicating number of bytes of data in the rest of the the buffer. */ extension_len = (unsigned int*)(&alpn_buffer[cur]); cur += sizeof(unsigned int); /* The next four bytes are an indicator that this buffer will contain ALPN data, as opposed to NPN, for example. */ *(unsigned int*)&alpn_buffer[cur] = SecApplicationProtocolNegotiationExt_ALPN; cur += sizeof(unsigned int); /* The next two bytes will be an unsigned short indicating the number of bytes used to list the preferred protocols. */ list_len = (unsigned short*)(&alpn_buffer[cur]); cur += sizeof(unsigned short); list_start_index = cur; #ifdef USE_NGHTTP2 if(data->set.httpversion >= CURL_HTTP_VERSION_2) { memcpy(&alpn_buffer[cur], NGHTTP2_PROTO_ALPN, NGHTTP2_PROTO_ALPN_LEN); cur += NGHTTP2_PROTO_ALPN_LEN; infof(data, "schannel: ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID); } #endif alpn_buffer[cur++] = ALPN_HTTP_1_1_LENGTH; memcpy(&alpn_buffer[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH); cur += ALPN_HTTP_1_1_LENGTH; infof(data, "schannel: ALPN, offering %s\n", ALPN_HTTP_1_1); *list_len = cur - list_start_index; *extension_len = *list_len + sizeof(unsigned int) + sizeof(unsigned short); InitSecBuffer(&inbuf, SECBUFFER_APPLICATION_PROTOCOLS, alpn_buffer, cur); InitSecBufferDesc(&inbuf_desc, &inbuf, 1); } else { InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0); InitSecBufferDesc(&inbuf_desc, &inbuf, 1); } #else /* HAS_ALPN */ InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0); InitSecBufferDesc(&inbuf_desc, &inbuf, 1); #endif /* setup output buffer */ InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0); InitSecBufferDesc(&outbuf_desc, &outbuf, 1); Loading @@ -245,7 +310,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) sspi_status = s_pSecFn->InitializeSecurityContext( &connssl->cred->cred_handle, NULL, host_name, connssl->req_flags, 0, 0, NULL, 0, &connssl->ctxt->ctxt_handle, connssl->req_flags, 0, 0, &inbuf_desc, 0, &connssl->ctxt->ctxt_handle, &outbuf_desc, &connssl->ret_flags, &connssl->ctxt->time_stamp); Curl_unicodefree(host_name); Loading Loading @@ -535,6 +600,10 @@ schannel_connect_step3(struct connectdata *conn, int sockindex) struct SessionHandle *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; struct curl_schannel_cred *old_cred = NULL; #ifdef HAS_ALPN SECURITY_STATUS sspi_status = SEC_E_OK; SecPkgContext_ApplicationProtocol alpn_result; #endif bool incache; DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); Loading @@ -560,6 +629,41 @@ schannel_connect_step3(struct connectdata *conn, int sockindex) return CURLE_SSL_CONNECT_ERROR; } #ifdef HAS_ALPN if(data->set.ssl_enable_alpn) { sspi_status = s_pSecFn->QueryContextAttributes(&connssl->ctxt->ctxt_handle, SECPKG_ATTR_APPLICATION_PROTOCOL, &alpn_result); if(sspi_status != SEC_E_OK) { failf(data, "schannel: failed to retrieve ALPN result"); return CURLE_SSL_CONNECT_ERROR; } if(alpn_result.ProtoNegoStatus == SecApplicationProtocolNegotiationStatus_Success) { infof(data, "schannel: ALPN, server accepted to use %.*s\n", alpn_result.ProtocolIdSize, alpn_result.ProtocolId); #ifdef USE_NGHTTP2 if(alpn_result.ProtocolIdSize == NGHTTP2_PROTO_VERSION_ID_LEN && !memcmp(NGHTTP2_PROTO_VERSION_ID, alpn_result.ProtocolId, NGHTTP2_PROTO_VERSION_ID_LEN)) { conn->negnpn = CURL_HTTP_VERSION_2; } else #endif if(alpn_result.ProtocolIdSize == ALPN_HTTP_1_1_LENGTH && !memcmp(ALPN_HTTP_1_1, alpn_result.ProtocolId, ALPN_HTTP_1_1_LENGTH)) { conn->negnpn = CURL_HTTP_VERSION_1_1; } } else infof(data, "ALPN, server did not agree to a protocol\n"); } #endif /* increment the reference counter of the credential/session handle */ if(connssl->cred && connssl->ctxt) { connssl->cred->refcount++; Loading