diff options
author | Timur Pocheptsov <timur.pocheptsov@theqtcompany.com> | 2016-02-19 15:06:37 +0100 |
---|---|---|
committer | Timur Pocheptsov <timur.pocheptsov@theqtcompany.com> | 2016-03-21 15:01:12 +0000 |
commit | 765eab51036040d0659bc96bfdc1bbf991877862 (patch) | |
tree | 33087b5d61a031d47e75c7c538d2594cc136dff1 /src/network | |
parent | fb6000a74f57bd3c096f6a10142477bf2faf0ff2 (diff) |
qsslsocket/qsslcontext - add ALPN (OpenSSL only)
Application-Layer Protocol Negotiation (ALPN) - is a reworked revision
of Next Protocol Negotiation (NPN) we have in our OpenSSL code.
Can be used as a part of HTTP2 negotiation during TLS handshake.
Change-Id: I484ec528c81d4887a64749095ec292dfaec18330
Reviewed-by: Richard J. Moore <rich@kde.org>
Diffstat (limited to 'src/network')
-rw-r--r-- | src/network/ssl/qsslconfiguration.cpp | 20 | ||||
-rw-r--r-- | src/network/ssl/qsslcontext_openssl.cpp | 20 | ||||
-rw-r--r-- | src/network/ssl/qsslsocket_openssl.cpp | 15 | ||||
-rw-r--r-- | src/network/ssl/qsslsocket_openssl_symbols.cpp | 12 | ||||
-rw-r--r-- | src/network/ssl/qsslsocket_openssl_symbols_p.h | 13 |
5 files changed, 70 insertions, 10 deletions
diff --git a/src/network/ssl/qsslconfiguration.cpp b/src/network/ssl/qsslconfiguration.cpp index f9bb28e033..1fff2c31dd 100644 --- a/src/network/ssl/qsslconfiguration.cpp +++ b/src/network/ssl/qsslconfiguration.cpp @@ -119,7 +119,8 @@ const char QSslConfiguration::NextProtocolHttp1_1[] = "http/1.1"; /*! \enum QSslConfiguration::NextProtocolNegotiationStatus - Describes the status of the Next Protocol Negotiation (NPN). + Describes the status of the Next Protocol Negotiation (NPN) or + Application-Layer Protocol Negotiation (ALPN). \value NextProtocolNegotiationNone No application protocol has been negotiated (yet). @@ -812,8 +813,9 @@ QVector<QSslEllipticCurve> QSslConfiguration::supportedEllipticCurves() \since 5.3 This function returns the protocol negotiated with the server - if the Next Protocol Negotiation (NPN) TLS extension was enabled. - In order for the NPN extension to be enabled, setAllowedNextProtocols() + if the Next Protocol Negotiation (NPN) or Application-Layer Protocol + Negotiation (ALPN) TLS extension was enabled. + In order for the NPN/ALPN extension to be enabled, setAllowedNextProtocols() needs to be called explicitly before connecting to the server. If no protocol could be negotiated or the extension was not enabled, @@ -830,9 +832,10 @@ QByteArray QSslConfiguration::nextNegotiatedProtocol() const \since 5.3 This function sets the allowed \a protocols to be negotiated with the - server through the Next Protocol Negotiation (NPN) TLS extension; each + server through the Next Protocol Negotiation (NPN) or Application-Layer + Protocol Negotiation (ALPN) TLS extension; each element in \a protocols must define one allowed protocol. - The function must be called explicitly before connecting to send the NPN + The function must be called explicitly before connecting to send the NPN/ALPN extension in the SSL handshake. Whether or not the negotiation succeeded can be queried through nextProtocolNegotiationStatus(). @@ -852,8 +855,8 @@ void QSslConfiguration::setAllowedNextProtocols(QList<QByteArray> protocols) \since 5.3 This function returns the allowed protocols to be negotiated with the - server through the Next Protocol Negotiation (NPN) TLS extension, as set - by setAllowedNextProtocols(). + server through the Next Protocol Negotiation (NPN) or Application-Layer + Protocol Negotiation (ALPN) TLS extension, as set by setAllowedNextProtocols(). \sa nextNegotiatedProtocol(), nextProtocolNegotiationStatus(), setAllowedNextProtocols(), QSslConfiguration::NextProtocolSpdy3_0, QSslConfiguration::NextProtocolHttp1_1 */ @@ -865,7 +868,8 @@ QList<QByteArray> QSslConfiguration::allowedNextProtocols() const /*! \since 5.3 - This function returns the status of the Next Protocol Negotiation (NPN). + This function returns the status of the Next Protocol Negotiation (NPN) + or Application-Layer Protocol Negotiation (ALPN). If the feature has not been enabled through setAllowedNextProtocols(), this function returns NextProtocolNegotiationNone. The status will be set before emitting the encrypted() signal. diff --git a/src/network/ssl/qsslcontext_openssl.cpp b/src/network/ssl/qsslcontext_openssl.cpp index b3786f989e..543e87c0ca 100644 --- a/src/network/ssl/qsslcontext_openssl.cpp +++ b/src/network/ssl/qsslcontext_openssl.cpp @@ -457,7 +457,25 @@ SSL* QSslContext::createSsl() m_npnContext.data = reinterpret_cast<unsigned char *>(m_supportedNPNVersions.data()); m_npnContext.len = m_supportedNPNVersions.count(); m_npnContext.status = QSslConfiguration::NextProtocolNegotiationNone; - q_SSL_CTX_set_next_proto_select_cb(ctx, next_proto_cb, &m_npnContext); +#if OPENSSL_VERSION_NUMBER >= 0x10002000L + if (q_SSLeay() >= 0x10002000L) { + // Callback's type has a parameter 'const unsigned char ** out' + // since it was introduced in 1.0.2. Internally, OpenSSL's own code + // (tests/examples) cast it to unsigned char * (since it's 'out'). + // We just re-use our NPN callback and cast here: + typedef int (*alpn_callback_t) (SSL *, const unsigned char **, unsigned char *, + const unsigned char *, unsigned int, void *); + // With ALPN callback is for a server side only, for a client m_npnContext.status + // will stay in NextProtocolNegotiationNone. + q_SSL_CTX_set_alpn_select_cb(ctx, alpn_callback_t(next_proto_cb), &m_npnContext); + // Client: + q_SSL_set_alpn_protos(ssl, m_npnContext.data, m_npnContext.len); + } else { +#else + { +#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L ... + q_SSL_CTX_set_next_proto_select_cb(ctx, next_proto_cb, &m_npnContext); + } } #endif // OPENSSL_VERSION_NUMBER >= 0x1000100fL ... diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp index ac6b2df595..fea73edc63 100644 --- a/src/network/ssl/qsslsocket_openssl.cpp +++ b/src/network/ssl/qsslsocket_openssl.cpp @@ -1565,7 +1565,20 @@ void QSslSocketBackendPrivate::continueHandshake() } else { const unsigned char *proto = 0; unsigned int proto_len = 0; - q_SSL_get0_next_proto_negotiated(ssl, &proto, &proto_len); +#if OPENSSL_VERSION_NUMBER >= 0x10002000L + if (q_SSLeay() >= 0x10002000L) { + q_SSL_get0_alpn_selected(ssl, &proto, &proto_len); + if (proto_len && mode == QSslSocket::SslClientMode) { + // Client does not have a callback that sets it ... + configuration.nextProtocolNegotiationStatus = QSslConfiguration::NextProtocolNegotiationNegotiated; + } + } else { +#else + { +#endif + q_SSL_get0_next_proto_negotiated(ssl, &proto, &proto_len); + } + if (proto_len) configuration.nextNegotiatedProtocol = QByteArray(reinterpret_cast<const char *>(proto), proto_len); else diff --git a/src/network/ssl/qsslsocket_openssl_symbols.cpp b/src/network/ssl/qsslsocket_openssl_symbols.cpp index d0982377fb..05b7e2da7f 100644 --- a/src/network/ssl/qsslsocket_openssl_symbols.cpp +++ b/src/network/ssl/qsslsocket_openssl_symbols.cpp @@ -418,6 +418,18 @@ DEFINEFUNC3(void, SSL_CTX_set_next_proto_select_cb, SSL_CTX *s, s, void *arg, arg, return, DUMMYARG) DEFINEFUNC3(void, SSL_get0_next_proto_negotiated, const SSL *s, s, const unsigned char **data, data, unsigned *len, len, return, DUMMYARG) +#if OPENSSL_VERSION_NUMBER >= 0x10002000L +DEFINEFUNC3(int, SSL_set_alpn_protos, SSL *s, s, const unsigned char *protos, protos, + unsigned protos_len, protos_len, return -1, return) +DEFINEFUNC3(void, SSL_CTX_set_alpn_select_cb, SSL_CTX *s, s, + int (*cb) (SSL *ssl, const unsigned char **out, + unsigned char *outlen, + const unsigned char *in, + unsigned int inlen, void *arg), cb, + void *arg, arg, return, DUMMYARG) +DEFINEFUNC3(void, SSL_get0_alpn_selected, const SSL *s, s, const unsigned char **data, data, + unsigned *len, len, return, DUMMYARG) +#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L ... #endif // OPENSSL_VERSION_NUMBER >= 0x1000100fL ... DEFINEFUNC(DH *, DH_new, DUMMYARG, DUMMYARG, return 0, return) DEFINEFUNC(void, DH_free, DH *dh, dh, return, DUMMYARG) diff --git a/src/network/ssl/qsslsocket_openssl_symbols_p.h b/src/network/ssl/qsslsocket_openssl_symbols_p.h index 36e041b6cb..5a6c934d1a 100644 --- a/src/network/ssl/qsslsocket_openssl_symbols_p.h +++ b/src/network/ssl/qsslsocket_openssl_symbols_p.h @@ -558,6 +558,19 @@ void q_SSL_CTX_set_next_proto_select_cb(SSL_CTX *s, void *arg); void q_SSL_get0_next_proto_negotiated(const SSL *s, const unsigned char **data, unsigned *len); +#if OPENSSL_VERSION_NUMBER >= 0x10002000L +int q_SSL_set_alpn_protos(SSL *ssl, const unsigned char *protos, + unsigned protos_len); +void q_SSL_CTX_set_alpn_select_cb(SSL_CTX *ctx, + int (*cb) (SSL *ssl, + const unsigned char **out, + unsigned char *outlen, + const unsigned char *in, + unsigned int inlen, + void *arg), void *arg); +void q_SSL_get0_alpn_selected(const SSL *ssl, const unsigned char **data, + unsigned *len); +#endif #endif // OPENSSL_VERSION_NUMBER >= 0x1000100fL ... // Helper function |