static int s2n_composite_cipher_aes_sha_initial_hmac(struct s2n_session_key *key, uint8_t *sequence_number, uint8_t content_type, uint16_t protocol_version, uint16_t payload_and_eiv_len, int *extra) { uint8_t ctrl_buf[S2N_TLS12_AAD_LEN]; struct s2n_blob ctrl_blob = { .data = ctrl_buf, .size = S2N_TLS12_AAD_LEN }; struct s2n_stuffer ctrl_stuffer; GUARD(s2n_stuffer_init(&ctrl_stuffer, &ctrl_blob)); GUARD(s2n_stuffer_write_bytes(&ctrl_stuffer, sequence_number, S2N_TLS_SEQUENCE_NUM_LEN)); GUARD(s2n_stuffer_write_uint8(&ctrl_stuffer, content_type)); GUARD(s2n_stuffer_write_uint8(&ctrl_stuffer, protocol_version / 10)); GUARD(s2n_stuffer_write_uint8(&ctrl_stuffer, protocol_version % 10)); GUARD(s2n_stuffer_write_uint16(&ctrl_stuffer, payload_and_eiv_len)); /* This will unnecessarily mangle the input buffer, which is fine since it's temporary * Return value will be length of digest, padding, and padding length byte. * See https://github.com/openssl/openssl/blob/master/crypto/evp/e_aes_cbc_hmac_sha1.c#L814 * and https://github.com/openssl/openssl/blob/4f0c475719defd7c051964ef9964cc6e5b3a63bf/ssl/record/ssl3_record.c#L743 */ int ctrl_ret = EVP_CIPHER_CTX_ctrl(key->evp_cipher_ctx, EVP_CTRL_AEAD_TLS1_AAD, S2N_TLS12_AAD_LEN, ctrl_buf); if (ctrl_ret < 0) { S2N_ERROR(S2N_ERR_INITIAL_HMAC); } *extra = ctrl_ret; return 0; }
int s2n_server_hello_send(struct s2n_connection *conn) { uint32_t gmt_unix_time = time(NULL); struct s2n_stuffer *out = &conn->handshake.io; struct s2n_stuffer server_random; struct s2n_blob b, r; uint8_t session_id_len = 0; uint8_t protocol_version[S2N_TLS_PROTOCOL_VERSION_LEN]; b.data = conn->pending.server_random; b.size = S2N_TLS_RANDOM_DATA_LEN; /* Create the server random data */ GUARD(s2n_stuffer_init(&server_random, &b)); GUARD(s2n_stuffer_write_uint32(&server_random, gmt_unix_time)); r.data = s2n_stuffer_raw_write(&server_random, S2N_TLS_RANDOM_DATA_LEN - 4); r.size = S2N_TLS_RANDOM_DATA_LEN - 4; notnull_check(r.data); GUARD(s2n_get_public_random_data(&r)); conn->actual_protocol_version = MIN(conn->client_protocol_version, conn->server_protocol_version); protocol_version[0] = conn->actual_protocol_version / 10; protocol_version[1] = conn->actual_protocol_version % 10; conn->pending.signature_digest_alg = S2N_HASH_MD5_SHA1; if (conn->actual_protocol_version == S2N_TLS12) { conn->pending.signature_digest_alg = S2N_HASH_SHA1; } GUARD(s2n_stuffer_write_bytes(out, protocol_version, S2N_TLS_PROTOCOL_VERSION_LEN)); GUARD(s2n_stuffer_write_bytes(out, conn->pending.server_random, S2N_TLS_RANDOM_DATA_LEN)); GUARD(s2n_stuffer_write_uint8(out, session_id_len)); GUARD(s2n_stuffer_write_bytes(out, conn->pending.cipher_suite->value, S2N_TLS_CIPHER_SUITE_LEN)); GUARD(s2n_stuffer_write_uint8(out, S2N_TLS_COMPRESSION_METHOD_NULL)); GUARD(s2n_server_extensions_send(conn, out)); conn->actual_protocol_version_established = 1; return 0; }
int s2n_client_hello_send(struct s2n_connection *conn) { uint32_t gmt_unix_time = time(NULL); struct s2n_stuffer *out = &conn->handshake.io; struct s2n_stuffer client_random; struct s2n_blob b, r; uint8_t session_id_len = 0; uint8_t client_protocol_version[S2N_TLS_PROTOCOL_VERSION_LEN]; b.data = conn->secure.client_random; b.size = S2N_TLS_RANDOM_DATA_LEN; /* Create the client random data */ GUARD(s2n_stuffer_init(&client_random, &b)); GUARD(s2n_stuffer_write_uint32(&client_random, gmt_unix_time)); r.data = s2n_stuffer_raw_write(&client_random, S2N_TLS_RANDOM_DATA_LEN - 4); r.size = S2N_TLS_RANDOM_DATA_LEN - 4; notnull_check(r.data); GUARD(s2n_get_public_random_data(&r)); client_protocol_version[0] = conn->client_protocol_version / 10; client_protocol_version[1] = conn->client_protocol_version % 10; conn->client_hello_version = conn->client_protocol_version; GUARD(s2n_stuffer_write_bytes(out, client_protocol_version, S2N_TLS_PROTOCOL_VERSION_LEN)); GUARD(s2n_stuffer_copy(&client_random, out, S2N_TLS_RANDOM_DATA_LEN)); GUARD(s2n_stuffer_write_uint8(out, session_id_len)); GUARD(s2n_stuffer_write_uint16(out, conn->config->cipher_preferences->count * S2N_TLS_CIPHER_SUITE_LEN)); GUARD(s2n_stuffer_write_bytes(out, conn->config->cipher_preferences->wire_format, conn->config->cipher_preferences->count * S2N_TLS_CIPHER_SUITE_LEN)); /* Zero compression methods */ GUARD(s2n_stuffer_write_uint8(out, 1)); GUARD(s2n_stuffer_write_uint8(out, 0)); /* Write the extensions */ GUARD(s2n_client_extensions_send(conn, out)); return 0; }
int s2n_client_finished_send(struct s2n_connection *conn) { uint8_t *our_version; GUARD(s2n_prf_key_expansion(conn)); GUARD(s2n_prf_client_finished(conn)); struct s2n_blob seq = {.data = conn->pending.client_sequence_number, .size = sizeof(conn->pending.client_sequence_number) }; GUARD(s2n_blob_zero(&seq)); our_version = conn->handshake.client_finished; /* Update the client to use the pending cipher suite */ conn->client = &conn->pending; if (conn->actual_protocol_version == S2N_SSLv3) { GUARD(s2n_stuffer_write_bytes(&conn->handshake.io, our_version, S2N_SSL_FINISHED_LEN)); } else { GUARD(s2n_stuffer_write_bytes(&conn->handshake.io, our_version, S2N_TLS_FINISHED_LEN)); } conn->handshake.next_state = SERVER_CHANGE_CIPHER_SPEC; return 0; }
static int s2n_stuffer_pem_read_contents(struct s2n_stuffer *pem, struct s2n_stuffer *asn1) { uint8_t base64_buf[64] = { 0 }; struct s2n_blob base64__blob = { .data = base64_buf, .size = sizeof(base64_buf) }; struct s2n_stuffer base64_stuffer = {{0}}; GUARD(s2n_stuffer_init(&base64_stuffer, &base64__blob)); while (1) { char c; /* Peek to see if the next char is a dash, meaning end of pem_contents */ GUARD(s2n_stuffer_peek_char(pem, &c)); if (c == '-') { break; } else { /* Else, move read pointer forward by 1 byte since we will be consuming it. */ GUARD(s2n_stuffer_skip_read(pem, 1)); } /* Skip non-base64 characters */ if (!s2n_is_base64_char(c)) { continue; } /* Flush base64_stuffer to asn1 stuffer if we're out of space, and reset base64_stuffer read/write pointers */ if (s2n_stuffer_space_remaining(&base64_stuffer) == 0) { GUARD(s2n_stuffer_read_base64(&base64_stuffer, asn1)); GUARD(s2n_stuffer_rewrite(&base64_stuffer)); } /* Copy next char to base64_stuffer */ GUARD(s2n_stuffer_write_bytes(&base64_stuffer, (uint8_t *) &c, 1)); }; /* Flush any remaining bytes to asn1 */ GUARD(s2n_stuffer_read_base64(&base64_stuffer, asn1)); return 0; } static int s2n_stuffer_data_from_pem(struct s2n_stuffer *pem, struct s2n_stuffer *asn1, const char *keyword) { GUARD(s2n_stuffer_pem_read_begin(pem, keyword)); GUARD(s2n_stuffer_pem_read_contents(pem, asn1)); GUARD(s2n_stuffer_pem_read_end(pem, keyword)); return 0; }
/* Due to the need to support some older assemblers, * we cannot use either the compiler intrinsics or * the RDRAND assembly mnemonic. For this reason, * we're using the opcode directly (0F C7/6). This * stores the result in eax. * * volatile is important to prevent the compiler from * re-ordering or optimizing the use of RDRAND. */ int s2n_get_rdrand_data(struct s2n_blob *out) { #if defined(__x86_64__)||defined(__i386__) int space_remaining = 0; struct s2n_stuffer stuffer; union { uint64_t u64; uint8_t u8[8]; } output; GUARD(s2n_stuffer_init(&stuffer, out)); while((space_remaining = s2n_stuffer_space_remaining(&stuffer))) { int success = 0; for (int tries = 0; tries < 10; tries++) { __asm__ __volatile__( ".byte 0x48;\n" ".byte 0x0f;\n" ".byte 0xc7;\n" ".byte 0xf0;\n" "adcl $0x00, %%ebx;\n" :"=b"(success), "=a"(output.u64) :"b"(0) :"cc" ); if (success) { break; } } if (!success) { return -1; } int data_to_fill = MIN(sizeof(output), space_remaining); GUARD(s2n_stuffer_write_bytes(&stuffer, output.u8, data_to_fill)); } return 0; #else return -1; #endif }
int s2n_record_write_protocol_version(struct s2n_connection *conn) { uint8_t record_protocol_version = conn->actual_protocol_version; if (conn->server_protocol_version == s2n_unknown_protocol_version) { /* Some legacy TLS implementations can't handle records with protocol version higher than TLS1.0. * To provide maximum compatibility, send record version as TLS1.0 if server protocol version isn't * established yet, which happens only during ClientHello message. Note, this has no effect on * protocol version in ClientHello, so we're still able to negotiate protocol versions above TLS1.0 */ record_protocol_version = MIN(record_protocol_version, S2N_TLS10); } uint8_t protocol_version[S2N_TLS_PROTOCOL_VERSION_LEN]; protocol_version[0] = record_protocol_version / 10; protocol_version[1] = record_protocol_version % 10; GUARD(s2n_stuffer_write_bytes(&conn->out, protocol_version, S2N_TLS_PROTOCOL_VERSION_LEN)); return 0; }
int s2n_record_write(struct s2n_connection *conn, uint8_t content_type, struct s2n_blob *in) { struct s2n_blob out, iv, aad; uint8_t padding = 0; uint16_t block_size = 0; uint8_t aad_gen[S2N_TLS_MAX_AAD_LEN] = { 0 }; uint8_t aad_iv[S2N_TLS_MAX_IV_LEN] = { 0 }; uint8_t *sequence_number = conn->server->server_sequence_number; struct s2n_hmac_state *mac = &conn->server->server_record_mac; struct s2n_session_key *session_key = &conn->server->server_key; const struct s2n_cipher_suite *cipher_suite = conn->server->cipher_suite; uint8_t *implicit_iv = conn->server->server_implicit_iv; if (conn->mode == S2N_CLIENT) { sequence_number = conn->client->client_sequence_number; mac = &conn->client->client_record_mac; session_key = &conn->client->client_key; cipher_suite = conn->client->cipher_suite; implicit_iv = conn->client->client_implicit_iv; } S2N_ERROR_IF(s2n_stuffer_data_available(&conn->out), S2N_ERR_BAD_MESSAGE); uint8_t mac_digest_size; GUARD(s2n_hmac_digest_size(mac->alg, &mac_digest_size)); /* Before we do anything, we need to figure out what the length of the * fragment is going to be. */ uint16_t data_bytes_to_take = MIN(in->size, s2n_record_max_write_payload_size(conn)); uint16_t extra = overhead(conn); /* If we have padding to worry about, figure that out too */ if (cipher_suite->record_alg->cipher->type == S2N_CBC) { block_size = cipher_suite->record_alg->cipher->io.cbc.block_size; if (((data_bytes_to_take + extra) % block_size)) { padding = block_size - ((data_bytes_to_take + extra) % block_size); } } else if (cipher_suite->record_alg->cipher->type == S2N_COMPOSITE) { block_size = cipher_suite->record_alg->cipher->io.comp.block_size; } /* Start the MAC with the sequence number */ GUARD(s2n_hmac_update(mac, sequence_number, S2N_TLS_SEQUENCE_NUM_LEN)); /* Now that we know the length, start writing the record */ GUARD(s2n_stuffer_write_uint8(&conn->out, content_type)); GUARD(s2n_record_write_protocol_version(conn)); /* First write a header that has the payload length, this is for the MAC */ GUARD(s2n_stuffer_write_uint16(&conn->out, data_bytes_to_take)); if (conn->actual_protocol_version > S2N_SSLv3) { GUARD(s2n_hmac_update(mac, conn->out.blob.data, S2N_TLS_RECORD_HEADER_LENGTH)); } else { /* SSLv3 doesn't include the protocol version in the MAC */ GUARD(s2n_hmac_update(mac, conn->out.blob.data, 1)); GUARD(s2n_hmac_update(mac, conn->out.blob.data + 3, 2)); } /* Compute non-payload parts of the MAC(seq num, type, proto vers, fragment length) for composite ciphers. * Composite "encrypt" will MAC the payload data and fill in padding. */ if (cipher_suite->record_alg->cipher->type == S2N_COMPOSITE) { /* Only fragment length is needed for MAC, but the EVP ctrl function needs fragment length + eiv len. */ uint16_t payload_and_eiv_len = data_bytes_to_take; if (conn->actual_protocol_version > S2N_TLS10) { payload_and_eiv_len += block_size; } /* Outputs number of extra bytes required for MAC and padding */ int pad_and_mac_len; GUARD(cipher_suite->record_alg->cipher->io.comp.initial_hmac(session_key, sequence_number, content_type, conn->actual_protocol_version, payload_and_eiv_len, &pad_and_mac_len)); extra += pad_and_mac_len; } /* Rewrite the length to be the actual fragment length */ uint16_t actual_fragment_length = data_bytes_to_take + padding + extra; GUARD(s2n_stuffer_wipe_n(&conn->out, 2)); GUARD(s2n_stuffer_write_uint16(&conn->out, actual_fragment_length)); /* If we're AEAD, write the sequence number as an IV, and generate the AAD */ if (cipher_suite->record_alg->cipher->type == S2N_AEAD) { struct s2n_stuffer iv_stuffer = {{0}}; iv.data = aad_iv; iv.size = sizeof(aad_iv); GUARD(s2n_stuffer_init(&iv_stuffer, &iv)); if (cipher_suite->record_alg->flags & S2N_TLS12_AES_GCM_AEAD_NONCE) { /* Partially explicit nonce. See RFC 5288 Section 3 */ GUARD(s2n_stuffer_write_bytes(&conn->out, sequence_number, S2N_TLS_SEQUENCE_NUM_LEN)); GUARD(s2n_stuffer_write_bytes(&iv_stuffer, implicit_iv, cipher_suite->record_alg->cipher->io.aead.fixed_iv_size)); GUARD(s2n_stuffer_write_bytes(&iv_stuffer, sequence_number, S2N_TLS_SEQUENCE_NUM_LEN)); } else if (cipher_suite->record_alg->flags & S2N_TLS12_CHACHA_POLY_AEAD_NONCE) { /* Fully implicit nonce. See RFC7905 Section 2 */ uint8_t four_zeroes[4] = { 0 }; GUARD(s2n_stuffer_write_bytes(&iv_stuffer, four_zeroes, 4)); GUARD(s2n_stuffer_write_bytes(&iv_stuffer, sequence_number, S2N_TLS_SEQUENCE_NUM_LEN)); for(int i = 0; i < cipher_suite->record_alg->cipher->io.aead.fixed_iv_size; i++) { aad_iv[i] = aad_iv[i] ^ implicit_iv[i]; } } else { S2N_ERROR(S2N_ERR_INVALID_NONCE_TYPE); } /* Set the IV size to the amount of data written */ iv.size = s2n_stuffer_data_available(&iv_stuffer); aad.data = aad_gen; aad.size = sizeof(aad_gen); struct s2n_stuffer ad_stuffer = {{0}}; GUARD(s2n_stuffer_init(&ad_stuffer, &aad)); GUARD(s2n_aead_aad_init(conn, sequence_number, content_type, data_bytes_to_take, &ad_stuffer)); } else if (cipher_suite->record_alg->cipher->type == S2N_CBC || cipher_suite->record_alg->cipher->type == S2N_COMPOSITE) { iv.size = block_size; iv.data = implicit_iv; /* For TLS1.1/1.2; write the IV with random data */ if (conn->actual_protocol_version > S2N_TLS10) { GUARD(s2n_get_public_random_data(&iv)); GUARD(s2n_stuffer_write(&conn->out, &iv)); } } /* We are done with this sequence number, so we can increment it */ struct s2n_blob seq = {.data = sequence_number,.size = S2N_TLS_SEQUENCE_NUM_LEN }; GUARD(s2n_increment_sequence_number(&seq)); /* Write the plaintext data */ out.data = in->data; out.size = data_bytes_to_take; GUARD(s2n_stuffer_write(&conn->out, &out)); GUARD(s2n_hmac_update(mac, out.data, out.size)); /* Write the digest */ uint8_t *digest = s2n_stuffer_raw_write(&conn->out, mac_digest_size); notnull_check(digest); GUARD(s2n_hmac_digest(mac, digest, mac_digest_size)); GUARD(s2n_hmac_reset(mac)); if (cipher_suite->record_alg->cipher->type == S2N_CBC) { /* Include padding bytes, each with the value 'p', and * include an extra padding length byte, also with the value 'p'. */ for (int i = 0; i <= padding; i++) { GUARD(s2n_stuffer_write_uint8(&conn->out, padding)); } } /* Rewind to rewrite/encrypt the packet */ GUARD(s2n_stuffer_rewrite(&conn->out)); /* Skip the header */ GUARD(s2n_stuffer_skip_write(&conn->out, S2N_TLS_RECORD_HEADER_LENGTH)); uint16_t encrypted_length = data_bytes_to_take + mac_digest_size; switch (cipher_suite->record_alg->cipher->type) { case S2N_AEAD: GUARD(s2n_stuffer_skip_write(&conn->out, cipher_suite->record_alg->cipher->io.aead.record_iv_size)); encrypted_length += cipher_suite->record_alg->cipher->io.aead.tag_size; break; case S2N_CBC: if (conn->actual_protocol_version > S2N_TLS10) { /* Leave the IV alone and unencrypted */ GUARD(s2n_stuffer_skip_write(&conn->out, iv.size)); } /* Encrypt the padding and the padding length byte too */ encrypted_length += padding + 1; break; case S2N_COMPOSITE: /* Composite CBC expects a pointer starting at explicit IV: [Explicit IV | fragment | MAC | padding | padding len ] * extra will account for the explicit IV len(if applicable), MAC digest len, padding len + padding byte. */ encrypted_length += extra; break; default: break; } /* Do the encryption */ struct s2n_blob en = {0}; en.size = encrypted_length; en.data = s2n_stuffer_raw_write(&conn->out, en.size); notnull_check(en.data); switch (cipher_suite->record_alg->cipher->type) { case S2N_STREAM: GUARD(cipher_suite->record_alg->cipher->io.stream.encrypt(session_key, &en, &en)); break; case S2N_CBC: GUARD(cipher_suite->record_alg->cipher->io.cbc.encrypt(session_key, &iv, &en, &en)); /* Copy the last encrypted block to be the next IV */ if (conn->actual_protocol_version < S2N_TLS11) { gte_check(en.size, block_size); memcpy_check(implicit_iv, en.data + en.size - block_size, block_size); } break; case S2N_AEAD: GUARD(cipher_suite->record_alg->cipher->io.aead.encrypt(session_key, &iv, &aad, &en, &en)); break; case S2N_COMPOSITE: /* This will: compute mac, append padding, append padding length, and encrypt */ GUARD(cipher_suite->record_alg->cipher->io.comp.encrypt(session_key, &iv, &en, &en)); /* Copy the last encrypted block to be the next IV */ gte_check(en.size, block_size); memcpy_check(implicit_iv, en.data + en.size - block_size, block_size); break; default: S2N_ERROR(S2N_ERR_CIPHER_TYPE); break; } conn->wire_bytes_out += actual_fragment_length + S2N_TLS_RECORD_HEADER_LENGTH; return data_bytes_to_take; }
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 s2n_server_extensions_send(struct s2n_connection *conn, struct s2n_stuffer *out) { uint16_t total_size = 0; uint8_t application_protocol_len = strlen(conn->application_protocol); if (application_protocol_len) { total_size += 7 + application_protocol_len; } if (s2n_server_can_send_ocsp(conn)) { total_size += 4; } if (conn->secure_renegotiation) { total_size += 5; } if (conn->secure.cipher_suite->key_exchange_alg->flags & S2N_KEY_EXCHANGE_ECC) { total_size += 6; } if (total_size == 0) { return 0; } GUARD(s2n_stuffer_write_uint16(out, total_size)); /* Write the Supported Points Format extention. * RFC 4492 section 5.2 states that the absence of this extension in the Server Hello * is equivalent to allowing only the uncompressed point format. Let's send the * extension in case clients(Openssl 1.0.0) don't honor the implied behavior. */ if (conn->secure.cipher_suite->key_exchange_alg->flags & S2N_KEY_EXCHANGE_ECC) { GUARD(s2n_stuffer_write_uint16(out, TLS_EXTENSION_EC_POINT_FORMATS)); /* Total extension length */ GUARD(s2n_stuffer_write_uint16(out, 2)); /* Format list length */ GUARD(s2n_stuffer_write_uint8(out, 1)); /* Only uncompressed format is supported. Interoperability shouldn't be an issue: * RFC 4492 Section 5.1.2: Implementations must support it for all of their curves. */ GUARD(s2n_stuffer_write_uint8(out, TLS_EC_FORMAT_UNCOMPRESSED)); } /* Write the renegotiation_info extension */ if (conn->secure_renegotiation) { GUARD(s2n_stuffer_write_uint16(out, TLS_EXTENSION_RENEGOTIATION_INFO)); /* renegotiation_info length */ GUARD(s2n_stuffer_write_uint16(out, 1)); /* renegotiated_connection length. Zero since we don't support renegotiation. */ GUARD(s2n_stuffer_write_uint8(out, 0)); } /* Write ALPN extension */ if (application_protocol_len) { GUARD(s2n_stuffer_write_uint16(out, TLS_EXTENSION_ALPN)); GUARD(s2n_stuffer_write_uint16(out, application_protocol_len + 3)); GUARD(s2n_stuffer_write_uint16(out, application_protocol_len + 1)); GUARD(s2n_stuffer_write_uint8(out, application_protocol_len)); GUARD(s2n_stuffer_write_bytes(out, (uint8_t *) conn->application_protocol, application_protocol_len)); } /* Write OCSP extension */ if (s2n_server_can_send_ocsp(conn)) { GUARD(s2n_stuffer_write_uint16(out, TLS_EXTENSION_STATUS_REQUEST)); GUARD(s2n_stuffer_write_uint16(out, 0)); } return 0; }
int s2n_stuffer_write_uint8(struct s2n_stuffer *stuffer, const uint8_t u) { GUARD(s2n_stuffer_write_bytes(stuffer, &u, 1)); return 0; }
int s2n_stuffer_write(struct s2n_stuffer *stuffer, const struct s2n_blob *in) { return s2n_stuffer_write_bytes(stuffer, in->data, in->size); }
{ uint8_t data[2]; GUARD(s2n_stuffer_read_bytes(stuffer, data, sizeof(data))); *u = data[0] << 8; *u |= data[1]; return 0; } int s2n_stuffer_write_uint16(struct s2n_stuffer *stuffer, const uint16_t u) { uint8_t data[2] = { u >> 8, u & 0xff }; GUARD(s2n_stuffer_write_bytes(stuffer, data, sizeof(data))); return 0; } int s2n_stuffer_read_uint24(struct s2n_stuffer *stuffer, uint32_t *u) { uint8_t data[3]; GUARD(s2n_stuffer_read_bytes(stuffer, data, sizeof(data))); *u = data[0] << 16; *u |= data[1] << 8; *u |= data[2]; return 0;