static int digest_ticket(const gnutls_datum_t * key, struct ticket_st *ticket, uint8_t * digest) { mac_hd_st digest_hd; uint16_t length16; int ret; ret = _gnutls_mac_init(&digest_hd, mac_to_entry(TICKET_MAC_ALGO), key->data, key->size); if (ret < 0) { gnutls_assert(); return ret; } _gnutls_mac(&digest_hd, ticket->key_name, TICKET_KEY_NAME_SIZE); _gnutls_mac(&digest_hd, ticket->IV, TICKET_IV_SIZE); length16 = _gnutls_conv_uint16(ticket->encrypted_state_len); _gnutls_mac(&digest_hd, &length16, 2); _gnutls_mac(&digest_hd, ticket->encrypted_state, ticket->encrypted_state_len); _gnutls_mac_deinit(&digest_hd, digest); return 0; }
/* generates the authentication data (data to be hashed only * and are not to be send). Returns their size. */ static inline int make_preamble (opaque * uint64_data, opaque type, int length, opaque ver, opaque * preamble) { opaque minor = _gnutls_version_get_minor (ver); opaque major = _gnutls_version_get_major (ver); opaque *p = preamble; uint16_t c_length; c_length = _gnutls_conv_uint16 (length); memcpy (p, uint64_data, 8); p += 8; *p = type; p++; if (ver != GNUTLS_SSL3) { /* TLS protocols */ *p = major; p++; *p = minor; p++; } memcpy (p, &c_length, 2); p += 2; return p - preamble; }
/* generates the authentication data (data to be hashed only * and are not to be sent). Returns their size. */ int _gnutls_make_preamble(uint8_t * uint64_data, uint8_t type, unsigned int length, const version_entry_st * ver, uint8_t preamble[MAX_PREAMBLE_SIZE]) { uint8_t *p = preamble; uint16_t c_length; c_length = _gnutls_conv_uint16(length); memcpy(p, uint64_data, 8); p += 8; *p = type; p++; #ifdef ENABLE_SSL3 if (ver->id != GNUTLS_SSL3) #endif { /* TLS protocols */ *p = ver->major; p++; *p = ver->minor; p++; } memcpy(p, &c_length, 2); p += 2; return p - preamble; }
/* generates the authentication data (data to be hashed only * and are not to be sent). Returns their size. */ static inline int make_preamble(uint8_t * uint64_data, uint8_t type, unsigned int length, const version_entry_st * ver, uint8_t * preamble) { uint8_t *p = preamble; uint16_t c_length; c_length = _gnutls_conv_uint16(length); memcpy(p, uint64_data, 8); p += 8; *p = type; p++; if (ver->id != GNUTLS_SSL3) { /* TLS protocols */ *p = ver->major; p++; *p = ver->minor; p++; } memcpy(p, &c_length, 2); p += 2; return p - preamble; }
/* Deciphers the ciphertext packet, and puts the result to compress_data, of compress_size. * Returns the actual compressed packet size. */ int _gnutls_ciphertext2compressed (gnutls_session_t session, opaque * compress_data, int compress_size, gnutls_datum_t ciphertext, uint8_t type, record_parameters_st * params) { uint8_t MAC[MAX_HASH_SIZE]; uint16_t c_length; uint8_t pad; int length; uint16_t blocksize; int ret, i, pad_failed = 0; opaque preamble[PREAMBLE_SIZE]; int preamble_size; int ver = gnutls_protocol_get_version (session); int hash_size = _gnutls_hash_get_algo_len (params->mac_algorithm); blocksize = gnutls_cipher_get_block_size (params->cipher_algorithm); /* actual decryption (inplace) */ switch (_gnutls_cipher_is_block (params->cipher_algorithm)) { case CIPHER_STREAM: if ((ret = _gnutls_cipher_decrypt (¶ms->read.cipher_state, ciphertext.data, ciphertext.size)) < 0) { gnutls_assert (); return ret; } length = ciphertext.size - hash_size; break; case CIPHER_BLOCK: if ((ciphertext.size < blocksize) || (ciphertext.size % blocksize != 0)) { gnutls_assert (); return GNUTLS_E_DECRYPTION_FAILED; } if ((ret = _gnutls_cipher_decrypt (¶ms->read.cipher_state, ciphertext.data, ciphertext.size)) < 0) { gnutls_assert (); return ret; } /* ignore the IV in TLS 1.1. */ if (_gnutls_version_has_explicit_iv (session->security_parameters.version)) { ciphertext.size -= blocksize; ciphertext.data += blocksize; if (ciphertext.size == 0) { gnutls_assert (); return GNUTLS_E_DECRYPTION_FAILED; } } pad = ciphertext.data[ciphertext.size - 1] + 1; /* pad */ if ((int) pad > (int) ciphertext.size - hash_size) { gnutls_assert (); _gnutls_record_log ("REC[%p]: Short record length %d > %d - %d (under attack?)\n", session, pad, ciphertext.size, hash_size); /* We do not fail here. We check below for the * the pad_failed. If zero means success. */ pad_failed = GNUTLS_E_DECRYPTION_FAILED; } length = ciphertext.size - hash_size - pad; /* Check the pading bytes (TLS 1.x) */ if (_gnutls_version_has_variable_padding (ver) && pad_failed == 0) for (i = 2; i < pad; i++) { if (ciphertext.data[ciphertext.size - i] != ciphertext.data[ciphertext.size - 1]) pad_failed = GNUTLS_E_DECRYPTION_FAILED; } break; default: gnutls_assert (); return GNUTLS_E_INTERNAL_ERROR; } if (length < 0) length = 0; c_length = _gnutls_conv_uint16 ((uint16_t) length); /* Pass the type, version, length and compressed through * MAC. */ if (params->mac_algorithm != GNUTLS_MAC_NULL) { digest_hd_st td; ret = mac_init (&td, params->mac_algorithm, params->read.mac_secret.data, params->read.mac_secret.size, ver); if (ret < 0) { gnutls_assert (); return GNUTLS_E_INTERNAL_ERROR; } preamble_size = make_preamble (UINT64DATA (params->read.sequence_number), type, c_length, ver, preamble); mac_hash (&td, preamble, preamble_size, ver); if (length > 0) mac_hash (&td, ciphertext.data, length, ver); mac_deinit (&td, MAC, ver); } /* This one was introduced to avoid a timing attack against the TLS * 1.0 protocol. */ if (pad_failed != 0) { gnutls_assert (); return pad_failed; } /* HMAC was not the same. */ if (memcmp (MAC, &ciphertext.data[length], hash_size) != 0) { gnutls_assert (); return GNUTLS_E_DECRYPTION_FAILED; } /* copy the decrypted stuff to compress_data. */ if (compress_size < length) { gnutls_assert (); return GNUTLS_E_DECOMPRESSION_FAILED; } memcpy (compress_data, ciphertext.data, length); return length; }
/* This is the actual encryption * Encrypts the given compressed datum, and puts the result to cipher_data, * which has cipher_size size. * return the actual encrypted data length. */ int _gnutls_compressed2ciphertext (gnutls_session_t session, opaque * cipher_data, int cipher_size, gnutls_datum_t compressed, content_type_t _type, int random_pad, record_parameters_st * params) { uint8_t MAC[MAX_HASH_SIZE]; uint16_t c_length; uint8_t pad; int length, ret; uint8_t type = _type; opaque preamble[PREAMBLE_SIZE]; int preamble_size; int hash_size = _gnutls_hash_get_algo_len (params->mac_algorithm); int blocksize = gnutls_cipher_get_block_size (params->cipher_algorithm); cipher_type_t block_algo = _gnutls_cipher_is_block (params->cipher_algorithm); opaque *data_ptr; int ver = gnutls_protocol_get_version (session); /* Initialize MAC */ c_length = _gnutls_conv_uint16 (compressed.size); if (params->mac_algorithm != GNUTLS_MAC_NULL) { /* actually when the algorithm in not the NULL one */ digest_hd_st td; ret = mac_init (&td, params->mac_algorithm, params->write.mac_secret.data, params->write.mac_secret.size, ver); if (ret < 0) { gnutls_assert (); return ret; } preamble_size = make_preamble (UINT64DATA (params->write.sequence_number), type, c_length, ver, preamble); mac_hash (&td, preamble, preamble_size, ver); mac_hash (&td, compressed.data, compressed.size, ver); mac_deinit (&td, MAC, ver); } /* Calculate the encrypted length (padding etc.) */ length = calc_enc_length (session, compressed.size, hash_size, &pad, random_pad, block_algo, blocksize); if (length < 0) { gnutls_assert (); return length; } /* copy the encrypted data to cipher_data. */ if (cipher_size < length) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } data_ptr = cipher_data; if (block_algo == CIPHER_BLOCK && _gnutls_version_has_explicit_iv (session->security_parameters.version)) { /* copy the random IV. */ ret = _gnutls_rnd (GNUTLS_RND_NONCE, data_ptr, blocksize); if (ret < 0) { gnutls_assert (); return ret; } data_ptr += blocksize; } memcpy (data_ptr, compressed.data, compressed.size); data_ptr += compressed.size; if (hash_size > 0) { memcpy (data_ptr, MAC, hash_size); data_ptr += hash_size; } if (block_algo == CIPHER_BLOCK && pad > 0) { memset (data_ptr, pad - 1, pad); } /* Actual encryption (inplace). */ ret = _gnutls_cipher_encrypt (¶ms->write.cipher_state, cipher_data, length); if (ret < 0) { gnutls_assert (); return ret; } return length; }
/* Deciphers the ciphertext packet, and puts the result to compress_data, of compress_size. * Returns the actual compressed packet size. */ int _gnutls_ciphertext2compressed (gnutls_session_t session, opaque * compress_data, int compress_size, gnutls_datum_t ciphertext, uint8_t type) { uint8_t MAC[MAX_HASH_SIZE]; uint16_t c_length; uint8_t pad; int length; digest_hd_st td; uint16_t blocksize; int ret, i, pad_failed = 0; uint8_t major, minor; gnutls_protocol_t ver; int hash_size = _gnutls_hash_get_algo_len (session->security_parameters. read_mac_algorithm); ver = gnutls_protocol_get_version (session); minor = _gnutls_version_get_minor (ver); major = _gnutls_version_get_major (ver); blocksize = _gnutls_cipher_get_block_size (session->security_parameters. read_bulk_cipher_algorithm); /* initialize MAC */ ret = mac_init (&td, session->security_parameters.read_mac_algorithm, session->connection_state.read_mac_secret.data, session->connection_state.read_mac_secret.size, ver); if (ret < 0 && session->security_parameters.read_mac_algorithm != GNUTLS_MAC_NULL) { gnutls_assert (); return GNUTLS_E_INTERNAL_ERROR; } /* actual decryption (inplace) */ switch (_gnutls_cipher_is_block (session->security_parameters.read_bulk_cipher_algorithm)) { case CIPHER_STREAM: if ((ret = _gnutls_cipher_decrypt (&session->connection_state. read_cipher_state, ciphertext.data, ciphertext.size)) < 0) { gnutls_assert (); return ret; } length = ciphertext.size - hash_size; break; case CIPHER_BLOCK: if ((ciphertext.size < blocksize) || (ciphertext.size % blocksize != 0)) { gnutls_assert (); return GNUTLS_E_DECRYPTION_FAILED; } if ((ret = _gnutls_cipher_decrypt (&session->connection_state. read_cipher_state, ciphertext.data, ciphertext.size)) < 0) { gnutls_assert (); return ret; } /* ignore the IV in TLS 1.1. */ if (session->security_parameters.version >= GNUTLS_TLS1_1) { ciphertext.size -= blocksize; ciphertext.data += blocksize; if (ciphertext.size == 0) { gnutls_assert (); return GNUTLS_E_DECRYPTION_FAILED; } } pad = ciphertext.data[ciphertext.size - 1] + 1; /* pad */ if ((int) pad > (int) ciphertext.size - hash_size) { gnutls_assert (); _gnutls_record_log ("REC[%x]: Short record length %d > %d - %d (under attack?)\n", session, pad, ciphertext.size, hash_size); /* We do not fail here. We check below for the * the pad_failed. If zero means success. */ pad_failed = GNUTLS_E_DECRYPTION_FAILED; } length = ciphertext.size - hash_size - pad; /* Check the pading bytes (TLS 1.x) */ if (ver >= GNUTLS_TLS1 && pad_failed == 0) for (i = 2; i < pad; i++) { if (ciphertext.data[ciphertext.size - i] != ciphertext.data[ciphertext.size - 1]) pad_failed = GNUTLS_E_DECRYPTION_FAILED; } break; default: gnutls_assert (); return GNUTLS_E_INTERNAL_ERROR; } if (length < 0) length = 0; c_length = _gnutls_conv_uint16 ((uint16_t) length); /* Pass the type, version, length and compressed through * MAC. */ if (session->security_parameters.read_mac_algorithm != GNUTLS_MAC_NULL) { _gnutls_hmac (&td, UINT64DATA (session->connection_state. read_sequence_number), 8); _gnutls_hmac (&td, &type, 1); if (ver >= GNUTLS_TLS1) { /* TLS 1.x */ _gnutls_hmac (&td, &major, 1); _gnutls_hmac (&td, &minor, 1); } _gnutls_hmac (&td, &c_length, 2); if (length > 0) _gnutls_hmac (&td, ciphertext.data, length); mac_deinit (&td, MAC, ver); } /* This one was introduced to avoid a timing attack against the TLS * 1.0 protocol. */ if (pad_failed != 0) return pad_failed; /* HMAC was not the same. */ if (memcmp (MAC, &ciphertext.data[length], hash_size) != 0) { gnutls_assert (); return GNUTLS_E_DECRYPTION_FAILED; } /* copy the decrypted stuff to compress_data. */ if (compress_size < length) { gnutls_assert (); return GNUTLS_E_DECOMPRESSION_FAILED; } memcpy (compress_data, ciphertext.data, length); return length; }
/* This is the actual encryption * Encrypts the given compressed datum, and puts the result to cipher_data, * which has cipher_size size. * return the actual encrypted data length. */ int _gnutls_compressed2ciphertext (gnutls_session_t session, opaque * cipher_data, int cipher_size, gnutls_datum_t compressed, content_type_t _type, int random_pad) { uint8_t MAC[MAX_HASH_SIZE]; uint16_t c_length; uint8_t pad; int length, ret; digest_hd_st td; uint8_t type = _type; uint8_t major, minor; int hash_size = _gnutls_hash_get_algo_len (session->security_parameters. write_mac_algorithm); gnutls_protocol_t ver; int blocksize = _gnutls_cipher_get_block_size (session->security_parameters. write_bulk_cipher_algorithm); cipher_type_t block_algo = _gnutls_cipher_is_block (session->security_parameters. write_bulk_cipher_algorithm); opaque *data_ptr; ver = gnutls_protocol_get_version (session); minor = _gnutls_version_get_minor (ver); major = _gnutls_version_get_major (ver); /* Initialize MAC */ ret = mac_init (&td, session->security_parameters.write_mac_algorithm, session->connection_state.write_mac_secret.data, session->connection_state.write_mac_secret.size, ver); if (ret < 0 && session->security_parameters.write_mac_algorithm != GNUTLS_MAC_NULL) { gnutls_assert (); return ret; } c_length = _gnutls_conv_uint16 (compressed.size); if (session->security_parameters.write_mac_algorithm != GNUTLS_MAC_NULL) { /* actually when the algorithm in not the NULL one */ _gnutls_hmac (&td, UINT64DATA (session->connection_state. write_sequence_number), 8); _gnutls_hmac (&td, &type, 1); if (ver >= GNUTLS_TLS1) { /* TLS 1.0 or higher */ _gnutls_hmac (&td, &major, 1); _gnutls_hmac (&td, &minor, 1); } _gnutls_hmac (&td, &c_length, 2); _gnutls_hmac (&td, compressed.data, compressed.size); mac_deinit (&td, MAC, ver); } /* Calculate the encrypted length (padding etc.) */ length = calc_enc_length (session, compressed.size, hash_size, &pad, random_pad, block_algo, blocksize); if (length < 0) { gnutls_assert (); return length; } /* copy the encrypted data to cipher_data. */ if (cipher_size < length) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } data_ptr = cipher_data; if (block_algo == CIPHER_BLOCK && session->security_parameters.version >= GNUTLS_TLS1_1) { /* copy the random IV. */ ret = _gnutls_rnd (GNUTLS_RND_NONCE, data_ptr, blocksize); if (ret < 0) { gnutls_assert (); return ret; } data_ptr += blocksize; } memcpy (data_ptr, compressed.data, compressed.size); data_ptr += compressed.size; if (hash_size > 0) { memcpy (data_ptr, MAC, hash_size); data_ptr += hash_size; } if (block_algo == CIPHER_BLOCK && pad > 0) { memset (data_ptr, pad - 1, pad); } /* Actual encryption (inplace). */ ret = _gnutls_cipher_encrypt (&session->connection_state.write_cipher_state, cipher_data, length); if (ret < 0) { gnutls_assert (); return ret; } return length; }