aboutsummaryrefslogtreecommitdiff
path: root/lib/vtls
diff options
context:
space:
mode:
authorJay Satiro <raysatiro@yahoo.com>2016-03-28 18:18:09 -0400
committerJay Satiro <raysatiro@yahoo.com>2016-03-28 18:18:09 -0400
commita43b22e05b726e7e080eda63f287f728392b7064 (patch)
treec005b07299f9a0833067de91e4c7d0c20294a74a /lib/vtls
parent67a762928ed33470e7423fd01e1860e9c61dedd7 (diff)
wolfssl: Add ALPN support
Diffstat (limited to 'lib/vtls')
-rw-r--r--lib/vtls/cyassl.c104
1 files changed, 99 insertions, 5 deletions
diff --git a/lib/vtls/cyassl.c b/lib/vtls/cyassl.c
index f6b57af68..7fa853678 100644
--- a/lib/vtls/cyassl.c
+++ b/lib/vtls/cyassl.c
@@ -77,6 +77,41 @@ and that's a problem since options.h hasn't been included yet. */
#define CYASSL_MAX_ERROR_SZ 80
#endif
+/* To determine what functions are available we rely on one or both of:
+ - the user's options.h generated by CyaSSL/wolfSSL
+ - the symbols detected by curl's configure
+ Since they are markedly different from one another, and one or the other may
+ not be available, we do some checking below to bring things in sync. */
+
+/* HAVE_ALPN is wolfSSL's build time symbol for enabling ALPN in options.h. */
+#ifndef HAVE_ALPN
+#ifdef HAVE_WOLFSSL_USEALPN
+#define HAVE_ALPN
+#endif
+#endif
+
+/* WOLFSSL_ALLOW_SSLV3 is wolfSSL's build time symbol for enabling SSLv3 in
+ options.h, but is only seen in >= 3.6.6 since that's when they started
+ disabling SSLv3 by default. */
+#ifndef WOLFSSL_ALLOW_SSLV3
+#if (LIBCYASSL_VERSION_HEX < 0x03006006) || \
+ defined(HAVE_WOLFSSLV3_CLIENT_METHOD)
+#define WOLFSSL_ALLOW_SSLV3
+#endif
+#endif
+
+/* KEEP_PEER_CERT is a product of the presence of build time symbol
+ OPENSSL_EXTRA without NO_CERTS, depending on the version. KEEP_PEER_CERT is
+ in wolfSSL's settings.h, and the latter two are build time symbols in
+ options.h. */
+#ifndef KEEP_PEER_CERT
+#if defined(HAVE_CYASSL_GET_PEER_CERTIFICATE) || \
+ defined(HAVE_WOLFSSL_GET_PEER_CERTIFICATE) || \
+ (defined(OPENSSL_EXTRA) && !defined(NO_CERTS))
+#define KEEP_PEER_CERT
+#endif
+#endif
+
static Curl_recv cyassl_recv;
static Curl_send cyassl_send;
@@ -143,9 +178,7 @@ cyassl_connect_step1(struct connectdata *conn,
use_sni(TRUE);
break;
case CURL_SSLVERSION_SSLv3:
- /* before WolfSSL SSLv3 was enabled by default, and starting in WolfSSL
- we check for its presence since it is built without it by default */
-#if !defined(WOLFSSL_VERSION) || defined(HAVE_WOLFSSLV3_CLIENT_METHOD)
+#ifdef WOLFSSL_ALLOW_SSLV3
req_method = SSLv3_client_method();
use_sni(FALSE);
#else
@@ -309,6 +342,33 @@ cyassl_connect_step1(struct connectdata *conn,
return CURLE_OUT_OF_MEMORY;
}
+#ifdef HAVE_ALPN
+ if(data->set.ssl_enable_alpn) {
+ char protocols[128];
+ *protocols = '\0';
+
+ /* wolfSSL's ALPN protocol name list format is a comma separated string of
+ protocols in descending order of preference, eg: "h2,http/1.1" */
+
+#ifdef USE_NGHTTP2
+ if(data->set.httpversion >= CURL_HTTP_VERSION_2) {
+ strcpy(protocols + strlen(protocols), NGHTTP2_PROTO_VERSION_ID ",");
+ infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID);
+ }
+#endif
+
+ strcpy(protocols + strlen(protocols), ALPN_HTTP_1_1);
+ infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1);
+
+ if(wolfSSL_UseALPN(conssl->handle, protocols,
+ (unsigned)strlen(protocols),
+ WOLFSSL_ALPN_CONTINUE_ON_MISMATCH) != SSL_SUCCESS) {
+ failf(data, "SSL: failed setting ALPN protocols");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+#endif /* HAVE_ALPN */
+
/* Check if there's a cached ID we can/should use here! */
if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)) {
/* we got a session id, use it! */
@@ -413,8 +473,7 @@ cyassl_connect_step2(struct connectdata *conn,
}
if(data->set.str[STRING_SSL_PINNEDPUBLICKEY]) {
-#if defined(HAVE_WOLFSSL_GET_PEER_CERTIFICATE) || \
- defined(HAVE_CYASSL_GET_PEER_CERTIFICATE)
+#ifdef KEEP_PEER_CERT
X509 *x509;
const char *x509_der;
int x509_der_len;
@@ -457,6 +516,41 @@ cyassl_connect_step2(struct connectdata *conn,
#endif
}
+#ifdef HAVE_ALPN
+ if(data->set.ssl_enable_alpn) {
+ int rc;
+ char *protocol = NULL;
+ unsigned short protocol_len = 0;
+
+ rc = wolfSSL_ALPN_GetProtocol(conssl->handle, &protocol, &protocol_len);
+
+ if(rc == SSL_SUCCESS) {
+ infof(data, "ALPN, server accepted to use %.*s\n", protocol_len,
+ protocol);
+
+ if(protocol_len == ALPN_HTTP_1_1_LENGTH &&
+ !memcmp(protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH))
+ conn->negnpn = CURL_HTTP_VERSION_1_1;
+#ifdef USE_NGHTTP2
+ else if(data->set.httpversion >= CURL_HTTP_VERSION_2 &&
+ protocol_len == NGHTTP2_PROTO_VERSION_ID_LEN &&
+ !memcmp(protocol, NGHTTP2_PROTO_VERSION_ID,
+ NGHTTP2_PROTO_VERSION_ID_LEN))
+ conn->negnpn = CURL_HTTP_VERSION_2;
+#endif
+ else
+ infof(data, "ALPN, unrecognized protocol %.*s\n", protocol_len,
+ protocol);
+ }
+ else if(rc == SSL_ALPN_NOT_FOUND)
+ infof(data, "ALPN, server did not agree to a protocol\n");
+ else {
+ failf(data, "ALPN, failure getting protocol, error %d", rc);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+#endif /* HAVE_ALPN */
+
conssl->connecting_state = ssl_connect_3;
infof(data, "SSL connected\n");