int main(int argc, char **argv) { uint8_t u8; uint16_t u16; uint32_t u32; uint32_t stuffer_size = nondet_uint32(); __CPROVER_assume(stuffer_size > 0); uint32_t entropy_size = nondet_uint32(); __CPROVER_assume(entropy_size > 0); uint8_t entropy[entropy_size]; struct s2n_stuffer stuffer; GUARD(s2n_stuffer_alloc(&stuffer, stuffer_size)); struct s2n_blob in = {.data = entropy,.size = entropy_size}; GUARD(s2n_stuffer_write(&stuffer, &in)); GUARD(s2n_stuffer_wipe(&stuffer)); while(nondet_bool()) { GUARD(s2n_stuffer_write_uint8(&stuffer, nondet_uint64())); } while(nondet_bool()) { GUARD(s2n_stuffer_read_uint8(&stuffer, &u8)); } GUARD(s2n_stuffer_wipe(&stuffer)); while(nondet_bool()) { GUARD(s2n_stuffer_write_uint16(&stuffer, nondet_uint64())); } while(nondet_bool()) { GUARD(s2n_stuffer_read_uint16(&stuffer, &u16)); } GUARD(s2n_stuffer_wipe(&stuffer)); while(nondet_bool()) { GUARD(s2n_stuffer_write_uint24(&stuffer, nondet_uint64())); } while(nondet_bool()) { GUARD(s2n_stuffer_read_uint24(&stuffer, &u32)); } GUARD(s2n_stuffer_wipe(&stuffer)); while(nondet_bool()) { GUARD(s2n_stuffer_write_uint32(&stuffer, nondet_uint64())); } while(nondet_bool()) { GUARD(s2n_stuffer_read_uint32(&stuffer, &u32)); } GUARD(s2n_stuffer_free(&stuffer)); }
int s2n_handshake_parse_header(struct s2n_connection *conn, uint8_t * message_type, uint32_t * length) { if (s2n_stuffer_data_available(&conn->handshake.io) < TLS_HANDSHAKE_HEADER_LENGTH) { S2N_ERROR(S2N_ERR_SIZE_MISMATCH); } /* read the message header */ GUARD(s2n_stuffer_read_uint8(&conn->handshake.io, message_type)); GUARD(s2n_stuffer_read_uint24(&conn->handshake.io, length)); return 0; }
int s2n_server_status_recv(struct s2n_connection *conn) { uint8_t type; struct s2n_blob status = { .data = NULL, .size = 0 }; GUARD(s2n_stuffer_read_uint8(&conn->handshake.io, &type)); GUARD(s2n_stuffer_read_uint24(&conn->handshake.io, &status.size)); status.data = s2n_stuffer_raw_read(&conn->handshake.io, status.size); notnull_check(status.data); if (type == S2N_STATUS_REQUEST_OCSP) { GUARD(s2n_alloc(&conn->status_response, status.size)); memcpy_check(conn->status_response.data, status.data, status.size); conn->status_response.size = status.size; } return 0; }
int s2n_server_cert_recv(struct s2n_connection *conn) { uint32_t size_of_all_certificates; GUARD(s2n_stuffer_read_uint24(&conn->handshake.io, &size_of_all_certificates)); S2N_ERROR_IF(size_of_all_certificates > s2n_stuffer_data_available(&conn->handshake.io) || size_of_all_certificates < 3, S2N_ERR_BAD_MESSAGE); s2n_cert_public_key public_key; GUARD(s2n_pkey_zero_init(&public_key)); s2n_cert_type cert_type; struct s2n_blob cert_chain = {0}; cert_chain.data = s2n_stuffer_raw_read(&conn->handshake.io, size_of_all_certificates); cert_chain.size = size_of_all_certificates; S2N_ERROR_IF(s2n_x509_validator_validate_cert_chain(&conn->x509_validator, conn, cert_chain.data, cert_chain.size, &cert_type, &public_key) != S2N_CERT_OK, S2N_ERR_CERT_UNTRUSTED); s2n_authentication_method expected_auth_method = conn->secure.cipher_suite->auth_method; switch (cert_type) { case S2N_CERT_TYPE_RSA_SIGN: if (expected_auth_method == S2N_AUTHENTICATION_RSA) { break; } case S2N_CERT_TYPE_ECDSA_SIGN: if (expected_auth_method == S2N_AUTHENTICATION_ECDSA) { break; } default: S2N_ERROR(S2N_ERR_CERT_TYPE_UNSUPPORTED); } conn->secure.client_cert_type = cert_type; s2n_pkey_setup_for_type(&public_key, cert_type); conn->secure.server_public_key = public_key; return 0; }
int s2n_server_status_recv(struct s2n_connection *conn) { uint8_t type; struct s2n_blob status = { .data = NULL, .size = 0 }; GUARD(s2n_stuffer_read_uint8(&conn->handshake.io, &type)); GUARD(s2n_stuffer_read_uint24(&conn->handshake.io, &status.size)); status.data = s2n_stuffer_raw_read(&conn->handshake.io, status.size); notnull_check(status.data); if (type == S2N_STATUS_REQUEST_OCSP) { GUARD(s2n_alloc(&conn->status_response, status.size)); memcpy_check(conn->status_response.data, status.data, status.size); conn->status_response.size = status.size; } conn->handshake.next_state = SERVER_HELLO_DONE; if (conn->pending.cipher_suite->key_exchange_alg->flags & S2N_KEY_EXCHANGE_EPH) { conn->handshake.next_state = SERVER_KEY; } return 0; }
s2n_cert_validation_code s2n_x509_validator_validate_cert_chain(struct s2n_x509_validator *validator, struct s2n_connection *conn, uint8_t *cert_chain_in, uint32_t cert_chain_len, s2n_cert_type *cert_type, struct s2n_pkey *public_key_out) { if (!validator->skip_cert_validation && !s2n_x509_trust_store_has_certs(validator->trust_store)) { return S2N_CERT_ERR_UNTRUSTED; } DEFER_CLEANUP(X509_STORE_CTX *ctx = NULL, X509_STORE_CTX_free_pointer); struct s2n_blob cert_chain_blob = {.data = cert_chain_in, .size = cert_chain_len}; DEFER_CLEANUP(struct s2n_stuffer cert_chain_in_stuffer = {{0}}, s2n_stuffer_free); if (s2n_stuffer_init(&cert_chain_in_stuffer, &cert_chain_blob) < 0) { return S2N_CERT_ERR_INVALID; } if (s2n_stuffer_write(&cert_chain_in_stuffer, &cert_chain_blob) < 0) { return S2N_CERT_ERR_INVALID; } uint32_t certificate_count = 0; X509 *server_cert = NULL; DEFER_CLEANUP(struct s2n_pkey public_key = {{{0}}}, s2n_pkey_free); s2n_pkey_zero_init(&public_key); while (s2n_stuffer_data_available(&cert_chain_in_stuffer) && certificate_count < validator->max_chain_depth) { uint32_t certificate_size = 0; if (s2n_stuffer_read_uint24(&cert_chain_in_stuffer, &certificate_size) < 0) { return S2N_CERT_ERR_INVALID; } if (certificate_size == 0 || certificate_size > s2n_stuffer_data_available(&cert_chain_in_stuffer)) { return S2N_CERT_ERR_INVALID; } struct s2n_blob asn1cert = {0}; asn1cert.data = s2n_stuffer_raw_read(&cert_chain_in_stuffer, certificate_size); asn1cert.size = certificate_size; if (asn1cert.data == NULL) { return S2N_CERT_ERR_INVALID; } const uint8_t *data = asn1cert.data; if (!validator->skip_cert_validation) { /* the cert is der encoded, just convert it. */ server_cert = d2i_X509(NULL, &data, asn1cert.size); if (!server_cert) { return S2N_CERT_ERR_INVALID; } /* add the cert to the chain. */ if (!sk_X509_push(validator->cert_chain, server_cert)) { X509_free(server_cert); return S2N_CERT_ERR_INVALID; } } /* Pull the public key from the first certificate */ if (certificate_count == 0) { if (s2n_asn1der_to_public_key_and_type(&public_key, cert_type, &asn1cert) < 0) { return S2N_CERT_ERR_INVALID; } } certificate_count++; } /* if this occurred we exceeded validator->max_chain_depth */ if (!validator->skip_cert_validation && s2n_stuffer_data_available(&cert_chain_in_stuffer)) { return S2N_CERT_ERR_MAX_CHAIN_DEPTH_EXCEEDED; } if (certificate_count < 1) { return S2N_CERT_ERR_INVALID; } if (!validator->skip_cert_validation) { X509 *leaf = sk_X509_value(validator->cert_chain, 0); if (!leaf) { return S2N_CERT_ERR_INVALID; } if (conn->verify_host_fn && !s2n_verify_host_information(validator, conn, leaf)) { return S2N_CERT_ERR_UNTRUSTED; } /* now that we have a chain, get the store and check against it. */ ctx = X509_STORE_CTX_new(); int op_code = X509_STORE_CTX_init(ctx, validator->trust_store->trust_store, leaf, validator->cert_chain); if (op_code <= 0) { return S2N_CERT_ERR_INVALID; } X509_VERIFY_PARAM *param = X509_STORE_CTX_get0_param(ctx); X509_VERIFY_PARAM_set_depth(param, validator->max_chain_depth); uint64_t current_sys_time = 0; conn->config->wall_clock(conn->config->sys_clock_ctx, ¤t_sys_time); /* this wants seconds not nanoseconds */ time_t current_time = (time_t)(current_sys_time / 1000000000); X509_STORE_CTX_set_time(ctx, 0, current_time); op_code = X509_verify_cert(ctx); if (op_code <= 0) { return S2N_CERT_ERR_UNTRUSTED; } } *public_key_out = public_key; /* Reset the old struct, so we don't clean up public_key_out */ s2n_pkey_zero_init(&public_key); return S2N_CERT_OK; }