/* This is called when we want send our certificate */ int _gnutls_send_client_certificate(gnutls_session_t session, int again) { gnutls_buffer_st data; int ret = 0; if (session->internals.crt_requested == 0) return 0; if (session->internals.auth_struct-> gnutls_generate_client_certificate == NULL) return 0; _gnutls_buffer_init(&data); if (again == 0) { #ifdef ENABLE_SSL3 if (get_num_version(session) != GNUTLS_SSL3 || session->internals.selected_cert_list_length > 0) #endif { /* TLS 1.x or SSL 3.0 with a valid certificate */ ret = session->internals.auth_struct-> gnutls_generate_client_certificate(session, &data); if (ret < 0) { gnutls_assert(); goto cleanup; } } } #ifdef ENABLE_SSL3 /* In the SSL 3.0 protocol we need to send a * no certificate alert instead of an * empty certificate. */ if (get_num_version(session) == GNUTLS_SSL3 && session->internals.selected_cert_list_length == 0) { ret = gnutls_alert_send(session, GNUTLS_AL_WARNING, GNUTLS_A_SSL3_NO_CERTIFICATE); } else /* TLS 1.0 or SSL 3.0 with a valid certificate */ #endif ret = send_handshake(session, data.data, data.length, GNUTLS_HANDSHAKE_CERTIFICATE_PKT); cleanup: _gnutls_buffer_clear(&data); return ret; }
/* return RSA(random) using the peers public key */ int _gnutls_gen_rsa_client_kx(gnutls_session_t session, gnutls_buffer_st * data) { cert_auth_info_t auth = session->key.auth_info; gnutls_datum_t sdata; /* data to send */ gnutls_pk_params_st params; int ret; if (auth == NULL) { /* this shouldn't have happened. The proc_certificate * function should have detected that. */ gnutls_assert(); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } session->key.key.size = GNUTLS_MASTER_SIZE; session->key.key.data = gnutls_malloc(session->key.key.size); if (session->key.key.data == NULL) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } ret = _gnutls_rnd(GNUTLS_RND_RANDOM, session->key.key.data, session->key.key.size); if (ret < 0) { gnutls_assert(); return ret; } if (session->internals.rsa_pms_version[0] == 0) { session->key.key.data[0] = _gnutls_get_adv_version_major(session); session->key.key.data[1] = _gnutls_get_adv_version_minor(session); } else { /* use the version provided */ session->key.key.data[0] = session->internals.rsa_pms_version[0]; session->key.key.data[1] = session->internals.rsa_pms_version[1]; } /* move RSA parameters to key (session). */ if ((ret = _gnutls_get_public_rsa_params(session, ¶ms)) < 0) { gnutls_assert(); return ret; } ret = _gnutls_pk_encrypt(GNUTLS_PK_RSA, &sdata, &session->key.key, ¶ms); gnutls_pk_params_release(¶ms); if (ret < 0) return gnutls_assert_val(ret); if (get_num_version(session) == GNUTLS_SSL3) { /* SSL 3.0 */ _gnutls_buffer_replace_data(data, &sdata); return data->length; } else { /* TLS 1 */ ret = _gnutls_buffer_append_data_prefix(data, 16, sdata.data, sdata.size); _gnutls_free_datum(&sdata); return ret; } }
static int proc_rsa_client_kx(gnutls_session_t session, uint8_t * data, size_t _data_size) { gnutls_datum_t plaintext; gnutls_datum_t ciphertext; int ret, dsize; int use_rnd_key = 0; ssize_t data_size = _data_size; gnutls_datum_t rndkey = {NULL, 0}; if (get_num_version(session) == GNUTLS_SSL3) { /* SSL 3.0 */ ciphertext.data = data; ciphertext.size = data_size; } else { /* TLS 1.0 */ DECR_LEN(data_size, 2); ciphertext.data = &data[2]; dsize = _gnutls_read_uint16(data); if (dsize != data_size) { gnutls_assert(); return GNUTLS_E_UNEXPECTED_PACKET_LENGTH; } ciphertext.size = dsize; } rndkey.size = GNUTLS_MASTER_SIZE; rndkey.data = gnutls_malloc(rndkey.size); if (rndkey.data == NULL) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } /* we do not need strong random numbers here. */ ret = _gnutls_rnd(GNUTLS_RND_NONCE, rndkey.data, rndkey.size); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = gnutls_privkey_decrypt_data(session->internals.selected_key, 0, &ciphertext, &plaintext); if (ret < 0 || plaintext.size != GNUTLS_MASTER_SIZE) { /* In case decryption fails then don't inform * the peer. Just use a random key. (in order to avoid * attack against pkcs-1 formating). */ _gnutls_debug_log("auth_rsa: Possible PKCS #1 format attack\n"); use_rnd_key = 1; } else { /* If the secret was properly formatted, then * check the version number. */ if (_gnutls_get_adv_version_major(session) != plaintext.data[0] || (session->internals.priorities.allow_wrong_pms == 0 && _gnutls_get_adv_version_minor(session) != plaintext.data[1])) { /* No error is returned here, if the version number check * fails. We proceed normally. * That is to defend against the attack described in the paper * "Attacking RSA-based sessions in SSL/TLS" by Vlastimil Klima, * Ondej Pokorny and Tomas Rosa. */ _gnutls_debug_log("auth_rsa: Possible PKCS #1 version check format attack\n"); } } if (use_rnd_key != 0) { session->key.key.data = rndkey.data; session->key.key.size = rndkey.size; rndkey.data = NULL; } else { session->key.key.data = plaintext.data; session->key.key.size = plaintext.size; } /* This is here to avoid the version check attack * discussed above. */ session->key.key.data[0] = _gnutls_get_adv_version_major(session); session->key.key.data[1] = _gnutls_get_adv_version_minor(session); ret = 0; cleanup: gnutls_free(rndkey.data); return ret; }
/** * gnutls_session_get_desc: * @session: is a gnutls session * * This function returns a string describing the current session. * The string is null terminated and allocated using gnutls_malloc(). * * Returns: a description of the protocols and algorithms in the current session. * * Since: 3.1.10 **/ char *gnutls_session_get_desc(gnutls_session_t session) { gnutls_kx_algorithm_t kx; unsigned type; char kx_name[32]; char proto_name[32]; const char *curve_name = NULL; unsigned dh_bits = 0; unsigned mac_id; char *desc; kx = session->security_parameters.kx_algorithm; if (kx == GNUTLS_KX_ANON_ECDH || kx == GNUTLS_KX_ECDHE_PSK || kx == GNUTLS_KX_ECDHE_RSA || kx == GNUTLS_KX_ECDHE_ECDSA) { curve_name = gnutls_ecc_curve_get_name(gnutls_ecc_curve_get (session)); } else if (kx == GNUTLS_KX_ANON_DH || kx == GNUTLS_KX_DHE_PSK || kx == GNUTLS_KX_DHE_RSA || kx == GNUTLS_KX_DHE_DSS) { dh_bits = gnutls_dh_get_prime_bits(session); } if (curve_name != NULL) snprintf(kx_name, sizeof(kx_name), "%s-%s", gnutls_kx_get_name(kx), curve_name); else if (dh_bits != 0) snprintf(kx_name, sizeof(kx_name), "%s-%u", gnutls_kx_get_name(kx), dh_bits); else snprintf(kx_name, sizeof(kx_name), "%s", gnutls_kx_get_name(kx)); type = gnutls_certificate_type_get(session); if (type == GNUTLS_CRT_X509) snprintf(proto_name, sizeof(proto_name), "%s", gnutls_protocol_get_name(get_num_version (session))); else snprintf(proto_name, sizeof(proto_name), "%s-%s", gnutls_protocol_get_name(get_num_version (session)), gnutls_certificate_type_get_name(type)); gnutls_protocol_get_name(get_num_version(session)), desc = gnutls_malloc(DESC_SIZE); if (desc == NULL) return NULL; mac_id = gnutls_mac_get(session); if (mac_id == GNUTLS_MAC_AEAD) { /* no need to print */ snprintf(desc, DESC_SIZE, "(%s)-(%s)-(%s)", proto_name, kx_name, gnutls_cipher_get_name(gnutls_cipher_get(session))); } else { snprintf(desc, DESC_SIZE, "(%s)-(%s)-(%s)-(%s)", proto_name, kx_name, gnutls_cipher_get_name(gnutls_cipher_get(session)), gnutls_mac_get_name(mac_id)); } return desc; }
/** * gnutls_session_get_desc: * @session: is a gnutls session * * This function returns a string describing the current session. * The string is null terminated and allocated using gnutls_malloc(). * * If initial negotiation is not complete when this function is called, * %NULL will be returned. * * Returns: a description of the protocols and algorithms in the current session. * * Since: 3.1.10 **/ char *gnutls_session_get_desc(gnutls_session_t session) { gnutls_kx_algorithm_t kx; const char *kx_str; unsigned type; char kx_name[32]; char proto_name[32]; const char *curve_name = NULL; unsigned dh_bits = 0; unsigned mac_id; char *desc; if (session->internals.initial_negotiation_completed == 0) return NULL; kx = session->security_parameters.kx_algorithm; if (kx == GNUTLS_KX_ANON_ECDH || kx == GNUTLS_KX_ECDHE_PSK || kx == GNUTLS_KX_ECDHE_RSA || kx == GNUTLS_KX_ECDHE_ECDSA) { curve_name = gnutls_ecc_curve_get_name(gnutls_ecc_curve_get (session)); #if defined(ENABLE_DHE) || defined(ENABLE_ANON) } else if (kx == GNUTLS_KX_ANON_DH || kx == GNUTLS_KX_DHE_PSK || kx == GNUTLS_KX_DHE_RSA || kx == GNUTLS_KX_DHE_DSS) { dh_bits = gnutls_dh_get_prime_bits(session); #endif } kx_str = gnutls_kx_get_name(kx); if (kx_str) { if (curve_name != NULL) snprintf(kx_name, sizeof(kx_name), "%s-%s", kx_str, curve_name); else if (dh_bits != 0) snprintf(kx_name, sizeof(kx_name), "%s-%u", kx_str, dh_bits); else snprintf(kx_name, sizeof(kx_name), "%s", kx_str); } else { strcpy(kx_name, "NULL"); } type = gnutls_certificate_type_get(session); if (type == GNUTLS_CRT_X509) snprintf(proto_name, sizeof(proto_name), "%s", gnutls_protocol_get_name(get_num_version (session))); else snprintf(proto_name, sizeof(proto_name), "%s-%s", gnutls_protocol_get_name(get_num_version (session)), gnutls_certificate_type_get_name(type)); desc = gnutls_malloc(DESC_SIZE); if (desc == NULL) return NULL; mac_id = gnutls_mac_get(session); if (mac_id == GNUTLS_MAC_AEAD) { /* no need to print */ snprintf(desc, DESC_SIZE, "(%s)-(%s)-(%s)", proto_name, kx_name, gnutls_cipher_get_name(gnutls_cipher_get(session))); } else { snprintf(desc, DESC_SIZE, "(%s)-(%s)-(%s)-(%s)", proto_name, kx_name, gnutls_cipher_get_name(gnutls_cipher_get(session)), gnutls_mac_get_name(mac_id)); } return desc; }
int _gnutls_recv_client_certificate(gnutls_session_t session) { gnutls_buffer_st buf; int ret = 0; int optional; if (session->internals.auth_struct-> gnutls_process_client_certificate == NULL) return 0; /* if we have not requested a certificate then just return */ if (session->internals.send_cert_req == 0) { return 0; } if (session->internals.send_cert_req == GNUTLS_CERT_REQUIRE) optional = 0; else optional = 1; ret = _gnutls_recv_handshake(session, GNUTLS_HANDSHAKE_CERTIFICATE_PKT, optional, &buf); if (ret < 0) { /* Handle the case of old SSL3 clients who send * a warning alert instead of an empty certificate to indicate * no certificate. */ #ifdef ENABLE_SSL3 if (optional != 0 && ret == GNUTLS_E_WARNING_ALERT_RECEIVED && get_num_version(session) == GNUTLS_SSL3 && gnutls_alert_get(session) == GNUTLS_A_SSL3_NO_CERTIFICATE) { /* SSL3 does not send an empty certificate, * but this alert. So we just ignore it. */ gnutls_assert(); return 0; } #endif /* certificate was required */ if ((ret == GNUTLS_E_WARNING_ALERT_RECEIVED || ret == GNUTLS_E_FATAL_ALERT_RECEIVED) && optional == 0) { gnutls_assert(); return GNUTLS_E_NO_CERTIFICATE_FOUND; } return ret; } if (ret == 0 && buf.length == 0 && optional != 0) { /* Client has not sent the certificate message. * well I'm not sure we should accept this * behaviour. */ gnutls_assert(); ret = 0; goto cleanup; } ret = session->internals.auth_struct-> gnutls_process_client_certificate(session, buf.data, buf.length); if (ret < 0 && ret != GNUTLS_E_NO_CERTIFICATE_FOUND) { gnutls_assert(); goto cleanup; } /* ok we should expect a certificate verify message now */ if (ret == GNUTLS_E_NO_CERTIFICATE_FOUND && optional != 0) ret = 0; else session->internals.crt_requested = 1; cleanup: _gnutls_buffer_clear(&buf); return ret; }
/* here we generate the TLS Master secret. */ static int generate_normal_master(gnutls_session_t session, gnutls_datum_t * premaster, int keep_premaster) { int ret = 0; char buf[512]; _gnutls_hard_log("INT: PREMASTER SECRET[%d]: %s\n", premaster->size, _gnutls_bin2hex(premaster->data, premaster->size, buf, sizeof(buf), NULL)); _gnutls_hard_log("INT: CLIENT RANDOM[%d]: %s\n", 32, _gnutls_bin2hex(session->security_parameters. client_random, 32, buf, sizeof(buf), NULL)); _gnutls_hard_log("INT: SERVER RANDOM[%d]: %s\n", 32, _gnutls_bin2hex(session->security_parameters. server_random, 32, buf, sizeof(buf), NULL)); if (session->security_parameters.ext_master_secret == 0) { uint8_t rnd[2 * GNUTLS_RANDOM_SIZE + 1]; memcpy(rnd, session->security_parameters.client_random, GNUTLS_RANDOM_SIZE); memcpy(&rnd[GNUTLS_RANDOM_SIZE], session->security_parameters.server_random, GNUTLS_RANDOM_SIZE); #ifdef ENABLE_SSL3 if (get_num_version(session) == GNUTLS_SSL3) { ret = _gnutls_ssl3_generate_random(premaster->data, premaster->size, rnd, 2 * GNUTLS_RANDOM_SIZE, GNUTLS_MASTER_SIZE, session->security_parameters. master_secret); } else #endif ret = _gnutls_PRF(session, premaster->data, premaster->size, MASTER_SECRET, MASTER_SECRET_SIZE, rnd, 2 * GNUTLS_RANDOM_SIZE, GNUTLS_MASTER_SIZE, session->security_parameters. master_secret); } else { gnutls_datum_t shash = {NULL, 0}; /* draft-ietf-tls-session-hash-02 */ ret = _gnutls_handshake_get_session_hash(session, &shash); if (ret < 0) return gnutls_assert_val(ret); #ifdef ENABLE_SSL3 if (get_num_version(session) == GNUTLS_SSL3) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); #endif ret = _gnutls_PRF(session, premaster->data, premaster->size, EXT_MASTER_SECRET, EXT_MASTER_SECRET_SIZE, shash.data, shash.size, GNUTLS_MASTER_SIZE, session->security_parameters. master_secret); gnutls_free(shash.data); } write_nss_key_log(session, premaster); if (!keep_premaster) _gnutls_free_temp_key_datum(premaster); if (ret < 0) return ret; _gnutls_hard_log("INT: MASTER SECRET: %s\n", _gnutls_bin2hex(session->security_parameters. master_secret, GNUTLS_MASTER_SIZE, buf, sizeof(buf), NULL)); return ret; }
/* This function is to be called after handshake, when master_secret, * client_random and server_random have been initialized. * This function creates the keys and stores them into pending session. * (session->cipher_specs) */ static int _gnutls_set_keys(gnutls_session_t session, record_parameters_st * params, int hash_size, int IV_size, int key_size) { /* FIXME: This function is too long */ uint8_t rnd[2 * GNUTLS_RANDOM_SIZE]; uint8_t rrnd[2 * GNUTLS_RANDOM_SIZE]; int pos, ret; int block_size; char buf[65]; /* avoid using malloc */ uint8_t key_block[2 * MAX_HASH_SIZE + 2 * MAX_CIPHER_KEY_SIZE + 2 * MAX_CIPHER_BLOCK_SIZE]; record_state_st *client_write, *server_write; if (session->security_parameters.entity == GNUTLS_CLIENT) { client_write = ¶ms->write; server_write = ¶ms->read; } else { client_write = ¶ms->read; server_write = ¶ms->write; } block_size = 2 * hash_size + 2 * key_size; block_size += 2 * IV_size; memcpy(rnd, session->security_parameters.server_random, GNUTLS_RANDOM_SIZE); memcpy(&rnd[GNUTLS_RANDOM_SIZE], session->security_parameters.client_random, GNUTLS_RANDOM_SIZE); memcpy(rrnd, session->security_parameters.client_random, GNUTLS_RANDOM_SIZE); memcpy(&rrnd[GNUTLS_RANDOM_SIZE], session->security_parameters.server_random, GNUTLS_RANDOM_SIZE); if (get_num_version(session) == GNUTLS_SSL3) { /* SSL 3 */ ret = _gnutls_ssl3_generate_random (session->security_parameters.master_secret, GNUTLS_MASTER_SIZE, rnd, 2 * GNUTLS_RANDOM_SIZE, block_size, key_block); } else { /* TLS 1.0 */ ret = _gnutls_PRF(session, session->security_parameters.master_secret, GNUTLS_MASTER_SIZE, keyexp, keyexp_length, rnd, 2 * GNUTLS_RANDOM_SIZE, block_size, key_block); } if (ret < 0) return gnutls_assert_val(ret); _gnutls_hard_log("INT: KEY BLOCK[%d]: %s\n", block_size, _gnutls_bin2hex(key_block, block_size, buf, sizeof(buf), NULL)); pos = 0; if (hash_size > 0) { if (_gnutls_set_datum (&client_write->mac_secret, &key_block[pos], hash_size) < 0) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); pos += hash_size; if (_gnutls_set_datum (&server_write->mac_secret, &key_block[pos], hash_size) < 0) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); pos += hash_size; } if (key_size > 0) { uint8_t *client_write_key, *server_write_key; int client_write_key_size, server_write_key_size; client_write_key = &key_block[pos]; client_write_key_size = key_size; pos += key_size; server_write_key = &key_block[pos]; server_write_key_size = key_size; pos += key_size; if (_gnutls_set_datum (&client_write->key, client_write_key, client_write_key_size) < 0) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); _gnutls_hard_log("INT: CLIENT WRITE KEY [%d]: %s\n", client_write_key_size, _gnutls_bin2hex(client_write_key, client_write_key_size, buf, sizeof(buf), NULL)); if (_gnutls_set_datum (&server_write->key, server_write_key, server_write_key_size) < 0) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); _gnutls_hard_log("INT: SERVER WRITE KEY [%d]: %s\n", server_write_key_size, _gnutls_bin2hex(server_write_key, server_write_key_size, buf, sizeof(buf), NULL)); } /* IV generation in export and non export ciphers. */ if (IV_size > 0) { if (_gnutls_set_datum (&client_write->IV, &key_block[pos], IV_size) < 0) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); pos += IV_size; if (_gnutls_set_datum (&server_write->IV, &key_block[pos], IV_size) < 0) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); _gnutls_hard_log("INT: CLIENT WRITE IV [%d]: %s\n", client_write->IV.size, _gnutls_bin2hex(client_write->IV.data, client_write->IV.size, buf, sizeof(buf), NULL)); _gnutls_hard_log("INT: SERVER WRITE IV [%d]: %s\n", server_write->IV.size, _gnutls_bin2hex(server_write->IV.data, server_write->IV.size, buf, sizeof(buf), NULL)); } return 0; }