Index: doc/tls.html ================================================================== --- doc/tls.html +++ doc/tls.html @@ -484,11 +484,11 @@
- info channel major minor message + info channel major minor message type
This form of callback is invoked by the OpenSSL function SSL_CTX_set_info_callback().
@@ -503,10 +503,14 @@ The message argument is a descriptive string which may be generated either by SSL_state_string_long() or by SSL_alert_desc_string_long(), depending on context. +
For alerts, the possible values for type are:
+
+
warning, fatal, and unknown.
+

Index: generic/tls.c ================================================================== --- generic/tls.c +++ generic/tls.c @@ -154,26 +154,26 @@ else if (where & SSL_CB_LOOP) minor = "loop"; else if (where & SSL_CB_EXIT) minor = "exit"; else minor = "unknown"; } + /* info channel major minor message type */ Tcl_ListObjAppendElement(interp, cmdPtr, Tcl_NewStringObj("info", -1)); Tcl_ListObjAppendElement(interp, cmdPtr, Tcl_NewStringObj(Tcl_GetChannelName(statePtr->self), -1)); Tcl_ListObjAppendElement(interp, cmdPtr, Tcl_NewStringObj(major, -1)); Tcl_ListObjAppendElement(interp, cmdPtr, Tcl_NewStringObj(minor, -1)); - if (where & (SSL_CB_LOOP|SSL_CB_EXIT)) { + if (where & SSL_CB_ALERT) { + Tcl_ListObjAppendElement(interp, cmdPtr, + Tcl_NewStringObj(SSL_alert_desc_string_long(ret), -1)); Tcl_ListObjAppendElement(interp, cmdPtr, - Tcl_NewStringObj(SSL_state_string_long(ssl), -1)); - } else if (where & SSL_CB_ALERT) { - const char *cp = (char *) SSL_alert_desc_string_long(ret); - - Tcl_ListObjAppendElement(interp, cmdPtr, Tcl_NewStringObj(cp, -1)); + Tcl_NewStringObj(SSL_alert_type_string_long(ret), -1)); } else { Tcl_ListObjAppendElement(interp, cmdPtr, Tcl_NewStringObj(SSL_state_string_long(ssl), -1)); + Tcl_ListObjAppendElement(interp, cmdPtr, Tcl_NewStringObj("info", -1)); } Tcl_Preserve((ClientData) interp); Tcl_Preserve((ClientData) statePtr); Tcl_IncrRefCount(cmdPtr); @@ -497,14 +497,15 @@ } /* *------------------------------------------------------------------- * - * ALPN Callback for Servers -- + * ALPN Callback for Servers and Clients -- * - * Perform server-side protocol (http/1.1, h2, h3, etc.) selection for the - * incoming connection. Called after Hello and server callbacks + * Perform protocol (http/1.1, h2, h3, etc.) selection for the + * incoming connection. Called after Hello and server callbacks. + * Where 'out' is selected protocol and 'in' is the peer advertised list. * * Results: * None * * Side effects: @@ -527,24 +528,26 @@ Tcl_Obj *cmdPtr; int code, res; dprintf("Called"); - if (statePtr->callback == (Tcl_Obj*)NULL) { - return SSL_TLSEXT_ERR_OK; - } else if (ssl == NULL) { + if (ssl == NULL || arg == NULL) { return SSL_TLSEXT_ERR_NOACK; } /* Select protocol */ if (SSL_select_next_proto(out, outlen, statePtr->protos, statePtr->protos_len, in, inlen) == OPENSSL_NPN_NEGOTIATED) { res = SSL_TLSEXT_ERR_OK; } else { - /* No overlap, so first client protocol used */ + /* No overlap, so use first client protocol */ res = SSL_TLSEXT_ERR_NOACK; } + + if (statePtr->callback == (Tcl_Obj*)NULL) { + return SSL_TLSEXT_ERR_OK; + } cmdPtr = Tcl_DuplicateObj(statePtr->callback); Tcl_ListObjAppendElement(interp, cmdPtr, Tcl_NewStringObj("alpn", -1)); Tcl_ListObjAppendElement(interp, cmdPtr, Tcl_NewStringObj(*out, -1)); @@ -565,10 +568,53 @@ Tcl_Release((ClientData) statePtr); Tcl_Release((ClientData) interp); return res; } +/* + *------------------------------------------------------------------- + * + * Advertise Protocols Callback for Servers Next Protocol Negotiation -- + * + * called when a TLS server needs a list of supported protocols for Next + * Protocol Negotiation. + * + * Results: + * None + * + * Side effects: + * + * Return codes: + * SSL_TLSEXT_ERR_OK: NPN protocol selected. The connection continues. + * SSL_TLSEXT_ERR_NOACK: NPN protocol not selected. The connection continues. + * + *------------------------------------------------------------------- + */ +#ifdef USE_NPN +static int +NPNCallback(const SSL *ssl, const unsigned char **out, unsigned int *outlen, void *arg) { + State *statePtr = (State*)arg; + + dprintf("Called"); + + if (ssl == NULL || arg == NULL) { + return SSL_TLSEXT_ERR_NOACK; + } + + /* Set protocols list */ + if (statePtr->protos != NULL) { + *out = statePtr->protos; + *outlen = statePtr->protos_len; + } else { + *out = NULL; + *outlen = 0; + return SSL_TLSEXT_ERR_NOACK; + } + return SSL_TLSEXT_ERR_OK; +} +#endif + /* *------------------------------------------------------------------- * * SNI Callback for Servers -- * @@ -600,20 +646,22 @@ int code; char *servername = NULL; dprintf("Called"); - if (statePtr->callback == (Tcl_Obj*)NULL) { - return SSL_TLSEXT_ERR_OK; - } else if (ssl == NULL) { + if (ssl == NULL || arg == NULL) { return SSL_TLSEXT_ERR_NOACK; } servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); if (!servername || servername[0] == '\0') { return SSL_TLSEXT_ERR_NOACK; } + + if (statePtr->callback == (Tcl_Obj*)NULL) { + return SSL_TLSEXT_ERR_OK; + } cmdPtr = Tcl_DuplicateObj(statePtr->callback); Tcl_ListObjAppendElement(interp, cmdPtr, Tcl_NewStringObj("sni", -1)); Tcl_ListObjAppendElement(interp, cmdPtr, Tcl_NewStringObj(servername , -1)); @@ -673,11 +721,11 @@ dprintf("Called"); if (statePtr->callback == (Tcl_Obj*)NULL) { return SSL_CLIENT_HELLO_SUCCESS; - } else if (ssl == NULL) { + } else if (ssl == NULL || arg == NULL) { return SSL_CLIENT_HELLO_ERROR; } /* Get names */ if (!SSL_client_hello_get0_ext(ssl, TLSEXT_TYPE_server_name, &p, &remaining) || remaining <= 2) { @@ -1354,23 +1402,34 @@ statePtr->p_bio = BIO_new_tcl(statePtr, BIO_NOCLOSE); statePtr->bio = BIO_new(BIO_f_ssl()); if (server) { /* Server callbacks */ - SSL_CTX_set_alpn_select_cb(statePtr->ctx, ALPNCallback, (void *)statePtr); SSL_CTX_set_tlsext_servername_arg(statePtr->ctx, (void *)statePtr); SSL_CTX_set_tlsext_servername_callback(statePtr->ctx, SNICallback); SSL_CTX_set_client_hello_cb(statePtr->ctx, HelloCallback, (void *)statePtr); + if (statePtr->protos != NULL) { + SSL_CTX_set_alpn_select_cb(statePtr->ctx, ALPNCallback, (void *)statePtr); +#ifdef USE_NPN + SSL_CTX_set_next_protos_advertised_cb(statePtr->ctx, NPNCallback, (void *)statePtr); +#endif + } /* Enable server to send cert request after handshake (TLS 1.3 only) */ if (request && post_handshake) { SSL_verify_client_post_handshake(statePtr->ssl); } statePtr->flags |= TLS_TCL_SERVER; SSL_set_accept_state(statePtr->ssl); } else { + /* Client callbacks */ + if (statePtr->protos != NULL) { +#ifdef USE_NPN + SSL_CTX_set_next_proto_select_cb(statePtr->ctx, ALPNCallback, (void *)statePtr); +#endif + } /* Session caching */ SSL_CTX_set_session_cache_mode(statePtr->ctx, SSL_SESS_CACHE_CLIENT | SSL_SESS_CACHE_NO_INTERNAL_STORE); SSL_CTX_sess_set_new_cb(statePtr->ctx, SessionCallback); /* Enable post handshake Authentication extension. TLS 1.3 only, not http/2. */ @@ -1592,11 +1651,11 @@ SSL_CTX_set_app_data(ctx, (void*)interp); /* remember the interpreter */ SSL_CTX_set_options(ctx, SSL_OP_ALL); /* all SSL bug workarounds */ SSL_CTX_set_options(ctx, off); /* disable protocol versions */ #if OPENSSL_VERSION_NUMBER < 0x10101000L - SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY); /* handle new handshakes in background */ + SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY); /* handle new handshakes in background. On by default in OpenSSL 1.1.1. */ #endif SSL_CTX_sess_set_cache_size(ctx, 128); /* Set user defined ciphers, cipher suites, and security level */ if ((ciphers != NULL) && !SSL_CTX_set_cipher_list(ctx, ciphers)) { @@ -2002,10 +2061,17 @@ /* Report the selected protocol as a result of the ALPN negotiation */ SSL_SESSION_get0_alpn_selected(session, &proto, &len2); Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("alpn", -1)); Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj((char *)proto, (int) len2)); + + /* Report the selected protocol as a result of the NPN negotiation */ +#ifdef USE_NPN + SSL_get0_next_proto_negotiated(ssl, &proto, &ulen); + Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("npn", -1)); + Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj((char *)proto, (int) ulen)); +#endif /* Resumable session */ Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("resumable", -1)); Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewIntObj(SSL_SESSION_is_resumable(session)));