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