Пример #1
0
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;
}
Пример #2
0
int s2n_server_key_send(struct s2n_connection *conn)
{
    struct s2n_hash_state *signature_hash = &conn->secure.signature_hash;
    const struct s2n_kex *key_exchange = conn->secure.cipher_suite->key_exchange_alg;
    struct s2n_stuffer *out = &conn->handshake.io;
    struct s2n_blob data_to_sign = {0};

    /* Call the negotiated key exchange method to send it's data */
    GUARD(s2n_kex_server_key_send(key_exchange, conn, &data_to_sign));

    /* Add common signature data */
    if (conn->actual_protocol_version == S2N_TLS12) {
        GUARD(s2n_stuffer_write_uint8(out, s2n_hash_alg_to_tls[ conn->secure.conn_hash_alg ]));
        GUARD(s2n_stuffer_write_uint8(out, conn->secure.conn_sig_alg));
    }

    /* Add the random data to the hash */
    GUARD(s2n_hash_init(signature_hash, conn->secure.conn_hash_alg));
    GUARD(s2n_hash_update(signature_hash, conn->secure.client_random, S2N_TLS_RANDOM_DATA_LEN));
    GUARD(s2n_hash_update(signature_hash, conn->secure.server_random, S2N_TLS_RANDOM_DATA_LEN));

    /* Add KEX specific data to the hash */
    GUARD(s2n_hash_update(signature_hash, data_to_sign.data, data_to_sign.size));

    /* Sign and write the signature */
    GUARD(s2n_write_signature_blob(out, conn->handshake_params.our_chain_and_key->private_key, signature_hash));
    return 0;
}
Пример #3
0
int s2n_send_client_signature_algorithms(struct s2n_stuffer *out)
{
    /* The array of hashes and signature algorithms we support */
    uint16_t preferred_hashes_len = sizeof(s2n_preferred_hashes) / sizeof(s2n_preferred_hashes[0]);
    uint16_t preferred_hashes_size = preferred_hashes_len * 2;
    GUARD(s2n_stuffer_write_uint16(out, preferred_hashes_size));

    for (int i =  0; i < preferred_hashes_len; i++) {
        GUARD(s2n_stuffer_write_uint8(out, s2n_preferred_hashes[i]));
        GUARD(s2n_stuffer_write_uint8(out, TLS_SIGNATURE_ALGORITHM_RSA));
    }
    return 0;
}
Пример #4
0
int s2n_client_ccs_recv(struct s2n_connection *conn)
{
    uint8_t type;

    GUARD(s2n_prf_client_finished(conn));

    struct s2n_blob seq = {.data = conn->secure.client_sequence_number,.size = sizeof(conn->secure.client_sequence_number) };
    GUARD(s2n_blob_zero(&seq));

    /* Update the client to use the cipher-suite */
    conn->client = &conn->secure;

    GUARD(s2n_stuffer_read_uint8(&conn->handshake.io, &type));
    S2N_ERROR_IF(type != CHANGE_CIPHER_SPEC_TYPE, S2N_ERR_BAD_MESSAGE);

    /* Flush any partial alert messages that were pending */
    GUARD(s2n_stuffer_wipe(&conn->alert_in));

    return 0;
}

