Branch data Line data Source code
1 : : /* 2 : : * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 : : * 4 : : * Licensed under the Apache License, Version 2.0 (the "License"). 5 : : * You may not use this file except in compliance with the License. 6 : : * A copy of the License is located at 7 : : * 8 : : * http://aws.amazon.com/apache2.0 9 : : * 10 : : * or in the "license" file accompanying this file. This file is distributed 11 : : * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 : : * express or implied. See the License for the specific language governing 13 : : * permissions and limitations under the License. 14 : : */ 15 : : 16 : : #include "tls/extensions/s2n_npn.h" 17 : : 18 : : #include "tls/extensions/s2n_client_alpn.h" 19 : : #include "tls/extensions/s2n_server_alpn.h" 20 : : #include "tls/s2n_protocol_preferences.h" 21 : : #include "tls/s2n_tls.h" 22 : : #include "tls/s2n_tls_parameters.h" 23 : : #include "utils/s2n_safety.h" 24 : : 25 : : bool s2n_npn_should_send(struct s2n_connection *conn) 26 : 7369 : { 27 : : /* 28 : : *= https://datatracker.ietf.org/doc/id/draft-agl-tls-nextprotoneg-03#section-3 29 : : *# For the same reasons, after a handshake has been performed for a 30 : : *# given connection, renegotiations on the same connection MUST NOT 31 : : *# include the "next_protocol_negotiation" extension. 32 : : */ 33 [ + + ][ + + ]: 7369 : return s2n_client_alpn_should_send(conn) && conn->config->npn_supported && !s2n_handshake_is_renegotiation(conn); [ + + ] 34 : 7369 : } 35 : : 36 : : int s2n_client_npn_recv(struct s2n_connection *conn, struct s2n_stuffer *extension) 37 : 11 : { 38 : : /* Only use the NPN extension to negotiate a protocol if we don't have 39 : : * an option to use the ALPN extension. 40 : : */ 41 [ + + ][ + + ]: 11 : if (s2n_npn_should_send(conn) && !s2n_server_alpn_should_send(conn)) { 42 : 3 : conn->npn_negotiated = true; 43 : 3 : } 44 : : 45 : 11 : return S2N_SUCCESS; 46 : 11 : } 47 : : 48 : : const s2n_extension_type s2n_client_npn_extension = { 49 : : .iana_value = TLS_EXTENSION_NPN, 50 : : .is_response = false, 51 : : .send = s2n_extension_send_noop, 52 : : .recv = s2n_client_npn_recv, 53 : : .should_send = s2n_npn_should_send, 54 : : .if_missing = s2n_extension_noop_if_missing, 55 : : }; 56 : : 57 : : bool s2n_server_npn_should_send(struct s2n_connection *conn) 58 : 6 : { 59 : 6 : return conn->npn_negotiated; 60 : 6 : } 61 : : 62 : : int s2n_server_npn_send(struct s2n_connection *conn, struct s2n_stuffer *out) 63 : 4 : { 64 : 4 : struct s2n_blob *app_protocols = NULL; 65 [ - + ]: 4 : POSIX_GUARD(s2n_connection_get_protocol_preferences(conn, &app_protocols)); 66 [ # # ][ - + ]: 4 : POSIX_ENSURE_REF(app_protocols); 67 : : 68 [ - + ]: 4 : POSIX_GUARD(s2n_stuffer_write(out, app_protocols)); 69 : : 70 : 4 : return S2N_SUCCESS; 71 : 4 : } 72 : : 73 : : int s2n_server_npn_recv(struct s2n_connection *conn, struct s2n_stuffer *extension) 74 : 7 : { 75 : 7 : struct s2n_blob *supported_protocols = NULL; 76 [ - + ]: 7 : POSIX_GUARD(s2n_connection_get_protocol_preferences(conn, &supported_protocols)); 77 [ - + ][ # # ]: 7 : POSIX_ENSURE_REF(supported_protocols); 78 : : 79 [ + + ]: 7 : if (supported_protocols->size == 0) { 80 : : /* No protocols configured */ 81 : 1 : return S2N_SUCCESS; 82 : 1 : } 83 : : 84 : : /* 85 : : *= https://datatracker.ietf.org/doc/id/draft-agl-tls-nextprotoneg-03#section-3 86 : : *# The "extension_data" field of a "next_protocol_negotiation" extension 87 : : *# in a "ServerHello" contains an optional list of protocols advertised 88 : : *# by the server. 89 : : */ 90 [ + + ]: 6 : if (s2n_stuffer_data_available(extension)) { 91 [ - + ]: 5 : POSIX_GUARD_RESULT(s2n_select_server_preference_protocol(conn, extension, supported_protocols)); 92 : 5 : } 93 : : 94 : : /* 95 : : *= https://datatracker.ietf.org/doc/id/draft-agl-tls-nextprotoneg-03#section-4 96 : : *# In the event that the client doesn't support any of server's protocols, or 97 : : *# the server doesn't advertise any, it SHOULD select the first protocol 98 : : *# that it supports. 99 : : */ 100 [ + + ]: 6 : if (s2n_get_application_protocol(conn) == NULL) { 101 : 3 : struct s2n_stuffer stuffer = { 0 }; 102 [ - + ]: 3 : POSIX_GUARD(s2n_stuffer_init(&stuffer, supported_protocols)); 103 [ - + ]: 3 : POSIX_GUARD(s2n_stuffer_skip_write(&stuffer, supported_protocols->size)); 104 : 3 : struct s2n_blob protocol = { 0 }; 105 [ - + ]: 3 : POSIX_GUARD_RESULT(s2n_protocol_preferences_read(&stuffer, &protocol)); 106 : : 107 [ - + ][ # # ]: 3 : POSIX_ENSURE_LT(protocol.size, sizeof(conn->application_protocol)); 108 [ - + ][ # # ]: 3 : POSIX_CHECKED_MEMCPY(conn->application_protocol, protocol.data, protocol.size); [ + - ] 109 : 3 : conn->application_protocol[protocol.size] = '\0'; 110 : 3 : } 111 : : 112 : 6 : conn->npn_negotiated = true; 113 : : 114 : 6 : return S2N_SUCCESS; 115 : 6 : } 116 : : 117 : : const s2n_extension_type s2n_server_npn_extension = { 118 : : .iana_value = TLS_EXTENSION_NPN, 119 : : .is_response = true, 120 : : .send = s2n_server_npn_send, 121 : : .recv = s2n_server_npn_recv, 122 : : .should_send = s2n_server_npn_should_send, 123 : : .if_missing = s2n_extension_noop_if_missing, 124 : : };