void SSL_get0_alpn_selected(const SSL *ssl, const unsigned char **data, unsigned int *len) { const char *alp = mbedtls_ssl_get_alpn_protocol(&((struct ssl_pm *)(ssl->ssl_pm))->ssl); *data = (const unsigned char *)alp; if (alp) *len = strlen(alp); else *len = 0; }
static CURLcode mbed_connect_step2(struct connectdata *conn, int sockindex) { int ret; struct SessionHandle *data = conn->data; struct ssl_connect_data* connssl = &conn->ssl[sockindex]; const mbedtls_x509_crt *peercert; #ifdef HAS_ALPN const char* next_protocol; #endif char errorbuf[128]; errorbuf[0] = 0; conn->recv[sockindex] = mbed_recv; conn->send[sockindex] = mbed_send; ret = mbedtls_ssl_handshake(&connssl->ssl); if(ret == MBEDTLS_ERR_SSL_WANT_READ) { connssl->connecting_state = ssl_connect_2_reading; return CURLE_OK; } else if(ret == MBEDTLS_ERR_SSL_WANT_WRITE) { connssl->connecting_state = ssl_connect_2_writing; return CURLE_OK; } else if(ret) { #ifdef MBEDTLS_ERROR_C mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); #endif /* MBEDTLS_ERROR_C */ failf(data, "ssl_handshake returned - mbedTLS: (-0x%04X) %s", -ret, errorbuf); return CURLE_SSL_CONNECT_ERROR; } infof(data, "mbedTLS: Handshake complete, cipher is %s\n", mbedtls_ssl_get_ciphersuite(&conn->ssl[sockindex].ssl) ); ret = mbedtls_ssl_get_verify_result(&conn->ssl[sockindex].ssl); if(ret && data->set.ssl.verifypeer) { if(ret & MBEDTLS_X509_BADCERT_EXPIRED) failf(data, "Cert verify failed: BADCERT_EXPIRED"); if(ret & MBEDTLS_X509_BADCERT_REVOKED) { failf(data, "Cert verify failed: BADCERT_REVOKED"); return CURLE_SSL_CACERT; } if(ret & MBEDTLS_X509_BADCERT_CN_MISMATCH) failf(data, "Cert verify failed: BADCERT_CN_MISMATCH"); if(ret & MBEDTLS_X509_BADCERT_NOT_TRUSTED) failf(data, "Cert verify failed: BADCERT_NOT_TRUSTED"); return CURLE_PEER_FAILED_VERIFICATION; } peercert = mbedtls_ssl_get_peer_cert(&connssl->ssl); if(peercert && data->set.verbose) { const size_t bufsize = 16384; char *buffer = malloc(bufsize); if(!buffer) return CURLE_OUT_OF_MEMORY; if(mbedtls_x509_crt_info(buffer, bufsize, "* ", peercert) > 0) infof(data, "Dumping cert info:\n%s\n", buffer); else infof(data, "Unable to dump certificate information.\n"); free(buffer); } if(data->set.str[STRING_SSL_PINNEDPUBLICKEY]) { int size; CURLcode result; mbedtls_x509_crt *p; unsigned char pubkey[PUB_DER_MAX_BYTES]; if(!peercert || !peercert->raw.p || !peercert->raw.len) { failf(data, "Failed due to missing peer certificate"); return CURLE_SSL_PINNEDPUBKEYNOTMATCH; } p = calloc(1, sizeof(*p)); if(!p) return CURLE_OUT_OF_MEMORY; mbedtls_x509_crt_init(p); /* Make a copy of our const peercert because mbedtls_pk_write_pubkey_der needs a non-const key, for now. https://github.com/ARMmbed/mbedtls/issues/396 */ if(mbedtls_x509_crt_parse_der(p, peercert->raw.p, peercert->raw.len)) { failf(data, "Failed copying peer certificate"); mbedtls_x509_crt_free(p); free(p); return CURLE_SSL_PINNEDPUBKEYNOTMATCH; } size = mbedtls_pk_write_pubkey_der(&p->pk, pubkey, PUB_DER_MAX_BYTES); if(size <= 0) { failf(data, "Failed copying public key from peer certificate"); mbedtls_x509_crt_free(p); free(p); return CURLE_SSL_PINNEDPUBKEYNOTMATCH; } /* mbedtls_pk_write_pubkey_der writes data at the end of the buffer. */ result = Curl_pin_peer_pubkey(data, data->set.str[STRING_SSL_PINNEDPUBLICKEY], &pubkey[PUB_DER_MAX_BYTES - size], size); if(result) { mbedtls_x509_crt_free(p); free(p); return result; } mbedtls_x509_crt_free(p); free(p); } #ifdef HAS_ALPN if(conn->bits.tls_enable_alpn) { next_protocol = mbedtls_ssl_get_alpn_protocol(&connssl->ssl); if(next_protocol) { infof(data, "ALPN, server accepted to use %s\n", next_protocol); #ifdef USE_NGHTTP2 if(!strncmp(next_protocol, NGHTTP2_PROTO_VERSION_ID, NGHTTP2_PROTO_VERSION_ID_LEN) && !next_protocol[NGHTTP2_PROTO_VERSION_ID_LEN]) { conn->negnpn = CURL_HTTP_VERSION_2; } else #endif if(!strncmp(next_protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH) && !next_protocol[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 connssl->connecting_state = ssl_connect_3; infof(data, "SSL connected\n"); return CURLE_OK; }
/** * @brief Start the SSL client. * @param[in] pssl: mbedtls ssl struct. * @param[in] psocket. The underlying file descriptor. * @param[in] server_addr. server address. * @param[in] custom_config: custome config. * @return The result. 0 is ok. */ static int nghttp2_ssl_start(mbedtls_ssl_context *pssl, mbedtls_net_context *psocket, http2_server_addr_t *server_addr, http2_ssl_custom_conf_t *custom_config) { /* * 0. Init */ int ret = -1; /* alpn */ const char *alpn_list[5]; char a[] = "http/1.1"; char b[] = "h2"; char c[] = "h2-14"; char d[] = "h2-16"; alpn_list[0] = b; alpn_list[1] = c; alpn_list[2] = d; alpn_list[3] = a; alpn_list[4] = NULL; if (0 != (ret = nghttp2_ssl_client_init(pssl, psocket, custom_config))) { NGHTTP2_DBG( " failed ! nghttp2_ssl_client_init returned -0x%04x", -ret ); return ret; } NGHTTP2_DBG(" . Connecting to tcp/%s/%4d...", server_addr->host, server_addr->port); /* * 1. Start the connection */ if (0 != (ret = mbedtls_net_connect(psocket, server_addr->host, "443", MBEDTLS_NET_PROTO_TCP))) { NGHTTP2_DBG(" failed ! net_connect returned -0x%04x", -ret); return ret; } NGHTTP2_DBG( " ok" ); /* * 2. Setup stuff */ NGHTTP2_DBG( " . Setting up the SSL/TLS structure..." ); if ( ( ret = mbedtls_ssl_config_defaults( &(custom_config->conf), MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT ) ) != 0 ) { NGHTTP2_DBG( " failed\n ! mbedtls_ssl_config_defaults returned %d\n\n", ret ); return ret; } NGHTTP2_DBG( " ok" ); /* alpn */ if ((ret = mbedtls_ssl_conf_alpn_protocols(&(custom_config->conf), alpn_list)) != 0) { printf("mbedtls_ssl_conf_alpn_protocols failed ret = %d\r\n", ret); return ret; } /* OPTIONAL is not optimal for security, * but makes interop easier in this simplified example */ mbedtls_ssl_conf_authmode( &(custom_config->conf), custom_config->common_settings.authmode ); mbedtls_ssl_conf_ca_chain( &(custom_config->conf), &(custom_config->verify_source.cacertl), custom_config->verify_source.ca_crl ); mbedtls_ssl_conf_rng( &(custom_config->conf), custom_config->common_settings.f_random, &ctr_drbg ); mbedtls_ssl_conf_dbg( &(custom_config->conf), custom_config->common_settings.f_debug, NULL ); mbedtls_ssl_conf_cert_profile( &(custom_config->conf), &mbedtls_x509_crt_profile_myclient); mbedtls_ssl_conf_ciphersuites(&(custom_config->conf), (const int *)&nghttp2_ciphersuite); if ( ( ret = mbedtls_ssl_setup( pssl, &(custom_config->conf) ) ) != 0 ) { NGHTTP2_DBG( " failed\n ! mbedtls_ssl_setup returned %d\n\n", ret ); return ret; } /* * set host name, related with SNI */ if ( ( ret = mbedtls_ssl_set_hostname(pssl, server_addr->host) ) != 0 ) { printf( " failed\n ! mbedtls_ssl_set_hostname returned %d\n\n", ret ); return ret; } mbedtls_ssl_set_bio( pssl, psocket, custom_config->common_settings.f_send, custom_config->common_settings.f_recv, mbedtls_net_recv_timeout ); mbedtls_ssl_conf_read_timeout(&(custom_config->conf), 10000); mbedtls_ssl_conf_min_version(&(custom_config->conf), MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3); /* * 4. Handshake */ NGHTTP2_DBG(". Performing the SSL/TLS handshake..."); while ((ret = mbedtls_ssl_handshake(pssl)) != 0) { if ((ret != MBEDTLS_ERR_SSL_WANT_READ) && (ret != MBEDTLS_ERR_SSL_WANT_WRITE)) { NGHTTP2_DBG( " failed ! mbedtls_ssl_handshake returned -0x%04x", -ret); return ret; } } { /* you can check if alpn_str is "h2", if not, should fallback to http/1. */ const char *alpn_str = mbedtls_ssl_get_alpn_protocol(pssl); NGHTTP2_DBG("[ application layer protocol chosen is %s ]", alpn_str ? alpn_str : "(none)"); if (alpn_str == NULL) { ret = NOT_SUPPORT_H2; //you can define an value you know return ret; } } NGHTTP2_DBG( " ok" ); /* * 5. Verify the server certificate */ NGHTTP2_DBG(" Verifying peer X.509 certificate..."); http2_verify_source_t *verify_source = &custom_config->verify_source; if ((NULL != verify_source->f_confirm) && (0 != (ret = verify_source->f_confirm(mbedtls_ssl_get_verify_result(pssl))))) { NGHTTP2_DBG(" failed ! verify result not confirmed."); return ret; } return 0; }
int SSLContext::getALPNProtocol(State & state, SSLContextData * ssl_context_data) { Stack * stack = state.stack; stack->push<const std::string &>(mbedtls_ssl_get_alpn_protocol(ssl_context_data->context)); return 1; }
static CURLcode mbedtls_connect_step2(struct connectdata *conn, int sockindex) { int ret; struct SessionHandle *data = conn->data; struct ssl_connect_data* connssl = &conn->ssl[sockindex]; char buffer[1024]; #ifdef HAS_ALPN const char* next_protocol; #endif char errorbuf[128]; errorbuf[0] = 0; conn->recv[sockindex] = mbedtls_recv; conn->send[sockindex] = mbedtls_send; ret = mbedtls_ssl_handshake(&connssl->ssl); if(ret == MBEDTLS_ERR_SSL_WANT_READ) { connssl->connecting_state = ssl_connect_2_reading; return CURLE_OK; } else if(ret == MBEDTLS_ERR_SSL_WANT_WRITE) { connssl->connecting_state = ssl_connect_2_writing; return CURLE_OK; } else if(ret) { #ifdef MBEDTLS_ERROR_C mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); #endif /* MBEDTLS_ERROR_C */ failf(data, "ssl_handshake returned - mbedTLS: (-0x%04X) %s", -ret, errorbuf); return CURLE_SSL_CONNECT_ERROR; } infof(data, "mbedTLS: Handshake complete, cipher is %s\n", mbedtls_ssl_get_ciphersuite(&conn->ssl[sockindex].ssl) ); ret = mbedtls_ssl_get_verify_result(&conn->ssl[sockindex].ssl); if(ret && data->set.ssl.verifypeer) { if(ret & MBEDTLS_X509_BADCERT_EXPIRED) failf(data, "Cert verify failed: BADCERT_EXPIRED"); if(ret & MBEDTLS_X509_BADCERT_REVOKED) { failf(data, "Cert verify failed: BADCERT_REVOKED"); return CURLE_SSL_CACERT; } if(ret & MBEDTLS_X509_BADCERT_CN_MISMATCH) failf(data, "Cert verify failed: BADCERT_CN_MISMATCH"); if(ret & MBEDTLS_X509_BADCERT_NOT_TRUSTED) failf(data, "Cert verify failed: BADCERT_NOT_TRUSTED"); return CURLE_PEER_FAILED_VERIFICATION; } if(mbedtls_ssl_get_peer_cert(&(connssl->ssl))) { /* If the session was resumed, there will be no peer certs */ memset(buffer, 0, sizeof(buffer)); if(mbedtls_x509_crt_info(buffer, sizeof(buffer), (char *)"* ", mbedtls_ssl_get_peer_cert(&(connssl->ssl))) != -1) infof(data, "Dumping cert info:\n%s\n", buffer); } #ifdef HAS_ALPN if(data->set.ssl_enable_alpn) { next_protocol = mbedtls_ssl_get_alpn_protocol(&connssl->ssl); if(next_protocol) { infof(data, "ALPN, server accepted to use %s\n", next_protocol); #ifdef USE_NGHTTP2 if(!strncmp(next_protocol, NGHTTP2_PROTO_VERSION_ID, NGHTTP2_PROTO_VERSION_ID_LEN) && !next_protocol[NGHTTP2_PROTO_VERSION_ID_LEN]) { conn->negnpn = CURL_HTTP_VERSION_2; } else #endif if(!strncmp(next_protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH) && !next_protocol[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 connssl->connecting_state = ssl_connect_3; infof(data, "SSL connected\n"); return CURLE_OK; }