1 /** 2 * TLS Record Handling 3 * 4 * Copyright: 5 * (C) 2004-2012,2014 Jack Lloyd 6 * (C) 2014-2015 Etienne Cimon 7 * 8 * License: 9 * Botan is released under the Simplified BSD License (see LICENSE.md) 10 */ 11 module botan.tls.record; 12 13 import botan.constants; 14 static if (BOTAN_HAS_TLS): 15 package: 16 17 import botan.libstate.libstate; 18 import botan.tls.magic; 19 import botan.tls.version_; 20 import botan.tls.seq_numbers; 21 import botan.tls.session_key; 22 import botan.tls.ciphersuite; 23 import botan.tls.exceptn; 24 import botan.modes.aead.aead; 25 import botan.mac.mac; 26 import botan.algo_factory.algo_factory; 27 import botan.rng.rng; 28 import botan.block.block_cipher; 29 import botan.stream.stream_cipher; 30 import botan.utils.rounding; 31 import botan.utils.xor_buf; 32 import botan.utils.loadstor; 33 import botan.utils.types; 34 import std.algorithm; 35 import std.datetime; 36 import memutils.refcounted; 37 38 //alias ConnectionCipherState = RefCounted!ConnectionCipherStateImpl; 39 40 /** 41 * TLS Cipher State 42 */ 43 final class ConnectionCipherState 44 { 45 public: 46 /** 47 * Initialize a new cipher state 48 */ 49 this()(TLSProtocolVersion _version, 50 ConnectionSide side, bool our_side, 51 in TLSCiphersuite suite, auto const ref TLSSessionKeys keys) 52 { 53 m_start_time = Clock.currTime(UTC()); 54 m_implicit_nonce_size = suite.nonceBytesFromRecord(); 55 m_explicit_nonce_size = suite.nonceBytesFromHandshake(); 56 m_is_ssl3 = _version == TLSProtocolVersion.SSL_V3; 57 SymmetricKey mac_key, cipher_key; 58 InitializationVector iv; 59 60 if (side == CLIENT) 61 { 62 cipher_key = keys.clientCipherKey().dup; 63 iv = keys.clientIv().dup; 64 mac_key = keys.clientMacKey().dup; 65 } 66 else 67 { 68 cipher_key = keys.serverCipherKey().dup; 69 iv = keys.serverIv().dup; 70 mac_key = keys.serverMacKey().dup; 71 } 72 73 const string cipher_algo = suite.cipherAlgo(); 74 const string mac_algo = suite.macAlgo(); 75 76 if (AEADMode aead = getAead(cipher_algo, our_side ? ENCRYPTION : DECRYPTION)) 77 { 78 m_aead = aead; 79 m_aead.setKey(cipher_key ~ mac_key); 80 81 assert(iv.length == nonceBytesFromHandshake(), "Matching nonce sizes"); 82 m_nonce = iv.bitsOf(); 83 assert(nonceBytesFromRecord() == 0 || nonceBytesFromRecord() == 8, 84 "Ciphersuite uses implemented IV length"); 85 m_nonce.resize(m_nonce.length + 8); 86 return; 87 } 88 89 AlgorithmFactory af = globalState().algorithmFactory(); 90 91 if (const BlockCipher bc = af.prototypeBlockCipher(cipher_algo)) 92 { 93 m_block_cipher = bc.clone(); 94 m_block_cipher.setKey(cipher_key); 95 m_block_cipher_cbc_state = iv.bitsOf(); 96 m_block_size = bc.blockSize; 97 98 if (_version.supportsExplicitCbcIvs()) 99 m_iv_size = m_block_size; 100 } 101 else if (const StreamCipher sc = af.prototypeStreamCipher(cipher_algo)) 102 { 103 m_stream_cipher = sc.clone(); 104 m_stream_cipher.setKey(cipher_key); 105 } 106 else 107 throw new InvalidArgument("Unknown TLS cipher " ~ cipher_algo); 108 109 if (_version == TLSProtocolVersion.SSL_V3) 110 m_mac = af.makeMac("SSL3-MAC(" ~ mac_algo ~ ")"); 111 else 112 m_mac = af.makeMac("HMAC(" ~ mac_algo ~ ")"); 113 114 m_mac.setKey(mac_key); 115 } 116 117 AEADMode aead() { return *m_aead; } 118 119 ref const(SecureVector!ubyte) aeadNonce(ulong seq) 120 { 121 storeBigEndian(seq, &m_nonce[nonceBytesFromHandshake()]); 122 return m_nonce; 123 } 124 125 ref const(SecureVector!ubyte) aeadNonce(const(ubyte)* record, size_t record_len, ulong seq) 126 { 127 128 if(nonceBytesFromRecord()) 129 { 130 if(record_len < nonceBytesFromRecord()) 131 throw new DecodingError("Invalid AEAD packet too short to be valid"); 132 copyMem(&m_nonce[nonceBytesFromHandshake()], record, nonceBytesFromRecord()); 133 } 134 else 135 { 136 /* 137 nonce_len == 0 is assumed to mean no nonce in the message but 138 instead the AEAD uses the seq number in network order. 139 */ 140 storeBigEndian(seq, &m_nonce[nonceBytesFromHandshake()]); 141 } 142 return m_nonce; 143 } 144 145 146 ref const(SecureVector!ubyte) formatAd(ulong seq, ubyte msg_type, TLSProtocolVersion _version, ushort msg_length) 147 { 148 m_ad.clear(); 149 foreach (size_t i; 0 .. 8) 150 m_ad.pushBack(get_byte(i, seq)); 151 m_ad.pushBack(msg_type); 152 153 if (_version != TLSProtocolVersion.SSL_V3) 154 { 155 m_ad.pushBack(_version.majorVersion()); 156 m_ad.pushBack(_version.minorVersion()); 157 } 158 159 m_ad.pushBack(get_byte(0, msg_length)); 160 m_ad.pushBack(get_byte(1, msg_length)); 161 162 return m_ad; 163 } 164 165 BlockCipher blockCipher() { return *m_block_cipher; } 166 167 StreamCipher streamCipher() { return *m_stream_cipher; } 168 169 MessageAuthenticationCode mac() { return *m_mac; } 170 171 ref SecureVector!ubyte cbcState() { return m_block_cipher_cbc_state; } 172 173 size_t blockSize() const { return m_block_size; } 174 175 size_t macSize() const { return m_mac.outputLength; } 176 177 size_t ivSize() const { return m_iv_size; } 178 179 size_t nonceBytesFromRecord() const { return m_implicit_nonce_size; } 180 181 size_t nonceBytesFromHandshake() const { return m_explicit_nonce_size; } 182 183 bool cipherPaddingSingleByte() const { return m_is_ssl3; } 184 185 bool cbcWithoutExplicitIv() const 186 { return (m_block_size > 0) && (m_iv_size == 0); } 187 188 Duration age() const 189 { 190 return Clock.currTime(UTC()) - m_start_time; 191 } 192 193 private: 194 SysTime m_start_time; 195 Unique!BlockCipher m_block_cipher; 196 SecureVector!ubyte m_block_cipher_cbc_state; 197 Unique!StreamCipher m_stream_cipher; 198 Unique!MessageAuthenticationCode m_mac; 199 200 Unique!AEADMode m_aead; 201 SecureVector!ubyte m_nonce, m_ad; 202 203 size_t m_block_size; 204 size_t m_explicit_nonce_size; 205 size_t m_implicit_nonce_size; 206 size_t m_iv_size; 207 bool m_is_ssl3; 208 } 209 210 /** 211 * Create a TLS record 212 * Params: 213 * output = the output record is placed here 214 * msg_type = is the type of the message (handshake, alert, ...) 215 * msg = is the plaintext message 216 * msg_length = is the length of msg 217 * _version = is the protocol version 218 * seq = is the sequence number 219 * cipherstate = is the writing cipher state 220 * rng = is a random number generator 221 * Returns: number of bytes written to write_buffer 222 */ 223 void writeRecord(ref SecureVector!ubyte output, 224 ubyte msg_type, const(ubyte)* msg, size_t msg_length, 225 TLSProtocolVersion _version, 226 ulong seq, 227 ConnectionCipherState cs, 228 RandomNumberGenerator rng) 229 { 230 output.clear(); 231 232 output.pushBack(msg_type); 233 output.pushBack(_version.majorVersion()); 234 output.pushBack(_version.minorVersion()); 235 236 if (_version.isDatagramProtocol()) 237 { 238 foreach (size_t i; 0 .. 8) 239 output.pushBack(get_byte(i, seq)); 240 } 241 242 if (!cs) // initial unencrypted handshake records 243 { 244 output.pushBack(get_byte(0, cast(ushort) msg_length)); 245 output.pushBack(get_byte(1, cast(ushort) msg_length)); 246 247 output ~= msg[0 .. msg_length]; 248 249 return; 250 } 251 252 if (AEADMode aead = cs.aead()) 253 { 254 const size_t ctext_size = aead.outputLength(msg_length); 255 256 const(SecureVector!ubyte)* nonce = &cs.aeadNonce(seq); 257 258 // wrong if start returns something 259 const size_t rec_size = ctext_size + cs.nonceBytesFromRecord(); 260 261 assert(rec_size <= 0xFFFF, "Ciphertext length fits in field"); 262 263 output.pushBack(get_byte!ushort(0, cast(ushort) rec_size)); 264 output.pushBack(get_byte!ushort(1, cast(ushort) rec_size)); 265 266 aead.setAssociatedDataVec(cs.formatAd(seq, msg_type, _version, cast(ushort) msg_length)); 267 268 output ~= nonce.ptr[cs.nonceBytesFromHandshake() .. cs.nonceBytesFromHandshake() + cs.nonceBytesFromRecord()]; 269 auto start_vec = aead.start(*nonce); 270 assert(start_vec.empty, "AEAD doesn't return anything from start"); 271 272 const size_t offset = output.length; 273 output ~= msg[0 .. msg_length]; 274 aead.finish(output, offset); 275 276 assert(output.length == offset + ctext_size, "Expected size"); 277 278 assert(output.length < MAX_CIPHERTEXT_SIZE, 279 "Produced ciphertext larger than protocol allows"); 280 return; 281 } 282 283 cs.mac().update(cs.formatAd(seq, msg_type, _version, cast(ushort) msg_length)); 284 285 cs.mac().update(msg, msg_length); 286 287 const size_t block_size = cs.blockSize(); 288 const size_t iv_size = cs.ivSize(); 289 const size_t mac_size = cs.macSize(); 290 291 const size_t buf_size = roundUp(iv_size + msg_length + mac_size + (block_size ? 1 : 0), block_size); 292 293 if (buf_size > MAX_CIPHERTEXT_SIZE) 294 throw new InternalError("Output record is larger than allowed by protocol"); 295 296 output.pushBack(get_byte!ushort(0, cast(ushort) buf_size)); 297 output.pushBack(get_byte!ushort(1, cast(ushort) buf_size)); 298 299 const size_t header_size = output.length; 300 301 if (iv_size) 302 { 303 output.resize(output.length + iv_size); 304 rng.randomize(&output[$- iv_size], iv_size); 305 } 306 output ~= msg[0 .. msg_length]; 307 output.resize(output.length + mac_size); 308 cs.mac().flushInto(&output[output.length - mac_size]); 309 310 if (block_size) 311 { 312 const size_t pad_val = buf_size - (iv_size + msg_length + mac_size + 1); 313 314 foreach (size_t i; 0 .. (pad_val + 1)) 315 output.pushBack(pad_val); 316 } 317 318 if (buf_size > MAX_CIPHERTEXT_SIZE) 319 throw new InternalError("Produced ciphertext larger than protocol allows"); 320 321 assert(buf_size + header_size == output.length, "Output buffer is sized properly"); 322 323 if (StreamCipher sc = cs.streamCipher()) 324 { 325 sc.cipher1(&output[header_size], buf_size); 326 } 327 else if (BlockCipher bc = cs.blockCipher()) 328 { 329 SecureVector!ubyte* cbc_state = &cs.cbcState(); 330 331 assert(buf_size % block_size == 0, 332 "Buffer is an even multiple of block size"); 333 334 ubyte* buf = &output[header_size]; 335 336 const size_t blocks = buf_size / block_size; 337 338 xorBuf(buf, cbc_state.ptr, block_size); 339 bc.encrypt(buf); 340 341 for (size_t i = 1; i < blocks; ++i) 342 { 343 xorBuf(&buf[block_size*i], &buf[block_size*(i-1)], block_size); 344 bc.encrypt(&buf[block_size*i]); 345 } 346 347 (*cbc_state)[] = buf[block_size*(blocks-1) .. block_size*blocks]; 348 } 349 else 350 throw new InternalError("NULL cipher not supported"); 351 } 352 353 /** 354 * Decode a TLS record 355 * Returns: zero if full message, else number of bytes still needed 356 */ 357 size_t readTLSRecord(ref SecureVector!ubyte readbuf, 358 const(ubyte)* input, size_t input_sz, 359 ref size_t consumed, 360 ref SecureVector!ubyte record, 361 ref ulong record_sequence, 362 ref TLSProtocolVersion record_version, 363 ref RecordType record_type, 364 ConnectionSequenceNumbers sequence_numbers, 365 const(ConnectionCipherState) delegate(ushort) const get_cipherstate) 366 { 367 consumed = 0; 368 if (readbuf.length < TLS_HEADER_SIZE) // header incomplete? 369 { 370 if (size_t needed = fillBufferTo(readbuf, input, input_sz, consumed, TLS_HEADER_SIZE)) 371 return needed; 372 373 assert(readbuf.length == TLS_HEADER_SIZE, "Have an entire header"); 374 } 375 376 // Possible SSLv2 format client hello 377 if (!sequence_numbers && (readbuf[0] & 0x80) && (readbuf[2] == 1)) 378 { 379 if (readbuf[3] == 0 && readbuf[4] == 2) 380 throw new TLSException(TLSAlert.PROTOCOL_VERSION, "TLSClient claims to only support SSLv2, rejecting"); 381 382 if (readbuf[3] >= 3) // SSLv2 mapped TLS hello, then? 383 { 384 const size_t record_len = make_ushort(readbuf[0], readbuf[1]) & 0x7FFF; 385 386 if (size_t needed = fillBufferTo(readbuf, 387 input, input_sz, consumed, 388 record_len + 2)) 389 return needed; 390 391 assert(readbuf.length == (record_len + 2), "Have the entire SSLv2 hello"); 392 393 // Fake v3-style handshake message wrapper 394 record_version = TLSProtocolVersion(TLSProtocolVersion.TLS_V10); 395 record_sequence = 0; 396 record_type = HANDSHAKE; 397 398 record.resize(4 + readbuf.length - 2); 399 400 record[0] = CLIENT_HELLO_SSLV2; 401 record[1] = 0; 402 record[2] = readbuf[0] & 0x7F; 403 record[3] = readbuf[1]; 404 copyMem(&record[4], &readbuf[2], readbuf.length - 2); 405 406 readbuf.clear(); 407 return 0; 408 } 409 } 410 411 record_version = TLSProtocolVersion(readbuf[1], readbuf[2]); 412 413 assert(!record_version.isDatagramProtocol(), "Expected TLS"); 414 415 const size_t record_len = make_ushort(readbuf[TLS_HEADER_SIZE-2], readbuf[TLS_HEADER_SIZE-1]); 416 if (record_len > MAX_CIPHERTEXT_SIZE) 417 throw new TLSException(TLSAlert.RECORD_OVERFLOW, "Received a record that exceeds maximum size: " ~ cast(string)readbuf[]); 418 419 if(record_len == 0) 420 throw new TLSException(TLSAlert.DECODE_ERROR, "Received a completely empty record"); 421 422 if (size_t needed = fillBufferTo(readbuf, input, input_sz, consumed, TLS_HEADER_SIZE + record_len)) 423 return needed; 424 425 assert(cast(size_t)(TLS_HEADER_SIZE) + record_len == readbuf.length, "Have the full record"); 426 427 record_type = cast(RecordType)(readbuf[0]); 428 429 ushort epoch = 0; 430 431 if (sequence_numbers) 432 { 433 record_sequence = sequence_numbers.nextReadSequence(); 434 epoch = sequence_numbers.currentReadEpoch(); 435 } 436 else 437 { 438 // server initial handshake case 439 record_sequence = 0; 440 epoch = 0; 441 } 442 443 ubyte* record_contents = readbuf.ptr + TLS_HEADER_SIZE; 444 445 if (epoch == 0) // Unencrypted initial handshake 446 { 447 record[] = readbuf.ptr[TLS_HEADER_SIZE .. TLS_HEADER_SIZE + record_len]; 448 readbuf.clear(); 449 return 0; // got a full record 450 } 451 // Otherwise, decrypt, check MAC, return plaintext 452 auto ccs = get_cipherstate(epoch); 453 ConnectionCipherState cs = cast(ConnectionCipherState) ccs; 454 455 assert(cs, "Have cipherstate for this epoch"); 456 decryptRecord(record, 457 record_contents, 458 record_len, 459 record_sequence, 460 record_version, 461 record_type, 462 cs); 463 464 if (sequence_numbers) 465 sequence_numbers.readAccept(record_sequence); 466 readbuf.clear(); 467 return 0; 468 } 469 470 size_t readDTLSRecord(ref SecureVector!ubyte readbuf, 471 const(ubyte)* input, size_t input_sz, 472 ref size_t consumed, 473 ref SecureVector!ubyte record, 474 ref ulong record_sequence, 475 ref TLSProtocolVersion record_version, 476 ref RecordType record_type, 477 ConnectionSequenceNumbers sequence_numbers, 478 const(ConnectionCipherState) delegate(ushort) const get_cipherstate) 479 { 480 consumed = 0; 481 if (readbuf.length < DTLS_HEADER_SIZE) // header incomplete? 482 { 483 if (fillBufferTo(readbuf, input, input_sz, consumed, DTLS_HEADER_SIZE)) 484 { 485 readbuf.clear(); 486 return 0; 487 } 488 489 assert(readbuf.length == DTLS_HEADER_SIZE, "Have an entire header"); 490 } 491 492 record_version = TLSProtocolVersion(readbuf[1], readbuf[2]); 493 494 assert(record_version.isDatagramProtocol(), "Expected DTLS"); 495 496 const size_t record_len = make_ushort(readbuf[DTLS_HEADER_SIZE-2], readbuf[DTLS_HEADER_SIZE-1]); 497 498 // Invalid packet: 499 if(record_len == 0 || record_len > MAX_CIPHERTEXT_SIZE) 500 { 501 readbuf.clear(); 502 return 0; 503 } 504 505 if (fillBufferTo(readbuf, input, input_sz, consumed, DTLS_HEADER_SIZE + record_len)) 506 { 507 // Truncated packet? 508 readbuf.clear(); 509 return 0; // wrong for DTLS? 510 } 511 512 assert(cast(size_t)(DTLS_HEADER_SIZE) + record_len == readbuf.length, "Have the full record"); 513 514 record_type = cast(RecordType)(readbuf[0]); 515 516 ushort epoch = 0; 517 518 record_sequence = loadBigEndian!ulong(&readbuf[3], 0); 519 epoch = (record_sequence >> 48); 520 521 if (sequence_numbers && sequence_numbers.alreadySeen(record_sequence)) 522 { 523 readbuf.clear(); 524 return 0; 525 } 526 527 ubyte* record_contents = &readbuf[DTLS_HEADER_SIZE]; 528 529 if (epoch == 0) // Unencrypted initial handshake 530 { 531 record[] = readbuf.ptr[DTLS_HEADER_SIZE .. DTLS_HEADER_SIZE + record_len]; 532 readbuf.clear(); 533 return 0; // got a full record 534 } 535 try 536 { 537 // Otherwise, decrypt, check MAC, return plaintext 538 auto ccs = get_cipherstate(epoch); 539 ConnectionCipherState cs = cast(ConnectionCipherState) ccs; 540 541 assert(cs, "Have cipherstate for this epoch"); 542 543 decryptRecord(record, 544 record_contents, 545 record_len, 546 record_sequence, 547 record_version, 548 record_type, 549 cs); 550 } catch (Exception e) { 551 readbuf.clear(); 552 record_type = NO_RECORD; 553 return 0; 554 } 555 556 if (sequence_numbers) 557 sequence_numbers.readAccept(record_sequence); 558 559 readbuf.clear(); 560 return 0; 561 } 562 563 size_t readRecord(ref SecureVector!ubyte readbuf, 564 const(ubyte)* input, size_t input_sz, 565 bool is_datagram, 566 ref size_t consumed, 567 ref SecureVector!ubyte record, 568 ref ulong record_sequence, 569 ref TLSProtocolVersion record_version, 570 ref RecordType record_type, 571 ConnectionSequenceNumbers sequence_numbers, 572 const(ConnectionCipherState) delegate(ushort) const get_cipherstate) 573 { 574 if (is_datagram) 575 return readDTLSRecord(readbuf, input, input_sz, consumed, record, record_sequence, record_version, 576 record_type, sequence_numbers, get_cipherstate); 577 else 578 return readTLSRecord(readbuf, input, input_sz, consumed, record, record_sequence, record_version, 579 record_type, sequence_numbers, get_cipherstate); 580 } 581 582 private: 583 584 size_t fillBufferTo(ref SecureVector!ubyte readbuf, ref const(ubyte)* input, 585 ref size_t input_size, ref size_t input_consumed, 586 size_t desired) 587 { 588 if (readbuf.length >= desired) 589 return 0; // already have it 590 591 const size_t taken = std.algorithm.min(input_size, desired - readbuf.length); 592 593 readbuf ~= input[0 .. taken]; 594 input_consumed += taken; 595 input_size -= taken; 596 input += taken; 597 598 return (desired - readbuf.length); // how many bytes do we still need? 599 } 600 601 /* 602 * Checks the TLS padding. Returns 0 if the padding is invalid (we 603 * count the padding_length field as part of the padding size so a 604 * valid padding will always be at least one ubyte long), or the length 605 * of the padding otherwise. This is actually padding_length + 1 606 * because both the padding and padding_length fields are padding from 607 * our perspective. 608 * 609 * Returning 0 in the error case should ensure the MAC check will fail. 610 * This approach is suggested in section 6.2.3.2 of RFC 5246. 611 * 612 * Also returns 0 if block_size == 0, so can be safely called with a 613 * stream cipher in use. 614 * 615 * @fixme This should run in constant time 616 */ 617 size_t tlsPaddingCheck(bool sslv3_padding, size_t block_size, const(ubyte)* record, in size_t record_len) 618 { 619 const size_t padding_length = record[(record_len-1)]; 620 621 if (padding_length >= record_len) 622 return 0; 623 624 /* 625 * SSL v3 requires that the padding be less than the block size 626 * but not does specify the value of the padding bytes. 627 */ 628 if (sslv3_padding) 629 { 630 if (padding_length > 0 && padding_length < block_size) 631 return (padding_length + 1); 632 else 633 return 0; 634 } 635 636 /* 637 * TLS v1.0 and up require all the padding bytes be the same value 638 * and allows up to 255 bytes. 639 */ 640 const size_t pad_start = record_len - padding_length - 1; 641 642 size_t cmp = 0; 643 644 foreach (size_t i; 0 .. padding_length) 645 cmp += record[pad_start + i] ^ padding_length; 646 647 return cmp ? 0 : padding_length + 1; 648 } 649 650 void cbcDecryptRecord(const(ubyte)* record_contents, size_t record_len, 651 ConnectionCipherState cs, BlockCipher bc) 652 { 653 const size_t block_size = cs.blockSize(); 654 655 assert(record_len % block_size == 0, "Buffer is an even multiple of block size"); 656 657 const size_t blocks = record_len / block_size; 658 659 assert(blocks >= 1, "At least one ciphertext block"); 660 661 ubyte* buf = cast(ubyte*)record_contents; 662 663 SecureVector!ubyte last_ciphertext = SecureVector!ubyte(block_size); 664 copyMem(last_ciphertext.ptr, buf, block_size); 665 666 bc.decrypt(buf); 667 xorBuf(buf, &cs.cbcState()[0], block_size); 668 669 SecureVector!ubyte last_ciphertext2; 670 671 for (size_t i = 1; i < blocks; ++i) 672 { 673 last_ciphertext2[] = buf[block_size*i .. block_size*(i+1)]; 674 bc.decrypt(&buf[block_size*i]); 675 xorBuf(&buf[block_size*i], last_ciphertext.ptr, block_size); 676 std.algorithm.swap(last_ciphertext, last_ciphertext2); 677 } 678 679 cs.cbcState() = last_ciphertext; 680 } 681 682 void decryptRecord(ref SecureVector!ubyte output, 683 const(ubyte)* record_contents, size_t record_len, 684 ulong record_sequence, 685 TLSProtocolVersion record_version, 686 RecordType record_type, 687 ConnectionCipherState cs) 688 { 689 if (AEADMode aead = cs.aead()) 690 { 691 const(SecureVector!ubyte)* nonce = &cs.aeadNonce(record_contents, record_len, record_sequence); 692 const(ubyte)* msg = &record_contents[cs.nonceBytesFromRecord()]; 693 const size_t msg_length = record_len - cs.nonceBytesFromRecord(); 694 695 const size_t ptext_size = aead.outputLength(msg_length); 696 697 aead.setAssociatedDataVec(cs.formatAd(record_sequence, record_type, record_version, cast(ushort) ptext_size)); 698 699 output ~= aead.start(*nonce); 700 701 const size_t offset = output.length; 702 output ~= msg[0 .. msg_length]; 703 aead.finish(output, offset); 704 705 assert(output.length == ptext_size + offset, "Produced expected size"); 706 } 707 else 708 { 709 // GenericBlockCipher / GenericStreamCipher case 710 711 bool padding_bad = false; 712 size_t pad_size = 0; 713 714 if (StreamCipher sc = cs.streamCipher()) 715 { 716 sc.cipher1(record_contents, record_len); 717 // no padding to check or remove 718 } 719 else if (BlockCipher bc = cs.blockCipher()) 720 { 721 cbcDecryptRecord(record_contents, record_len, cs, bc); 722 723 pad_size = tlsPaddingCheck(cs.cipherPaddingSingleByte(), 724 cs.blockSize(), 725 record_contents, record_len); 726 727 padding_bad = (pad_size == 0); 728 } 729 else 730 { 731 throw new InternalError("No cipher state set but needed to decrypt"); 732 } 733 734 const size_t mac_size = cs.macSize(); 735 const size_t iv_size = cs.ivSize(); 736 737 const size_t mac_pad_iv_size = mac_size + pad_size + iv_size; 738 739 if (record_len < mac_pad_iv_size) 740 throw new DecodingError("Record sent with invalid length"); 741 742 const(ubyte)* plaintext_block = &record_contents[iv_size]; 743 const ushort plaintext_length = cast(ushort)(record_len - mac_pad_iv_size); 744 745 cs.mac().update(cs.formatAd(record_sequence, record_type, record_version, plaintext_length)); 746 747 cs.mac().update(plaintext_block, plaintext_length); 748 749 Vector!ubyte mac_buf = Vector!ubyte(mac_size); 750 cs.mac().flushInto(mac_buf.ptr); 751 752 const size_t mac_offset = record_len - (mac_size + pad_size); 753 754 const bool mac_bad = !sameMem(&record_contents[mac_offset], mac_buf.ptr, mac_size); 755 756 if (mac_bad || padding_bad) 757 throw new TLSException(TLSAlert.BAD_RECORD_MAC, "Message authentication failure"); 758 759 output[] = plaintext_block[0 .. plaintext_length]; 760 } 761 }