aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/restricted/aws/s2n/tls/s2n_connection.h
blob: deacc58d820df0579b9bcaa05d977a69c0694fbf (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
/*
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 *  http://aws.amazon.com/apache2.0
 *
 * or in the "license" file accompanying this file. This file is distributed
 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */

#pragma once

#include <errno.h>
#include "api/s2n.h"
#include <signal.h>
#include <stdint.h>

#include "stuffer/s2n_stuffer.h"

#include "tls/s2n_client_hello.h"
#include "tls/s2n_config.h"
#include "tls/s2n_crypto.h"
#include "tls/s2n_early_data.h"
#include "tls/s2n_ecc_preferences.h"
#include "tls/s2n_handshake.h"
#include "tls/s2n_kem_preferences.h"
#include "tls/s2n_key_update.h"
#include "tls/s2n_prf.h"
#include "tls/s2n_quic_support.h"
#include "tls/s2n_record.h"
#include "tls/s2n_security_policies.h"
#include "tls/s2n_tls_parameters.h"
#include "tls/s2n_x509_validator.h"

#include "crypto/s2n_hash.h"
#include "crypto/s2n_hmac.h"

#include "utils/s2n_mem.h"
#include "utils/s2n_timer.h"

#define S2N_TLS_PROTOCOL_VERSION_LEN    2

#define S2N_PEER_MODE(our_mode) ((our_mode + 1) % 2)

#define is_handshake_complete(conn) (APPLICATION_DATA == s2n_conn_get_current_message_type(conn))

typedef enum {
    S2N_NO_TICKET = 0,
    S2N_DECRYPT_TICKET,
    S2N_NEW_TICKET
} s2n_session_ticket_status;

struct s2n_connection {
    /* Is this connection using CORK/SO_RCVLOWAT optimizations? Only valid when the connection is using
     * managed_send_io
     */
    unsigned corked_io:1;

    /* Session resumption indicator on client side */
    unsigned client_session_resumed:1;

    /* Connection can be used by a QUIC implementation */
    unsigned quic_enabled:1;

    /* Determines if we're currently sending or receiving in s2n_shutdown */
    unsigned close_notify_queued:1;

    /* s2n does not support renegotiation.
     * RFC5746 Section 4.3 suggests servers implement a minimal version of the
     * renegotiation_info extension even if renegotiation is not supported.
     * Some clients may fail the handshake if a corresponding renegotiation_info
     * extension is not sent back by the server.
     */
    unsigned secure_renegotiation:1;
    /* Was the EC point formats sent by the client */
    unsigned ec_point_formats:1;

    /* whether the connection address is ipv6 or not */
    unsigned ipv6:1;

    /* Whether server_name extension was used to make a decision on cert selection.
     * RFC6066 Section 3 states that server which used server_name to make a decision
     * on certificate or security settings has to send an empty server_name.
     */
    unsigned server_name_used:1;

    /* If write fd is broken */
    unsigned write_fd_broken:1;

    /* Has the user set their own I/O callbacks or is this connection using the
     * default socket-based I/O set by s2n */
    unsigned managed_send_io:1;
    unsigned managed_recv_io:1;

    /* Key update data */
    unsigned key_update_pending:1;

    /* Early data supported by caller.
     * If a caller does not use any APIs that support early data,
     * do not negotiate early data.
     */
    unsigned early_data_expected:1;

    /* Connection overrides server_max_early_data_size */
    unsigned server_max_early_data_size_overridden:1;

    /* Connection overrides psk_mode.
     * This means that the connection will keep the existing value of psk_params->type,
     * even when setting a new config. */
    unsigned psk_mode_overridden:1;

    /* Have we received a close notify alert from the peer. */
    unsigned close_notify_received:1;

    /* Connection negotiated an EMS */
    unsigned ems_negotiated:1;

    /* Connection successfully set a ticket on the connection */
    unsigned set_session:1;

    /* Buffer multiple records before flushing them.
     * This allows multiple records to be written with one socket send. */
    unsigned multirecord_send:1;

    /* If enabled, this connection will free each of its IO buffers after all data
     * has been flushed */
    unsigned dynamic_buffers:1;

    /* Indicates protocol negotiation will be done through the NPN extension
     * instead of the ALPN extension */
    unsigned npn_negotiated:1;

    /* The configuration (cert, key .. etc ) */
    struct s2n_config *config;

    /* Overrides Security Policy in config if non-null */
    const struct s2n_security_policy *security_policy_override;

    /* The user defined context associated with connection */
    void *context;

    /* The user defined secret callback and context */
    s2n_secret_cb secret_cb;
    void *secret_cb_context;

    /* The send and receive callbacks don't have to be the same (e.g. two pipes) */
    s2n_send_fn *send;
    s2n_recv_fn *recv;

    /* The context passed to the I/O callbacks */
    void *send_io_context;
    void *recv_io_context;

    /* Track request/response extensions to ensure correct response extension behavior.
     *
     * We need to track client and server extensions separately because some
     * extensions (like request_status and other Certificate extensions) can
     * be requested by the client, the server, or both.
     */
    s2n_extension_bitfield extension_requests_sent;
    s2n_extension_bitfield extension_requests_received;
    s2n_extension_bitfield extension_responses_received;

    /* Is this connection a client or a server connection */
    s2n_mode mode;

    /* Does s2n handle the blinding, or does the application */
    s2n_blinding blinding;

    /* A timer to measure the time between record writes */
    struct s2n_timer write_timer;

    /* last written time */
    uint64_t last_write_elapsed;

    /* When fatal errors occurs, s2n imposes a pause before
     * the connection is closed. If non-zero, this value tracks
     * how many nanoseconds to pause - which will be relative to
     * the write_timer value. */
    uint64_t delay;

    /* The session id */
    uint8_t session_id[S2N_TLS_SESSION_ID_MAX_LEN];
    uint8_t session_id_len;

    /* The version advertised by the client, by the
     * server, and the actual version we are currently
     * speaking. */
    uint8_t client_hello_version;
    uint8_t client_protocol_version;
    uint8_t server_protocol_version;
    uint8_t actual_protocol_version;

    /* Flag indicating whether a protocol version has been
     * negotiated yet. */
    uint8_t actual_protocol_version_established;

    /* Our crypto parameters */
    struct s2n_crypto_parameters *initial;
    struct s2n_crypto_parameters *secure;
    union s2n_secrets secrets;

    /* Which set is the client/server actually using? */
    struct s2n_crypto_parameters *client;
    struct s2n_crypto_parameters *server;

    /* Contains parameters needed to negotiate a shared secret */
    struct s2n_kex_parameters kex_params;

    /* Contains parameters needed during the handshake phase */
    struct s2n_handshake_parameters handshake_params;

    /* Our PSK parameters */
    struct s2n_psk_parameters psk_params;

    /* The PRF needs some storage elements to work with */
    struct s2n_prf_working_space *prf_space;

    /* Whether to use client_cert_auth_type stored in s2n_config or in this s2n_connection.
     *
     * By default the s2n_connection will defer to s2n_config->client_cert_auth_type on whether or not to use Client Auth.
     * But users can override Client Auth at the connection level using s2n_connection_set_client_auth_type() without mutating
     * s2n_config since s2n_config can be shared between multiple s2n_connections. */
    uint8_t client_cert_auth_type_overridden;

    /* Whether or not the s2n_connection should require the Client to authenticate itself to the server. Only used if
     * client_cert_auth_type_overridden is non-zero. */
    s2n_cert_auth_type client_cert_auth_type;

    /* Our workhorse stuffers, used for buffering the plaintext
     * and encrypted data in both directions.
     */
    uint8_t header_in_data[S2N_TLS_RECORD_HEADER_LENGTH];
    struct s2n_stuffer header_in;
    struct s2n_stuffer in;
    struct s2n_stuffer out;
    enum { ENCRYPTED, PLAINTEXT } in_status;

    /* How much of the current user buffer have we already
     * encrypted and sent or have pending for the wire but have
     * not acknowledged to the user.
     */
    ssize_t current_user_data_consumed;

    /* An alert may be fragmented across multiple records,
     * this stuffer is used to re-assemble.
     */
    uint8_t alert_in_data[S2N_ALERT_LENGTH];
    struct s2n_stuffer alert_in;

    /* An alert may be partially written in the outbound
     * direction, so we keep this as a small 2 byte queue.
     *
     * We keep separate queues for alerts generated by
     * readers (a response to an alert from a peer) and writers (an
     * intentional shutdown) so that the s2n reader and writer
     * can be separate duplex I/O threads.
     */
    uint8_t reader_alert_out_data[S2N_ALERT_LENGTH];
    uint8_t writer_alert_out_data[S2N_ALERT_LENGTH];
    struct s2n_stuffer reader_alert_out;
    struct s2n_stuffer writer_alert_out;

    /* Our handshake state machine */
    struct s2n_handshake handshake;

    /* Maximum outgoing fragment size for this connection. Does not limit
     * incoming record size.
     *
     * This value is updated when:
     *   1. s2n_connection_prefer_low_latency is set
     *   2. s2n_connection_prefer_throughput is set
     *   3. TLS Maximum Fragment Length extension is negotiated
     *
     * Default value: S2N_DEFAULT_FRAGMENT_LENGTH
     */
    uint16_t max_outgoing_fragment_length;

    /* The number of bytes to send before changing the record size. 
     * If this value > 0 then dynamic TLS record size is enabled. Otherwise, the feature is disabled (default). 
     */
    uint32_t dynamic_record_resize_threshold;

    /* Reset record size back to a single segment after threshold seconds of inactivity */
    uint16_t dynamic_record_timeout_threshold;

    /* The number of bytes consumed during a period of application activity.
     * Used for dynamic record sizing. */
    uint64_t active_application_bytes_consumed;

    /* Negotiated TLS extension Maximum Fragment Length code.
     * If set, the client and server have both agreed to fragment their records to the given length. */
    uint8_t negotiated_mfl_code;

    /* Keep some accounting on each connection */
    uint64_t wire_bytes_in;
    uint64_t wire_bytes_out;
    uint64_t early_data_bytes;

    /* Is the connection open or closed ? We use C's only
     * atomic type as both the reader and the writer threads
     * may declare a connection closed.
     *
     * A connection can be gracefully closed or hard-closed.
     * When gracefully closed the reader or the writer mark
     * the connection as closing, and then the writer will
     * send an alert message before closing the connection
     * and marking it as closed.
     *
     * A hard-close goes straight to closed with no alert
     * message being sent.
     */
    sig_atomic_t closing;
    sig_atomic_t closed;

    /* TLS extension data */
    char server_name[S2N_MAX_SERVER_NAME + 1];

    /* The application protocol decided upon during the client hello.
     * If ALPN is being used, then:
     * In server mode, this will be set by the time client_hello_cb is invoked.
     * In client mode, this will be set after is_handshake_complete(connection) is true.
     */
    char application_protocol[256];

    /* OCSP stapling response data */
    s2n_status_request_type status_type;
    struct s2n_blob status_response;

    /* Certificate Transparency response data */
    s2n_ct_support_level ct_level_requested;
    struct s2n_blob ct_response;

    /* QUIC transport parameters data: https://tools.ietf.org/html/draft-ietf-quic-tls-29#section-8.2 */
    struct s2n_blob our_quic_transport_parameters;
    struct s2n_blob peer_quic_transport_parameters;

    struct s2n_client_hello client_hello;

    struct s2n_x509_validator x509_validator;

    /* After a connection is created this is the verification function that should always be used. At init time,
     * the config should be checked for a verify callback and each connection should default to that. However,
     * from the user's perspective, it's sometimes simpler to manage state by attaching each validation function/data
     * to the connection, instead of globally to a single config.*/
    s2n_verify_host_fn verify_host_fn;
    void *data_for_verify_host;
    uint8_t verify_host_fn_overridden;

    /* Session ticket data */
    s2n_session_ticket_status session_ticket_status;
    struct s2n_blob client_ticket;
    uint32_t ticket_lifetime_hint;
    struct s2n_ticket_fields tls13_ticket_fields;

    /* Session ticket extension from client to attempt to decrypt as the server. */
    uint8_t ticket_ext_data[S2N_TLS12_TICKET_SIZE_IN_BYTES];
    struct s2n_stuffer client_ticket_to_decrypt;

    /* application protocols overridden */
    struct s2n_blob application_protocols_overridden;

    /* Cookie extension data */
    struct s2n_blob cookie;

    /* Flags to prevent users from calling methods recursively.
     * This can be an easy mistake to make when implementing callbacks.
     */
    bool send_in_use;
    bool recv_in_use;
    bool negotiate_in_use;
    
    uint16_t tickets_to_send;
    uint16_t tickets_sent;

    s2n_early_data_state early_data_state;
    uint32_t server_max_early_data_size;
    struct s2n_blob server_early_data_context;
    uint32_t server_keying_material_lifetime;
};

S2N_CLEANUP_RESULT s2n_connection_ptr_free(struct s2n_connection **s2n_connection);

int s2n_connection_is_managed_corked(const struct s2n_connection *s2n_connection);
int s2n_connection_is_client_auth_enabled(struct s2n_connection *s2n_connection);

/* Kill a bad connection */
int s2n_connection_kill(struct s2n_connection *conn);

/* Send/recv a stuffer to/from a connection */
int s2n_connection_send_stuffer(struct s2n_stuffer *stuffer, struct s2n_connection *conn, uint32_t len);
int s2n_connection_recv_stuffer(struct s2n_stuffer *stuffer, struct s2n_connection *conn, uint32_t len);

S2N_RESULT s2n_connection_wipe_all_keyshares(struct s2n_connection *conn);

/* If dynamic buffers are enabled, the IO buffers may be freed if they are completely consumed */
S2N_RESULT s2n_connection_dynamic_free_in_buffer(struct s2n_connection *conn);
S2N_RESULT s2n_connection_dynamic_free_out_buffer(struct s2n_connection *conn);

int s2n_connection_get_cipher_preferences(struct s2n_connection *conn, const struct s2n_cipher_preferences **cipher_preferences);
int s2n_connection_get_security_policy(struct s2n_connection *conn, const struct s2n_security_policy **security_policy);
int s2n_connection_get_kem_preferences(struct s2n_connection *conn, const struct s2n_kem_preferences **kem_preferences);
int s2n_connection_get_signature_preferences(struct s2n_connection *conn, const struct s2n_signature_preferences **signature_preferences);
int s2n_connection_get_ecc_preferences(struct s2n_connection *conn, const struct s2n_ecc_preferences **ecc_preferences);
int s2n_connection_get_protocol_preferences(struct s2n_connection *conn, struct s2n_blob **protocol_preferences);
int s2n_connection_set_client_auth_type(struct s2n_connection *conn, s2n_cert_auth_type cert_auth_type);
int s2n_connection_get_client_auth_type(struct s2n_connection *conn, s2n_cert_auth_type *client_cert_auth_type);
int s2n_connection_get_client_cert_chain(struct s2n_connection *conn, uint8_t **der_cert_chain_out, uint32_t *cert_chain_len);
int s2n_connection_get_peer_cert_chain(const struct s2n_connection *conn, struct s2n_cert_chain_and_key *cert_chain_and_key);
uint8_t s2n_connection_get_protocol_version(const struct s2n_connection *conn);
S2N_RESULT s2n_connection_set_max_fragment_length(struct s2n_connection *conn, uint16_t length);