int s2n_client_ccs_send(struct s2n_connection *conn)
{
    GUARD(s2n_stuffer_write_uint8(&conn->handshake.io, CHANGE_CIPHER_SPEC_TYPE));

    return 0;
}
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));
}
Пример #6
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;
}
Пример #7
0
int s2n_server_status_send(struct s2n_connection *conn)
{
    uint32_t length = conn->config->cert_and_key_pairs->ocsp_status.size + 4;
    GUARD(s2n_stuffer_write_uint24(&conn->handshake.io, length));

    GUARD(s2n_stuffer_write_uint8(&conn->handshake.io, (uint8_t)S2N_STATUS_REQUEST_OCSP));
    GUARD(s2n_stuffer_write_uint24(&conn->handshake.io, conn->config->cert_and_key_pairs->ocsp_status.size));
    GUARD(s2n_stuffer_write(&conn->handshake.io, &conn->config->cert_and_key_pairs->ocsp_status));

    return 0;
}
Пример #8
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;
}
static int s2n_dhe_server_key_send(struct s2n_connection *conn)
{
    struct s2n_blob serverDHparams, signature;
    struct s2n_stuffer *out = &conn->handshake.io;
    struct s2n_hash_state signature_hash;

    /* Duplicate the DH key from the config */
    GUARD(s2n_dh_params_copy(conn->config->dhparams, &conn->secure.server_dh_params));

    /* Generate an ephemeral key */
    GUARD(s2n_dh_generate_ephemeral_key(&conn->secure.server_dh_params));

    /* Write it out */
    GUARD(s2n_dh_params_to_p_g_Ys(&conn->secure.server_dh_params, out, &serverDHparams));

    if (conn->actual_protocol_version == S2N_TLS12) {
        GUARD(s2n_stuffer_write_uint8(out, TLS_HASH_ALGORITHM_SHA1));
        GUARD(s2n_stuffer_write_uint8(out, TLS_SIGNATURE_ALGORITHM_RSA));
    }

    GUARD(s2n_hash_init(&signature_hash, conn->secure.signature_digest_alg));
    GUARD(s2n_hash_update(&signature_hash, conn->secure.client_random, S2N_TLS_RANDOM_DATA_LEN));
    GUARD(s2n_hash_update(&signature_hash, conn->secure.server_random, S2N_TLS_RANDOM_DATA_LEN));
    GUARD(s2n_hash_update(&signature_hash, serverDHparams.data, serverDHparams.size));

    signature.size = s2n_rsa_private_encrypted_size(&conn->config->cert_and_key_pairs->private_key);
    GUARD(s2n_stuffer_write_uint16(out, signature.size));

    signature.data = s2n_stuffer_raw_write(out, signature.size);
    notnull_check(signature.data);

    if (s2n_rsa_sign(&conn->config->cert_and_key_pairs->private_key, &signature_hash, &signature) < 0) {
        S2N_ERROR(S2N_ERR_DH_FAILED_SIGNING);
    }

    return 0;
}
Пример #10
0
int s2n_handshake_write_header(struct s2n_connection *conn, uint8_t message_type)
{
    if (s2n_stuffer_data_available(&conn->handshake.io)) {
        S2N_ERROR(S2N_ERR_HANDSHAKE_STATE);
    }

    /* Write the message header */
    GUARD(s2n_stuffer_write_uint8(&conn->handshake.io, message_type));

    /* Leave the length blank for now */
    uint16_t length = 0;
    GUARD(s2n_stuffer_write_uint24(&conn->handshake.io, length));

    return 0;
}
Пример #11
0
int s2n_server_status_send(struct s2n_connection *conn)
{
    uint32_t length = conn->config->cert_and_key_pairs->ocsp_status.size + 4;
    GUARD(s2n_stuffer_write_uint24(&conn->handshake.io, length));

    GUARD(s2n_stuffer_write_uint8(&conn->handshake.io, (uint8_t)S2N_STATUS_REQUEST_OCSP));
    GUARD(s2n_stuffer_write_uint24(&conn->handshake.io, conn->config->cert_and_key_pairs->ocsp_status.size));
    GUARD(s2n_stuffer_write(&conn->handshake.io, &conn->config->cert_and_key_pairs->ocsp_status));

    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;
}
Пример #12
0
/**
 * Helper function: read n bits of hex data.
 */
static int s2n_stuffer_read_n_bits_hex(struct s2n_stuffer *stuffer, uint8_t n, uint64_t *u)
{
    uint8_t hex_data[16];
    struct s2n_blob b = { .data = hex_data, .size = n / 4 };

    GUARD(s2n_stuffer_read(stuffer, &b));

    /* Start with u = 0 */
    *u = 0;

    for (int i = 0; i < b.size; i++) {
        *u <<= 4;
        if (b.data[i] >= '0' && b.data[i] <= '9') {
            *u |= b.data[i] - '0';
        } else if (b.data[i] >= 'a' && b.data[i] <= 'f') {
            *u |= b.data[i] - 'a' + 10;
        } else if (b.data[i] >= 'A' && b.data[i] <= 'F') {
            *u |= b.data[i] - 'A' + 10;
        } else {
            S2N_ERROR(S2N_ERR_BAD_MESSAGE);
        }
    }

    return 0;
}

