int s2n_dh_compute_shared_secret_as_server(struct s2n_dh_params *server_dh_params, struct s2n_stuffer *Yc_in, struct s2n_blob *shared_key) { uint16_t Yc_length; struct s2n_blob Yc; int shared_key_size; BIGNUM *pub_key; GUARD(s2n_check_all_dh_params(server_dh_params)); GUARD(s2n_stuffer_read_uint16(Yc_in, &Yc_length)); Yc.size = Yc_length; Yc.data = s2n_stuffer_raw_read(Yc_in, Yc.size); notnull_check(Yc.data); pub_key = BN_bin2bn((const unsigned char *)Yc.data, Yc.size, NULL); notnull_check(pub_key); GUARD(s2n_alloc(shared_key, DH_size(server_dh_params->dh))); shared_key_size = DH_compute_key(shared_key->data, pub_key, server_dh_params->dh); if (shared_key_size <= 0) { BN_free(pub_key); S2N_ERROR(S2N_ERR_DH_SHARED_SECRET); } shared_key->size = shared_key_size; BN_free(pub_key); return 0; }
int s2n_x509_trust_store_add_pem(struct s2n_x509_trust_store *store, const char *pem) { notnull_check(store); notnull_check(pem); if (!store->trust_store) { store->trust_store = X509_STORE_new(); } DEFER_CLEANUP(struct s2n_stuffer pem_in_stuffer = {{0}}, s2n_stuffer_free); DEFER_CLEANUP(struct s2n_stuffer der_out_stuffer = {{0}}, s2n_stuffer_free); GUARD(s2n_stuffer_alloc_ro_from_string(&pem_in_stuffer, pem)); GUARD(s2n_stuffer_growable_alloc(&der_out_stuffer, 2048)); do { DEFER_CLEANUP(struct s2n_blob next_cert = {0}, s2n_free); GUARD(s2n_stuffer_certificate_from_pem(&pem_in_stuffer, &der_out_stuffer)); GUARD(s2n_alloc(&next_cert, s2n_stuffer_data_available(&der_out_stuffer))); GUARD(s2n_stuffer_read(&der_out_stuffer, &next_cert)); const uint8_t *data = next_cert.data; DEFER_CLEANUP(X509 *ca_cert = d2i_X509(NULL, &data, next_cert.size), X509_free_pointer); S2N_ERROR_IF(ca_cert == NULL, S2N_ERR_DECODE_CERTIFICATE); GUARD_OSSL(X509_STORE_add_cert(store->trust_store, ca_cert), S2N_ERR_DECODE_CERTIFICATE); } while (s2n_stuffer_data_available(&pem_in_stuffer)); return 0; }
struct s2n_connection *s2n_connection_new(s2n_mode mode) { struct s2n_blob blob; struct s2n_connection *conn; GUARD_PTR(s2n_alloc(&blob, sizeof(struct s2n_connection))); GUARD_PTR(s2n_blob_zero(&blob)); if (mode == S2N_CLIENT) { /* At present s2n is not suitable for use in client mode, as it * does not perform any certificate validation. However it is useful * to use S2N in client mode for testing purposes. An environment * variable is required to be set for the client mode to work. */ if (getenv("S2N_ENABLE_CLIENT_MODE") == NULL) { s2n_free(&blob); S2N_ERROR_PTR(S2N_ERR_CLIENT_MODE_DISABLED); } } /* Cast 'through' void to acknowledge that we are changing alignment, * which is ok, as blob.data is always aligned. */ conn = (struct s2n_connection *)(void *)blob.data; conn->mode = mode; conn->blinding = S2N_BUILT_IN_BLINDING; conn->config = &s2n_default_config; /* Allocate the fixed-size stuffers */ blob.data = conn->alert_in_data; blob.size = S2N_ALERT_LENGTH; GUARD_PTR(s2n_stuffer_init(&conn->alert_in, &blob)); blob.data = conn->reader_alert_out_data; blob.size = S2N_ALERT_LENGTH; GUARD_PTR(s2n_stuffer_init(&conn->reader_alert_out, &blob)); blob.data = conn->writer_alert_out_data; blob.size = S2N_ALERT_LENGTH; GUARD_PTR(s2n_stuffer_init(&conn->writer_alert_out, &blob)); GUARD_PTR(s2n_stuffer_alloc(&conn->out, S2N_DEFAULT_RECORD_LENGTH)); /* Initialize the growable stuffers. Zero length at first, but the resize * in _wipe will fix that */ blob.data = conn->header_in_data; blob.size = S2N_TLS_RECORD_HEADER_LENGTH; GUARD_PTR(s2n_stuffer_init(&conn->header_in, &blob)); GUARD_PTR(s2n_stuffer_growable_alloc(&conn->in, 0)); GUARD_PTR(s2n_stuffer_growable_alloc(&conn->handshake.io, 0)); GUARD_PTR(s2n_connection_wipe(conn)); GUARD_PTR(s2n_timer_start(conn->config, &conn->write_timer)); return conn; }
int s2n_stuffer_alloc(struct s2n_stuffer *stuffer, const uint32_t size) { GUARD(s2n_alloc(&stuffer->blob, size)); GUARD(s2n_stuffer_init(stuffer, &stuffer->blob)); stuffer->alloced = 1; return 0; }
int s2n_dup(struct s2n_blob *from, struct s2n_blob *to) { eq_check(to->size, 0); eq_check(to->data, NULL); GUARD(s2n_alloc(to, from->size)); memcpy_check(to->data, from->data, to->size); return 0; }
int s2n_kem_generate_keypair(struct s2n_kem_keypair *kem_keys) { notnull_check(kem_keys); const struct s2n_kem *kem = kem_keys->negotiated_kem; notnull_check(kem->generate_keypair); eq_check(kem_keys->public_key.size, kem->public_key_length); notnull_check(kem_keys->public_key.data); /* The private key is needed for client_key_recv and must be saved */ GUARD(s2n_alloc(&kem_keys->private_key, kem->private_key_length)); GUARD(kem->generate_keypair(kem_keys->public_key.data, kem_keys->private_key.data)); return 0; }
struct s2n_map *s2n_map_new() { struct s2n_blob mem; struct s2n_map *map; GUARD_PTR(s2n_alloc(&mem, sizeof(struct s2n_map))); map = (void *) mem.data; map->capacity = 0; map->size = 0; map->immutable = 0; map->table = NULL; GUARD_PTR(s2n_map_embiggen(map, S2N_INITIAL_TABLE_SIZE)); return map; }
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_kem_decapsulate(const struct s2n_kem_keypair *kem_keys, struct s2n_blob *shared_secret, const struct s2n_blob *ciphertext) { notnull_check(kem_keys); const struct s2n_kem *kem = kem_keys->negotiated_kem; notnull_check(kem->decapsulate); eq_check(kem_keys->private_key.size, kem->private_key_length); notnull_check(kem_keys->private_key.data); eq_check(ciphertext->size, kem->ciphertext_length); notnull_check(ciphertext->data); GUARD(s2n_alloc(shared_secret, kem_keys->negotiated_kem->shared_secret_key_length)); GUARD(kem->decapsulate(shared_secret->data, ciphertext->data, kem_keys->private_key.data)); return 0; }
struct s2n_config *s2n_config_new(void) { struct s2n_blob allocator; struct s2n_config *new_config; GUARD_PTR(s2n_alloc(&allocator, sizeof(struct s2n_config))); new_config = (struct s2n_config *)(void *)allocator.data; new_config->cert_and_key_pairs = NULL; new_config->dhparams = NULL; new_config->application_protocols.data = NULL; new_config->application_protocols.size = 0; new_config->status_request_type = S2N_STATUS_REQUEST_NONE; new_config->nanoseconds_since_epoch = get_nanoseconds_since_epoch; GUARD_PTR(s2n_config_set_cipher_preferences(new_config, "default")); return new_config; }
int s2n_dh_compute_shared_secret_as_client(struct s2n_dh_params *server_dh_params, struct s2n_stuffer *Yc_out, struct s2n_blob *shared_key) { struct s2n_dh_params client_params; uint8_t *client_pub_key; uint16_t client_pub_key_size; int shared_key_size; GUARD(s2n_dh_params_check(server_dh_params)); GUARD(s2n_dh_params_copy(server_dh_params, &client_params)); GUARD(s2n_dh_generate_ephemeral_key(&client_params)); GUARD(s2n_alloc(shared_key, DH_size(server_dh_params->dh))); const BIGNUM *client_pub_key_bn = s2n_get_Ys_dh_param(&client_params); client_pub_key_size = BN_num_bytes(client_pub_key_bn); GUARD(s2n_stuffer_write_uint16(Yc_out, client_pub_key_size)); client_pub_key = s2n_stuffer_raw_write(Yc_out, client_pub_key_size); if (client_pub_key == NULL) { GUARD(s2n_free(shared_key)); GUARD(s2n_dh_params_free(&client_params)); S2N_ERROR(S2N_ERR_DH_WRITING_PUBLIC_KEY); } if (BN_bn2bin(client_pub_key_bn, client_pub_key) != client_pub_key_size) { GUARD(s2n_free(shared_key)); GUARD(s2n_dh_params_free(&client_params)); S2N_ERROR(S2N_ERR_DH_COPYING_PUBLIC_KEY); } /* server_dh_params already validated */ const BIGNUM *server_pub_key_bn = s2n_get_Ys_dh_param(server_dh_params); shared_key_size = DH_compute_key(shared_key->data, server_pub_key_bn, client_params.dh); if (shared_key_size < 0) { GUARD(s2n_free(shared_key)); GUARD(s2n_dh_params_free(&client_params)); S2N_ERROR(S2N_ERR_DH_SHARED_SECRET); } shared_key->size = shared_key_size; GUARD(s2n_dh_params_free(&client_params)); return 0; }
static int s2n_map_embiggen(struct s2n_map *map, uint32_t capacity) { struct s2n_blob mem; struct s2n_map tmp; if (map->immutable) { S2N_ERROR(S2N_ERR_MAP_IMMUTABLE); } GUARD(s2n_alloc(&mem, (capacity * sizeof(struct s2n_map_entry)))); GUARD(s2n_blob_zero(&mem)); tmp.capacity = capacity; tmp.size = 0; tmp.table = (void *) mem.data; tmp.immutable = 0; tmp.sha256 = map->sha256; for (int i = 0; i < map->capacity; i++) { if (map->table[i].key.size) { GUARD(s2n_map_add(&tmp, &map->table[i].key, &map->table[i].value)); GUARD(s2n_free(&map->table[i].key)); GUARD(s2n_free(&map->table[i].value)); } } /* Free the old memory */ mem.data = (void *) map->table; mem.size = map->capacity * sizeof(struct s2n_map_entry); GUARD(s2n_free(&mem)); /* Clone the temporary map */ map->capacity = tmp.capacity; map->size = tmp.size; map->table = tmp.table; map->immutable = 0; map->sha256 = tmp.sha256; return 0; }
static int s2n_ecdsa_keys_match(const struct s2n_pkey *pub, const struct s2n_pkey *priv) { uint8_t input[16] = { 1 }; DEFER_CLEANUP(struct s2n_blob signature = { 0 }, s2n_free); DEFER_CLEANUP(struct s2n_hash_state state_in = { 0 }, s2n_hash_free); DEFER_CLEANUP(struct s2n_hash_state state_out = { 0 }, s2n_hash_free); /* s2n_hash_new only allocates memory when using high-level EVP hashes, currently restricted to FIPS mode. */ GUARD(s2n_hash_new(&state_in)); GUARD(s2n_hash_new(&state_out)); GUARD(s2n_hash_init(&state_in, S2N_HASH_SHA1)); GUARD(s2n_hash_init(&state_out, S2N_HASH_SHA1)); GUARD(s2n_hash_update(&state_in, input, sizeof(input))); GUARD(s2n_hash_update(&state_out, input, sizeof(input))); GUARD(s2n_alloc(&signature, s2n_ecdsa_der_signature_size(priv))); GUARD(s2n_ecdsa_sign(priv, &state_in, &signature)); GUARD(s2n_ecdsa_verify(pub, &state_out, &signature)); 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; }
int s2n_config_free_cert_chain_and_key(struct s2n_config *config) { struct s2n_blob b = { .data = (uint8_t *) config->cert_and_key_pairs, .size = sizeof(struct s2n_cert_chain_and_key) }; /* If there were cert and key pairs set, walk the chain and free the certs */ if (config->cert_and_key_pairs) { struct s2n_cert_chain *node = config->cert_and_key_pairs->head; while (node) { struct s2n_blob n = { .data = (uint8_t *)node, .size = sizeof(struct s2n_cert_chain) }; /* Free the cert */ GUARD(s2n_free(&node->cert)); /* Advance to next */ node = node->next; /* Free the node */ GUARD(s2n_free(&n)); } GUARD(s2n_rsa_private_key_free(&config->cert_and_key_pairs->private_key)); GUARD(s2n_free(&config->cert_and_key_pairs->ocsp_status)); } GUARD(s2n_free(&b)); return 0; } int s2n_config_free_dhparams(struct s2n_config *config) { struct s2n_blob b = { .data = (uint8_t *) config->dhparams, .size = sizeof(struct s2n_dh_params) }; if (config->dhparams) { GUARD(s2n_dh_params_free(config->dhparams)); } GUARD(s2n_free(&b)); return 0; } int s2n_config_free(struct s2n_config *config) { struct s2n_blob b = {.data = (uint8_t *) config,.size = sizeof(struct s2n_config) }; GUARD(s2n_config_free_cert_chain_and_key(config)); GUARD(s2n_config_free_dhparams(config)); GUARD(s2n_free(&config->application_protocols)); GUARD(s2n_free(&b)); return 0; } int s2n_config_set_cipher_preferences(struct s2n_config *config, const char *version) { for (int i = 0; selection[i].version != NULL; i++) { if (!strcasecmp(version, selection[i].version)) { config->cipher_preferences = selection[i].preferences; return 0; } } s2n_errno = S2N_ERR_INVALID_CIPHER_PREFERENCES; return -1; } int s2n_config_set_protocol_preferences(struct s2n_config *config, const char * const *protocols, int protocol_count) { struct s2n_stuffer protocol_stuffer; GUARD(s2n_free(&config->application_protocols)); if (protocols == NULL || protocol_count == 0) { /* NULL value indicates no prference, so nothing to do */ return 0; } GUARD(s2n_stuffer_growable_alloc(&protocol_stuffer, 256)); for (int i = 0; i < protocol_count; i++) { size_t length = strlen(protocols[i]); uint8_t protocol[255]; if (length > 255 || (s2n_stuffer_data_available(&protocol_stuffer) + length + 1) > 65535) { return S2N_ERR_APPLICATION_PROTOCOL_TOO_LONG; } memcpy_check(protocol, protocols[i], length); GUARD(s2n_stuffer_write_uint8(&protocol_stuffer, length)); GUARD(s2n_stuffer_write_bytes(&protocol_stuffer, protocol, length)); } uint32_t size = s2n_stuffer_data_available(&protocol_stuffer); /* config->application_protocols blob now owns this data */ config->application_protocols.size = size; config->application_protocols.data = s2n_stuffer_raw_read(&protocol_stuffer, size); notnull_check(config->application_protocols.data); return 0; } int s2n_config_set_status_request_type(struct s2n_config *config, s2n_status_request_type type) { config->status_request_type = type; return 0; } int s2n_config_add_cert_chain_and_key_with_status(struct s2n_config *config, char *cert_chain_pem, char *private_key_pem, const uint8_t *status, uint32_t length) { struct s2n_stuffer chain_in_stuffer, cert_out_stuffer, key_in_stuffer, key_out_stuffer; struct s2n_blob key_blob; struct s2n_blob mem; /* Allocate the memory for the chain and key struct */ GUARD(s2n_alloc(&mem, sizeof(struct s2n_cert_chain_and_key))); config->cert_and_key_pairs = (struct s2n_cert_chain_and_key *)(void *)mem.data; config->cert_and_key_pairs->ocsp_status.data = NULL; config->cert_and_key_pairs->ocsp_status.size = 0; /* Put the private key pem in a stuffer */ GUARD(s2n_stuffer_alloc_ro_from_string(&key_in_stuffer, private_key_pem)); GUARD(s2n_stuffer_growable_alloc(&key_out_stuffer, strlen(private_key_pem))); /* Convert pem to asn1 and asn1 to the private key */ GUARD(s2n_stuffer_rsa_private_key_from_pem(&key_in_stuffer, &key_out_stuffer)); GUARD(s2n_stuffer_free(&key_in_stuffer)); key_blob.size = s2n_stuffer_data_available(&key_out_stuffer); key_blob.data = s2n_stuffer_raw_read(&key_out_stuffer, key_blob.size); notnull_check(key_blob.data); GUARD(s2n_asn1der_to_rsa_private_key(&config->cert_and_key_pairs->private_key, &key_blob)); GUARD(s2n_stuffer_free(&key_out_stuffer)); /* Turn the chain into a stuffer */ GUARD(s2n_stuffer_alloc_ro_from_string(&chain_in_stuffer, cert_chain_pem)); GUARD(s2n_stuffer_growable_alloc(&cert_out_stuffer, 2048)); struct s2n_cert_chain **insert = &config->cert_and_key_pairs->head; uint32_t chain_size = 0; do { struct s2n_cert_chain *new_node; if (s2n_stuffer_certificate_from_pem(&chain_in_stuffer, &cert_out_stuffer) < 0) { if (chain_size == 0) { S2N_ERROR(S2N_ERR_NO_CERTIFICATE_IN_PEM); } break; } GUARD(s2n_alloc(&mem, sizeof(struct s2n_cert_chain))); new_node = (struct s2n_cert_chain *)(void *)mem.data; GUARD(s2n_alloc(&new_node->cert, s2n_stuffer_data_available(&cert_out_stuffer))); GUARD(s2n_stuffer_read(&cert_out_stuffer, &new_node->cert)); /* Additional 3 bytes for the length field in the protocol */ chain_size += new_node->cert.size + 3; new_node->next = NULL; *insert = new_node; insert = &new_node->next; } while (s2n_stuffer_data_available(&chain_in_stuffer)); GUARD(s2n_stuffer_free(&chain_in_stuffer)); GUARD(s2n_stuffer_free(&cert_out_stuffer)); config->cert_and_key_pairs->chain_size = chain_size; if (status && length > 0) { GUARD(s2n_alloc(&config->cert_and_key_pairs->ocsp_status, length)); memcpy_check(config->cert_and_key_pairs->ocsp_status.data, status, length); } return 0; } int s2n_config_add_cert_chain_and_key(struct s2n_config *config, char *cert_chain_pem, char *private_key_pem) { GUARD(s2n_config_add_cert_chain_and_key_with_status(config, cert_chain_pem, private_key_pem, NULL, 0)); return 0; } int s2n_config_add_dhparams(struct s2n_config *config, char *dhparams_pem) { struct s2n_stuffer dhparams_in_stuffer, dhparams_out_stuffer; struct s2n_blob dhparams_blob; struct s2n_blob mem; /* Allocate the memory for the chain and key struct */ GUARD(s2n_alloc(&mem, sizeof(struct s2n_dh_params))); config->dhparams = (struct s2n_dh_params *)(void *)mem.data; GUARD(s2n_stuffer_alloc_ro_from_string(&dhparams_in_stuffer, dhparams_pem)); GUARD(s2n_stuffer_growable_alloc(&dhparams_out_stuffer, strlen(dhparams_pem))); /* Convert pem to asn1 and asn1 to the private key */ GUARD(s2n_stuffer_dhparams_from_pem(&dhparams_in_stuffer, &dhparams_out_stuffer)); GUARD(s2n_stuffer_free(&dhparams_in_stuffer)); dhparams_blob.size = s2n_stuffer_data_available(&dhparams_out_stuffer); dhparams_blob.data = s2n_stuffer_raw_read(&dhparams_out_stuffer, dhparams_blob.size); notnull_check(dhparams_blob.data); GUARD(s2n_pkcs3_to_dh_params(config->dhparams, &dhparams_blob)); GUARD(s2n_free(&dhparams_blob)); return 0; } int s2n_config_set_nanoseconds_since_epoch_callback(struct s2n_config *config, int (*nanoseconds_since_epoch)(void *, uint64_t *), void * data) { notnull_check(nanoseconds_since_epoch); config->nanoseconds_since_epoch = nanoseconds_since_epoch; config->data_for_nanoseconds_since_epoch = data; return 0; }
int main(int argc, char **argv) { struct s2n_stuffer certificate_in, certificate_out; struct s2n_stuffer dhparams_in, dhparams_out; struct s2n_stuffer rsa_key_in, rsa_key_out; struct s2n_blob b; BEGIN_TEST(); EXPECT_SUCCESS(s2n_stuffer_alloc(&certificate_in, sizeof(certificate))); EXPECT_SUCCESS(s2n_stuffer_alloc(&certificate_out, sizeof(certificate))); EXPECT_SUCCESS(s2n_stuffer_alloc(&dhparams_in, sizeof(dhparams))); EXPECT_SUCCESS(s2n_stuffer_alloc(&dhparams_out, sizeof(dhparams))); EXPECT_SUCCESS(s2n_stuffer_alloc(&rsa_key_in, sizeof(private_key))); EXPECT_SUCCESS(s2n_stuffer_alloc(&rsa_key_out, sizeof(private_key))); b.data = certificate; b.size = sizeof(certificate); EXPECT_SUCCESS(s2n_stuffer_write(&certificate_in, &b)); b.data = private_key; b.size = sizeof(private_key); EXPECT_SUCCESS(s2n_stuffer_write(&rsa_key_in, &b)); b.data = dhparams; b.size = sizeof(dhparams); EXPECT_SUCCESS(s2n_stuffer_write(&dhparams_in, &b)); EXPECT_SUCCESS(s2n_stuffer_certificate_from_pem(&certificate_in, &certificate_out)); EXPECT_SUCCESS(s2n_stuffer_rsa_private_key_from_pem(&rsa_key_in, &rsa_key_out)); EXPECT_SUCCESS(s2n_stuffer_dhparams_from_pem(&dhparams_in, &dhparams_out)); struct s2n_rsa_private_key priv_key; struct s2n_rsa_public_key pub_key; b.size = s2n_stuffer_data_available(&certificate_out); b.data = s2n_stuffer_raw_read(&certificate_out, b.size); EXPECT_SUCCESS(s2n_asn1der_to_rsa_public_key(&pub_key, &b)); b.size = s2n_stuffer_data_available(&rsa_key_out); b.data = s2n_stuffer_raw_read(&rsa_key_out, b.size); EXPECT_SUCCESS(s2n_asn1der_to_rsa_private_key(&priv_key, &b)); EXPECT_SUCCESS(s2n_rsa_keys_match(&pub_key, &priv_key)); struct s2n_connection *conn; EXPECT_NOT_NULL(conn = s2n_connection_new(S2N_SERVER)); EXPECT_SUCCESS(s2n_config_add_cert_chain_and_key(conn->config, (char *)chain, (char *)private_key)); struct s2n_dh_params dh_params; b.size = s2n_stuffer_data_available(&dhparams_out); b.data = s2n_stuffer_raw_read(&dhparams_out, b.size); EXPECT_SUCCESS(s2n_pkcs3_to_dh_params(&dh_params, &b)); EXPECT_SUCCESS(s2n_config_add_dhparams(conn->config, (char *)dhparams)); /* Try signing and verification with RSA */ uint8_t inputpad[] = "Hello world!"; struct s2n_blob signature; struct s2n_hash_state tls10_one, tls10_two, tls12_one, tls12_two; EXPECT_SUCCESS(s2n_hash_init(&tls10_one, S2N_HASH_MD5_SHA1)); EXPECT_SUCCESS(s2n_hash_init(&tls10_two, S2N_HASH_MD5_SHA1)); EXPECT_SUCCESS(s2n_hash_init(&tls12_one, S2N_HASH_SHA1)); EXPECT_SUCCESS(s2n_hash_init(&tls12_two, S2N_HASH_SHA1)); EXPECT_SUCCESS(s2n_alloc(&signature, s2n_rsa_public_encrypted_size(&pub_key))); EXPECT_SUCCESS(s2n_hash_update(&tls10_one, inputpad, sizeof(inputpad))); EXPECT_SUCCESS(s2n_hash_update(&tls10_two, inputpad, sizeof(inputpad))); EXPECT_SUCCESS(s2n_rsa_sign(&priv_key, &tls10_one, &signature)); EXPECT_SUCCESS(s2n_rsa_verify(&pub_key, &tls10_two, &signature)); EXPECT_SUCCESS(s2n_hash_update(&tls12_one, inputpad, sizeof(inputpad))); EXPECT_SUCCESS(s2n_hash_update(&tls12_two, inputpad, sizeof(inputpad))); EXPECT_SUCCESS(s2n_rsa_sign(&priv_key, &tls12_one, &signature)); EXPECT_SUCCESS(s2n_rsa_verify(&pub_key, &tls12_two, &signature)); EXPECT_SUCCESS(s2n_dh_params_free(&dh_params)); EXPECT_SUCCESS(s2n_rsa_private_key_free(&priv_key)); EXPECT_SUCCESS(s2n_rsa_public_key_free(&pub_key)); EXPECT_SUCCESS(s2n_config_free_dhparams(conn->config)); EXPECT_SUCCESS(s2n_config_free_cert_chain_and_key(conn->config)); EXPECT_SUCCESS(s2n_connection_free(conn)); EXPECT_SUCCESS(s2n_free(&signature)); EXPECT_SUCCESS(s2n_stuffer_free(&certificate_in)); EXPECT_SUCCESS(s2n_stuffer_free(&certificate_out)); EXPECT_SUCCESS(s2n_stuffer_free(&dhparams_in)); EXPECT_SUCCESS(s2n_stuffer_free(&dhparams_out)); EXPECT_SUCCESS(s2n_stuffer_free(&rsa_key_in)); EXPECT_SUCCESS(s2n_stuffer_free(&rsa_key_out)); END_TEST(); }
int main(int argc, char **argv) { BEGIN_TEST(); EXPECT_SUCCESS(setenv("S2N_ENABLE_CLIENT_MODE", "1", 0)); /* Part 1 setup a client and server connection with everything they need for a key exchange */ struct s2n_connection *client_conn, *server_conn; EXPECT_NOT_NULL(client_conn = s2n_connection_new(S2N_CLIENT)); EXPECT_NOT_NULL(server_conn = s2n_connection_new(S2N_SERVER)); struct s2n_config *server_config, *client_config; client_config = s2n_fetch_unsafe_client_testing_config(); GUARD(s2n_connection_set_config(client_conn, client_config)); /* Part 1.1 setup server's keypair and the give the client the certificate */ char *cert_chain; char *private_key; char *client_chain; EXPECT_NOT_NULL(cert_chain = malloc(S2N_MAX_TEST_PEM_SIZE)); EXPECT_NOT_NULL(private_key = malloc(S2N_MAX_TEST_PEM_SIZE)); EXPECT_NOT_NULL(client_chain = malloc(S2N_MAX_TEST_PEM_SIZE)); EXPECT_NOT_NULL(server_config = s2n_config_new()); EXPECT_SUCCESS(s2n_read_test_pem(S2N_RSA_2048_PKCS1_CERT_CHAIN, cert_chain, S2N_MAX_TEST_PEM_SIZE)); EXPECT_SUCCESS(s2n_read_test_pem(S2N_RSA_2048_PKCS1_KEY, private_key, S2N_MAX_TEST_PEM_SIZE)); EXPECT_SUCCESS(s2n_read_test_pem(S2N_RSA_2048_PKCS1_LEAF_CERT, client_chain, S2N_MAX_TEST_PEM_SIZE)); struct s2n_cert_chain_and_key *chain_and_key; EXPECT_NOT_NULL(chain_and_key = s2n_cert_chain_and_key_new()); EXPECT_SUCCESS(s2n_cert_chain_and_key_load_pem(chain_and_key, cert_chain, private_key)); EXPECT_SUCCESS(s2n_config_add_cert_chain_and_key_to_store(server_config, chain_and_key)); EXPECT_SUCCESS(s2n_connection_set_config(server_conn, server_config)); GUARD(s2n_set_signature_hash_pair_from_preference_list(server_conn, &server_conn->handshake_params.client_sig_hash_algs, &server_conn->secure.conn_hash_alg, &server_conn->secure.conn_sig_alg)); DEFER_CLEANUP(struct s2n_stuffer certificate_in = {{0}}, s2n_stuffer_free); EXPECT_SUCCESS(s2n_stuffer_alloc(&certificate_in, S2N_MAX_TEST_PEM_SIZE)); DEFER_CLEANUP(struct s2n_stuffer certificate_out = {{0}}, s2n_stuffer_free); EXPECT_SUCCESS(s2n_stuffer_alloc(&certificate_out, S2N_MAX_TEST_PEM_SIZE)); struct s2n_blob temp_blob; temp_blob.data = (uint8_t *) client_chain; temp_blob.size = strlen(client_chain) + 1; EXPECT_SUCCESS(s2n_stuffer_write(&certificate_in, &temp_blob)); EXPECT_SUCCESS(s2n_stuffer_certificate_from_pem(&certificate_in, &certificate_out)); temp_blob.size = s2n_stuffer_data_available(&certificate_out); temp_blob.data = s2n_stuffer_raw_read(&certificate_out, temp_blob.size); s2n_cert_type cert_type; EXPECT_SUCCESS(s2n_asn1der_to_public_key_and_type(&client_conn->secure.server_public_key, &cert_type, &temp_blob)); server_conn->handshake_params.our_chain_and_key = chain_and_key; EXPECT_SUCCESS(setup_connection(server_conn)); EXPECT_SUCCESS(setup_connection(client_conn)); #if S2N_LIBCRYPTO_SUPPORTS_CUSTOM_RAND /* Read the seed from the RSP_FILE and create the DRBG for the test. Since the seed is the same (and prediction * resistance is off) all calls to generate random data will return the same sequence. Thus the server always * generates the same ECDHE point and KEM public key, the client does the same. */ FILE *kat_file = fopen(RSP_FILE_NAME, "r"); EXPECT_NOT_NULL(kat_file); EXPECT_SUCCESS(s2n_alloc(&kat_entropy_blob, 48)); EXPECT_SUCCESS(ReadHex(kat_file, kat_entropy_blob.data, 48, "seed = ")); struct s2n_drbg drbg = {.entropy_generator = &s2n_entropy_generator}; s2n_stack_blob(personalization_string, 32, 32); EXPECT_SUCCESS(s2n_drbg_instantiate(&drbg, &personalization_string, S2N_DANGEROUS_AES_256_CTR_NO_DF_NO_PR)); EXPECT_SUCCESS(s2n_set_private_drbg_for_test(drbg)); #endif /* Part 2 server sends key first */ EXPECT_SUCCESS(s2n_server_key_send(server_conn)); /* Part 2.1 verify the results as best we can */ EXPECT_EQUAL(server_conn->handshake.io.write_cursor, SERVER_KEY_MESSAGE_LENGTH); struct s2n_blob server_key_message = {.size = SERVER_KEY_MESSAGE_LENGTH, .data = s2n_stuffer_raw_read(&server_conn->handshake.io, SERVER_KEY_MESSAGE_LENGTH)}; #if S2N_LIBCRYPTO_SUPPORTS_CUSTOM_RAND /* Part 2.1.1 if we're running in known answer mode check the server's key exchange message matches the expected value */ uint8_t expected_server_key_message[SERVER_KEY_MESSAGE_LENGTH]; EXPECT_SUCCESS(ReadHex(kat_file, expected_server_key_message, SERVER_KEY_MESSAGE_LENGTH, "expected_server_key_exchange = ")); EXPECT_BYTEARRAY_EQUAL(expected_server_key_message, server_key_message.data, SERVER_KEY_MESSAGE_LENGTH); #endif /* Part 2.2 copy server's message to the client's stuffer */ s2n_stuffer_write(&client_conn->handshake.io, &server_key_message); /* Part 3 client recvs the server's key and sends the client key exchange message */ EXPECT_SUCCESS(s2n_server_key_recv(client_conn)); EXPECT_SUCCESS(s2n_client_key_send(client_conn)); /* Part 3.1 verify the results as best we can */ EXPECT_EQUAL(client_conn->handshake.io.write_cursor - client_conn->handshake.io.read_cursor, CLIENT_KEY_MESSAGE_LENGTH); struct s2n_blob client_key_message = {.size = CLIENT_KEY_MESSAGE_LENGTH, .data = s2n_stuffer_raw_read(&client_conn->handshake.io, CLIENT_KEY_MESSAGE_LENGTH)}; #if S2N_LIBCRYPTO_SUPPORTS_CUSTOM_RAND /* Part 3.1.1 if we're running in known answer mode check the client's key exchange message matches the expected value */ uint8_t expected_client_key_message[CLIENT_KEY_MESSAGE_LENGTH]; EXPECT_SUCCESS(ReadHex(kat_file, expected_client_key_message, CLIENT_KEY_MESSAGE_LENGTH, "expected_client_key_exchange = ")); EXPECT_BYTEARRAY_EQUAL(expected_client_key_message, client_key_message.data, CLIENT_KEY_MESSAGE_LENGTH); #endif /* Part 3.2 copy the client's message back to the server's stuffer */ s2n_stuffer_write(&server_conn->handshake.io, &client_key_message); /* Part 4 server receives the client's message */ EXPECT_SUCCESS(s2n_client_key_recv(server_conn)); /* Part 4.1 verify results as best we can, the client and server should at least have the same master secret */ EXPECT_BYTEARRAY_EQUAL(server_conn->secure.master_secret, client_conn->secure.master_secret, S2N_TLS_SECRET_LEN); #if S2N_LIBCRYPTO_SUPPORTS_CUSTOM_RAND /* Part 4.1.1 if we're running in known answer mode check that both the client and server got the expected master secret * from the RSP_FILE */ uint8_t expected_master_secret[S2N_TLS_SECRET_LEN]; EXPECT_SUCCESS(ReadHex(kat_file, expected_master_secret, S2N_TLS_SECRET_LEN, "expected_master_secret = ")); EXPECT_BYTEARRAY_EQUAL(expected_master_secret, client_conn->secure.master_secret, S2N_TLS_SECRET_LEN); EXPECT_BYTEARRAY_EQUAL(expected_master_secret, server_conn->secure.master_secret, S2N_TLS_SECRET_LEN); #endif EXPECT_SUCCESS(s2n_cert_chain_and_key_free(chain_and_key)); EXPECT_SUCCESS(s2n_connection_free(client_conn)); EXPECT_SUCCESS(s2n_connection_free(server_conn)); EXPECT_SUCCESS(s2n_config_free(server_config)); free(cert_chain); free(client_chain); free(private_key); #if S2N_LIBCRYPTO_SUPPORTS_CUSTOM_RAND /* Extra cleanup needed for the known answer test */ fclose(kat_file); #endif END_TEST(); }