Webserver+3d print
Embed:
(wiki syntax)
Show/hide line numbers
tls_record.c
Go to the documentation of this file.
00001 /** 00002 * @file tls_record.c 00003 * @brief TLS record protocol 00004 * 00005 * @section License 00006 * 00007 * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved. 00008 * 00009 * This file is part of CycloneSSL Open. 00010 * 00011 * This program is free software; you can redistribute it and/or 00012 * modify it under the terms of the GNU General Public License 00013 * as published by the Free Software Foundation; either version 2 00014 * of the License, or (at your option) any later version. 00015 * 00016 * This program is distributed in the hope that it will be useful, 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 * GNU General Public License for more details. 00020 * 00021 * You should have received a copy of the GNU General Public License 00022 * along with this program; if not, write to the Free Software Foundation, 00023 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00024 * 00025 * @author Oryx Embedded SARL (www.oryx-embedded.com) 00026 * @version 1.7.6 00027 **/ 00028 00029 //Switch to the appropriate trace level 00030 #define TRACE_LEVEL TLS_TRACE_LEVEL 00031 00032 //Dependencies 00033 #include <string.h> 00034 #include "tls.h" 00035 #include "tls_common.h" 00036 #include "tls_record.h" 00037 #include "tls_misc.h" 00038 #include "ssl_common.h" 00039 #include "cipher_mode_cbc.h" 00040 #include "cipher_mode_ccm.h" 00041 #include "cipher_mode_gcm.h" 00042 #include "chacha20_poly1305.h" 00043 #include "debug.h" 00044 00045 //Check SSL library configuration 00046 #if (TLS_SUPPORT == ENABLED) 00047 00048 00049 /** 00050 * @brief Write protocol data 00051 * @param[in] context Pointer to the TLS context 00052 * @param[in] data Pointer to the data buffer 00053 * @param[in] length Number of data bytes to be written 00054 * @param[in] contentType Higher level protocol 00055 * @return Error code 00056 **/ 00057 00058 error_t tlsWriteProtocolData(TlsContext *context, 00059 const void *data, size_t length, TlsContentType contentType) 00060 { 00061 error_t error; 00062 size_t n; 00063 uint8_t *p; 00064 00065 //Initialize status code 00066 error = NO_ERROR; 00067 00068 //Fragmentation process 00069 while(!error) 00070 { 00071 if(context->txBufferLen == 0) 00072 { 00073 //Check the length of the data 00074 if(length > context->txRecordMaxLen) 00075 { 00076 //Report an error 00077 error = ERROR_MESSAGE_TOO_LONG; 00078 } 00079 else if(length > 0) 00080 { 00081 //The hash value is updated for each handshake message, 00082 //except for HelloRequest messages 00083 if(contentType == TLS_TYPE_HANDSHAKE) 00084 tlsUpdateHandshakeHash(context, data, length); 00085 00086 //Make room for the encryption overhead 00087 memmove(context->txBuffer + context->txBufferSize - length, data, length); 00088 00089 //Save record type 00090 context->txBufferType = contentType; 00091 //Set the length of the buffer 00092 context->txBufferLen = length; 00093 //Point to the beginning of the buffer 00094 context->txBufferPos = 0; 00095 } 00096 else 00097 { 00098 //We are done 00099 break; 00100 } 00101 } 00102 else if(context->txBufferPos < context->txBufferLen) 00103 { 00104 //Number of bytes left to send 00105 n = context->txBufferLen - context->txBufferPos; 00106 //Point to the current fragment 00107 p = context->txBuffer + context->txBufferSize - n; 00108 //The record length must not exceed 16384 bytes 00109 n = MIN(n, TLS_MAX_RECORD_LENGTH); 00110 00111 //Send TLS record 00112 error = tlsWriteRecord(context, p, n, context->txBufferType); 00113 00114 //Check status code 00115 if(!error) 00116 { 00117 //Advance data pointer 00118 context->txBufferPos += n; 00119 } 00120 } 00121 else 00122 { 00123 //Prepare to send new protocol data 00124 context->txBufferLen = 0; 00125 context->txBufferPos = 0; 00126 00127 //We are done 00128 break; 00129 } 00130 } 00131 00132 //Return status code 00133 return error; 00134 } 00135 00136 00137 /** 00138 * @brief Read protocol data 00139 * @param[in] context Pointer to the TLS context 00140 * @param[out] data Pointer to the received data 00141 * @param[out] length Number of data bytes that were received 00142 * @param[out] contentType Higher level protocol 00143 * @return Error code 00144 **/ 00145 00146 error_t tlsReadProtocolData(TlsContext *context, 00147 void **data, size_t *length, TlsContentType *contentType) 00148 { 00149 error_t error; 00150 size_t n; 00151 TlsContentType type; 00152 TlsHandshake *message; 00153 00154 //Initialize status code 00155 error = NO_ERROR; 00156 00157 //Fragment reassembly process 00158 do 00159 { 00160 //Empty receive buffer? 00161 if(context->rxBufferLen == 0) 00162 { 00163 //Read a TLS record 00164 error = tlsReadRecord(context, context->rxBuffer, 00165 context->rxBufferSize, &n, &type); 00166 00167 //Check status code 00168 if(!error) 00169 { 00170 //Save record type 00171 context->rxBufferType = type; 00172 //Number of bytes available for reading 00173 context->rxBufferLen = n; 00174 //Rewind to the beginning of the buffer 00175 context->rxBufferPos = 0; 00176 } 00177 } 00178 //Imcomplete message received? 00179 else if(error == ERROR_MORE_DATA_REQUIRED) 00180 { 00181 //Make room at the end of the buffer 00182 if(context->rxBufferPos > 0) 00183 { 00184 //Move unread data to the beginning of the buffer 00185 memmove(context->rxBuffer, context->rxBuffer + 00186 context->rxBufferPos, context->rxBufferLen); 00187 00188 //Rewind to the beginning of the buffer 00189 context->rxBufferPos = 0; 00190 } 00191 00192 //Read a TLS record 00193 error = tlsReadRecord(context, context->rxBuffer + context->rxBufferLen, 00194 context->rxBufferSize - context->rxBufferLen, &n, &type); 00195 00196 //Check status code 00197 if(!error) 00198 { 00199 //Fragmented records with mixed types cannot be interleaved 00200 if(type != context->rxBufferType) 00201 error = ERROR_UNEXPECTED_MESSAGE; 00202 } 00203 00204 //Check status code 00205 if(!error) 00206 { 00207 //Number of bytes available for reading 00208 context->rxBufferLen += n; 00209 } 00210 } 00211 00212 //Check status code 00213 if(!error) 00214 { 00215 //Handshake message received? 00216 if(context->rxBufferType == TLS_TYPE_HANDSHAKE) 00217 { 00218 //A message may be fragmented across several records 00219 if(context->rxBufferLen < sizeof(TlsHandshake)) 00220 { 00221 //Read an additional record 00222 error = ERROR_MORE_DATA_REQUIRED; 00223 } 00224 else 00225 { 00226 //Point to the handshake message 00227 message = (TlsHandshake *) (context->rxBuffer + context->rxBufferPos); 00228 //Retrieve the length of the handshake message 00229 n = sizeof(TlsHandshake) + LOAD24BE(message->length); 00230 00231 //A message may be fragmented across several records 00232 if(context->rxBufferLen < n) 00233 { 00234 //Read an additional record 00235 error = ERROR_MORE_DATA_REQUIRED; 00236 } 00237 else 00238 { 00239 //Pass the handshake message to the higher layer 00240 error = NO_ERROR; 00241 } 00242 } 00243 } 00244 //ChangeCipherSpec message received? 00245 else if(context->rxBufferType == TLS_TYPE_CHANGE_CIPHER_SPEC) 00246 { 00247 //A message may be fragmented across several records 00248 if(context->rxBufferLen < sizeof(TlsChangeCipherSpec)) 00249 { 00250 //Read an additional record 00251 error = ERROR_MORE_DATA_REQUIRED; 00252 } 00253 else 00254 { 00255 //Length of the ChangeCipherSpec message 00256 n = sizeof(TlsChangeCipherSpec); 00257 //Pass the ChangeCipherSpec message to the higher layer 00258 error = NO_ERROR; 00259 } 00260 } 00261 //Alert message received? 00262 else if(context->rxBufferType == TLS_TYPE_ALERT) 00263 { 00264 //A message may be fragmented across several records 00265 if(context->rxBufferLen < sizeof(TlsAlert)) 00266 { 00267 //Read an additional record 00268 error = ERROR_MORE_DATA_REQUIRED; 00269 } 00270 else 00271 { 00272 //Length of the Alert message 00273 n = sizeof(TlsAlert); 00274 //Pass the Alert message to the higher layer 00275 error = NO_ERROR; 00276 } 00277 } 00278 //Application data received? 00279 else if(context->rxBufferType == TLS_TYPE_APPLICATION_DATA) 00280 { 00281 //Length of the application data 00282 n = context->rxBufferLen; 00283 //Pass the application data to the higher layer 00284 error = NO_ERROR; 00285 } 00286 //Unknown content type? 00287 else 00288 { 00289 //Report an error 00290 error = ERROR_UNEXPECTED_MESSAGE; 00291 } 00292 } 00293 00294 //Read as many records as necessary to reassemble the data 00295 } while(error == ERROR_MORE_DATA_REQUIRED); 00296 00297 //Successful processing? 00298 if(!error) 00299 { 00300 //Pointer to the received data 00301 *data = context->rxBuffer + context->rxBufferPos; 00302 //Length, in byte, of the data 00303 *length = n; 00304 //Protocol type 00305 *contentType = context->rxBufferType; 00306 } 00307 00308 //Return status code 00309 return error; 00310 } 00311 00312 00313 /** 00314 * @brief Send a TLS record 00315 * @param[in] context Pointer to the TLS context 00316 * @param[in] data Pointer to the record data 00317 * @param[in] length Length of the record data 00318 * @param[in] contentType Record type 00319 * @return Error code 00320 **/ 00321 00322 error_t tlsWriteRecord(TlsContext *context, const uint8_t *data, 00323 size_t length, TlsContentType contentType) 00324 { 00325 error_t error; 00326 size_t n; 00327 TlsRecord *record; 00328 00329 //Point to the TLS record 00330 record = (TlsRecord *) context->txBuffer; 00331 00332 //Initialize status code 00333 error = NO_ERROR; 00334 00335 //Send process 00336 while(!error) 00337 { 00338 //Send as much data as possible 00339 if(context->txRecordLen == 0) 00340 { 00341 //Format TLS record 00342 record->type = contentType; 00343 record->version = htons(context->version); 00344 record->length = htons(length); 00345 00346 //Copy record data 00347 memmove(record->data, data, length); 00348 00349 //Debug message 00350 TRACE_DEBUG("Sending TLS record (%" PRIuSIZE " bytes)...\r\n", length); 00351 TRACE_DEBUG_ARRAY(" ", record, length + sizeof(TlsRecord)); 00352 00353 //Protect record payload? 00354 if(context->changeCipherSpecSent) 00355 { 00356 //Encrypt TLS record 00357 error = tlsEncryptRecord(context, record); 00358 } 00359 00360 //Check status code 00361 if(!error) 00362 { 00363 //Actual length of the record data 00364 context->txRecordLen = sizeof(TlsRecord) + ntohs(record->length); 00365 //Point to the beginning of the record 00366 context->txRecordPos = 0; 00367 } 00368 } 00369 else if(context->txRecordPos < context->txRecordLen) 00370 { 00371 //Total number of bytes that have been written 00372 n = 0; 00373 00374 //Send more data 00375 error = context->sendCallback(context->handle, 00376 context->txBuffer + context->txRecordPos, 00377 context->txRecordLen - context->txRecordPos, &n, 0); 00378 00379 //Check status code 00380 if(error == NO_ERROR || error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT) 00381 { 00382 //Advance data pointer 00383 context->txRecordPos += n; 00384 } 00385 else 00386 { 00387 //The write operation has failed 00388 error = ERROR_WRITE_FAILED; 00389 } 00390 } 00391 else 00392 { 00393 //Prepare to send the next TLS record 00394 context->txRecordLen = 0; 00395 context->txRecordPos = 0; 00396 00397 //We are done 00398 break; 00399 } 00400 } 00401 00402 //Return status code 00403 return error; 00404 } 00405 00406 00407 /** 00408 * @brief Receive a TLS record 00409 * @param[in] context Pointer to the TLS context 00410 * @param[out] data Buffer where to store the record data 00411 * @param[in] size Maximum acceptable size for the incoming record 00412 * @param[out] length Length of the record data 00413 * @param[out] contentType Record type 00414 * @return Error code 00415 **/ 00416 00417 error_t tlsReadRecord(TlsContext *context, uint8_t *data, 00418 size_t size, size_t *length, TlsContentType *contentType) 00419 { 00420 error_t error; 00421 size_t n; 00422 TlsRecord *record; 00423 00424 //Point to the buffer where to store the incoming TLS record 00425 record = (TlsRecord *) data; 00426 00427 //Initialize status code 00428 error = NO_ERROR; 00429 00430 //Receive process 00431 while(!error) 00432 { 00433 //Read as much data as possible 00434 if(context->rxRecordPos < sizeof(TlsRecord)) 00435 { 00436 //Make sure that the buffer is large enough to hold the record header 00437 if(size >= sizeof(TlsRecord)) 00438 { 00439 //Total number of bytes that have been received 00440 n = 0; 00441 00442 //Read TLS record header 00443 error = context->receiveCallback(context->handle, 00444 data + context->rxRecordPos, 00445 sizeof(TlsRecord) - context->rxRecordPos, &n, 0); 00446 00447 //Check status code 00448 if(error == NO_ERROR || error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT) 00449 { 00450 //Advance data pointer 00451 context->rxRecordPos += n; 00452 00453 //TLS record header successfully received? 00454 if(context->rxRecordPos >= sizeof(TlsRecord)) 00455 { 00456 //Debug message 00457 TRACE_DEBUG("Record header received:\r\n"); 00458 TRACE_DEBUG_ARRAY(" ", record, sizeof(record)); 00459 00460 //Retrieve the length of the TLS record 00461 context->rxRecordLen = sizeof(TlsRecord) + ntohs(record->length); 00462 } 00463 } 00464 else 00465 { 00466 //The read operation has failed 00467 error = ERROR_READ_FAILED; 00468 } 00469 } 00470 else 00471 { 00472 //Report an error 00473 error = ERROR_RECORD_OVERFLOW; 00474 } 00475 } 00476 else if(context->rxRecordPos < context->rxRecordLen) 00477 { 00478 //Make sure that the buffer is large enough to hold the entire record 00479 if(size >= context->rxRecordLen) 00480 { 00481 //Total number of bytes that have been received 00482 n = 0; 00483 00484 //Read TLS record contents 00485 error = context->receiveCallback(context->handle, 00486 data + context->rxRecordPos, 00487 context->rxRecordLen - context->rxRecordPos, &n, 0); 00488 00489 //Check status code 00490 if(error == NO_ERROR || error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT) 00491 { 00492 //Advance data pointer 00493 context->rxRecordPos += n; 00494 } 00495 else 00496 { 00497 //The read operation has failed 00498 error = ERROR_READ_FAILED; 00499 } 00500 } 00501 else 00502 { 00503 //Report an error 00504 error = ERROR_RECORD_OVERFLOW; 00505 } 00506 } 00507 else 00508 { 00509 //Check current state 00510 if(context->state > TLS_STATE_SERVER_HELLO) 00511 { 00512 //Once the server has sent the ServerHello message, enforce 00513 //incoming record versions 00514 if(ntohs(record->version) != context->version) 00515 error = ERROR_VERSION_NOT_SUPPORTED; 00516 } 00517 00518 //Check status code 00519 if(!error) 00520 { 00521 //Record payload is protected? 00522 if(context->changeCipherSpecReceived) 00523 { 00524 //Decrypt TLS record 00525 error = tlsDecryptRecord(context, record); 00526 } 00527 } 00528 00529 //Check status code 00530 if(!error) 00531 { 00532 //Actual length of the record data 00533 *length = ntohs(record->length); 00534 //Record type 00535 *contentType = (TlsContentType) record->type; 00536 00537 //Debug message 00538 TRACE_DEBUG("TLS record received (%" PRIuSIZE " bytes)...\r\n", *length); 00539 TRACE_DEBUG_ARRAY(" ", record, *length + sizeof(TlsRecord)); 00540 00541 //Discard record header 00542 memmove(data, record->data, *length); 00543 00544 //Prepare to receive the next TLS record 00545 context->rxRecordLen = 0; 00546 context->rxRecordPos = 0; 00547 00548 //We are done 00549 break; 00550 } 00551 } 00552 } 00553 00554 //Return status code 00555 return error; 00556 } 00557 00558 00559 /** 00560 * @brief Encrypt an outgoing TLS record 00561 * @param[in] context Pointer to the TLS context 00562 * @param[in,out] record TLS record to be encrypted 00563 * @return Error code 00564 **/ 00565 00566 error_t tlsEncryptRecord(TlsContext *context, TlsRecord *record) 00567 { 00568 error_t error; 00569 size_t length; 00570 00571 //Convert the length field to host byte order 00572 length = ntohs(record->length); 00573 00574 //Message authentication is required? 00575 if(context->hashAlgo != NULL) 00576 { 00577 #if (TLS_MAX_VERSION >= SSL_VERSION_3_0 && TLS_MIN_VERSION <= SSL_VERSION_3_0) 00578 //Check whether SSL 3.0 is currently used 00579 if(context->version == SSL_VERSION_3_0) 00580 { 00581 //SSL 3.0 uses an older obsolete version of the HMAC construction 00582 error = sslComputeMac(context, context->writeMacKey, 00583 context->writeSeqNum, record, record->data, length, record->data + length); 00584 //Any error to report? 00585 if(error) 00586 return error; 00587 } 00588 else 00589 #endif 00590 #if (TLS_MAX_VERSION >= TLS_VERSION_1_0 && TLS_MIN_VERSION <= TLS_VERSION_1_2) 00591 //Check whether TLS 1.0, TLS 1.1 or TLS 1.2 is currently used 00592 if(context->version >= TLS_VERSION_1_0) 00593 { 00594 //TLS uses a HMAC construction 00595 hmacInit(&context->hmacContext, context->hashAlgo, 00596 context->writeMacKey, context->macKeyLen); 00597 00598 //Compute MAC over the sequence number and the record contents 00599 hmacUpdate(&context->hmacContext, context->writeSeqNum, sizeof(TlsSequenceNumber)); 00600 hmacUpdate(&context->hmacContext, record, length + sizeof(TlsRecord)); 00601 00602 //Append the resulting MAC to the message 00603 hmacFinal(&context->hmacContext, record->data + length); 00604 } 00605 else 00606 #endif 00607 //The negotiated TLS version is not valid... 00608 { 00609 //Report an error 00610 return ERROR_INVALID_VERSION; 00611 } 00612 00613 //Debug message 00614 TRACE_DEBUG("Write sequence number:\r\n"); 00615 TRACE_DEBUG_ARRAY(" ", context->writeSeqNum, sizeof(TlsSequenceNumber)); 00616 TRACE_DEBUG("Computed MAC:\r\n"); 00617 TRACE_DEBUG_ARRAY(" ", record->data + length, context->hashAlgo->digestSize); 00618 00619 //Adjust the length of the message 00620 length += context->hashAlgo->digestSize; 00621 //Fix length field 00622 record->length = htons(length); 00623 00624 //Increment sequence number 00625 tlsIncSequenceNumber(context->writeSeqNum); 00626 } 00627 00628 //Encryption is required? 00629 if(context->cipherMode != CIPHER_MODE_NULL) 00630 { 00631 //Debug message 00632 TRACE_DEBUG("Record to be encrypted (%" PRIuSIZE " bytes):\r\n", length); 00633 TRACE_DEBUG_ARRAY(" ", record, length + sizeof(TlsRecord)); 00634 00635 #if (TLS_STREAM_CIPHER_SUPPORT == ENABLED) 00636 //Stream cipher? 00637 if(context->cipherMode == CIPHER_MODE_STREAM) 00638 { 00639 //Encrypt record contents 00640 context->cipherAlgo->encryptStream(context->writeCipherContext, 00641 record->data, record->data, length); 00642 } 00643 else 00644 #endif 00645 #if (TLS_CBC_CIPHER_SUPPORT == ENABLED) 00646 //CBC block cipher? 00647 if(context->cipherMode == CIPHER_MODE_CBC) 00648 { 00649 size_t i; 00650 size_t paddingLength; 00651 00652 #if (TLS_MAX_VERSION >= TLS_VERSION_1_1 && TLS_MIN_VERSION <= TLS_VERSION_1_2) 00653 //TLS 1.1 and 1.2 use an explicit IV 00654 if(context->version >= TLS_VERSION_1_1) 00655 { 00656 //Make room for the IV at the beginning of the data 00657 memmove(record->data + context->recordIvLen, record->data, length); 00658 00659 //The initialization vector should be chosen at random 00660 error = context->prngAlgo->read(context->prngContext, 00661 record->data, context->recordIvLen); 00662 //Any error to report? 00663 if(error) 00664 return error; 00665 00666 //Adjust the length of the message 00667 length += context->recordIvLen; 00668 } 00669 #endif 00670 //Get the actual amount of bytes in the last block 00671 paddingLength = (length + 1) % context->cipherAlgo->blockSize; 00672 00673 //Padding is added to force the length of the plaintext to be 00674 //an integral multiple of the cipher's block length 00675 if(paddingLength > 0) 00676 paddingLength = context->cipherAlgo->blockSize - paddingLength; 00677 00678 //Write padding bytes 00679 for(i = 0; i <= paddingLength; i++) 00680 record->data[length + i] = (uint8_t) paddingLength; 00681 00682 //Compute the length of the resulting message 00683 length += paddingLength + 1; 00684 //Fix length field 00685 record->length = htons(length); 00686 00687 //Debug message 00688 TRACE_DEBUG("Record with padding (%" PRIuSIZE " bytes):\r\n", length); 00689 TRACE_DEBUG_ARRAY(" ", record, length + sizeof(TlsRecord)); 00690 00691 //CBC encryption 00692 error = cbcEncrypt(context->cipherAlgo, context->writeCipherContext, 00693 context->writeIv, record->data, record->data, length); 00694 //Any error to report? 00695 if(error) 00696 return error; 00697 } 00698 else 00699 #endif 00700 #if (TLS_CCM_CIPHER_SUPPORT == ENABLED || TLS_CCM_8_CIPHER_SUPPORT == ENABLED || \ 00701 TLS_GCM_CIPHER_SUPPORT == ENABLED) 00702 //CCM or GCM AEAD cipher? 00703 if(context->cipherMode == CIPHER_MODE_CCM || 00704 context->cipherMode == CIPHER_MODE_GCM) 00705 { 00706 uint8_t *data; 00707 uint8_t *tag; 00708 size_t nonceLength; 00709 uint8_t nonce[12]; 00710 uint8_t a[13]; 00711 00712 //Determine the total length of the nonce 00713 nonceLength = context->fixedIvLen + context->recordIvLen; 00714 //The salt is the implicit part of the nonce and is not sent in the packet 00715 memcpy(nonce, context->writeIv, context->fixedIvLen); 00716 00717 //The explicit part of the nonce is chosen by the sender 00718 error = context->prngAlgo->read(context->prngContext, 00719 nonce + context->fixedIvLen, context->recordIvLen); 00720 //Any error to report? 00721 if(error) 00722 return error; 00723 00724 //Make room for the explicit nonce at the beginning of the record 00725 memmove(record->data + context->recordIvLen, record->data, length); 00726 //The explicit part of the nonce is carried in each TLS record 00727 memcpy(record->data, nonce + context->fixedIvLen, context->recordIvLen); 00728 00729 //Additional data to be authenticated 00730 memcpy(a, context->writeSeqNum, sizeof(TlsSequenceNumber)); 00731 memcpy(a + sizeof(TlsSequenceNumber), record, sizeof(TlsRecord)); 00732 00733 //Point to the plaintext 00734 data = record->data + context->recordIvLen; 00735 //Point to the buffer where to store the authentication tag 00736 tag = data + length; 00737 00738 #if (TLS_CCM_CIPHER_SUPPORT == ENABLED || TLS_CCM_8_CIPHER_SUPPORT == ENABLED) 00739 //CCM AEAD cipher? 00740 if(context->cipherMode == CIPHER_MODE_CCM) 00741 { 00742 //Authenticated encryption using CCM 00743 error = ccmEncrypt(context->cipherAlgo, context->writeCipherContext, 00744 nonce, nonceLength, a, 13, data, data, length, tag, context->authTagLen); 00745 } 00746 else 00747 #endif 00748 #if (TLS_GCM_CIPHER_SUPPORT == ENABLED) 00749 //GCM AEAD cipher? 00750 if(context->cipherMode == CIPHER_MODE_GCM) 00751 { 00752 //Authenticated encryption using GCM 00753 error = gcmEncrypt(context->writeGcmContext, nonce, nonceLength, 00754 a, 13, data, data, length, tag, context->authTagLen); 00755 } 00756 else 00757 #endif 00758 //Invalid cipher mode? 00759 { 00760 //The specified cipher mode is not supported 00761 error = ERROR_UNSUPPORTED_CIPHER_MODE; 00762 } 00763 00764 //Failed to encrypt data? 00765 if(error) 00766 return error; 00767 00768 //Compute the length of the resulting message 00769 length += context->recordIvLen + context->authTagLen; 00770 //Fix length field 00771 record->length = htons(length); 00772 00773 //Increment sequence number 00774 tlsIncSequenceNumber(context->writeSeqNum); 00775 } 00776 else 00777 #endif 00778 #if (TLS_CHACHA20_POLY1305_SUPPORT == ENABLED) 00779 //ChaCha20Poly1305 AEAD cipher? 00780 if(context->cipherMode == CIPHER_MODE_CHACHA20_POLY1305) 00781 { 00782 size_t i; 00783 uint8_t *tag; 00784 uint8_t nonce[12]; 00785 uint8_t a[13]; 00786 00787 //The 64-bit record sequence number is serialized as an 8-byte, 00788 //big-endian value and padded on the left with four 0x00 bytes 00789 memcpy(nonce + 4, context->writeSeqNum, 8); 00790 memset(nonce, 0, 4); 00791 00792 //The padded sequence number is XORed with the write IV to form 00793 //the 96-bit nonce 00794 for(i = 0; i < context->fixedIvLen; i++) 00795 nonce[i] ^= context->writeIv[i]; 00796 00797 //Additional data to be authenticated 00798 memcpy(a, context->writeSeqNum, sizeof(TlsSequenceNumber)); 00799 memcpy(a + sizeof(TlsSequenceNumber), record, sizeof(TlsRecord)); 00800 00801 //Point to the buffer where to store the authentication tag 00802 tag = record->data + length; 00803 00804 //Authenticated encryption using ChaCha20Poly1305 00805 error = chacha20Poly1305Encrypt(context->writeEncKey, context->encKeyLen, 00806 nonce, 12, a, 13, record->data, record->data, length, tag, context->authTagLen); 00807 //Failed to encrypt data? 00808 if(error) 00809 return error; 00810 00811 //Compute the length of the resulting message 00812 length += context->authTagLen; 00813 //Fix length field 00814 record->length = htons(length); 00815 00816 //Increment sequence number 00817 tlsIncSequenceNumber(context->writeSeqNum); 00818 } 00819 else 00820 #endif 00821 //Invalid cipher mode? 00822 { 00823 //The specified cipher mode is not supported 00824 return ERROR_UNSUPPORTED_CIPHER_MODE; 00825 } 00826 00827 //Debug message 00828 TRACE_DEBUG("Encrypted record (%" PRIuSIZE " bytes):\r\n", length); 00829 TRACE_DEBUG_ARRAY(" ", record, length + sizeof(TlsRecord)); 00830 } 00831 00832 //Successful encryption 00833 return NO_ERROR; 00834 } 00835 00836 00837 /** 00838 * @brief Decrypt an incoming TLS record 00839 * @param[in] context Pointer to the TLS context 00840 * @param[in,out] record TLS record to be decrypted 00841 * @return Error code 00842 **/ 00843 00844 error_t tlsDecryptRecord(TlsContext *context, TlsRecord *record) 00845 { 00846 error_t error; 00847 size_t length; 00848 00849 //Convert the length field to host byte order 00850 length = ntohs(record->length); 00851 00852 //Decrypt record if necessary 00853 if(context->cipherMode != CIPHER_MODE_NULL) 00854 { 00855 //Debug message 00856 TRACE_DEBUG("Record to be decrypted (%" PRIuSIZE " bytes):\r\n", length); 00857 TRACE_DEBUG_ARRAY(" ", record, length + sizeof(TlsRecord)); 00858 00859 #if (TLS_STREAM_CIPHER_SUPPORT == ENABLED) 00860 //Stream cipher? 00861 if(context->cipherMode == CIPHER_MODE_STREAM) 00862 { 00863 //Decrypt record contents 00864 context->cipherAlgo->decryptStream(context->readCipherContext, 00865 record->data, record->data, length); 00866 } 00867 else 00868 #endif 00869 #if (TLS_CBC_CIPHER_SUPPORT == ENABLED) 00870 //CBC block cipher? 00871 if(context->cipherMode == CIPHER_MODE_CBC) 00872 { 00873 size_t i; 00874 size_t paddingLength; 00875 00876 //The length of the data must be a multiple of the block size 00877 if((length % context->cipherAlgo->blockSize) != 0) 00878 return ERROR_DECODING_FAILED; 00879 00880 //CBC decryption 00881 error = cbcDecrypt(context->cipherAlgo, context->readCipherContext, 00882 context->readIv, record->data, record->data, length); 00883 //Any error to report? 00884 if(error) 00885 return error; 00886 00887 //Debug message 00888 TRACE_DEBUG("Record with padding (%" PRIuSIZE " bytes):\r\n", length); 00889 TRACE_DEBUG_ARRAY(" ", record, length + sizeof(TlsRecord)); 00890 00891 #if (TLS_MAX_VERSION >= TLS_VERSION_1_1 && TLS_MIN_VERSION <= TLS_VERSION_1_2) 00892 //TLS 1.1 and 1.2 use an explicit IV 00893 if(context->version >= TLS_VERSION_1_1) 00894 { 00895 //Make sure the message length is acceptable 00896 if(length < context->recordIvLen) 00897 return ERROR_DECODING_FAILED; 00898 00899 //Adjust the length of the message 00900 length -= context->recordIvLen; 00901 //Discard the first cipher block (corresponding to the explicit IV) 00902 memmove(record->data, record->data + context->recordIvLen, length); 00903 } 00904 #endif 00905 //Make sure the message length is acceptable 00906 if(length < context->cipherAlgo->blockSize) 00907 return ERROR_DECODING_FAILED; 00908 00909 //Compute the length of the padding string 00910 paddingLength = record->data[length - 1]; 00911 //Erroneous padding length? 00912 if(paddingLength >= length) 00913 return ERROR_BAD_RECORD_MAC; 00914 00915 //The receiver must check the padding 00916 for(i = 0; i <= paddingLength; i++) 00917 { 00918 //Each byte in the padding data must be filled 00919 //with the padding length value 00920 if(record->data[length - 1 - i] != paddingLength) 00921 return ERROR_BAD_RECORD_MAC; 00922 } 00923 00924 //Remove padding bytes 00925 length -= paddingLength + 1; 00926 //Fix the length field of the TLS record 00927 record->length = htons(length); 00928 } 00929 else 00930 #endif 00931 #if (TLS_CCM_CIPHER_SUPPORT == ENABLED || TLS_CCM_8_CIPHER_SUPPORT == ENABLED || \ 00932 TLS_GCM_CIPHER_SUPPORT == ENABLED) 00933 //CCM or GCM AEAD cipher? 00934 if(context->cipherMode == CIPHER_MODE_CCM || 00935 context->cipherMode == CIPHER_MODE_GCM) 00936 { 00937 uint8_t *ciphertext; 00938 uint8_t *tag; 00939 size_t nonceLength; 00940 uint8_t nonce[12]; 00941 uint8_t a[13]; 00942 00943 //Make sure the message length is acceptable 00944 if(length < (context->recordIvLen + context->authTagLen)) 00945 return ERROR_DECODING_FAILED; 00946 00947 //Determine the total length of the nonce 00948 nonceLength = context->fixedIvLen + context->recordIvLen; 00949 //The salt is the implicit part of the nonce and is not sent in the packet 00950 memcpy(nonce, context->readIv, context->fixedIvLen); 00951 //The explicit part of the nonce is chosen by the sender 00952 memcpy(nonce + context->fixedIvLen, record->data, context->recordIvLen); 00953 00954 //Calculate the length of the ciphertext 00955 length -= context->recordIvLen + context->authTagLen; 00956 //Fix the length field of the TLS record 00957 record->length = htons(length); 00958 00959 //Additional data to be authenticated 00960 memcpy(a, context->readSeqNum, sizeof(TlsSequenceNumber)); 00961 memcpy(a + sizeof(TlsSequenceNumber), record, sizeof(TlsRecord)); 00962 00963 //Point to the ciphertext 00964 ciphertext = record->data + context->recordIvLen; 00965 //Point to the authentication tag 00966 tag = ciphertext + length; 00967 00968 #if (TLS_CCM_CIPHER_SUPPORT == ENABLED || TLS_CCM_8_CIPHER_SUPPORT == ENABLED) 00969 //CCM AEAD cipher? 00970 if(context->cipherMode == CIPHER_MODE_CCM) 00971 { 00972 //Authenticated decryption using CCM 00973 error = ccmDecrypt(context->cipherAlgo, context->readCipherContext, 00974 nonce, nonceLength, a, 13, ciphertext, ciphertext, length, tag, context->authTagLen); 00975 } 00976 else 00977 #endif 00978 #if (TLS_GCM_CIPHER_SUPPORT == ENABLED) 00979 //GCM AEAD cipher? 00980 if(context->cipherMode == CIPHER_MODE_GCM) 00981 { 00982 //Authenticated decryption using GCM 00983 error = gcmDecrypt(context->readGcmContext, nonce, nonceLength, 00984 a, 13, ciphertext, ciphertext, length, tag, context->authTagLen); 00985 } 00986 else 00987 #endif 00988 //Invalid cipher mode? 00989 { 00990 //The specified cipher mode is not supported 00991 error = ERROR_UNSUPPORTED_CIPHER_MODE; 00992 } 00993 00994 //Wrong authentication tag? 00995 if(error) 00996 return ERROR_BAD_RECORD_MAC; 00997 00998 //Discard the explicit part of the nonce 00999 memmove(record->data, record->data + context->recordIvLen, length); 01000 01001 //Increment sequence number 01002 tlsIncSequenceNumber(context->readSeqNum); 01003 } 01004 else 01005 #endif 01006 #if (TLS_CHACHA20_POLY1305_SUPPORT == ENABLED) 01007 //ChaCha20Poly1305 AEAD cipher? 01008 if(context->cipherMode == CIPHER_MODE_CHACHA20_POLY1305) 01009 { 01010 size_t i; 01011 uint8_t *tag; 01012 uint8_t nonce[12]; 01013 uint8_t a[13]; 01014 01015 //Make sure the message length is acceptable 01016 if(length < context->authTagLen) 01017 return ERROR_DECODING_FAILED; 01018 01019 //The 64-bit record sequence number is serialized as an 8-byte, 01020 //big-endian value and padded on the left with four 0x00 bytes 01021 memcpy(nonce + 4, context->readSeqNum, 8); 01022 memset(nonce, 0, 4); 01023 01024 //The padded sequence number is XORed with the read IV to form 01025 //the 96-bit nonce 01026 for(i = 0; i < context->fixedIvLen; i++) 01027 nonce[i] ^= context->readIv[i]; 01028 01029 //Calculate the length of the ciphertext 01030 length -= context->authTagLen; 01031 //Fix the length field of the TLS record 01032 record->length = htons(length); 01033 01034 //Additional data to be authenticated 01035 memcpy(a, context->readSeqNum, sizeof(TlsSequenceNumber)); 01036 memcpy(a + sizeof(TlsSequenceNumber), record, sizeof(TlsRecord)); 01037 01038 //Point to the authentication tag 01039 tag = record->data + length; 01040 01041 //Authenticated decryption using ChaCha20Poly1305 01042 error = chacha20Poly1305Decrypt(context->readEncKey, context->encKeyLen, 01043 nonce, 12, a, 13, record->data, record->data, length, tag, context->authTagLen); 01044 //Wrong authentication tag? 01045 if(error) 01046 return ERROR_BAD_RECORD_MAC; 01047 01048 //Increment sequence number 01049 tlsIncSequenceNumber(context->readSeqNum); 01050 } 01051 else 01052 #endif 01053 //Invalid cipher mode? 01054 { 01055 //The specified cipher mode is not supported 01056 return ERROR_UNSUPPORTED_CIPHER_MODE; 01057 } 01058 01059 //Debug message 01060 TRACE_DEBUG("Decrypted record (%" PRIuSIZE " bytes):\r\n", length); 01061 TRACE_DEBUG_ARRAY(" ", record, length + sizeof(TlsRecord)); 01062 } 01063 01064 //Check message authentication code if necessary 01065 if(context->hashAlgo != NULL) 01066 { 01067 //Make sure the message length is acceptable 01068 if(length < context->hashAlgo->digestSize) 01069 return ERROR_DECODING_FAILED; 01070 01071 //Adjust the length of the message 01072 length -= context->hashAlgo->digestSize; 01073 //Fix the length field of the TLS record 01074 record->length = htons(length); 01075 01076 #if (TLS_MAX_VERSION >= SSL_VERSION_3_0 && TLS_MIN_VERSION <= SSL_VERSION_3_0) 01077 //Check whether SSL 3.0 is currently used 01078 if(context->version == SSL_VERSION_3_0) 01079 { 01080 //SSL 3.0 uses an older obsolete version of the HMAC construction 01081 error = sslComputeMac(context, context->readMacKey, context->readSeqNum, 01082 record, record->data, length, context->hmacContext.digest); 01083 //Any error to report? 01084 if(error) 01085 return error; 01086 } 01087 else 01088 #endif 01089 #if (TLS_MAX_VERSION >= TLS_VERSION_1_0 && TLS_MIN_VERSION <= TLS_VERSION_1_2) 01090 //Check whether TLS 1.0, TLS 1.1 or TLS 1.2 is currently used 01091 if(context->version >= TLS_VERSION_1_0) 01092 { 01093 //TLS uses a HMAC construction 01094 hmacInit(&context->hmacContext, context->hashAlgo, 01095 context->readMacKey, context->macKeyLen); 01096 01097 //Compute MAC over the sequence number and the record contents 01098 hmacUpdate(&context->hmacContext, context->readSeqNum, sizeof(TlsSequenceNumber)); 01099 hmacUpdate(&context->hmacContext, record, sizeof(TlsRecord)); 01100 hmacUpdate(&context->hmacContext, record->data, length); 01101 hmacFinal(&context->hmacContext, NULL); 01102 } 01103 else 01104 #endif 01105 //The negotiated TLS version is not valid... 01106 { 01107 //Report an error 01108 return ERROR_INVALID_VERSION; 01109 } 01110 01111 //Debug message 01112 TRACE_DEBUG("Read sequence number:\r\n"); 01113 TRACE_DEBUG_ARRAY(" ", context->readSeqNum, sizeof(TlsSequenceNumber)); 01114 TRACE_DEBUG("Computed MAC:\r\n"); 01115 TRACE_DEBUG_ARRAY(" ", context->hmacContext.digest, context->hashAlgo->digestSize); 01116 01117 //Check the message authentication code 01118 if(memcmp(record->data + length, context->hmacContext.digest, context->hashAlgo->digestSize)) 01119 return ERROR_BAD_RECORD_MAC; 01120 01121 //Increment sequence number 01122 tlsIncSequenceNumber(context->readSeqNum); 01123 } 01124 01125 //Successful decryption 01126 return NO_ERROR; 01127 } 01128 01129 01130 /** 01131 * @brief Increment sequence number 01132 * @param[in] seqNum Sequence number to increment 01133 **/ 01134 01135 void tlsIncSequenceNumber(TlsSequenceNumber seqNum) 01136 { 01137 int_t i; 01138 01139 //Sequence numbers are stored MSB first 01140 for(i = 7; i >= 0; i--) 01141 { 01142 //Increment the current byte 01143 seqNum[i]++; 01144 //Propagate the carry if necessary 01145 if(seqNum[i] != 0) 01146 break; 01147 } 01148 } 01149 01150 #endif 01151
Generated on Tue Jul 12 2022 17:10:17 by