int s2n_stuffer_read_hex(struct s2n_stuffer *stuffer, struct s2n_stuffer *out, uint32_t n)
{
    gte_check(s2n_stuffer_space_remaining(out), n);

    for (int i = 0; i < n; i++) {
        uint8_t c;
        GUARD(s2n_stuffer_read_uint8_hex(stuffer, &c));
        GUARD(s2n_stuffer_write_uint8(out, c));
    }

    return 0;
}
Пример #13
0
int s2n_kem_server_key_send(struct s2n_connection *conn, struct s2n_blob *data_to_sign)
{
    struct s2n_stuffer *out = &conn->handshake.io;
    const struct s2n_kem *kem = conn->secure.s2n_kem_keys.negotiated_kem;

    data_to_sign->data = s2n_stuffer_raw_write(out, 0);
    notnull_check(data_to_sign->data);

    GUARD(s2n_stuffer_write_uint8(out, kem->kem_extension_id));
    GUARD(s2n_stuffer_write_uint16(out, kem->public_key_length));

    /* The public key is not needed after this method, write it straight to the stuffer */
    struct s2n_blob *public_key = &conn->secure.s2n_kem_keys.public_key;
    public_key->data = s2n_stuffer_raw_write(out, kem->public_key_length);
    notnull_check(public_key->data);
    public_key->size = kem->public_key_length;

    GUARD(s2n_kem_generate_keypair(&conn->secure.s2n_kem_keys));

    data_to_sign->size = sizeof(kem_extension_size) + sizeof(kem_public_key_size) +  public_key->size;

    return 0;
}
Пример #14
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;
}
Пример #15
0
int s2n_client_extensions_send(struct s2n_connection *conn, struct s2n_stuffer *out)
{
    uint16_t total_size = 0;

    /* Signature algorithms */
    if (conn->actual_protocol_version == S2N_TLS12) {
        total_size += (sizeof(s2n_preferred_hashes) * 2) + 6;
    }

    uint16_t application_protocols_len = conn->config->application_protocols.size;
    uint16_t server_name_len = strlen(conn->server_name);
    uint16_t mfl_code_len = sizeof(conn->config->mfl_code);

    if (server_name_len) {
        total_size += 9 + server_name_len;
    }
    if (application_protocols_len) {
        total_size += 6 + application_protocols_len;
    }
    if (conn->config->status_request_type != S2N_STATUS_REQUEST_NONE) {
        total_size += 9;
    }
    if (conn->config->ct_type != S2N_CT_SUPPORT_NONE) {
        total_size += 4;
    }
    if (conn->config->mfl_code != S2N_TLS_MAX_FRAG_LEN_EXT_NONE) {
        total_size += 5;
    }

    /* Write ECC extensions: Supported Curves and Supported Point Formats */
    int ec_curves_count = sizeof(s2n_ecc_supported_curves) / sizeof(s2n_ecc_supported_curves[0]);
    total_size += 12 + ec_curves_count * 2;

    GUARD(s2n_stuffer_write_uint16(out, total_size));

    if (conn->actual_protocol_version == S2N_TLS12) {
        GUARD(s2n_send_client_signature_algorithms_extension(conn, out));
    }

    if (server_name_len) {
        /* Write the server name */
        GUARD(s2n_stuffer_write_uint16(out, TLS_EXTENSION_SERVER_NAME));
        GUARD(s2n_stuffer_write_uint16(out, server_name_len + 5));

        /* Size of all of the server names */
        GUARD(s2n_stuffer_write_uint16(out, server_name_len + 3));

        /* Name type - host name, RFC3546 */
        GUARD(s2n_stuffer_write_uint8(out, 0));

        struct s2n_blob server_name;
        server_name.data = (uint8_t *) conn->server_name;
        server_name.size = server_name_len;
        GUARD(s2n_stuffer_write_uint16(out, server_name_len));
        GUARD(s2n_stuffer_write(out, &server_name));
    }

    /* Write ALPN extension */
    if (application_protocols_len) {
        GUARD(s2n_stuffer_write_uint16(out, TLS_EXTENSION_ALPN));
        GUARD(s2n_stuffer_write_uint16(out, application_protocols_len + 2));
        GUARD(s2n_stuffer_write_uint16(out, application_protocols_len));
        GUARD(s2n_stuffer_write(out, &conn->config->application_protocols));
    }

    if (conn->config->status_request_type != S2N_STATUS_REQUEST_NONE) {
        /* We only support OCSP */
        eq_check(conn->config->status_request_type, S2N_STATUS_REQUEST_OCSP);
        GUARD(s2n_stuffer_write_uint16(out, TLS_EXTENSION_STATUS_REQUEST));
        GUARD(s2n_stuffer_write_uint16(out, 5));
        GUARD(s2n_stuffer_write_uint8(out, (uint8_t) conn->config->status_request_type));
        GUARD(s2n_stuffer_write_uint16(out, 0));
        GUARD(s2n_stuffer_write_uint16(out, 0));
    }

    /* Write Certificate Transparency extension */
    if (conn->config->ct_type != S2N_CT_SUPPORT_NONE) {
        GUARD(s2n_stuffer_write_uint16(out, TLS_EXTENSION_SCT_LIST));
        GUARD(s2n_stuffer_write_uint16(out, 0));
    }

    /* Write Maximum Fragmentation Length extension */
    if (conn->config->mfl_code != S2N_TLS_MAX_FRAG_LEN_EXT_NONE) {
        GUARD(s2n_stuffer_write_uint16(out, TLS_EXTENSION_MAX_FRAG_LEN));
        GUARD(s2n_stuffer_write_uint16(out, mfl_code_len));
        GUARD(s2n_stuffer_write_uint8(out, conn->config->mfl_code));
    }

    /*
     * RFC 4492: Clients SHOULD send both the Supported Elliptic Curves Extension
     * and the Supported Point Formats Extension.
     */
    {
        GUARD(s2n_stuffer_write_uint16(out, TLS_EXTENSION_ELLIPTIC_CURVES));
        GUARD(s2n_stuffer_write_uint16(out, 2 + ec_curves_count * 2));
        /* Curve list len */
        GUARD(s2n_stuffer_write_uint16(out, ec_curves_count * 2));
        /* Curve list */
        for (int i = 0; i < ec_curves_count; i++) {
            GUARD(s2n_stuffer_write_uint16(out, s2n_ecc_supported_curves[i].iana_id));
        }

        GUARD(s2n_stuffer_write_uint16(out, TLS_EXTENSION_EC_POINT_FORMATS));
        GUARD(s2n_stuffer_write_uint16(out, 2));
        /* Point format list len */
        GUARD(s2n_stuffer_write_uint8(out, 1));
        /* Only allow uncompressed format */
        GUARD(s2n_stuffer_write_uint8(out, 0));
    }

    return 0;
}
Пример #16
0
/**
 * Private helper: write n (up to 64) bits of hex data
 */
