int _gnutls_fips_perform_self_checks1(void) { int ret; _gnutls_switch_lib_state(LIB_STATE_SELFTEST); /* Tests the FIPS algorithms used by nettle internally. * In our case we test AES-CBC since nettle's AES is used by * the DRBG-AES. */ /* ciphers - one test per cipher */ ret = gnutls_cipher_self_test(0, GNUTLS_CIPHER_AES_128_CBC); if (ret < 0) { gnutls_assert(); goto error; } return 0; error: _gnutls_switch_lib_state(LIB_STATE_ERROR); _gnutls_audit_log(NULL, "FIPS140-2 self testing part1 failed\n"); return GNUTLS_E_SELF_TEST_ERROR; }
int _gnutls_record_buffer_get_packet(content_type_t type, gnutls_session_t session, gnutls_packet_t *packet) { mbuffer_st *bufel; bufel = _mbuffer_head_pop_first(&session->internals.record_buffer); if (bufel == NULL) return gnutls_assert_val (GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE); if (type != bufel->type) { if (IS_DTLS(session)) _gnutls_audit_log(session, "Discarded unexpected %s (%d) packet (expecting: %s)\n", _gnutls_packet2str(bufel->type), (int) bufel->type, _gnutls_packet2str(type)); _mbuffer_head_remove_bytes(&session->internals. record_buffer, bufel->msg.size); return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET); } *packet = bufel; return bufel->msg.size - bufel->mark; }
/** * gnutls_dh_set_prime_bits: * @session: is a #gnutls_session_t structure. * @bits: is the number of bits * * This function sets the number of bits, for use in a Diffie-Hellman * key exchange. This is used both in DH ephemeral and DH anonymous * cipher suites. This will set the minimum size of the prime that * will be used for the handshake. * * In the client side it sets the minimum accepted number of bits. If * a server sends a prime with less bits than that * %GNUTLS_E_DH_PRIME_UNACCEPTABLE will be returned by the handshake. * * Note that values lower than 512 bits may allow decryption of the * exchanged data. * * The function has no effect in server side. * * Note that since 3.1.7 this function is deprecated. The minimum * number of bits is set by the priority string level. * Also this function must be called after gnutls_priority_set_direct() * or the set value may be overridden by the selected priority options. * * **/ void gnutls_dh_set_prime_bits(gnutls_session_t session, unsigned int bits) { if (bits <= 512 && bits != 0) _gnutls_audit_log(session, "Note that the security level of the Diffie-Hellman key exchange has been lowered to %u bits and this may allow decryption of the session data\n", bits); session->internals.priorities.dh_prime_bits = bits; }
/** * gnutls_dh_set_prime_bits: * @session: is a #gnutls_session_t structure. * @bits: is the number of bits * * This function sets the number of bits, for use in a Diffie-Hellman * key exchange. This is used both in DH ephemeral and DH anonymous * cipher suites. This will set the minimum size of the prime that * will be used for the handshake. * * In the client side it sets the minimum accepted number of bits. If * a server sends a prime with less bits than that * %GNUTLS_E_DH_PRIME_UNACCEPTABLE will be returned by the handshake. * * Note that values lower than 512 bits may allow decryption of the * exchanged data. * * The function has no effect in server side. * * Note that since 3.1.7 this function is deprecated. The minimum * number of bits is set by the priority string level. * Also this function must be called after gnutls_priority_set_direct() * or the set value may be overridden by the selected priority options. * * **/ void gnutls_dh_set_prime_bits(gnutls_session_t session, unsigned int bits) { if (bits <= gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, GNUTLS_SEC_PARAM_VERY_WEAK) && bits != 0) _gnutls_audit_log(session, "Note that the security level of the Diffie-Hellman key exchange has been lowered to %u bits and this may allow decryption of the session data\n", bits); session->internals.priorities.dh_prime_bits = bits; }
static int check_key_usage_for_enc(gnutls_session_t session, unsigned key_usage) { if (key_usage != 0) { if (!(key_usage & GNUTLS_KEY_KEY_ENCIPHERMENT) && !(key_usage & GNUTLS_KEY_KEY_AGREEMENT)) { gnutls_assert(); if (session->internals.priorities.allow_key_usage_violation == 0) { _gnutls_audit_log(session, "Peer's certificate does not allow encryption. Key usage violation detected.\n"); return GNUTLS_E_KEY_USAGE_VIOLATION; } else { _gnutls_audit_log(session, "Peer's certificate does not allow encryption. Key usage violation detected (ignored).\n"); } } } return 0; }
/** * gnutls_dtls_cookie_verify: * @key: is a random key to be used at cookie generation * @client_data: contains data identifying the client (i.e. address) * @client_data_size: The size of client's data * @_msg: An incoming message that initiates a connection. * @msg_size: The size of the message. * @prestate: The cookie of this client. * * This function will verify an incoming message for * a valid cookie. If a valid cookie is returned then * it should be associated with the session using * gnutls_dtls_prestate_set(); * * Returns: %GNUTLS_E_SUCCESS (0) on success, or a negative error code. * * Since: 3.0 **/ int gnutls_dtls_cookie_verify(gnutls_datum_t* key, void* client_data, size_t client_data_size, void* _msg, size_t msg_size, gnutls_dtls_prestate_st* prestate) { gnutls_datum_t cookie; int ret; unsigned int pos, sid_size; uint8_t * msg = _msg; uint8_t digest[C_HASH_SIZE]; if (key == NULL || key->data == NULL || key->size == 0) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); /* format: * version - 2 bytes * random - 32 bytes * session_id - 1 byte length + content * cookie - 1 byte length + content */ pos = 34+DTLS_RECORD_HEADER_SIZE+DTLS_HANDSHAKE_HEADER_SIZE; if (msg_size < pos+1) return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH); sid_size = msg[pos++]; if (sid_size > 32 || msg_size < pos+sid_size+1) return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH); pos += sid_size; cookie.size = msg[pos++]; if (msg_size < pos+cookie.size+1) return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH); cookie.data = &msg[pos]; if (cookie.size != COOKIE_SIZE) { if (cookie.size > 0) _gnutls_audit_log(NULL, "Received cookie with illegal size %d. Expected %d\n", (int)cookie.size, COOKIE_SIZE); return gnutls_assert_val(GNUTLS_E_BAD_COOKIE); } ret = _gnutls_hmac_fast(C_HASH, key->data, key->size, client_data, client_data_size, digest); if (ret < 0) return gnutls_assert_val(ret); if (memcmp(digest, cookie.data, COOKIE_MAC_SIZE) != 0) return gnutls_assert_val(GNUTLS_E_BAD_COOKIE); prestate->record_seq = msg[10]; /* client's record seq */ prestate->hsk_read_seq = msg[DTLS_RECORD_HEADER_SIZE+5]; /* client's hsk seq */ prestate->hsk_write_seq = 0;/* we always send zero for this msg */ return 0; }
int _gnutls_record_buffer_get(content_type_t type, gnutls_session_t session, uint8_t * data, size_t length, uint8_t seq[8]) { gnutls_datum_t msg; mbuffer_st *bufel; if (length == 0 || data == NULL) { gnutls_assert(); return GNUTLS_E_INVALID_REQUEST; } bufel = _mbuffer_head_get_first(&session->internals.record_buffer, &msg); if (bufel == NULL) return gnutls_assert_val (GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE); if (type != bufel->type) { if (IS_DTLS(session)) _gnutls_audit_log(session, "Discarded unexpected %s (%d) packet (expecting: %s (%d))\n", _gnutls_packet2str(bufel->type), (int) bufel->type, _gnutls_packet2str(type), (int) type); else _gnutls_debug_log("received unexpected packet: %s(%d)\n", _gnutls_packet2str(bufel->type), (int)bufel->type); _mbuffer_head_remove_bytes(&session->internals. record_buffer, msg.size); return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET); } if (msg.size <= length) length = msg.size; if (seq) memcpy(seq, bufel->record_sequence.i, 8); memcpy(data, msg.data, length); _mbuffer_head_remove_bytes(&session->internals.record_buffer, length); return length; }
inline static int check_recv_type (content_type_t recv_type) { switch (recv_type) { case GNUTLS_CHANGE_CIPHER_SPEC: case GNUTLS_ALERT: case GNUTLS_HANDSHAKE: case GNUTLS_APPLICATION_DATA: return 0; default: gnutls_assert (); _gnutls_audit_log("Received record packet of unknown type %u\n", (unsigned int)recv_type); return GNUTLS_E_UNEXPECTED_PACKET; } }
/* @ms: is the number of milliseconds to wait for data. Use zero for indefinite. * * This will receive record layer packets and add them to * application_data_buffer and handshake_data_buffer. * * If the htype is not -1 then handshake timeouts * will be enforced. */ ssize_t _gnutls_recv_in_buffers (gnutls_session_t session, content_type_t type, gnutls_handshake_description_t htype, unsigned int ms) { uint64 *packet_sequence; gnutls_datum_t ciphertext; mbuffer_st* bufel = NULL, *decrypted = NULL; gnutls_datum_t t; int ret; unsigned int empty_fragments = 0; record_parameters_st *record_params; record_state_st *record_state; struct tls_record_st record; begin: if (empty_fragments > session->internals.priorities.max_empty_records) { gnutls_assert (); return GNUTLS_E_TOO_MANY_EMPTY_PACKETS; } if (session->internals.read_eof != 0) { /* if we have already read an EOF */ return 0; } else if (session_is_valid (session) != 0 || session->internals.may_not_read != 0) return gnutls_assert_val(GNUTLS_E_INVALID_SESSION); /* get the record state parameters */ ret = _gnutls_epoch_get (session, EPOCH_READ_CURRENT, &record_params); if (ret < 0) return gnutls_assert_val (ret); /* Safeguard against processing data with an incomplete cipher state. */ if (!record_params->initialized) return gnutls_assert_val (GNUTLS_E_INTERNAL_ERROR); record_state = &record_params->read; /* receive headers */ ret = recv_headers(session, type, htype, &record, &ms); if (ret < 0) { ret = gnutls_assert_val_fatal(ret); goto recv_error; } if (IS_DTLS(session)) packet_sequence = &record.sequence; else packet_sequence = &record_state->sequence_number; /* Read the packet data and insert it to record_recv_buffer. */ ret = _gnutls_io_read_buffered (session, record.packet_size, record.type, &ms); if (ret != record.packet_size) { gnutls_assert(); goto recv_error; } /* ok now we are sure that we have read all the data - so * move on ! */ ret = _mbuffer_linearize (&session->internals.record_recv_buffer); if (ret < 0) return gnutls_assert_val(ret); bufel = _mbuffer_head_get_first (&session->internals.record_recv_buffer, NULL); if (bufel == NULL) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); /* We allocate the maximum possible to allow few compressed bytes to expand to a * full record. */ decrypted = _mbuffer_alloc(record.length, record.length); if (decrypted == NULL) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); ciphertext.data = (uint8_t*)_mbuffer_get_udata_ptr(bufel) + record.header_size; ciphertext.size = record.length; /* decrypt the data we got. */ t.data = _mbuffer_get_udata_ptr(decrypted); t.size = _mbuffer_get_udata_size(decrypted); ret = _gnutls_decrypt (session, &ciphertext, &t, record.type, record_params, packet_sequence); if (ret >= 0) _mbuffer_set_udata_size(decrypted, ret); _mbuffer_head_remove_bytes (&session->internals.record_recv_buffer, record.header_size + record.length); if (ret < 0) { gnutls_assert(); _gnutls_audit_log(session, "Discarded message[%u] due to invalid decryption\n", (unsigned int)_gnutls_uint64touint32 (packet_sequence)); goto sanity_check_error; } /* check for duplicates. We check after the message * is processed and authenticated to avoid someone * messing with our windows. */ if (IS_DTLS(session) && session->internals.no_replay_protection == 0) { ret = _dtls_record_check(record_params, packet_sequence); if (ret < 0) { _gnutls_audit_log(session, "Discarded duplicate message[%u.%u]: %s\n", (unsigned int)record.sequence.i[0]*256 +(unsigned int)record.sequence.i[1], (unsigned int) _gnutls_uint64touint32 (packet_sequence), _gnutls_packet2str (record.type)); goto sanity_check_error; } _gnutls_record_log ("REC[%p]: Decrypted Packet[%u.%u] %s(%d) with length: %d\n", session, (unsigned int)record.sequence.i[0]*256 +(unsigned int)record.sequence.i[1], (unsigned int) _gnutls_uint64touint32 (packet_sequence), _gnutls_packet2str (record.type), record.type, (int)_mbuffer_get_udata_size(decrypted)); } else { _gnutls_record_log ("REC[%p]: Decrypted Packet[%u] %s(%d) with length: %d\n", session, (unsigned int) _gnutls_uint64touint32 (packet_sequence), _gnutls_packet2str (record.type), record.type, (int)_mbuffer_get_udata_size(decrypted)); } /* increase sequence number */ if (!IS_DTLS(session) && sequence_increment (session, &record_state->sequence_number) != 0) { session_invalidate (session); gnutls_assert (); ret = GNUTLS_E_RECORD_LIMIT_REACHED; goto sanity_check_error; } /* (originally for) TLS 1.0 CBC protection. * Actually this code is called if we just received * an empty packet. An empty TLS packet is usually * sent to protect some vulnerabilities in the CBC mode. * In that case we go to the beginning and start reading * the next packet. */ if (_mbuffer_get_udata_size(decrypted) == 0) { _mbuffer_xfree(&decrypted); empty_fragments++; goto begin; } if (record.v2) decrypted->htype = GNUTLS_HANDSHAKE_CLIENT_HELLO_V2; else { uint8_t * p = _mbuffer_get_udata_ptr(decrypted); decrypted->htype = p[0]; } ret = record_add_to_buffers (session, &record, type, htype, packet_sequence, decrypted); /* bufel is now either deinitialized or buffered somewhere else */ if (ret < 0) return gnutls_assert_val(ret); return ret; discard: session->internals.dtls.packets_dropped++; /* discard the whole received fragment. */ bufel = _mbuffer_head_pop_first(&session->internals.record_recv_buffer); _mbuffer_xfree(&bufel); return gnutls_assert_val(GNUTLS_E_AGAIN); sanity_check_error: if (IS_DTLS(session)) { session->internals.dtls.packets_dropped++; ret = gnutls_assert_val(GNUTLS_E_AGAIN); goto cleanup; } session_unresumable (session); session_invalidate (session); cleanup: _mbuffer_xfree(&decrypted); return ret; recv_error: if (ret < 0 && (gnutls_error_is_fatal (ret) == 0 || ret == GNUTLS_E_TIMEDOUT)) return ret; if (type == GNUTLS_ALERT) /* we were expecting close notify */ { session_invalidate (session); gnutls_assert (); return 0; } if (IS_DTLS(session)) { goto discard; } session_invalidate (session); session_unresumable (session); if (ret == 0) return GNUTLS_E_UNEXPECTED_PACKET_LENGTH; else return ret; }
static int recv_headers( gnutls_session_t session, content_type_t type, gnutls_handshake_description_t htype, struct tls_record_st* record, unsigned int *ms) { int ret; gnutls_datum_t raw; /* raw headers */ /* Read the headers. */ record->header_size = record->packet_size = RECORD_HEADER_SIZE(session); ret = _gnutls_io_read_buffered (session, record->header_size, -1, ms); if (ret != record->header_size) { if (ret < 0 && gnutls_error_is_fatal (ret) == 0) return ret; if (ret > 0) ret = GNUTLS_E_UNEXPECTED_PACKET_LENGTH; else if (ret == 0) ret = GNUTLS_E_PREMATURE_TERMINATION; return gnutls_assert_val(ret); } ret = _mbuffer_linearize (&session->internals.record_recv_buffer); if (ret < 0) return gnutls_assert_val(ret); _mbuffer_head_get_first (&session->internals.record_recv_buffer, &raw); if (raw.size < RECORD_HEADER_SIZE(session)) return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH); record_read_headers (session, raw.data, type, htype, record); /* Check if the DTLS epoch is valid */ if (IS_DTLS(session)) { if (_gnutls_epoch_is_valid(session, record->epoch) == 0) { _gnutls_audit_log(session, "Discarded message[%u] with invalid epoch %u.\n", (unsigned int)_gnutls_uint64touint32 (&record->sequence), (unsigned int)record->sequence.i[0]*256+(unsigned int)record->sequence.i[1]); gnutls_assert(); /* doesn't matter, just a fatal error */ return GNUTLS_E_UNEXPECTED_PACKET_LENGTH; } } /* Here we check if the Type of the received packet is * ok. */ if ((ret = check_recv_type (session, record->type)) < 0) return gnutls_assert_val(ret); /* Here we check if the advertized version is the one we * negotiated in the handshake. */ if ((ret = record_check_version (session, htype, record->version)) < 0) return gnutls_assert_val(ret); if (record->length > MAX_RECV_SIZE(session)) { _gnutls_audit_log (session, "Received packet with illegal length: %u\n", (unsigned int)record->length); return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH); } _gnutls_record_log ("REC[%p]: Expected Packet %s(%d)\n", session, _gnutls_packet2str (type), type); _gnutls_record_log ("REC[%p]: Received Packet %s(%d) with length: %d\n", session, _gnutls_packet2str (record->type), record->type, record->length); return 0; }
/* receive the key exchange message ( n, g, s, B) */ int _gnutls_proc_srp_server_kx(gnutls_session_t session, uint8_t * data, size_t _data_size) { uint8_t n_s; uint16_t n_g, n_n, n_b; size_t _n_g, _n_n, _n_b; const uint8_t *data_n; const uint8_t *data_g; const uint8_t *data_s; const uint8_t *data_b; int i, ret; uint8_t hd[SRP_MAX_HASH_SIZE]; char *username, *password; ssize_t data_size = _data_size; gnutls_srp_client_credentials_t cred; extension_priv_data_t epriv; srp_ext_st *priv; ret = _gnutls_ext_get_session_data(session, GNUTLS_EXTENSION_SRP, &epriv); if (ret < 0) { gnutls_assert(); return GNUTLS_E_UNKNOWN_SRP_USERNAME; } priv = epriv; cred = (gnutls_srp_client_credentials_t) _gnutls_get_cred(session, GNUTLS_CRD_SRP); if (cred == NULL) { gnutls_assert(); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } if (priv->username == NULL) { username = cred->username; password = cred->password; } else { username = priv->username; password = priv->password; } if (username == NULL || password == NULL) { gnutls_assert(); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } i = 0; /* Read N */ DECR_LEN(data_size, 2); n_n = _gnutls_read_uint16(&data[i]); i += 2; DECR_LEN(data_size, n_n); data_n = &data[i]; i += n_n; /* Read G */ DECR_LEN(data_size, 2); n_g = _gnutls_read_uint16(&data[i]); i += 2; DECR_LEN(data_size, n_g); data_g = &data[i]; i += n_g; /* Read salt */ DECR_LEN(data_size, 1); n_s = data[i]; i += 1; DECR_LEN(data_size, n_s); data_s = &data[i]; i += n_s; /* Read B */ DECR_LEN(data_size, 2); n_b = _gnutls_read_uint16(&data[i]); i += 2; DECR_LEN(data_size, n_b); data_b = &data[i]; i += n_b; _n_g = n_g; _n_n = n_n; _n_b = n_b; if (_gnutls_mpi_init_scan_nz(&N, data_n, _n_n) != 0) { gnutls_assert(); return GNUTLS_E_MPI_SCAN_FAILED; } if (_gnutls_mpi_init_scan_nz(&G, data_g, _n_g) != 0) { gnutls_assert(); return GNUTLS_E_MPI_SCAN_FAILED; } if (_gnutls_mpi_init_scan_nz(&B, data_b, _n_b) != 0) { gnutls_assert(); return GNUTLS_E_MPI_SCAN_FAILED; } /* Check if the g and n are from the SRP * draft. Otherwise check if N is a prime and G * a generator. */ if ((ret = check_g_n(data_g, _n_g, data_n, _n_n)) < 0) { _gnutls_audit_log(session, "SRP group parameters are not in the white list. Checking validity.\n"); if ((ret = group_check_g_n(session, G, N)) < 0) { gnutls_assert(); return ret; } } /* Checks if b % n == 0 */ if ((ret = check_param_mod_n(B, N, 0)) < 0) { gnutls_assert(); return ret; } /* generate x = SHA(s | SHA(U | ":" | p)) * (or the equivalent using bcrypt) */ if ((ret = _gnutls_calc_srp_x(username, password, (uint8_t *) data_s, n_s, &_n_g, hd)) < 0) { gnutls_assert(); return ret; } if (_gnutls_mpi_init_scan_nz(&session->key.x, hd, _n_g) != 0) { gnutls_assert(); return GNUTLS_E_MPI_SCAN_FAILED; } return i; /* return the processed data * needed in auth_srp_rsa. */ }
/* Deciphers the ciphertext packet, and puts the result to compress_data, of compress_size. * Returns the actual compressed packet size. */ static int ciphertext_to_compressed(gnutls_session_t session, gnutls_datum_t * ciphertext, gnutls_datum_t * compressed, uint8_t type, record_parameters_st * params, uint64 * sequence) { uint8_t tag[MAX_HASH_SIZE]; uint8_t nonce[MAX_CIPHER_BLOCK_SIZE]; const uint8_t *tag_ptr = NULL; unsigned int pad = 0, i; int length, length_to_decrypt; uint16_t blocksize; int ret; unsigned int tmp_pad_failed = 0; unsigned int pad_failed = 0; uint8_t preamble[MAX_PREAMBLE_SIZE]; unsigned int preamble_size = 0; const version_entry_st *ver = get_version(session); unsigned int tag_size = _gnutls_auth_cipher_tag_len(¶ms->read.cipher_state); unsigned int explicit_iv = _gnutls_version_has_explicit_iv(ver); unsigned imp_iv_size, exp_iv_size; unsigned cipher_type = _gnutls_cipher_type(params->cipher); bool etm = 0; if (unlikely(ver == NULL)) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); imp_iv_size = _gnutls_cipher_get_implicit_iv_size(params->cipher); exp_iv_size = _gnutls_cipher_get_explicit_iv_size(params->cipher); blocksize = _gnutls_cipher_get_block_size(params->cipher); if (params->etm !=0 && cipher_type == CIPHER_BLOCK) etm = 1; /* if EtM mode and not AEAD */ if (etm) { if (unlikely(ciphertext->size < tag_size)) return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH); preamble_size = make_preamble(UINT64DATA(*sequence), type, ciphertext->size-tag_size, ver, preamble); ret = _gnutls_auth_cipher_add_auth(¶ms->read. cipher_state, preamble, preamble_size); if (unlikely(ret < 0)) return gnutls_assert_val(ret); ret = _gnutls_auth_cipher_add_auth(¶ms->read. cipher_state, ciphertext->data, ciphertext->size-tag_size); if (unlikely(ret < 0)) return gnutls_assert_val(ret); ret = _gnutls_auth_cipher_tag(¶ms->read.cipher_state, tag, tag_size); if (unlikely(ret < 0)) return gnutls_assert_val(ret); if (unlikely(gnutls_memcmp(tag, &ciphertext->data[ciphertext->size-tag_size], tag_size) != 0)) { /* HMAC was not the same. */ return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); } } /* actual decryption (inplace) */ switch (cipher_type) { case CIPHER_AEAD: /* The way AEAD ciphers are defined in RFC5246, it allows * only stream ciphers. */ if (unlikely(_gnutls_auth_cipher_is_aead(¶ms->read. cipher_state) == 0)) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); /* Values in AEAD are pretty fixed in TLS 1.2 for 128-bit block */ if (unlikely (params->read.IV.data == NULL || params->read.IV.size != 4)) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); if (unlikely(ciphertext->size < tag_size + exp_iv_size)) return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH); memcpy(nonce, params->read.IV.data, imp_iv_size); memcpy(&nonce[imp_iv_size], ciphertext->data, exp_iv_size); ciphertext->data += exp_iv_size; ciphertext->size -= exp_iv_size; length = ciphertext->size - tag_size; length_to_decrypt = ciphertext->size; /* Pass the type, version, length and compressed through * MAC. */ preamble_size = make_preamble(UINT64DATA(*sequence), type, length, ver, preamble); if (unlikely ((unsigned) length_to_decrypt > compressed->size)) { _gnutls_audit_log(session, "Received %u bytes, while expecting less than %u\n", (unsigned int) length_to_decrypt, (unsigned int) compressed->size); return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); } ret = _gnutls_aead_cipher_decrypt(¶ms->read.cipher_state.cipher, nonce, exp_iv_size + imp_iv_size, preamble, preamble_size, tag_size, ciphertext->data, length_to_decrypt, compressed->data, compressed->size); if (unlikely(ret < 0)) return gnutls_assert_val(ret); return length; break; case CIPHER_STREAM: if (unlikely(ciphertext->size < tag_size)) return gnutls_assert_val (GNUTLS_E_UNEXPECTED_PACKET_LENGTH); length_to_decrypt = ciphertext->size; length = ciphertext->size - tag_size; tag_ptr = compressed->data + length; /* Pass the type, version, length and compressed through * MAC. */ preamble_size = make_preamble(UINT64DATA(*sequence), type, length, ver, preamble); ret = _gnutls_auth_cipher_add_auth(¶ms->read. cipher_state, preamble, preamble_size); if (unlikely(ret < 0)) return gnutls_assert_val(ret); if (unlikely ((unsigned) length_to_decrypt > compressed->size)) { _gnutls_audit_log(session, "Received %u bytes, while expecting less than %u\n", (unsigned int) length_to_decrypt, (unsigned int) compressed->size); return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); } ret = _gnutls_auth_cipher_decrypt2(¶ms->read. cipher_state, ciphertext->data, length_to_decrypt, compressed->data, compressed->size); if (unlikely(ret < 0)) return gnutls_assert_val(ret); break; case CIPHER_BLOCK: if (unlikely(ciphertext->size < blocksize)) return gnutls_assert_val (GNUTLS_E_UNEXPECTED_PACKET_LENGTH); if (etm == 0) { if (unlikely(ciphertext->size % blocksize != 0)) return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH); } else { if (unlikely((ciphertext->size - tag_size) % blocksize != 0)) return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH); } /* ignore the IV in TLS 1.1+ */ if (explicit_iv) { _gnutls_auth_cipher_setiv(¶ms->read. cipher_state, ciphertext->data, blocksize); memcpy(nonce, ciphertext->data, blocksize); ciphertext->size -= blocksize; ciphertext->data += blocksize; } if (unlikely(ciphertext->size < tag_size + 1)) return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); /* we don't use the auth_cipher interface here, since * TLS with block ciphers is impossible to be used under such * an API. (the length of plaintext is required to calculate * auth_data, but it is not available before decryption). */ if (unlikely(ciphertext->size > compressed->size)) return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); if (etm == 0) { ret = _gnutls_cipher_decrypt2(¶ms->read.cipher_state. cipher, ciphertext->data, ciphertext->size, compressed->data, compressed->size); if (unlikely(ret < 0)) return gnutls_assert_val(ret); pad = compressed->data[ciphertext->size - 1]; /* pad */ /* Check the pading bytes (TLS 1.x). * Note that we access all 256 bytes of ciphertext for padding check * because there is a timing channel in that memory access (in certain CPUs). */ if (ver->id != GNUTLS_SSL3) for (i = 2; i <= MIN(256, ciphertext->size); i++) { tmp_pad_failed |= (compressed-> data[ciphertext->size - i] != pad); pad_failed |= ((i <= (1 + pad)) & (tmp_pad_failed)); } if (unlikely (pad_failed != 0 || (1 + pad > ((int) ciphertext->size - tag_size)))) { /* We do not fail here. We check below for the * the pad_failed. If zero means success. */ pad_failed = 1; pad = 0; } length = ciphertext->size - tag_size - pad - 1; tag_ptr = &compressed->data[length]; /* Pass the type, version, length and compressed through * MAC. */ preamble_size = make_preamble(UINT64DATA(*sequence), type, length, ver, preamble); ret = _gnutls_auth_cipher_add_auth(¶ms->read. cipher_state, preamble, preamble_size); if (unlikely(ret < 0)) return gnutls_assert_val(ret); ret = _gnutls_auth_cipher_add_auth(¶ms->read. cipher_state, compressed->data, length); if (unlikely(ret < 0)) return gnutls_assert_val(ret); } else { /* EtM */ ret = _gnutls_cipher_decrypt2(¶ms->read.cipher_state. cipher, ciphertext->data, ciphertext->size - tag_size, compressed->data, compressed->size); if (unlikely(ret < 0)) return gnutls_assert_val(ret); pad = compressed->data[ciphertext->size - tag_size - 1]; /* pad */ length = ciphertext->size - tag_size - pad - 1; if (unlikely(length < 0)) return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); } break; default: return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); } /* STREAM or BLOCK arrive here */ if (etm == 0) { ret = _gnutls_auth_cipher_tag(¶ms->read.cipher_state, tag, tag_size); if (unlikely(ret < 0)) return gnutls_assert_val(ret); /* Here there could be a timing leakage in CBC ciphersuites that * could be exploited if the cost of a successful memcmp is high. * A constant time memcmp would help there, but it is not easy to maintain * against compiler optimizations. Currently we rely on the fact that * a memcmp comparison is negligible over the crypto operations. */ if (unlikely (gnutls_memcmp(tag, tag_ptr, tag_size) != 0 || pad_failed != 0)) { /* HMAC was not the same. */ dummy_wait(params, compressed, pad_failed, pad, length + preamble_size); return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); } } return length; }
/* This is a receive function for the gnutls handshake * protocol. Makes sure that we have received all data. * * htype is the next handshake packet expected. */ int _gnutls_parse_record_buffered_msgs(gnutls_session_t session) { gnutls_datum_t msg; mbuffer_st *bufel = NULL, *prev = NULL; int ret; size_t data_size; handshake_buffer_st *recv_buf = session->internals.handshake_recv_buffer; bufel = _mbuffer_head_get_first(&session->internals.record_buffer, &msg); if (bufel == NULL) return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; if (!IS_DTLS(session)) { ssize_t append, header_size; do { if (bufel->type != GNUTLS_HANDSHAKE) return gnutls_assert_val (GNUTLS_E_UNEXPECTED_PACKET); if (unlikely (session->internals.handshake_recv_buffer_size == 0 && msg.size < HANDSHAKE_HEADER_SIZE(session) && session->internals.handshake_header_recv_buffer.byte_length < HANDSHAKE_HEADER_SIZE(session) - msg.size)) { bufel = _mbuffer_head_pop_first(&session->internals.record_buffer); _mbuffer_enqueue(&session->internals.handshake_header_recv_buffer, bufel); break; } else if (session->internals.handshake_recv_buffer_size > 0 && recv_buf[0].length > recv_buf[0].data.length) { /* this is the rest of a previous message */ append = MIN(msg.size, recv_buf[0].length - recv_buf[0].data.length); ret = _gnutls_buffer_append_data(&recv_buf [0].data, msg.data, append); if (ret < 0) return gnutls_assert_val(ret); _mbuffer_head_remove_bytes(&session-> internals. record_buffer, append); } else { /* received new message */ if (unlikely (session->internals. handshake_header_recv_buffer.length > 0)) { bufel = _mbuffer_head_pop_first(&session->internals. record_buffer); _mbuffer_enqueue(&session->internals. handshake_header_recv_buffer, bufel); ret = _mbuffer_linearize_align16(&session->internals. handshake_header_recv_buffer, get_total_headers(session)); if (ret < 0) return gnutls_assert_val(ret); bufel = _mbuffer_head_pop_first(&session->internals. handshake_header_recv_buffer); _mbuffer_head_push_first(&session->internals. record_buffer, bufel); } ret = parse_handshake_header(session, bufel, &recv_buf[0]); if (ret < 0) return gnutls_assert_val(ret); header_size = ret; session->internals. handshake_recv_buffer_size = 1; _mbuffer_set_uhead_size(bufel, header_size); data_size = MIN(recv_buf[0].length, _mbuffer_get_udata_size(bufel)); ret = _gnutls_buffer_append_data(&recv_buf [0].data, _mbuffer_get_udata_ptr (bufel), data_size); if (ret < 0) return gnutls_assert_val(ret); _mbuffer_set_uhead_size(bufel, 0); _mbuffer_head_remove_bytes(&session-> internals. record_buffer, data_size + header_size); } /* if packet is complete then return it */ if (recv_buf[0].length == recv_buf[0].data.length) { return 0; } bufel = _mbuffer_head_get_first(&session->internals. record_buffer, &msg); } while (bufel != NULL); /* if we are here it means that the received packets were not * enough to complete the handshake packet. */ return gnutls_assert_val(GNUTLS_E_AGAIN); } else { /* DTLS */ handshake_buffer_st tmp; do { /* we now * 0. parse headers * 1. insert to handshake_recv_buffer * 2. sort handshake_recv_buffer on sequence numbers * 3. return first packet if completed or GNUTLS_E_AGAIN. */ do { if (bufel->type != GNUTLS_HANDSHAKE) { gnutls_assert(); goto next; /* ignore packet */ } _gnutls_handshake_buffer_init(&tmp); ret = parse_handshake_header(session, bufel, &tmp); if (ret < 0) { gnutls_assert(); _gnutls_audit_log(session, "Invalid handshake packet headers. Discarding.\n"); break; } _mbuffer_consume(&session->internals. record_buffer, bufel, ret); data_size = MIN(tmp.length, tmp.end_offset - tmp.start_offset + 1); ret = _gnutls_buffer_append_data(&tmp.data, _mbuffer_get_udata_ptr (bufel), data_size); if (ret < 0) return gnutls_assert_val(ret); _mbuffer_consume(&session->internals. record_buffer, bufel, data_size); ret = merge_handshake_packet(session, &tmp); if (ret < 0) return gnutls_assert_val(ret); } while (_mbuffer_get_udata_size(bufel) > 0); prev = bufel; bufel = _mbuffer_dequeue(&session->internals. record_buffer, bufel); _mbuffer_xfree(&prev); continue; next: bufel = _mbuffer_head_get_next(bufel, NULL); } while (bufel != NULL); /* sort in descending order */ if (session->internals.handshake_recv_buffer_size > 1) qsort(recv_buf, session->internals. handshake_recv_buffer_size, sizeof(recv_buf[0]), handshake_compare); while (session->internals.handshake_recv_buffer_size > 0 && recv_buf[LAST_ELEMENT].sequence < session->internals.dtls.hsk_read_seq) { _gnutls_audit_log(session, "Discarded replayed handshake packet with sequence %d\n", recv_buf[LAST_ELEMENT].sequence); _gnutls_handshake_buffer_clear(&recv_buf [LAST_ELEMENT]); session->internals.handshake_recv_buffer_size--; } return 0; } }
/** * gnutls_x509_trust_list_add_cas: * @list: The structure of the list * @clist: A list of CAs * @clist_size: The length of the CA list * @flags: should be 0 or an or'ed sequence of %GNUTLS_TL options. * * This function will add the given certificate authorities * to the trusted list. The list of CAs must not be deinitialized * during this structure's lifetime. * * If the flag %GNUTLS_TL_NO_DUPLICATES is specified, then * the provided @clist entries that are duplicates will not be * added to the list and will be deinitialized. * * Returns: The number of added elements is returned. * * Since: 3.0.0 **/ int gnutls_x509_trust_list_add_cas(gnutls_x509_trust_list_t list, const gnutls_x509_crt_t * clist, unsigned clist_size, unsigned int flags) { unsigned i, j; uint32_t hash; int ret; unsigned exists; for (i = 0; i < clist_size; i++) { exists = 0; hash = hash_pjw_bare(clist[i]->raw_dn.data, clist[i]->raw_dn.size); hash %= list->size; /* avoid duplicates */ if (flags & GNUTLS_TL_NO_DUPLICATES || flags & GNUTLS_TL_NO_DUPLICATE_KEY) { for (j=0;j<list->node[hash].trusted_ca_size;j++) { if (flags & GNUTLS_TL_NO_DUPLICATES) ret = _gnutls_check_if_same_cert(list->node[hash].trusted_cas[j], clist[i]); else ret = _gnutls_check_if_same_key(list->node[hash].trusted_cas[j], clist[i], 1); if (ret != 0) { exists = 1; break; } } if (exists != 0) { gnutls_x509_crt_deinit(list->node[hash].trusted_cas[j]); list->node[hash].trusted_cas[j] = clist[i]; continue; } } list->node[hash].trusted_cas = gnutls_realloc_fast(list->node[hash].trusted_cas, (list->node[hash].trusted_ca_size + 1) * sizeof(list->node[hash]. trusted_cas[0])); if (list->node[hash].trusted_cas == NULL) { gnutls_assert(); return i; } if (gnutls_x509_crt_get_version(clist[i]) >= 3 && gnutls_x509_crt_get_ca_status(clist[i], NULL) <= 0) { gnutls_datum_t dn; gnutls_assert(); if (gnutls_x509_crt_get_dn2(clist[i], &dn) >= 0) { _gnutls_audit_log(NULL, "There was a non-CA certificate in the trusted list: %s.\n", dn.data); gnutls_free(dn.data); } } list->node[hash].trusted_cas[list->node[hash]. trusted_ca_size] = clist[i]; list->node[hash].trusted_ca_size++; if (flags & GNUTLS_TL_USE_IN_TLS) { ret = add_new_ca_to_rdn_seq(list, clist[i]); if (ret < 0) { gnutls_assert(); return i; } } } return i; }
static int verify_tls_hash(gnutls_session_t session, const version_entry_st * ver, gnutls_pcert_st * cert, const gnutls_datum_t * hash_concat, gnutls_datum_t * signature, size_t sha1pos, gnutls_sign_algorithm_t sign_algo, gnutls_pk_algorithm_t pk_algo) { int ret; gnutls_datum_t vdata; unsigned int key_usage = 0, flags; if (cert == NULL) { gnutls_assert(); return GNUTLS_E_CERTIFICATE_ERROR; } gnutls_pubkey_get_key_usage(cert->pubkey, &key_usage); /* If the certificate supports signing continue. */ if (key_usage != 0) if (!(key_usage & GNUTLS_KEY_DIGITAL_SIGNATURE)) { gnutls_assert(); _gnutls_audit_log(session, "Peer's certificate does not allow digital signatures. Key usage violation detected (ignored).\n"); } if (pk_algo == GNUTLS_PK_UNKNOWN) pk_algo = gnutls_pubkey_get_pk_algorithm(cert->pubkey, NULL); switch (pk_algo) { case GNUTLS_PK_RSA: vdata.data = hash_concat->data; vdata.size = hash_concat->size; /* verify signature */ if (!_gnutls_version_has_selectable_sighash(ver)) flags = GNUTLS_PUBKEY_VERIFY_FLAG_TLS_RSA; else flags = 0; break; case GNUTLS_PK_DSA: case GNUTLS_PK_EC: vdata.data = &hash_concat->data[sha1pos]; vdata.size = hash_concat->size - sha1pos; flags = 0; break; default: gnutls_assert(); return GNUTLS_E_INTERNAL_ERROR; } gnutls_sign_algorithm_set_server(session, sign_algo); ret = gnutls_pubkey_verify_hash2(cert->pubkey, sign_algo, flags, &vdata, signature); if (ret < 0) return gnutls_assert_val(ret); return 0; }
/* This will create a PKCS1 or DSA signature, as defined in the TLS protocol. * Cert is the certificate of the corresponding private key. It is only checked if * it supports signing. */ static int sign_tls_hash(gnutls_session_t session, const mac_entry_st * hash_algo, gnutls_pcert_st * cert, gnutls_privkey_t pkey, const gnutls_datum_t * hash_concat, gnutls_datum_t * signature) { const version_entry_st *ver = get_version(session); unsigned int key_usage = 0; /* If our certificate supports signing */ if (cert != NULL) { gnutls_pubkey_get_key_usage(cert->pubkey, &key_usage); if (key_usage != 0) if (!(key_usage & GNUTLS_KEY_DIGITAL_SIGNATURE)) { gnutls_assert(); _gnutls_audit_log(session, "Peer's certificate does not allow digital signatures. Key usage violation detected (ignored).\n"); } /* External signing. Deprecated. To be removed. */ if (!pkey) { int ret; if (!session->internals.sign_func) return gnutls_assert_val (GNUTLS_E_INSUFFICIENT_CREDENTIALS); if (!_gnutls_version_has_selectable_sighash(ver)) return (*session->internals.sign_func) (session, session->internals.sign_func_userdata, cert->type, &cert->cert, hash_concat, signature); else { gnutls_datum_t digest; ret = _gnutls_set_datum(&digest, hash_concat->data, hash_concat->size); if (ret < 0) return gnutls_assert_val(ret); ret = pk_prepare_hash (gnutls_pubkey_get_pk_algorithm (cert->pubkey, NULL), hash_algo, &digest); if (ret < 0) { gnutls_assert(); goto es_cleanup; } ret = (*session->internals.sign_func) (session, session->internals.sign_func_userdata, cert->type, &cert->cert, &digest, signature); es_cleanup: gnutls_free(digest.data); return ret; } } } if (!_gnutls_version_has_selectable_sighash(ver)) return gnutls_privkey_sign_raw_data(pkey, 0, hash_concat, signature); else return gnutls_privkey_sign_hash(pkey, (gnutls_digest_algorithm_t)hash_algo->id, 0, hash_concat, signature); }
/* This is a receive function for the gnutls handshake * protocol. Makes sure that we have received all data. */ static int parse_record_buffered_msgs (gnutls_session_t session, gnutls_handshake_description_t htype, handshake_buffer_st * hsk) { gnutls_datum_t msg; mbuffer_st* bufel = NULL, *prev = NULL; int ret; size_t data_size; handshake_buffer_st* recv_buf = session->internals.handshake_recv_buffer; bufel = _mbuffer_head_get_first(&session->internals.record_buffer, &msg); if (bufel == NULL) return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; if (!IS_DTLS(session)) { ssize_t remain, append, header_size; do { if (bufel->type != GNUTLS_HANDSHAKE) return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET); /* if we have a half received message the complete it. */ remain = recv_buf[0].length - recv_buf[0].data.length; /* this is the rest of a previous message */ if (session->internals.handshake_recv_buffer_size > 0 && recv_buf[0].length > 0 && remain > 0) { if (msg.size <= remain) append = msg.size; else append = remain; ret = _gnutls_buffer_append_data(&recv_buf[0].data, msg.data, append); if (ret < 0) return gnutls_assert_val(ret); _mbuffer_head_remove_bytes(&session->internals.record_buffer, append); } else /* received new message */ { ret = parse_handshake_header(session, bufel, htype, &recv_buf[0]); if (ret < 0) return gnutls_assert_val(ret); header_size = ret; session->internals.handshake_recv_buffer_size = 1; _mbuffer_set_uhead_size(bufel, header_size); data_size = MIN(recv_buf[0].length, _mbuffer_get_udata_size(bufel)); ret = _gnutls_buffer_append_data(&recv_buf[0].data, _mbuffer_get_udata_ptr(bufel), data_size); if (ret < 0) return gnutls_assert_val(ret); _mbuffer_set_uhead_size(bufel, 0); _mbuffer_head_remove_bytes(&session->internals.record_buffer, data_size+header_size); if (cmp_hsk_types(htype, recv_buf[0].htype) == 0) { /* an unexpected packet */ hsk->htype = recv_buf[0].htype; return gnutls_assert_val(GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET); } } /* if packet is complete then return it */ if (recv_buf[0].length == recv_buf[0].data.length) { return get_last_packet(session, htype, hsk); } bufel = _mbuffer_head_get_first(&session->internals.record_buffer, &msg); } while(bufel != NULL); /* if we are here it means that the received packets were not * enough to complete the handshake packet. */ return gnutls_assert_val(GNUTLS_E_AGAIN); } else /* DTLS */ { handshake_buffer_st tmp; do { /* we now * 0. parse headers * 1. insert to handshake_recv_buffer * 2. sort handshake_recv_buffer on sequence numbers * 3. return first packet if completed or GNUTLS_E_AGAIN. */ do { if (bufel->type != GNUTLS_HANDSHAKE) { gnutls_assert(); goto next; /* ignore packet */ } _gnutls_handshake_buffer_init(&tmp); ret = parse_handshake_header(session, bufel, htype, &tmp); if (ret < 0) { gnutls_assert(); _gnutls_audit_log("Invalid handshake packet headers. Discarding.\n"); break; } _mbuffer_consume(&session->internals.record_buffer, bufel, ret); data_size = MIN(tmp.length, tmp.end_offset-tmp.start_offset+1); ret = _gnutls_buffer_append_data(&tmp.data, _mbuffer_get_udata_ptr(bufel), data_size); if (ret < 0) return gnutls_assert_val(ret); _mbuffer_consume(&session->internals.record_buffer, bufel, data_size); ret = merge_handshake_packet(session, &tmp); if (ret < 0) return gnutls_assert_val(ret); } while(_mbuffer_get_udata_size(bufel) > 0); prev = bufel; bufel = _mbuffer_dequeue(&session->internals.record_buffer, bufel); _mbuffer_xfree(&prev); continue; next: bufel = _mbuffer_head_get_next(bufel, NULL); } while(bufel != NULL); /* sort in descending order */ if (session->internals.handshake_recv_buffer_size > 1) qsort(recv_buf, session->internals.handshake_recv_buffer_size, sizeof(recv_buf[0]), handshake_compare); while(session->internals.handshake_recv_buffer_size > 0 && recv_buf[LAST_ELEMENT].sequence < session->internals.dtls.hsk_read_seq) { _gnutls_audit_log("Discarded replayed handshake packet with sequence %d\n", recv_buf[LAST_ELEMENT].sequence); _gnutls_handshake_buffer_clear(&recv_buf[LAST_ELEMENT]); session->internals.handshake_recv_buffer_size--; } return get_last_packet(session, htype, hsk); } }
/* returns the last stored handshake packet. */ static int get_last_packet(gnutls_session_t session, gnutls_handshake_description_t htype, handshake_buffer_st * hsk, unsigned int optional) { handshake_buffer_st *recv_buf = session->internals.handshake_recv_buffer; if (IS_DTLS(session)) { if (session->internals.handshake_recv_buffer_size == 0 || (session->internals.dtls.hsk_read_seq != recv_buf[LAST_ELEMENT].sequence)) goto timeout; if (htype != recv_buf[LAST_ELEMENT].htype) { if (optional == 0) _gnutls_audit_log(session, "Received unexpected handshake message '%s' (%d). Expected '%s' (%d)\n", _gnutls_handshake2str (recv_buf[0].htype), (int) recv_buf[0].htype, _gnutls_handshake2str (htype), (int) htype); return gnutls_assert_val (GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET); } else if ((recv_buf[LAST_ELEMENT].start_offset == 0 && recv_buf[LAST_ELEMENT].end_offset == recv_buf[LAST_ELEMENT].length - 1) || recv_buf[LAST_ELEMENT].length == 0) { session->internals.dtls.hsk_read_seq++; _gnutls_handshake_buffer_move(hsk, &recv_buf [LAST_ELEMENT]); session->internals.handshake_recv_buffer_size--; return 0; } else { /* if we don't have a complete handshake message, but we * have queued data waiting, try again to reconstruct the * handshake packet, using the queued */ if (recv_buf[LAST_ELEMENT].end_offset != recv_buf[LAST_ELEMENT].length - 1 && record_check_unprocessed(session) > 0) return gnutls_assert_val(GNUTLS_E_INT_CHECK_AGAIN); else goto timeout; } } else { /* TLS */ if (session->internals.handshake_recv_buffer_size > 0 && recv_buf[0].length == recv_buf[0].data.length) { if (cmp_hsk_types(htype, recv_buf[0].htype) == 0) { return gnutls_assert_val (GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET); } _gnutls_handshake_buffer_move(hsk, &recv_buf[0]); session->internals.handshake_recv_buffer_size--; return 0; } else return gnutls_assert_val (GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE); } timeout: RETURN_DTLS_EAGAIN_OR_TIMEOUT(session, 0); }
static int decrypt_packet_tls13(gnutls_session_t session, gnutls_datum_t *ciphertext, gnutls_datum_t *plain, content_type_t *type, record_parameters_st *params, gnutls_uint64 *sequence) { uint8_t nonce[MAX_CIPHER_IV_SIZE]; size_t length, length_to_decrypt; int ret; const version_entry_st *ver = get_version(session); unsigned int tag_size = params->read.aead_tag_size; unsigned iv_size; unsigned j; volatile unsigned length_set; uint8_t aad[5]; if (unlikely(ver == NULL)) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); if (params->cipher->id == GNUTLS_CIPHER_NULL) { if (plain->size < ciphertext->size) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); length = ciphertext->size; memcpy(plain->data, ciphertext->data, length); return length; } iv_size = _gnutls_cipher_get_iv_size(params->cipher); /* The way AEAD ciphers are defined in RFC5246, it allows * only stream ciphers. */ if (unlikely(ciphertext->size < tag_size)) return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); if (unlikely(params->read.iv_size != iv_size || iv_size < 8)) return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); memcpy(nonce, params->read.iv, params->read.iv_size); memxor(&nonce[iv_size-8], UINT64DATA(*sequence), 8); length = ciphertext->size - tag_size; length_to_decrypt = ciphertext->size; if (unlikely ((unsigned) length_to_decrypt > plain->size)) { _gnutls_audit_log(session, "Received %u bytes, while expecting less than %u\n", (unsigned int) length_to_decrypt, (unsigned int) plain->size); return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); } aad[0] = GNUTLS_APPLICATION_DATA; aad[1] = 0x03; aad[2] = 0x03; _gnutls_write_uint16(ciphertext->size, &aad[3]); ret = gnutls_aead_cipher_decrypt(¶ms->read.ctx.aead, nonce, iv_size, aad, sizeof(aad), tag_size, ciphertext->data, length_to_decrypt, plain->data, &length); if (unlikely(ret < 0)) return gnutls_assert_val(ret); /* 1 octet for content type */ if (length > max_decrypted_size(session) + 1) { _gnutls_audit_log (session, "Received packet with illegal length: %u\n", (unsigned int) length); return gnutls_assert_val(GNUTLS_E_RECORD_OVERFLOW); } length_set = 0; /* now figure the actual data size. We intentionally iterate through all data, * to avoid leaking the padding length due to timing differences in processing. */ for (j=length;j>0;j--) { if (plain->data[j-1]!=0 && length_set == 0) { *type = plain->data[j-1]; length = j-1; length_set = 1; if (!(session->internals.flags & GNUTLS_SAFE_PADDING_CHECK)) break; } } if (!length_set) return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); return length; }
int _gnutls_fips_perform_self_checks2(void) { int ret; _gnutls_switch_lib_state(LIB_STATE_SELFTEST); /* Tests the FIPS algorithms */ /* ciphers - one test per cipher */ ret = gnutls_cipher_self_test(0, GNUTLS_CIPHER_3DES_CBC); if (ret < 0) { gnutls_assert(); goto error; } ret = gnutls_cipher_self_test(0, GNUTLS_CIPHER_AES_256_GCM); if (ret < 0) { gnutls_assert(); goto error; } /* MAC (includes message digest test) */ ret = gnutls_mac_self_test(0, GNUTLS_MAC_SHA1); if (ret < 0) { gnutls_assert(); goto error; } ret = gnutls_mac_self_test(0, GNUTLS_MAC_SHA224); if (ret < 0) { gnutls_assert(); goto error; } ret = gnutls_mac_self_test(0, GNUTLS_MAC_SHA256); if (ret < 0) { gnutls_assert(); goto error; } ret = gnutls_mac_self_test(0, GNUTLS_MAC_SHA384); if (ret < 0) { gnutls_assert(); goto error; } ret = gnutls_mac_self_test(0, GNUTLS_MAC_SHA512); if (ret < 0) { gnutls_assert(); goto error; } /* PK */ ret = gnutls_pk_self_test(0, GNUTLS_PK_RSA); if (ret < 0) { gnutls_assert(); goto error; } ret = gnutls_pk_self_test(0, GNUTLS_PK_DSA); if (ret < 0) { gnutls_assert(); goto error; } ret = gnutls_pk_self_test(0, GNUTLS_PK_EC); if (ret < 0) { gnutls_assert(); goto error; } ret = gnutls_pk_self_test(0, GNUTLS_PK_DH); if (ret < 0) { gnutls_assert(); goto error; } if (_gnutls_rnd_ops.self_test == NULL) { gnutls_assert(); goto error; } ret = _gnutls_rnd_ops.self_test(); if (ret < 0) { gnutls_assert(); goto error; } if (_skip_integrity_checks == 0) { ret = check_binary_integrity(GNUTLS_LIBRARY_NAME, "gnutls_global_init"); if (ret == 0) { gnutls_assert(); goto error; } ret = check_binary_integrity(NETTLE_LIBRARY_NAME, "nettle_aes_set_encrypt_key"); if (ret == 0) { gnutls_assert(); goto error; } ret = check_binary_integrity(HOGWEED_LIBRARY_NAME, "nettle_mpz_sizeinbase_256_u"); if (ret == 0) { gnutls_assert(); goto error; } ret = check_binary_integrity(GMP_LIBRARY_NAME, "__gmpz_init"); if (ret == 0) { gnutls_assert(); goto error; } } return 0; error: _gnutls_switch_lib_state(LIB_STATE_ERROR); _gnutls_audit_log(NULL, "FIPS140-2 self testing part 2 failed\n"); return GNUTLS_E_SELF_TEST_ERROR; }
int proc_rsa_export_client_kx (gnutls_session_t session, opaque * data, size_t _data_size) { gnutls_datum_t plaintext; gnutls_datum_t ciphertext; int ret, dsize; bigint_t *params; int params_len; int randomize_key = 0; ssize_t data_size = _data_size; if (gnutls_protocol_get_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; } ret = _gnutls_get_private_rsa_params (session, ¶ms, ¶ms_len); if (ret < 0) { gnutls_assert (); return ret; } ret = _gnutls_pkcs1_rsa_decrypt (&plaintext, &ciphertext, params, params_len, 2); /* btype==2 */ 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_assert (); _gnutls_audit_log ("auth_rsa: Possible PKCS #1 format attack\n"); randomize_key = 1; } else { /* If the secret was properly formatted, then * check the version number. */ if (_gnutls_get_adv_version_major (session) != plaintext.data[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_assert (); _gnutls_audit_log ("auth_rsa: Possible PKCS #1 version check format attack\n"); } } if (randomize_key != 0) { 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; } /* we do not need strong random numbers here. */ ret = _gnutls_rnd (GNUTLS_RND_NONCE, session->key->key.data, session->key->key.size); if (ret < 0) { gnutls_assert (); return ret; } } 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); return 0; }
/* Deciphers the ciphertext packet, and puts the result to plain. * Returns the actual plaintext packet size. */ static int decrypt_packet(gnutls_session_t session, gnutls_datum_t * ciphertext, gnutls_datum_t * plain, content_type_t type, record_parameters_st * params, gnutls_uint64 * sequence) { uint8_t tag[MAX_HASH_SIZE]; uint8_t nonce[MAX_CIPHER_IV_SIZE]; const uint8_t *tag_ptr = NULL; unsigned int pad = 0; int length, length_to_decrypt; uint16_t blocksize; int ret; uint8_t preamble[MAX_PREAMBLE_SIZE]; unsigned int preamble_size = 0; const version_entry_st *ver = get_version(session); unsigned int tag_size = _gnutls_auth_cipher_tag_len(¶ms->read.ctx.tls12); unsigned int explicit_iv = _gnutls_version_has_explicit_iv(ver); unsigned imp_iv_size, exp_iv_size; unsigned cipher_type = _gnutls_cipher_type(params->cipher); bool etm = 0; if (unlikely(ver == NULL)) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); imp_iv_size = _gnutls_cipher_get_implicit_iv_size(params->cipher); exp_iv_size = _gnutls_cipher_get_explicit_iv_size(params->cipher); blocksize = _gnutls_cipher_get_block_size(params->cipher); if (params->etm !=0 && cipher_type == CIPHER_BLOCK) etm = 1; /* if EtM mode and not AEAD */ if (etm) { if (unlikely(ciphertext->size < tag_size)) return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH); preamble_size = _gnutls_make_preamble(UINT64DATA(*sequence), type, ciphertext->size-tag_size, ver, preamble); ret = _gnutls_auth_cipher_add_auth(¶ms->read. ctx.tls12, preamble, preamble_size); if (unlikely(ret < 0)) return gnutls_assert_val(ret); ret = _gnutls_auth_cipher_add_auth(¶ms->read. ctx.tls12, ciphertext->data, ciphertext->size-tag_size); if (unlikely(ret < 0)) return gnutls_assert_val(ret); ret = _gnutls_auth_cipher_tag(¶ms->read.ctx.tls12, tag, tag_size); if (unlikely(ret < 0)) return gnutls_assert_val(ret); if (unlikely(gnutls_memcmp(tag, &ciphertext->data[ciphertext->size-tag_size], tag_size) != 0)) { /* HMAC was not the same. */ return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); } } /* actual decryption (inplace) */ switch (cipher_type) { case CIPHER_AEAD: /* The way AEAD ciphers are defined in RFC5246, it allows * only stream ciphers. */ if (unlikely(_gnutls_auth_cipher_is_aead(¶ms->read. ctx.tls12) == 0)) return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); if (unlikely(ciphertext->size < (tag_size + exp_iv_size))) return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); if (params->cipher->xor_nonce == 0) { /* Values in AEAD are pretty fixed in TLS 1.2 for 128-bit block */ if (unlikely(params->read.iv_size != 4)) return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); memcpy(nonce, params->read.iv, imp_iv_size); memcpy(&nonce[imp_iv_size], ciphertext->data, exp_iv_size); ciphertext->data += exp_iv_size; ciphertext->size -= exp_iv_size; } else { /* XOR nonce with IV */ if (unlikely(params->read.iv_size != 12 || imp_iv_size != 12 || exp_iv_size != 0)) return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); memset(nonce, 0, 4); memcpy(&nonce[4], UINT64DATA(*sequence), 8); memxor(nonce, params->read.iv, 12); } length = ciphertext->size - tag_size; length_to_decrypt = ciphertext->size; /* Pass the type, version, length and plain through * MAC. */ preamble_size = _gnutls_make_preamble(UINT64DATA(*sequence), type, length, ver, preamble); if (unlikely ((unsigned) length_to_decrypt > plain->size)) { _gnutls_audit_log(session, "Received %u bytes, while expecting less than %u\n", (unsigned int) length_to_decrypt, (unsigned int) plain->size); return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); } ret = _gnutls_aead_cipher_decrypt(¶ms->read.ctx.tls12.cipher, nonce, exp_iv_size + imp_iv_size, preamble, preamble_size, tag_size, ciphertext->data, length_to_decrypt, plain->data, plain->size); if (unlikely(ret < 0)) return gnutls_assert_val(ret); return length; break; case CIPHER_STREAM: if (unlikely(ciphertext->size < tag_size)) return gnutls_assert_val (GNUTLS_E_UNEXPECTED_PACKET_LENGTH); length_to_decrypt = ciphertext->size; length = ciphertext->size - tag_size; tag_ptr = plain->data + length; /* Pass the type, version, length and plain through * MAC. */ preamble_size = _gnutls_make_preamble(UINT64DATA(*sequence), type, length, ver, preamble); ret = _gnutls_auth_cipher_add_auth(¶ms->read. ctx.tls12, preamble, preamble_size); if (unlikely(ret < 0)) return gnutls_assert_val(ret); if (unlikely ((unsigned) length_to_decrypt > plain->size)) { _gnutls_audit_log(session, "Received %u bytes, while expecting less than %u\n", (unsigned int) length_to_decrypt, (unsigned int) plain->size); return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); } ret = _gnutls_auth_cipher_decrypt2(¶ms->read. ctx.tls12, ciphertext->data, length_to_decrypt, plain->data, plain->size); if (unlikely(ret < 0)) return gnutls_assert_val(ret); ret = _gnutls_auth_cipher_tag(¶ms->read.ctx.tls12, tag, tag_size); if (unlikely(ret < 0)) return gnutls_assert_val(ret); if (unlikely (gnutls_memcmp(tag, tag_ptr, tag_size) != 0)) { return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); } break; case CIPHER_BLOCK: if (unlikely(ciphertext->size < blocksize)) return gnutls_assert_val (GNUTLS_E_UNEXPECTED_PACKET_LENGTH); if (etm == 0) { if (unlikely(ciphertext->size % blocksize != 0)) return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH); } else { if (unlikely((ciphertext->size - tag_size) % blocksize != 0)) return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH); } /* ignore the IV in TLS 1.1+ */ if (explicit_iv) { _gnutls_auth_cipher_setiv(¶ms->read. ctx.tls12, ciphertext->data, blocksize); memcpy(nonce, ciphertext->data, blocksize); ciphertext->size -= blocksize; ciphertext->data += blocksize; } if (unlikely(ciphertext->size < tag_size + 1)) return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); /* we don't use the auth_cipher interface here, since * TLS with block ciphers is impossible to be used under such * an API. (the length of plaintext is required to calculate * auth_data, but it is not available before decryption). */ if (unlikely(ciphertext->size > plain->size)) return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); if (etm == 0) { ret = _gnutls_cipher_decrypt2(¶ms->read.ctx.tls12. cipher, ciphertext->data, ciphertext->size, plain->data, plain->size); if (unlikely(ret < 0)) return gnutls_assert_val(ret); ret = cbc_mac_verify(session, params, preamble, type, sequence, plain->data, ciphertext->size, tag_size); if (unlikely(ret < 0)) return gnutls_assert_val(ret); length = ret; } else { /* EtM */ ret = _gnutls_cipher_decrypt2(¶ms->read.ctx.tls12. cipher, ciphertext->data, ciphertext->size - tag_size, plain->data, plain->size); if (unlikely(ret < 0)) return gnutls_assert_val(ret); pad = plain->data[ciphertext->size - tag_size - 1]; /* pad */ length = ciphertext->size - tag_size - pad - 1; if (unlikely(length < 0)) return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); } break; default: return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); } return length; }