1 /* 2 * TLSv1 Record Protocol 3 * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 as 7 * published by the Free Software Foundation. 8 * 9 * Alternatively, this software may be distributed under the terms of BSD 10 * license. 11 * 12 * See README and COPYING for more details. 13 */ 14 15 #include "includes.h" 16 17 #include "common.h" 18 #include "crypto/md5.h" 19 #include "crypto/sha1.h" 20 #include "tlsv1_common.h" 21 #include "tlsv1_record.h" 22 23 24 /** 25 * tlsv1_record_set_cipher_suite - TLS record layer: Set cipher suite 26 * @rl: Pointer to TLS record layer data 27 * @cipher_suite: New cipher suite 28 * Returns: 0 on success, -1 on failure 29 * 30 * This function is used to prepare TLS record layer for cipher suite change. 31 * tlsv1_record_change_write_cipher() and 32 * tlsv1_record_change_read_cipher() functions can then be used to change the 33 * currently used ciphers. 34 */ 35 int tlsv1_record_set_cipher_suite(struct tlsv1_record_layer *rl, 36 u16 cipher_suite) 37 { 38 const struct tls_cipher_suite *suite; 39 const struct tls_cipher_data *data; 40 41 wpa_printf(MSG_DEBUG, "TLSv1: Selected cipher suite: 0x%04x", 42 cipher_suite); 43 rl->cipher_suite = cipher_suite; 44 45 suite = tls_get_cipher_suite(cipher_suite); 46 if (suite == NULL) 47 return -1; 48 49 if (suite->hash == TLS_HASH_MD5) { 50 rl->hash_alg = CRYPTO_HASH_ALG_HMAC_MD5; 51 rl->hash_size = MD5_MAC_LEN; 52 } else if (suite->hash == TLS_HASH_SHA) { 53 rl->hash_alg = CRYPTO_HASH_ALG_HMAC_SHA1; 54 rl->hash_size = SHA1_MAC_LEN; 55 } 56 57 data = tls_get_cipher_data(suite->cipher); 58 if (data == NULL) 59 return -1; 60 61 rl->key_material_len = data->key_material; 62 rl->iv_size = data->block_size; 63 rl->cipher_alg = data->alg; 64 65 return 0; 66 } 67 68 69 /** 70 * tlsv1_record_change_write_cipher - TLS record layer: Change write cipher 71 * @rl: Pointer to TLS record layer data 72 * Returns: 0 on success (cipher changed), -1 on failure 73 * 74 * This function changes TLS record layer to use the new cipher suite 75 * configured with tlsv1_record_set_cipher_suite() for writing. 76 */ 77 int tlsv1_record_change_write_cipher(struct tlsv1_record_layer *rl) 78 { 79 wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - New write cipher suite " 80 "0x%04x", rl->cipher_suite); 81 rl->write_cipher_suite = rl->cipher_suite; 82 os_memset(rl->write_seq_num, 0, TLS_SEQ_NUM_LEN); 83 84 if (rl->write_cbc) { 85 crypto_cipher_deinit(rl->write_cbc); 86 rl->write_cbc = NULL; 87 } 88 if (rl->cipher_alg != CRYPTO_CIPHER_NULL) { 89 rl->write_cbc = crypto_cipher_init(rl->cipher_alg, 90 rl->write_iv, rl->write_key, 91 rl->key_material_len); 92 if (rl->write_cbc == NULL) { 93 wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize " 94 "cipher"); 95 return -1; 96 } 97 } 98 99 return 0; 100 } 101 102 103 /** 104 * tlsv1_record_change_read_cipher - TLS record layer: Change read cipher 105 * @rl: Pointer to TLS record layer data 106 * Returns: 0 on success (cipher changed), -1 on failure 107 * 108 * This function changes TLS record layer to use the new cipher suite 109 * configured with tlsv1_record_set_cipher_suite() for reading. 110 */ 111 int tlsv1_record_change_read_cipher(struct tlsv1_record_layer *rl) 112 { 113 wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - New read cipher suite " 114 "0x%04x", rl->cipher_suite); 115 rl->read_cipher_suite = rl->cipher_suite; 116 os_memset(rl->read_seq_num, 0, TLS_SEQ_NUM_LEN); 117 118 if (rl->read_cbc) { 119 crypto_cipher_deinit(rl->read_cbc); 120 rl->read_cbc = NULL; 121 } 122 if (rl->cipher_alg != CRYPTO_CIPHER_NULL) { 123 rl->read_cbc = crypto_cipher_init(rl->cipher_alg, 124 rl->read_iv, rl->read_key, 125 rl->key_material_len); 126 if (rl->read_cbc == NULL) { 127 wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize " 128 "cipher"); 129 return -1; 130 } 131 } 132 133 return 0; 134 } 135 136 137 /** 138 * tlsv1_record_send - TLS record layer: Send a message 139 * @rl: Pointer to TLS record layer data 140 * @content_type: Content type (TLS_CONTENT_TYPE_*) 141 * @buf: Buffer to send (with TLS_RECORD_HEADER_LEN octets reserved in the 142 * beginning for record layer to fill in; payload filled in after this and 143 * extra space in the end for HMAC). 144 * @buf_size: Maximum buf size 145 * @payload_len: Length of the payload 146 * @out_len: Buffer for returning the used buf length 147 * Returns: 0 on success, -1 on failure 148 * 149 * This function fills in the TLS record layer header, adds HMAC, and encrypts 150 * the data using the current write cipher. 151 */ 152 int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf, 153 size_t buf_size, size_t payload_len, size_t *out_len) 154 { 155 u8 *pos, *ct_start, *length, *payload; 156 struct crypto_hash *hmac; 157 size_t clen; 158 159 pos = buf; 160 /* ContentType type */ 161 ct_start = pos; 162 *pos++ = content_type; 163 /* ProtocolVersion version */ 164 WPA_PUT_BE16(pos, TLS_VERSION); 165 pos += 2; 166 /* uint16 length */ 167 length = pos; 168 WPA_PUT_BE16(length, payload_len); 169 pos += 2; 170 171 /* opaque fragment[TLSPlaintext.length] */ 172 payload = pos; 173 pos += payload_len; 174 175 if (rl->write_cipher_suite != TLS_NULL_WITH_NULL_NULL) { 176 hmac = crypto_hash_init(rl->hash_alg, rl->write_mac_secret, 177 rl->hash_size); 178 if (hmac == NULL) { 179 wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed " 180 "to initialize HMAC"); 181 return -1; 182 } 183 crypto_hash_update(hmac, rl->write_seq_num, TLS_SEQ_NUM_LEN); 184 /* type + version + length + fragment */ 185 crypto_hash_update(hmac, ct_start, pos - ct_start); 186 clen = buf + buf_size - pos; 187 if (clen < rl->hash_size) { 188 wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Not " 189 "enough room for MAC"); 190 crypto_hash_finish(hmac, NULL, NULL); 191 return -1; 192 } 193 194 if (crypto_hash_finish(hmac, pos, &clen) < 0) { 195 wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed " 196 "to calculate HMAC"); 197 return -1; 198 } 199 wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Write HMAC", 200 pos, clen); 201 pos += clen; 202 if (rl->iv_size) { 203 size_t len = pos - payload; 204 size_t pad; 205 pad = (len + 1) % rl->iv_size; 206 if (pad) 207 pad = rl->iv_size - pad; 208 if (pos + pad + 1 > buf + buf_size) { 209 wpa_printf(MSG_DEBUG, "TLSv1: No room for " 210 "block cipher padding"); 211 return -1; 212 } 213 os_memset(pos, pad, pad + 1); 214 pos += pad + 1; 215 } 216 217 if (crypto_cipher_encrypt(rl->write_cbc, payload, 218 payload, pos - payload) < 0) 219 return -1; 220 } 221 222 WPA_PUT_BE16(length, pos - length - 2); 223 inc_byte_array(rl->write_seq_num, TLS_SEQ_NUM_LEN); 224 225 *out_len = pos - buf; 226 227 return 0; 228 } 229 230 231 /** 232 * tlsv1_record_receive - TLS record layer: Process a received message 233 * @rl: Pointer to TLS record layer data 234 * @in_data: Received data 235 * @in_len: Length of the received data 236 * @out_data: Buffer for output data (must be at least as long as in_data) 237 * @out_len: Set to maximum out_data length by caller; used to return the 238 * length of the used data 239 * @alert: Buffer for returning an alert value on failure 240 * Returns: 0 on success, -1 on failure 241 * 242 * This function decrypts the received message, verifies HMAC and TLS record 243 * layer header. 244 */ 245 int tlsv1_record_receive(struct tlsv1_record_layer *rl, 246 const u8 *in_data, size_t in_len, 247 u8 *out_data, size_t *out_len, u8 *alert) 248 { 249 size_t i, rlen, hlen; 250 u8 padlen; 251 struct crypto_hash *hmac; 252 u8 len[2], hash[100]; 253 254 wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Received", 255 in_data, in_len); 256 257 if (in_len < TLS_RECORD_HEADER_LEN) { 258 wpa_printf(MSG_DEBUG, "TLSv1: Too short record (in_len=%lu)", 259 (unsigned long) in_len); 260 *alert = TLS_ALERT_DECODE_ERROR; 261 return -1; 262 } 263 264 wpa_printf(MSG_DEBUG, "TLSv1: Received content type %d version %d.%d " 265 "length %d", in_data[0], in_data[1], in_data[2], 266 WPA_GET_BE16(in_data + 3)); 267 268 if (in_data[0] != TLS_CONTENT_TYPE_HANDSHAKE && 269 in_data[0] != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC && 270 in_data[0] != TLS_CONTENT_TYPE_ALERT && 271 in_data[0] != TLS_CONTENT_TYPE_APPLICATION_DATA) { 272 wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type 0x%x", 273 in_data[0]); 274 *alert = TLS_ALERT_UNEXPECTED_MESSAGE; 275 return -1; 276 } 277 278 if (WPA_GET_BE16(in_data + 1) != TLS_VERSION) { 279 wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version " 280 "%d.%d", in_data[1], in_data[2]); 281 *alert = TLS_ALERT_PROTOCOL_VERSION; 282 return -1; 283 } 284 285 rlen = WPA_GET_BE16(in_data + 3); 286 287 /* TLSCiphertext must not be more than 2^14+2048 bytes */ 288 if (TLS_RECORD_HEADER_LEN + rlen > 18432) { 289 wpa_printf(MSG_DEBUG, "TLSv1: Record overflow (len=%lu)", 290 (unsigned long) (TLS_RECORD_HEADER_LEN + rlen)); 291 *alert = TLS_ALERT_RECORD_OVERFLOW; 292 return -1; 293 } 294 295 in_data += TLS_RECORD_HEADER_LEN; 296 in_len -= TLS_RECORD_HEADER_LEN; 297 298 if (rlen > in_len) { 299 wpa_printf(MSG_DEBUG, "TLSv1: Not all record data included " 300 "(rlen=%lu > in_len=%lu)", 301 (unsigned long) rlen, (unsigned long) in_len); 302 *alert = TLS_ALERT_DECODE_ERROR; 303 return -1; 304 } 305 306 in_len = rlen; 307 308 if (*out_len < in_len) { 309 wpa_printf(MSG_DEBUG, "TLSv1: Not enough output buffer for " 310 "processing received record"); 311 *alert = TLS_ALERT_INTERNAL_ERROR; 312 return -1; 313 } 314 315 os_memcpy(out_data, in_data, in_len); 316 *out_len = in_len; 317 318 if (rl->read_cipher_suite != TLS_NULL_WITH_NULL_NULL) { 319 if (crypto_cipher_decrypt(rl->read_cbc, out_data, 320 out_data, in_len) < 0) { 321 *alert = TLS_ALERT_DECRYPTION_FAILED; 322 return -1; 323 } 324 if (rl->iv_size) { 325 if (in_len == 0) { 326 wpa_printf(MSG_DEBUG, "TLSv1: Too short record" 327 " (no pad)"); 328 *alert = TLS_ALERT_DECODE_ERROR; 329 return -1; 330 } 331 padlen = out_data[in_len - 1]; 332 if (padlen >= in_len) { 333 wpa_printf(MSG_DEBUG, "TLSv1: Incorrect pad " 334 "length (%u, in_len=%lu) in " 335 "received record", 336 padlen, (unsigned long) in_len); 337 *alert = TLS_ALERT_DECRYPTION_FAILED; 338 return -1; 339 } 340 for (i = in_len - padlen; i < in_len; i++) { 341 if (out_data[i] != padlen) { 342 wpa_hexdump(MSG_DEBUG, 343 "TLSv1: Invalid pad in " 344 "received record", 345 out_data + in_len - padlen, 346 padlen); 347 *alert = TLS_ALERT_DECRYPTION_FAILED; 348 return -1; 349 } 350 } 351 352 *out_len -= padlen + 1; 353 } 354 355 wpa_hexdump(MSG_MSGDUMP, 356 "TLSv1: Record Layer - Decrypted data", 357 out_data, in_len); 358 359 if (*out_len < rl->hash_size) { 360 wpa_printf(MSG_DEBUG, "TLSv1: Too short record; no " 361 "hash value"); 362 *alert = TLS_ALERT_INTERNAL_ERROR; 363 return -1; 364 } 365 366 *out_len -= rl->hash_size; 367 368 hmac = crypto_hash_init(rl->hash_alg, rl->read_mac_secret, 369 rl->hash_size); 370 if (hmac == NULL) { 371 wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed " 372 "to initialize HMAC"); 373 *alert = TLS_ALERT_INTERNAL_ERROR; 374 return -1; 375 } 376 377 crypto_hash_update(hmac, rl->read_seq_num, TLS_SEQ_NUM_LEN); 378 /* type + version + length + fragment */ 379 crypto_hash_update(hmac, in_data - TLS_RECORD_HEADER_LEN, 3); 380 WPA_PUT_BE16(len, *out_len); 381 crypto_hash_update(hmac, len, 2); 382 crypto_hash_update(hmac, out_data, *out_len); 383 hlen = sizeof(hash); 384 if (crypto_hash_finish(hmac, hash, &hlen) < 0) { 385 wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed " 386 "to calculate HMAC"); 387 return -1; 388 } 389 if (hlen != rl->hash_size || 390 os_memcmp(hash, out_data + *out_len, hlen) != 0) { 391 wpa_printf(MSG_DEBUG, "TLSv1: Invalid HMAC value in " 392 "received message"); 393 *alert = TLS_ALERT_BAD_RECORD_MAC; 394 return -1; 395 } 396 } 397 398 /* TLSCompressed must not be more than 2^14+1024 bytes */ 399 if (TLS_RECORD_HEADER_LEN + *out_len > 17408) { 400 wpa_printf(MSG_DEBUG, "TLSv1: Record overflow (len=%lu)", 401 (unsigned long) (TLS_RECORD_HEADER_LEN + *out_len)); 402 *alert = TLS_ALERT_RECORD_OVERFLOW; 403 return -1; 404 } 405 406 inc_byte_array(rl->read_seq_num, TLS_SEQ_NUM_LEN); 407 408 return 0; 409 } 410