static int s2n_stuffer_write_n_bits_hex(struct s2n_stuffer *stuffer, uint8_t n, uint64_t u)
{
    uint8_t hex_data[16] = { 0 };
    struct s2n_blob b = { .data = hex_data, .size = n / 4 };

    lte_check(n, 64);

    for (int i = b.size; i > 0; i--) {
        b.data[i - 1] = hex[u & 0x0f];
        u >>= 4;
    }

    GUARD(s2n_stuffer_write(stuffer, &b));

    return 0;
}

int s2n_stuffer_write_uint64_hex(struct s2n_stuffer *stuffer, uint64_t u)
{
    return s2n_stuffer_write_n_bits_hex(stuffer, 64, u);
}

int s2n_stuffer_write_uint32_hex(struct s2n_stuffer *stuffer, uint32_t u)
{
    return s2n_stuffer_write_n_bits_hex(stuffer, 32, u);
}

int s2n_stuffer_write_uint16_hex(struct s2n_stuffer *stuffer, uint16_t u)
{
    return s2n_stuffer_write_n_bits_hex(stuffer, 16, u);
}

int s2n_stuffer_write_uint8_hex(struct s2n_stuffer *stuffer, uint8_t u)
{
    return s2n_stuffer_write_n_bits_hex(stuffer, 8, u);
}

int s2n_stuffer_alloc_ro_from_hex_string(struct s2n_stuffer *stuffer, const char *str)
{
    if (strlen(str) % 2) {
        S2N_ERROR(S2N_ERR_SIZE_MISMATCH);
    }

    GUARD(s2n_stuffer_alloc(stuffer, strlen(str) / 2));

    for (int i = 0; i < strlen(str); i += 2) {
        uint8_t u = 0;

        if (str[i] >= '0' && str[i] <= '9') {
            u = str[i] - '0';
        } else if (str[i] >= 'a' && str[i] <= 'f') {
            u = str[i] - 'a' + 10;
        } else if (str[i] >= 'A' && str[i] <= 'F') {
            u = str[i] - 'A' + 10;
        } else {
            S2N_ERROR(S2N_ERR_BAD_MESSAGE);
        }
        u <<= 4;

        if (str[i + 1] >= '0' && str[i + 1] <= '9') {
            u |= str[i + 1] - '0';
        } else if (str[i + 1] >= 'a' && str[i + 1] <= 'f') {
            u |= str[i + 1] - 'a' + 10;
        } else if (str[i + 1] >= 'A' && str[i + 1] <= 'F') {
            u |= str[i + 1] - 'A' + 10;
        } else {
            S2N_ERROR(S2N_ERR_BAD_MESSAGE);
        }

        GUARD(s2n_stuffer_write_uint8(stuffer, u));
    }

    return 0;
}
Пример #17
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;
}
Пример #18
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;
}