Webserver+3d print
cyclone_ssl/tls_record.c@0:8918a71cdbe9, 2017-02-04 (annotated)
- Committer:
- Sergunb
- Date:
- Sat Feb 04 18:15:49 2017 +0000
- Revision:
- 0:8918a71cdbe9
nothing else
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
Sergunb | 0:8918a71cdbe9 | 1 | /** |
Sergunb | 0:8918a71cdbe9 | 2 | * @file tls_record.c |
Sergunb | 0:8918a71cdbe9 | 3 | * @brief TLS record protocol |
Sergunb | 0:8918a71cdbe9 | 4 | * |
Sergunb | 0:8918a71cdbe9 | 5 | * @section License |
Sergunb | 0:8918a71cdbe9 | 6 | * |
Sergunb | 0:8918a71cdbe9 | 7 | * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved. |
Sergunb | 0:8918a71cdbe9 | 8 | * |
Sergunb | 0:8918a71cdbe9 | 9 | * This file is part of CycloneSSL Open. |
Sergunb | 0:8918a71cdbe9 | 10 | * |
Sergunb | 0:8918a71cdbe9 | 11 | * This program is free software; you can redistribute it and/or |
Sergunb | 0:8918a71cdbe9 | 12 | * modify it under the terms of the GNU General Public License |
Sergunb | 0:8918a71cdbe9 | 13 | * as published by the Free Software Foundation; either version 2 |
Sergunb | 0:8918a71cdbe9 | 14 | * of the License, or (at your option) any later version. |
Sergunb | 0:8918a71cdbe9 | 15 | * |
Sergunb | 0:8918a71cdbe9 | 16 | * This program is distributed in the hope that it will be useful, |
Sergunb | 0:8918a71cdbe9 | 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
Sergunb | 0:8918a71cdbe9 | 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
Sergunb | 0:8918a71cdbe9 | 19 | * GNU General Public License for more details. |
Sergunb | 0:8918a71cdbe9 | 20 | * |
Sergunb | 0:8918a71cdbe9 | 21 | * You should have received a copy of the GNU General Public License |
Sergunb | 0:8918a71cdbe9 | 22 | * along with this program; if not, write to the Free Software Foundation, |
Sergunb | 0:8918a71cdbe9 | 23 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
Sergunb | 0:8918a71cdbe9 | 24 | * |
Sergunb | 0:8918a71cdbe9 | 25 | * @author Oryx Embedded SARL (www.oryx-embedded.com) |
Sergunb | 0:8918a71cdbe9 | 26 | * @version 1.7.6 |
Sergunb | 0:8918a71cdbe9 | 27 | **/ |
Sergunb | 0:8918a71cdbe9 | 28 | |
Sergunb | 0:8918a71cdbe9 | 29 | //Switch to the appropriate trace level |
Sergunb | 0:8918a71cdbe9 | 30 | #define TRACE_LEVEL TLS_TRACE_LEVEL |
Sergunb | 0:8918a71cdbe9 | 31 | |
Sergunb | 0:8918a71cdbe9 | 32 | //Dependencies |
Sergunb | 0:8918a71cdbe9 | 33 | #include <string.h> |
Sergunb | 0:8918a71cdbe9 | 34 | #include "tls.h" |
Sergunb | 0:8918a71cdbe9 | 35 | #include "tls_common.h" |
Sergunb | 0:8918a71cdbe9 | 36 | #include "tls_record.h" |
Sergunb | 0:8918a71cdbe9 | 37 | #include "tls_misc.h" |
Sergunb | 0:8918a71cdbe9 | 38 | #include "ssl_common.h" |
Sergunb | 0:8918a71cdbe9 | 39 | #include "cipher_mode_cbc.h" |
Sergunb | 0:8918a71cdbe9 | 40 | #include "cipher_mode_ccm.h" |
Sergunb | 0:8918a71cdbe9 | 41 | #include "cipher_mode_gcm.h" |
Sergunb | 0:8918a71cdbe9 | 42 | #include "chacha20_poly1305.h" |
Sergunb | 0:8918a71cdbe9 | 43 | #include "debug.h" |
Sergunb | 0:8918a71cdbe9 | 44 | |
Sergunb | 0:8918a71cdbe9 | 45 | //Check SSL library configuration |
Sergunb | 0:8918a71cdbe9 | 46 | #if (TLS_SUPPORT == ENABLED) |
Sergunb | 0:8918a71cdbe9 | 47 | |
Sergunb | 0:8918a71cdbe9 | 48 | |
Sergunb | 0:8918a71cdbe9 | 49 | /** |
Sergunb | 0:8918a71cdbe9 | 50 | * @brief Write protocol data |
Sergunb | 0:8918a71cdbe9 | 51 | * @param[in] context Pointer to the TLS context |
Sergunb | 0:8918a71cdbe9 | 52 | * @param[in] data Pointer to the data buffer |
Sergunb | 0:8918a71cdbe9 | 53 | * @param[in] length Number of data bytes to be written |
Sergunb | 0:8918a71cdbe9 | 54 | * @param[in] contentType Higher level protocol |
Sergunb | 0:8918a71cdbe9 | 55 | * @return Error code |
Sergunb | 0:8918a71cdbe9 | 56 | **/ |
Sergunb | 0:8918a71cdbe9 | 57 | |
Sergunb | 0:8918a71cdbe9 | 58 | error_t tlsWriteProtocolData(TlsContext *context, |
Sergunb | 0:8918a71cdbe9 | 59 | const void *data, size_t length, TlsContentType contentType) |
Sergunb | 0:8918a71cdbe9 | 60 | { |
Sergunb | 0:8918a71cdbe9 | 61 | error_t error; |
Sergunb | 0:8918a71cdbe9 | 62 | size_t n; |
Sergunb | 0:8918a71cdbe9 | 63 | uint8_t *p; |
Sergunb | 0:8918a71cdbe9 | 64 | |
Sergunb | 0:8918a71cdbe9 | 65 | //Initialize status code |
Sergunb | 0:8918a71cdbe9 | 66 | error = NO_ERROR; |
Sergunb | 0:8918a71cdbe9 | 67 | |
Sergunb | 0:8918a71cdbe9 | 68 | //Fragmentation process |
Sergunb | 0:8918a71cdbe9 | 69 | while(!error) |
Sergunb | 0:8918a71cdbe9 | 70 | { |
Sergunb | 0:8918a71cdbe9 | 71 | if(context->txBufferLen == 0) |
Sergunb | 0:8918a71cdbe9 | 72 | { |
Sergunb | 0:8918a71cdbe9 | 73 | //Check the length of the data |
Sergunb | 0:8918a71cdbe9 | 74 | if(length > context->txRecordMaxLen) |
Sergunb | 0:8918a71cdbe9 | 75 | { |
Sergunb | 0:8918a71cdbe9 | 76 | //Report an error |
Sergunb | 0:8918a71cdbe9 | 77 | error = ERROR_MESSAGE_TOO_LONG; |
Sergunb | 0:8918a71cdbe9 | 78 | } |
Sergunb | 0:8918a71cdbe9 | 79 | else if(length > 0) |
Sergunb | 0:8918a71cdbe9 | 80 | { |
Sergunb | 0:8918a71cdbe9 | 81 | //The hash value is updated for each handshake message, |
Sergunb | 0:8918a71cdbe9 | 82 | //except for HelloRequest messages |
Sergunb | 0:8918a71cdbe9 | 83 | if(contentType == TLS_TYPE_HANDSHAKE) |
Sergunb | 0:8918a71cdbe9 | 84 | tlsUpdateHandshakeHash(context, data, length); |
Sergunb | 0:8918a71cdbe9 | 85 | |
Sergunb | 0:8918a71cdbe9 | 86 | //Make room for the encryption overhead |
Sergunb | 0:8918a71cdbe9 | 87 | memmove(context->txBuffer + context->txBufferSize - length, data, length); |
Sergunb | 0:8918a71cdbe9 | 88 | |
Sergunb | 0:8918a71cdbe9 | 89 | //Save record type |
Sergunb | 0:8918a71cdbe9 | 90 | context->txBufferType = contentType; |
Sergunb | 0:8918a71cdbe9 | 91 | //Set the length of the buffer |
Sergunb | 0:8918a71cdbe9 | 92 | context->txBufferLen = length; |
Sergunb | 0:8918a71cdbe9 | 93 | //Point to the beginning of the buffer |
Sergunb | 0:8918a71cdbe9 | 94 | context->txBufferPos = 0; |
Sergunb | 0:8918a71cdbe9 | 95 | } |
Sergunb | 0:8918a71cdbe9 | 96 | else |
Sergunb | 0:8918a71cdbe9 | 97 | { |
Sergunb | 0:8918a71cdbe9 | 98 | //We are done |
Sergunb | 0:8918a71cdbe9 | 99 | break; |
Sergunb | 0:8918a71cdbe9 | 100 | } |
Sergunb | 0:8918a71cdbe9 | 101 | } |
Sergunb | 0:8918a71cdbe9 | 102 | else if(context->txBufferPos < context->txBufferLen) |
Sergunb | 0:8918a71cdbe9 | 103 | { |
Sergunb | 0:8918a71cdbe9 | 104 | //Number of bytes left to send |
Sergunb | 0:8918a71cdbe9 | 105 | n = context->txBufferLen - context->txBufferPos; |
Sergunb | 0:8918a71cdbe9 | 106 | //Point to the current fragment |
Sergunb | 0:8918a71cdbe9 | 107 | p = context->txBuffer + context->txBufferSize - n; |
Sergunb | 0:8918a71cdbe9 | 108 | //The record length must not exceed 16384 bytes |
Sergunb | 0:8918a71cdbe9 | 109 | n = MIN(n, TLS_MAX_RECORD_LENGTH); |
Sergunb | 0:8918a71cdbe9 | 110 | |
Sergunb | 0:8918a71cdbe9 | 111 | //Send TLS record |
Sergunb | 0:8918a71cdbe9 | 112 | error = tlsWriteRecord(context, p, n, context->txBufferType); |
Sergunb | 0:8918a71cdbe9 | 113 | |
Sergunb | 0:8918a71cdbe9 | 114 | //Check status code |
Sergunb | 0:8918a71cdbe9 | 115 | if(!error) |
Sergunb | 0:8918a71cdbe9 | 116 | { |
Sergunb | 0:8918a71cdbe9 | 117 | //Advance data pointer |
Sergunb | 0:8918a71cdbe9 | 118 | context->txBufferPos += n; |
Sergunb | 0:8918a71cdbe9 | 119 | } |
Sergunb | 0:8918a71cdbe9 | 120 | } |
Sergunb | 0:8918a71cdbe9 | 121 | else |
Sergunb | 0:8918a71cdbe9 | 122 | { |
Sergunb | 0:8918a71cdbe9 | 123 | //Prepare to send new protocol data |
Sergunb | 0:8918a71cdbe9 | 124 | context->txBufferLen = 0; |
Sergunb | 0:8918a71cdbe9 | 125 | context->txBufferPos = 0; |
Sergunb | 0:8918a71cdbe9 | 126 | |
Sergunb | 0:8918a71cdbe9 | 127 | //We are done |
Sergunb | 0:8918a71cdbe9 | 128 | break; |
Sergunb | 0:8918a71cdbe9 | 129 | } |
Sergunb | 0:8918a71cdbe9 | 130 | } |
Sergunb | 0:8918a71cdbe9 | 131 | |
Sergunb | 0:8918a71cdbe9 | 132 | //Return status code |
Sergunb | 0:8918a71cdbe9 | 133 | return error; |
Sergunb | 0:8918a71cdbe9 | 134 | } |
Sergunb | 0:8918a71cdbe9 | 135 | |
Sergunb | 0:8918a71cdbe9 | 136 | |
Sergunb | 0:8918a71cdbe9 | 137 | /** |
Sergunb | 0:8918a71cdbe9 | 138 | * @brief Read protocol data |
Sergunb | 0:8918a71cdbe9 | 139 | * @param[in] context Pointer to the TLS context |
Sergunb | 0:8918a71cdbe9 | 140 | * @param[out] data Pointer to the received data |
Sergunb | 0:8918a71cdbe9 | 141 | * @param[out] length Number of data bytes that were received |
Sergunb | 0:8918a71cdbe9 | 142 | * @param[out] contentType Higher level protocol |
Sergunb | 0:8918a71cdbe9 | 143 | * @return Error code |
Sergunb | 0:8918a71cdbe9 | 144 | **/ |
Sergunb | 0:8918a71cdbe9 | 145 | |
Sergunb | 0:8918a71cdbe9 | 146 | error_t tlsReadProtocolData(TlsContext *context, |
Sergunb | 0:8918a71cdbe9 | 147 | void **data, size_t *length, TlsContentType *contentType) |
Sergunb | 0:8918a71cdbe9 | 148 | { |
Sergunb | 0:8918a71cdbe9 | 149 | error_t error; |
Sergunb | 0:8918a71cdbe9 | 150 | size_t n; |
Sergunb | 0:8918a71cdbe9 | 151 | TlsContentType type; |
Sergunb | 0:8918a71cdbe9 | 152 | TlsHandshake *message; |
Sergunb | 0:8918a71cdbe9 | 153 | |
Sergunb | 0:8918a71cdbe9 | 154 | //Initialize status code |
Sergunb | 0:8918a71cdbe9 | 155 | error = NO_ERROR; |
Sergunb | 0:8918a71cdbe9 | 156 | |
Sergunb | 0:8918a71cdbe9 | 157 | //Fragment reassembly process |
Sergunb | 0:8918a71cdbe9 | 158 | do |
Sergunb | 0:8918a71cdbe9 | 159 | { |
Sergunb | 0:8918a71cdbe9 | 160 | //Empty receive buffer? |
Sergunb | 0:8918a71cdbe9 | 161 | if(context->rxBufferLen == 0) |
Sergunb | 0:8918a71cdbe9 | 162 | { |
Sergunb | 0:8918a71cdbe9 | 163 | //Read a TLS record |
Sergunb | 0:8918a71cdbe9 | 164 | error = tlsReadRecord(context, context->rxBuffer, |
Sergunb | 0:8918a71cdbe9 | 165 | context->rxBufferSize, &n, &type); |
Sergunb | 0:8918a71cdbe9 | 166 | |
Sergunb | 0:8918a71cdbe9 | 167 | //Check status code |
Sergunb | 0:8918a71cdbe9 | 168 | if(!error) |
Sergunb | 0:8918a71cdbe9 | 169 | { |
Sergunb | 0:8918a71cdbe9 | 170 | //Save record type |
Sergunb | 0:8918a71cdbe9 | 171 | context->rxBufferType = type; |
Sergunb | 0:8918a71cdbe9 | 172 | //Number of bytes available for reading |
Sergunb | 0:8918a71cdbe9 | 173 | context->rxBufferLen = n; |
Sergunb | 0:8918a71cdbe9 | 174 | //Rewind to the beginning of the buffer |
Sergunb | 0:8918a71cdbe9 | 175 | context->rxBufferPos = 0; |
Sergunb | 0:8918a71cdbe9 | 176 | } |
Sergunb | 0:8918a71cdbe9 | 177 | } |
Sergunb | 0:8918a71cdbe9 | 178 | //Imcomplete message received? |
Sergunb | 0:8918a71cdbe9 | 179 | else if(error == ERROR_MORE_DATA_REQUIRED) |
Sergunb | 0:8918a71cdbe9 | 180 | { |
Sergunb | 0:8918a71cdbe9 | 181 | //Make room at the end of the buffer |
Sergunb | 0:8918a71cdbe9 | 182 | if(context->rxBufferPos > 0) |
Sergunb | 0:8918a71cdbe9 | 183 | { |
Sergunb | 0:8918a71cdbe9 | 184 | //Move unread data to the beginning of the buffer |
Sergunb | 0:8918a71cdbe9 | 185 | memmove(context->rxBuffer, context->rxBuffer + |
Sergunb | 0:8918a71cdbe9 | 186 | context->rxBufferPos, context->rxBufferLen); |
Sergunb | 0:8918a71cdbe9 | 187 | |
Sergunb | 0:8918a71cdbe9 | 188 | //Rewind to the beginning of the buffer |
Sergunb | 0:8918a71cdbe9 | 189 | context->rxBufferPos = 0; |
Sergunb | 0:8918a71cdbe9 | 190 | } |
Sergunb | 0:8918a71cdbe9 | 191 | |
Sergunb | 0:8918a71cdbe9 | 192 | //Read a TLS record |
Sergunb | 0:8918a71cdbe9 | 193 | error = tlsReadRecord(context, context->rxBuffer + context->rxBufferLen, |
Sergunb | 0:8918a71cdbe9 | 194 | context->rxBufferSize - context->rxBufferLen, &n, &type); |
Sergunb | 0:8918a71cdbe9 | 195 | |
Sergunb | 0:8918a71cdbe9 | 196 | //Check status code |
Sergunb | 0:8918a71cdbe9 | 197 | if(!error) |
Sergunb | 0:8918a71cdbe9 | 198 | { |
Sergunb | 0:8918a71cdbe9 | 199 | //Fragmented records with mixed types cannot be interleaved |
Sergunb | 0:8918a71cdbe9 | 200 | if(type != context->rxBufferType) |
Sergunb | 0:8918a71cdbe9 | 201 | error = ERROR_UNEXPECTED_MESSAGE; |
Sergunb | 0:8918a71cdbe9 | 202 | } |
Sergunb | 0:8918a71cdbe9 | 203 | |
Sergunb | 0:8918a71cdbe9 | 204 | //Check status code |
Sergunb | 0:8918a71cdbe9 | 205 | if(!error) |
Sergunb | 0:8918a71cdbe9 | 206 | { |
Sergunb | 0:8918a71cdbe9 | 207 | //Number of bytes available for reading |
Sergunb | 0:8918a71cdbe9 | 208 | context->rxBufferLen += n; |
Sergunb | 0:8918a71cdbe9 | 209 | } |
Sergunb | 0:8918a71cdbe9 | 210 | } |
Sergunb | 0:8918a71cdbe9 | 211 | |
Sergunb | 0:8918a71cdbe9 | 212 | //Check status code |
Sergunb | 0:8918a71cdbe9 | 213 | if(!error) |
Sergunb | 0:8918a71cdbe9 | 214 | { |
Sergunb | 0:8918a71cdbe9 | 215 | //Handshake message received? |
Sergunb | 0:8918a71cdbe9 | 216 | if(context->rxBufferType == TLS_TYPE_HANDSHAKE) |
Sergunb | 0:8918a71cdbe9 | 217 | { |
Sergunb | 0:8918a71cdbe9 | 218 | //A message may be fragmented across several records |
Sergunb | 0:8918a71cdbe9 | 219 | if(context->rxBufferLen < sizeof(TlsHandshake)) |
Sergunb | 0:8918a71cdbe9 | 220 | { |
Sergunb | 0:8918a71cdbe9 | 221 | //Read an additional record |
Sergunb | 0:8918a71cdbe9 | 222 | error = ERROR_MORE_DATA_REQUIRED; |
Sergunb | 0:8918a71cdbe9 | 223 | } |
Sergunb | 0:8918a71cdbe9 | 224 | else |
Sergunb | 0:8918a71cdbe9 | 225 | { |
Sergunb | 0:8918a71cdbe9 | 226 | //Point to the handshake message |
Sergunb | 0:8918a71cdbe9 | 227 | message = (TlsHandshake *) (context->rxBuffer + context->rxBufferPos); |
Sergunb | 0:8918a71cdbe9 | 228 | //Retrieve the length of the handshake message |
Sergunb | 0:8918a71cdbe9 | 229 | n = sizeof(TlsHandshake) + LOAD24BE(message->length); |
Sergunb | 0:8918a71cdbe9 | 230 | |
Sergunb | 0:8918a71cdbe9 | 231 | //A message may be fragmented across several records |
Sergunb | 0:8918a71cdbe9 | 232 | if(context->rxBufferLen < n) |
Sergunb | 0:8918a71cdbe9 | 233 | { |
Sergunb | 0:8918a71cdbe9 | 234 | //Read an additional record |
Sergunb | 0:8918a71cdbe9 | 235 | error = ERROR_MORE_DATA_REQUIRED; |
Sergunb | 0:8918a71cdbe9 | 236 | } |
Sergunb | 0:8918a71cdbe9 | 237 | else |
Sergunb | 0:8918a71cdbe9 | 238 | { |
Sergunb | 0:8918a71cdbe9 | 239 | //Pass the handshake message to the higher layer |
Sergunb | 0:8918a71cdbe9 | 240 | error = NO_ERROR; |
Sergunb | 0:8918a71cdbe9 | 241 | } |
Sergunb | 0:8918a71cdbe9 | 242 | } |
Sergunb | 0:8918a71cdbe9 | 243 | } |
Sergunb | 0:8918a71cdbe9 | 244 | //ChangeCipherSpec message received? |
Sergunb | 0:8918a71cdbe9 | 245 | else if(context->rxBufferType == TLS_TYPE_CHANGE_CIPHER_SPEC) |
Sergunb | 0:8918a71cdbe9 | 246 | { |
Sergunb | 0:8918a71cdbe9 | 247 | //A message may be fragmented across several records |
Sergunb | 0:8918a71cdbe9 | 248 | if(context->rxBufferLen < sizeof(TlsChangeCipherSpec)) |
Sergunb | 0:8918a71cdbe9 | 249 | { |
Sergunb | 0:8918a71cdbe9 | 250 | //Read an additional record |
Sergunb | 0:8918a71cdbe9 | 251 | error = ERROR_MORE_DATA_REQUIRED; |
Sergunb | 0:8918a71cdbe9 | 252 | } |
Sergunb | 0:8918a71cdbe9 | 253 | else |
Sergunb | 0:8918a71cdbe9 | 254 | { |
Sergunb | 0:8918a71cdbe9 | 255 | //Length of the ChangeCipherSpec message |
Sergunb | 0:8918a71cdbe9 | 256 | n = sizeof(TlsChangeCipherSpec); |
Sergunb | 0:8918a71cdbe9 | 257 | //Pass the ChangeCipherSpec message to the higher layer |
Sergunb | 0:8918a71cdbe9 | 258 | error = NO_ERROR; |
Sergunb | 0:8918a71cdbe9 | 259 | } |
Sergunb | 0:8918a71cdbe9 | 260 | } |
Sergunb | 0:8918a71cdbe9 | 261 | //Alert message received? |
Sergunb | 0:8918a71cdbe9 | 262 | else if(context->rxBufferType == TLS_TYPE_ALERT) |
Sergunb | 0:8918a71cdbe9 | 263 | { |
Sergunb | 0:8918a71cdbe9 | 264 | //A message may be fragmented across several records |
Sergunb | 0:8918a71cdbe9 | 265 | if(context->rxBufferLen < sizeof(TlsAlert)) |
Sergunb | 0:8918a71cdbe9 | 266 | { |
Sergunb | 0:8918a71cdbe9 | 267 | //Read an additional record |
Sergunb | 0:8918a71cdbe9 | 268 | error = ERROR_MORE_DATA_REQUIRED; |
Sergunb | 0:8918a71cdbe9 | 269 | } |
Sergunb | 0:8918a71cdbe9 | 270 | else |
Sergunb | 0:8918a71cdbe9 | 271 | { |
Sergunb | 0:8918a71cdbe9 | 272 | //Length of the Alert message |
Sergunb | 0:8918a71cdbe9 | 273 | n = sizeof(TlsAlert); |
Sergunb | 0:8918a71cdbe9 | 274 | //Pass the Alert message to the higher layer |
Sergunb | 0:8918a71cdbe9 | 275 | error = NO_ERROR; |
Sergunb | 0:8918a71cdbe9 | 276 | } |
Sergunb | 0:8918a71cdbe9 | 277 | } |
Sergunb | 0:8918a71cdbe9 | 278 | //Application data received? |
Sergunb | 0:8918a71cdbe9 | 279 | else if(context->rxBufferType == TLS_TYPE_APPLICATION_DATA) |
Sergunb | 0:8918a71cdbe9 | 280 | { |
Sergunb | 0:8918a71cdbe9 | 281 | //Length of the application data |
Sergunb | 0:8918a71cdbe9 | 282 | n = context->rxBufferLen; |
Sergunb | 0:8918a71cdbe9 | 283 | //Pass the application data to the higher layer |
Sergunb | 0:8918a71cdbe9 | 284 | error = NO_ERROR; |
Sergunb | 0:8918a71cdbe9 | 285 | } |
Sergunb | 0:8918a71cdbe9 | 286 | //Unknown content type? |
Sergunb | 0:8918a71cdbe9 | 287 | else |
Sergunb | 0:8918a71cdbe9 | 288 | { |
Sergunb | 0:8918a71cdbe9 | 289 | //Report an error |
Sergunb | 0:8918a71cdbe9 | 290 | error = ERROR_UNEXPECTED_MESSAGE; |
Sergunb | 0:8918a71cdbe9 | 291 | } |
Sergunb | 0:8918a71cdbe9 | 292 | } |
Sergunb | 0:8918a71cdbe9 | 293 | |
Sergunb | 0:8918a71cdbe9 | 294 | //Read as many records as necessary to reassemble the data |
Sergunb | 0:8918a71cdbe9 | 295 | } while(error == ERROR_MORE_DATA_REQUIRED); |
Sergunb | 0:8918a71cdbe9 | 296 | |
Sergunb | 0:8918a71cdbe9 | 297 | //Successful processing? |
Sergunb | 0:8918a71cdbe9 | 298 | if(!error) |
Sergunb | 0:8918a71cdbe9 | 299 | { |
Sergunb | 0:8918a71cdbe9 | 300 | //Pointer to the received data |
Sergunb | 0:8918a71cdbe9 | 301 | *data = context->rxBuffer + context->rxBufferPos; |
Sergunb | 0:8918a71cdbe9 | 302 | //Length, in byte, of the data |
Sergunb | 0:8918a71cdbe9 | 303 | *length = n; |
Sergunb | 0:8918a71cdbe9 | 304 | //Protocol type |
Sergunb | 0:8918a71cdbe9 | 305 | *contentType = context->rxBufferType; |
Sergunb | 0:8918a71cdbe9 | 306 | } |
Sergunb | 0:8918a71cdbe9 | 307 | |
Sergunb | 0:8918a71cdbe9 | 308 | //Return status code |
Sergunb | 0:8918a71cdbe9 | 309 | return error; |
Sergunb | 0:8918a71cdbe9 | 310 | } |
Sergunb | 0:8918a71cdbe9 | 311 | |
Sergunb | 0:8918a71cdbe9 | 312 | |
Sergunb | 0:8918a71cdbe9 | 313 | /** |
Sergunb | 0:8918a71cdbe9 | 314 | * @brief Send a TLS record |
Sergunb | 0:8918a71cdbe9 | 315 | * @param[in] context Pointer to the TLS context |
Sergunb | 0:8918a71cdbe9 | 316 | * @param[in] data Pointer to the record data |
Sergunb | 0:8918a71cdbe9 | 317 | * @param[in] length Length of the record data |
Sergunb | 0:8918a71cdbe9 | 318 | * @param[in] contentType Record type |
Sergunb | 0:8918a71cdbe9 | 319 | * @return Error code |
Sergunb | 0:8918a71cdbe9 | 320 | **/ |
Sergunb | 0:8918a71cdbe9 | 321 | |
Sergunb | 0:8918a71cdbe9 | 322 | error_t tlsWriteRecord(TlsContext *context, const uint8_t *data, |
Sergunb | 0:8918a71cdbe9 | 323 | size_t length, TlsContentType contentType) |
Sergunb | 0:8918a71cdbe9 | 324 | { |
Sergunb | 0:8918a71cdbe9 | 325 | error_t error; |
Sergunb | 0:8918a71cdbe9 | 326 | size_t n; |
Sergunb | 0:8918a71cdbe9 | 327 | TlsRecord *record; |
Sergunb | 0:8918a71cdbe9 | 328 | |
Sergunb | 0:8918a71cdbe9 | 329 | //Point to the TLS record |
Sergunb | 0:8918a71cdbe9 | 330 | record = (TlsRecord *) context->txBuffer; |
Sergunb | 0:8918a71cdbe9 | 331 | |
Sergunb | 0:8918a71cdbe9 | 332 | //Initialize status code |
Sergunb | 0:8918a71cdbe9 | 333 | error = NO_ERROR; |
Sergunb | 0:8918a71cdbe9 | 334 | |
Sergunb | 0:8918a71cdbe9 | 335 | //Send process |
Sergunb | 0:8918a71cdbe9 | 336 | while(!error) |
Sergunb | 0:8918a71cdbe9 | 337 | { |
Sergunb | 0:8918a71cdbe9 | 338 | //Send as much data as possible |
Sergunb | 0:8918a71cdbe9 | 339 | if(context->txRecordLen == 0) |
Sergunb | 0:8918a71cdbe9 | 340 | { |
Sergunb | 0:8918a71cdbe9 | 341 | //Format TLS record |
Sergunb | 0:8918a71cdbe9 | 342 | record->type = contentType; |
Sergunb | 0:8918a71cdbe9 | 343 | record->version = htons(context->version); |
Sergunb | 0:8918a71cdbe9 | 344 | record->length = htons(length); |
Sergunb | 0:8918a71cdbe9 | 345 | |
Sergunb | 0:8918a71cdbe9 | 346 | //Copy record data |
Sergunb | 0:8918a71cdbe9 | 347 | memmove(record->data, data, length); |
Sergunb | 0:8918a71cdbe9 | 348 | |
Sergunb | 0:8918a71cdbe9 | 349 | //Debug message |
Sergunb | 0:8918a71cdbe9 | 350 | TRACE_DEBUG("Sending TLS record (%" PRIuSIZE " bytes)...\r\n", length); |
Sergunb | 0:8918a71cdbe9 | 351 | TRACE_DEBUG_ARRAY(" ", record, length + sizeof(TlsRecord)); |
Sergunb | 0:8918a71cdbe9 | 352 | |
Sergunb | 0:8918a71cdbe9 | 353 | //Protect record payload? |
Sergunb | 0:8918a71cdbe9 | 354 | if(context->changeCipherSpecSent) |
Sergunb | 0:8918a71cdbe9 | 355 | { |
Sergunb | 0:8918a71cdbe9 | 356 | //Encrypt TLS record |
Sergunb | 0:8918a71cdbe9 | 357 | error = tlsEncryptRecord(context, record); |
Sergunb | 0:8918a71cdbe9 | 358 | } |
Sergunb | 0:8918a71cdbe9 | 359 | |
Sergunb | 0:8918a71cdbe9 | 360 | //Check status code |
Sergunb | 0:8918a71cdbe9 | 361 | if(!error) |
Sergunb | 0:8918a71cdbe9 | 362 | { |
Sergunb | 0:8918a71cdbe9 | 363 | //Actual length of the record data |
Sergunb | 0:8918a71cdbe9 | 364 | context->txRecordLen = sizeof(TlsRecord) + ntohs(record->length); |
Sergunb | 0:8918a71cdbe9 | 365 | //Point to the beginning of the record |
Sergunb | 0:8918a71cdbe9 | 366 | context->txRecordPos = 0; |
Sergunb | 0:8918a71cdbe9 | 367 | } |
Sergunb | 0:8918a71cdbe9 | 368 | } |
Sergunb | 0:8918a71cdbe9 | 369 | else if(context->txRecordPos < context->txRecordLen) |
Sergunb | 0:8918a71cdbe9 | 370 | { |
Sergunb | 0:8918a71cdbe9 | 371 | //Total number of bytes that have been written |
Sergunb | 0:8918a71cdbe9 | 372 | n = 0; |
Sergunb | 0:8918a71cdbe9 | 373 | |
Sergunb | 0:8918a71cdbe9 | 374 | //Send more data |
Sergunb | 0:8918a71cdbe9 | 375 | error = context->sendCallback(context->handle, |
Sergunb | 0:8918a71cdbe9 | 376 | context->txBuffer + context->txRecordPos, |
Sergunb | 0:8918a71cdbe9 | 377 | context->txRecordLen - context->txRecordPos, &n, 0); |
Sergunb | 0:8918a71cdbe9 | 378 | |
Sergunb | 0:8918a71cdbe9 | 379 | //Check status code |
Sergunb | 0:8918a71cdbe9 | 380 | if(error == NO_ERROR || error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT) |
Sergunb | 0:8918a71cdbe9 | 381 | { |
Sergunb | 0:8918a71cdbe9 | 382 | //Advance data pointer |
Sergunb | 0:8918a71cdbe9 | 383 | context->txRecordPos += n; |
Sergunb | 0:8918a71cdbe9 | 384 | } |
Sergunb | 0:8918a71cdbe9 | 385 | else |
Sergunb | 0:8918a71cdbe9 | 386 | { |
Sergunb | 0:8918a71cdbe9 | 387 | //The write operation has failed |
Sergunb | 0:8918a71cdbe9 | 388 | error = ERROR_WRITE_FAILED; |
Sergunb | 0:8918a71cdbe9 | 389 | } |
Sergunb | 0:8918a71cdbe9 | 390 | } |
Sergunb | 0:8918a71cdbe9 | 391 | else |
Sergunb | 0:8918a71cdbe9 | 392 | { |
Sergunb | 0:8918a71cdbe9 | 393 | //Prepare to send the next TLS record |
Sergunb | 0:8918a71cdbe9 | 394 | context->txRecordLen = 0; |
Sergunb | 0:8918a71cdbe9 | 395 | context->txRecordPos = 0; |
Sergunb | 0:8918a71cdbe9 | 396 | |
Sergunb | 0:8918a71cdbe9 | 397 | //We are done |
Sergunb | 0:8918a71cdbe9 | 398 | break; |
Sergunb | 0:8918a71cdbe9 | 399 | } |
Sergunb | 0:8918a71cdbe9 | 400 | } |
Sergunb | 0:8918a71cdbe9 | 401 | |
Sergunb | 0:8918a71cdbe9 | 402 | //Return status code |
Sergunb | 0:8918a71cdbe9 | 403 | return error; |
Sergunb | 0:8918a71cdbe9 | 404 | } |
Sergunb | 0:8918a71cdbe9 | 405 | |
Sergunb | 0:8918a71cdbe9 | 406 | |
Sergunb | 0:8918a71cdbe9 | 407 | /** |
Sergunb | 0:8918a71cdbe9 | 408 | * @brief Receive a TLS record |
Sergunb | 0:8918a71cdbe9 | 409 | * @param[in] context Pointer to the TLS context |
Sergunb | 0:8918a71cdbe9 | 410 | * @param[out] data Buffer where to store the record data |
Sergunb | 0:8918a71cdbe9 | 411 | * @param[in] size Maximum acceptable size for the incoming record |
Sergunb | 0:8918a71cdbe9 | 412 | * @param[out] length Length of the record data |
Sergunb | 0:8918a71cdbe9 | 413 | * @param[out] contentType Record type |
Sergunb | 0:8918a71cdbe9 | 414 | * @return Error code |
Sergunb | 0:8918a71cdbe9 | 415 | **/ |
Sergunb | 0:8918a71cdbe9 | 416 | |
Sergunb | 0:8918a71cdbe9 | 417 | error_t tlsReadRecord(TlsContext *context, uint8_t *data, |
Sergunb | 0:8918a71cdbe9 | 418 | size_t size, size_t *length, TlsContentType *contentType) |
Sergunb | 0:8918a71cdbe9 | 419 | { |
Sergunb | 0:8918a71cdbe9 | 420 | error_t error; |
Sergunb | 0:8918a71cdbe9 | 421 | size_t n; |
Sergunb | 0:8918a71cdbe9 | 422 | TlsRecord *record; |
Sergunb | 0:8918a71cdbe9 | 423 | |
Sergunb | 0:8918a71cdbe9 | 424 | //Point to the buffer where to store the incoming TLS record |
Sergunb | 0:8918a71cdbe9 | 425 | record = (TlsRecord *) data; |
Sergunb | 0:8918a71cdbe9 | 426 | |
Sergunb | 0:8918a71cdbe9 | 427 | //Initialize status code |
Sergunb | 0:8918a71cdbe9 | 428 | error = NO_ERROR; |
Sergunb | 0:8918a71cdbe9 | 429 | |
Sergunb | 0:8918a71cdbe9 | 430 | //Receive process |
Sergunb | 0:8918a71cdbe9 | 431 | while(!error) |
Sergunb | 0:8918a71cdbe9 | 432 | { |
Sergunb | 0:8918a71cdbe9 | 433 | //Read as much data as possible |
Sergunb | 0:8918a71cdbe9 | 434 | if(context->rxRecordPos < sizeof(TlsRecord)) |
Sergunb | 0:8918a71cdbe9 | 435 | { |
Sergunb | 0:8918a71cdbe9 | 436 | //Make sure that the buffer is large enough to hold the record header |
Sergunb | 0:8918a71cdbe9 | 437 | if(size >= sizeof(TlsRecord)) |
Sergunb | 0:8918a71cdbe9 | 438 | { |
Sergunb | 0:8918a71cdbe9 | 439 | //Total number of bytes that have been received |
Sergunb | 0:8918a71cdbe9 | 440 | n = 0; |
Sergunb | 0:8918a71cdbe9 | 441 | |
Sergunb | 0:8918a71cdbe9 | 442 | //Read TLS record header |
Sergunb | 0:8918a71cdbe9 | 443 | error = context->receiveCallback(context->handle, |
Sergunb | 0:8918a71cdbe9 | 444 | data + context->rxRecordPos, |
Sergunb | 0:8918a71cdbe9 | 445 | sizeof(TlsRecord) - context->rxRecordPos, &n, 0); |
Sergunb | 0:8918a71cdbe9 | 446 | |
Sergunb | 0:8918a71cdbe9 | 447 | //Check status code |
Sergunb | 0:8918a71cdbe9 | 448 | if(error == NO_ERROR || error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT) |
Sergunb | 0:8918a71cdbe9 | 449 | { |
Sergunb | 0:8918a71cdbe9 | 450 | //Advance data pointer |
Sergunb | 0:8918a71cdbe9 | 451 | context->rxRecordPos += n; |
Sergunb | 0:8918a71cdbe9 | 452 | |
Sergunb | 0:8918a71cdbe9 | 453 | //TLS record header successfully received? |
Sergunb | 0:8918a71cdbe9 | 454 | if(context->rxRecordPos >= sizeof(TlsRecord)) |
Sergunb | 0:8918a71cdbe9 | 455 | { |
Sergunb | 0:8918a71cdbe9 | 456 | //Debug message |
Sergunb | 0:8918a71cdbe9 | 457 | TRACE_DEBUG("Record header received:\r\n"); |
Sergunb | 0:8918a71cdbe9 | 458 | TRACE_DEBUG_ARRAY(" ", record, sizeof(record)); |
Sergunb | 0:8918a71cdbe9 | 459 | |
Sergunb | 0:8918a71cdbe9 | 460 | //Retrieve the length of the TLS record |
Sergunb | 0:8918a71cdbe9 | 461 | context->rxRecordLen = sizeof(TlsRecord) + ntohs(record->length); |
Sergunb | 0:8918a71cdbe9 | 462 | } |
Sergunb | 0:8918a71cdbe9 | 463 | } |
Sergunb | 0:8918a71cdbe9 | 464 | else |
Sergunb | 0:8918a71cdbe9 | 465 | { |
Sergunb | 0:8918a71cdbe9 | 466 | //The read operation has failed |
Sergunb | 0:8918a71cdbe9 | 467 | error = ERROR_READ_FAILED; |
Sergunb | 0:8918a71cdbe9 | 468 | } |
Sergunb | 0:8918a71cdbe9 | 469 | } |
Sergunb | 0:8918a71cdbe9 | 470 | else |
Sergunb | 0:8918a71cdbe9 | 471 | { |
Sergunb | 0:8918a71cdbe9 | 472 | //Report an error |
Sergunb | 0:8918a71cdbe9 | 473 | error = ERROR_RECORD_OVERFLOW; |
Sergunb | 0:8918a71cdbe9 | 474 | } |
Sergunb | 0:8918a71cdbe9 | 475 | } |
Sergunb | 0:8918a71cdbe9 | 476 | else if(context->rxRecordPos < context->rxRecordLen) |
Sergunb | 0:8918a71cdbe9 | 477 | { |
Sergunb | 0:8918a71cdbe9 | 478 | //Make sure that the buffer is large enough to hold the entire record |
Sergunb | 0:8918a71cdbe9 | 479 | if(size >= context->rxRecordLen) |
Sergunb | 0:8918a71cdbe9 | 480 | { |
Sergunb | 0:8918a71cdbe9 | 481 | //Total number of bytes that have been received |
Sergunb | 0:8918a71cdbe9 | 482 | n = 0; |
Sergunb | 0:8918a71cdbe9 | 483 | |
Sergunb | 0:8918a71cdbe9 | 484 | //Read TLS record contents |
Sergunb | 0:8918a71cdbe9 | 485 | error = context->receiveCallback(context->handle, |
Sergunb | 0:8918a71cdbe9 | 486 | data + context->rxRecordPos, |
Sergunb | 0:8918a71cdbe9 | 487 | context->rxRecordLen - context->rxRecordPos, &n, 0); |
Sergunb | 0:8918a71cdbe9 | 488 | |
Sergunb | 0:8918a71cdbe9 | 489 | //Check status code |
Sergunb | 0:8918a71cdbe9 | 490 | if(error == NO_ERROR || error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT) |
Sergunb | 0:8918a71cdbe9 | 491 | { |
Sergunb | 0:8918a71cdbe9 | 492 | //Advance data pointer |
Sergunb | 0:8918a71cdbe9 | 493 | context->rxRecordPos += n; |
Sergunb | 0:8918a71cdbe9 | 494 | } |
Sergunb | 0:8918a71cdbe9 | 495 | else |
Sergunb | 0:8918a71cdbe9 | 496 | { |
Sergunb | 0:8918a71cdbe9 | 497 | //The read operation has failed |
Sergunb | 0:8918a71cdbe9 | 498 | error = ERROR_READ_FAILED; |
Sergunb | 0:8918a71cdbe9 | 499 | } |
Sergunb | 0:8918a71cdbe9 | 500 | } |
Sergunb | 0:8918a71cdbe9 | 501 | else |
Sergunb | 0:8918a71cdbe9 | 502 | { |
Sergunb | 0:8918a71cdbe9 | 503 | //Report an error |
Sergunb | 0:8918a71cdbe9 | 504 | error = ERROR_RECORD_OVERFLOW; |
Sergunb | 0:8918a71cdbe9 | 505 | } |
Sergunb | 0:8918a71cdbe9 | 506 | } |
Sergunb | 0:8918a71cdbe9 | 507 | else |
Sergunb | 0:8918a71cdbe9 | 508 | { |
Sergunb | 0:8918a71cdbe9 | 509 | //Check current state |
Sergunb | 0:8918a71cdbe9 | 510 | if(context->state > TLS_STATE_SERVER_HELLO) |
Sergunb | 0:8918a71cdbe9 | 511 | { |
Sergunb | 0:8918a71cdbe9 | 512 | //Once the server has sent the ServerHello message, enforce |
Sergunb | 0:8918a71cdbe9 | 513 | //incoming record versions |
Sergunb | 0:8918a71cdbe9 | 514 | if(ntohs(record->version) != context->version) |
Sergunb | 0:8918a71cdbe9 | 515 | error = ERROR_VERSION_NOT_SUPPORTED; |
Sergunb | 0:8918a71cdbe9 | 516 | } |
Sergunb | 0:8918a71cdbe9 | 517 | |
Sergunb | 0:8918a71cdbe9 | 518 | //Check status code |
Sergunb | 0:8918a71cdbe9 | 519 | if(!error) |
Sergunb | 0:8918a71cdbe9 | 520 | { |
Sergunb | 0:8918a71cdbe9 | 521 | //Record payload is protected? |
Sergunb | 0:8918a71cdbe9 | 522 | if(context->changeCipherSpecReceived) |
Sergunb | 0:8918a71cdbe9 | 523 | { |
Sergunb | 0:8918a71cdbe9 | 524 | //Decrypt TLS record |
Sergunb | 0:8918a71cdbe9 | 525 | error = tlsDecryptRecord(context, record); |
Sergunb | 0:8918a71cdbe9 | 526 | } |
Sergunb | 0:8918a71cdbe9 | 527 | } |
Sergunb | 0:8918a71cdbe9 | 528 | |
Sergunb | 0:8918a71cdbe9 | 529 | //Check status code |
Sergunb | 0:8918a71cdbe9 | 530 | if(!error) |
Sergunb | 0:8918a71cdbe9 | 531 | { |
Sergunb | 0:8918a71cdbe9 | 532 | //Actual length of the record data |
Sergunb | 0:8918a71cdbe9 | 533 | *length = ntohs(record->length); |
Sergunb | 0:8918a71cdbe9 | 534 | //Record type |
Sergunb | 0:8918a71cdbe9 | 535 | *contentType = (TlsContentType) record->type; |
Sergunb | 0:8918a71cdbe9 | 536 | |
Sergunb | 0:8918a71cdbe9 | 537 | //Debug message |
Sergunb | 0:8918a71cdbe9 | 538 | TRACE_DEBUG("TLS record received (%" PRIuSIZE " bytes)...\r\n", *length); |
Sergunb | 0:8918a71cdbe9 | 539 | TRACE_DEBUG_ARRAY(" ", record, *length + sizeof(TlsRecord)); |
Sergunb | 0:8918a71cdbe9 | 540 | |
Sergunb | 0:8918a71cdbe9 | 541 | //Discard record header |
Sergunb | 0:8918a71cdbe9 | 542 | memmove(data, record->data, *length); |
Sergunb | 0:8918a71cdbe9 | 543 | |
Sergunb | 0:8918a71cdbe9 | 544 | //Prepare to receive the next TLS record |
Sergunb | 0:8918a71cdbe9 | 545 | context->rxRecordLen = 0; |
Sergunb | 0:8918a71cdbe9 | 546 | context->rxRecordPos = 0; |
Sergunb | 0:8918a71cdbe9 | 547 | |
Sergunb | 0:8918a71cdbe9 | 548 | //We are done |
Sergunb | 0:8918a71cdbe9 | 549 | break; |
Sergunb | 0:8918a71cdbe9 | 550 | } |
Sergunb | 0:8918a71cdbe9 | 551 | } |
Sergunb | 0:8918a71cdbe9 | 552 | } |
Sergunb | 0:8918a71cdbe9 | 553 | |
Sergunb | 0:8918a71cdbe9 | 554 | //Return status code |
Sergunb | 0:8918a71cdbe9 | 555 | return error; |
Sergunb | 0:8918a71cdbe9 | 556 | } |
Sergunb | 0:8918a71cdbe9 | 557 | |
Sergunb | 0:8918a71cdbe9 | 558 | |
Sergunb | 0:8918a71cdbe9 | 559 | /** |
Sergunb | 0:8918a71cdbe9 | 560 | * @brief Encrypt an outgoing TLS record |
Sergunb | 0:8918a71cdbe9 | 561 | * @param[in] context Pointer to the TLS context |
Sergunb | 0:8918a71cdbe9 | 562 | * @param[in,out] record TLS record to be encrypted |
Sergunb | 0:8918a71cdbe9 | 563 | * @return Error code |
Sergunb | 0:8918a71cdbe9 | 564 | **/ |
Sergunb | 0:8918a71cdbe9 | 565 | |
Sergunb | 0:8918a71cdbe9 | 566 | error_t tlsEncryptRecord(TlsContext *context, TlsRecord *record) |
Sergunb | 0:8918a71cdbe9 | 567 | { |
Sergunb | 0:8918a71cdbe9 | 568 | error_t error; |
Sergunb | 0:8918a71cdbe9 | 569 | size_t length; |
Sergunb | 0:8918a71cdbe9 | 570 | |
Sergunb | 0:8918a71cdbe9 | 571 | //Convert the length field to host byte order |
Sergunb | 0:8918a71cdbe9 | 572 | length = ntohs(record->length); |
Sergunb | 0:8918a71cdbe9 | 573 | |
Sergunb | 0:8918a71cdbe9 | 574 | //Message authentication is required? |
Sergunb | 0:8918a71cdbe9 | 575 | if(context->hashAlgo != NULL) |
Sergunb | 0:8918a71cdbe9 | 576 | { |
Sergunb | 0:8918a71cdbe9 | 577 | #if (TLS_MAX_VERSION >= SSL_VERSION_3_0 && TLS_MIN_VERSION <= SSL_VERSION_3_0) |
Sergunb | 0:8918a71cdbe9 | 578 | //Check whether SSL 3.0 is currently used |
Sergunb | 0:8918a71cdbe9 | 579 | if(context->version == SSL_VERSION_3_0) |
Sergunb | 0:8918a71cdbe9 | 580 | { |
Sergunb | 0:8918a71cdbe9 | 581 | //SSL 3.0 uses an older obsolete version of the HMAC construction |
Sergunb | 0:8918a71cdbe9 | 582 | error = sslComputeMac(context, context->writeMacKey, |
Sergunb | 0:8918a71cdbe9 | 583 | context->writeSeqNum, record, record->data, length, record->data + length); |
Sergunb | 0:8918a71cdbe9 | 584 | //Any error to report? |
Sergunb | 0:8918a71cdbe9 | 585 | if(error) |
Sergunb | 0:8918a71cdbe9 | 586 | return error; |
Sergunb | 0:8918a71cdbe9 | 587 | } |
Sergunb | 0:8918a71cdbe9 | 588 | else |
Sergunb | 0:8918a71cdbe9 | 589 | #endif |
Sergunb | 0:8918a71cdbe9 | 590 | #if (TLS_MAX_VERSION >= TLS_VERSION_1_0 && TLS_MIN_VERSION <= TLS_VERSION_1_2) |
Sergunb | 0:8918a71cdbe9 | 591 | //Check whether TLS 1.0, TLS 1.1 or TLS 1.2 is currently used |
Sergunb | 0:8918a71cdbe9 | 592 | if(context->version >= TLS_VERSION_1_0) |
Sergunb | 0:8918a71cdbe9 | 593 | { |
Sergunb | 0:8918a71cdbe9 | 594 | //TLS uses a HMAC construction |
Sergunb | 0:8918a71cdbe9 | 595 | hmacInit(&context->hmacContext, context->hashAlgo, |
Sergunb | 0:8918a71cdbe9 | 596 | context->writeMacKey, context->macKeyLen); |
Sergunb | 0:8918a71cdbe9 | 597 | |
Sergunb | 0:8918a71cdbe9 | 598 | //Compute MAC over the sequence number and the record contents |
Sergunb | 0:8918a71cdbe9 | 599 | hmacUpdate(&context->hmacContext, context->writeSeqNum, sizeof(TlsSequenceNumber)); |
Sergunb | 0:8918a71cdbe9 | 600 | hmacUpdate(&context->hmacContext, record, length + sizeof(TlsRecord)); |
Sergunb | 0:8918a71cdbe9 | 601 | |
Sergunb | 0:8918a71cdbe9 | 602 | //Append the resulting MAC to the message |
Sergunb | 0:8918a71cdbe9 | 603 | hmacFinal(&context->hmacContext, record->data + length); |
Sergunb | 0:8918a71cdbe9 | 604 | } |
Sergunb | 0:8918a71cdbe9 | 605 | else |
Sergunb | 0:8918a71cdbe9 | 606 | #endif |
Sergunb | 0:8918a71cdbe9 | 607 | //The negotiated TLS version is not valid... |
Sergunb | 0:8918a71cdbe9 | 608 | { |
Sergunb | 0:8918a71cdbe9 | 609 | //Report an error |
Sergunb | 0:8918a71cdbe9 | 610 | return ERROR_INVALID_VERSION; |
Sergunb | 0:8918a71cdbe9 | 611 | } |
Sergunb | 0:8918a71cdbe9 | 612 | |
Sergunb | 0:8918a71cdbe9 | 613 | //Debug message |
Sergunb | 0:8918a71cdbe9 | 614 | TRACE_DEBUG("Write sequence number:\r\n"); |
Sergunb | 0:8918a71cdbe9 | 615 | TRACE_DEBUG_ARRAY(" ", context->writeSeqNum, sizeof(TlsSequenceNumber)); |
Sergunb | 0:8918a71cdbe9 | 616 | TRACE_DEBUG("Computed MAC:\r\n"); |
Sergunb | 0:8918a71cdbe9 | 617 | TRACE_DEBUG_ARRAY(" ", record->data + length, context->hashAlgo->digestSize); |
Sergunb | 0:8918a71cdbe9 | 618 | |
Sergunb | 0:8918a71cdbe9 | 619 | //Adjust the length of the message |
Sergunb | 0:8918a71cdbe9 | 620 | length += context->hashAlgo->digestSize; |
Sergunb | 0:8918a71cdbe9 | 621 | //Fix length field |
Sergunb | 0:8918a71cdbe9 | 622 | record->length = htons(length); |
Sergunb | 0:8918a71cdbe9 | 623 | |
Sergunb | 0:8918a71cdbe9 | 624 | //Increment sequence number |
Sergunb | 0:8918a71cdbe9 | 625 | tlsIncSequenceNumber(context->writeSeqNum); |
Sergunb | 0:8918a71cdbe9 | 626 | } |
Sergunb | 0:8918a71cdbe9 | 627 | |
Sergunb | 0:8918a71cdbe9 | 628 | //Encryption is required? |
Sergunb | 0:8918a71cdbe9 | 629 | if(context->cipherMode != CIPHER_MODE_NULL) |
Sergunb | 0:8918a71cdbe9 | 630 | { |
Sergunb | 0:8918a71cdbe9 | 631 | //Debug message |
Sergunb | 0:8918a71cdbe9 | 632 | TRACE_DEBUG("Record to be encrypted (%" PRIuSIZE " bytes):\r\n", length); |
Sergunb | 0:8918a71cdbe9 | 633 | TRACE_DEBUG_ARRAY(" ", record, length + sizeof(TlsRecord)); |
Sergunb | 0:8918a71cdbe9 | 634 | |
Sergunb | 0:8918a71cdbe9 | 635 | #if (TLS_STREAM_CIPHER_SUPPORT == ENABLED) |
Sergunb | 0:8918a71cdbe9 | 636 | //Stream cipher? |
Sergunb | 0:8918a71cdbe9 | 637 | if(context->cipherMode == CIPHER_MODE_STREAM) |
Sergunb | 0:8918a71cdbe9 | 638 | { |
Sergunb | 0:8918a71cdbe9 | 639 | //Encrypt record contents |
Sergunb | 0:8918a71cdbe9 | 640 | context->cipherAlgo->encryptStream(context->writeCipherContext, |
Sergunb | 0:8918a71cdbe9 | 641 | record->data, record->data, length); |
Sergunb | 0:8918a71cdbe9 | 642 | } |
Sergunb | 0:8918a71cdbe9 | 643 | else |
Sergunb | 0:8918a71cdbe9 | 644 | #endif |
Sergunb | 0:8918a71cdbe9 | 645 | #if (TLS_CBC_CIPHER_SUPPORT == ENABLED) |
Sergunb | 0:8918a71cdbe9 | 646 | //CBC block cipher? |
Sergunb | 0:8918a71cdbe9 | 647 | if(context->cipherMode == CIPHER_MODE_CBC) |
Sergunb | 0:8918a71cdbe9 | 648 | { |
Sergunb | 0:8918a71cdbe9 | 649 | size_t i; |
Sergunb | 0:8918a71cdbe9 | 650 | size_t paddingLength; |
Sergunb | 0:8918a71cdbe9 | 651 | |
Sergunb | 0:8918a71cdbe9 | 652 | #if (TLS_MAX_VERSION >= TLS_VERSION_1_1 && TLS_MIN_VERSION <= TLS_VERSION_1_2) |
Sergunb | 0:8918a71cdbe9 | 653 | //TLS 1.1 and 1.2 use an explicit IV |
Sergunb | 0:8918a71cdbe9 | 654 | if(context->version >= TLS_VERSION_1_1) |
Sergunb | 0:8918a71cdbe9 | 655 | { |
Sergunb | 0:8918a71cdbe9 | 656 | //Make room for the IV at the beginning of the data |
Sergunb | 0:8918a71cdbe9 | 657 | memmove(record->data + context->recordIvLen, record->data, length); |
Sergunb | 0:8918a71cdbe9 | 658 | |
Sergunb | 0:8918a71cdbe9 | 659 | //The initialization vector should be chosen at random |
Sergunb | 0:8918a71cdbe9 | 660 | error = context->prngAlgo->read(context->prngContext, |
Sergunb | 0:8918a71cdbe9 | 661 | record->data, context->recordIvLen); |
Sergunb | 0:8918a71cdbe9 | 662 | //Any error to report? |
Sergunb | 0:8918a71cdbe9 | 663 | if(error) |
Sergunb | 0:8918a71cdbe9 | 664 | return error; |
Sergunb | 0:8918a71cdbe9 | 665 | |
Sergunb | 0:8918a71cdbe9 | 666 | //Adjust the length of the message |
Sergunb | 0:8918a71cdbe9 | 667 | length += context->recordIvLen; |
Sergunb | 0:8918a71cdbe9 | 668 | } |
Sergunb | 0:8918a71cdbe9 | 669 | #endif |
Sergunb | 0:8918a71cdbe9 | 670 | //Get the actual amount of bytes in the last block |
Sergunb | 0:8918a71cdbe9 | 671 | paddingLength = (length + 1) % context->cipherAlgo->blockSize; |
Sergunb | 0:8918a71cdbe9 | 672 | |
Sergunb | 0:8918a71cdbe9 | 673 | //Padding is added to force the length of the plaintext to be |
Sergunb | 0:8918a71cdbe9 | 674 | //an integral multiple of the cipher's block length |
Sergunb | 0:8918a71cdbe9 | 675 | if(paddingLength > 0) |
Sergunb | 0:8918a71cdbe9 | 676 | paddingLength = context->cipherAlgo->blockSize - paddingLength; |
Sergunb | 0:8918a71cdbe9 | 677 | |
Sergunb | 0:8918a71cdbe9 | 678 | //Write padding bytes |
Sergunb | 0:8918a71cdbe9 | 679 | for(i = 0; i <= paddingLength; i++) |
Sergunb | 0:8918a71cdbe9 | 680 | record->data[length + i] = (uint8_t) paddingLength; |
Sergunb | 0:8918a71cdbe9 | 681 | |
Sergunb | 0:8918a71cdbe9 | 682 | //Compute the length of the resulting message |
Sergunb | 0:8918a71cdbe9 | 683 | length += paddingLength + 1; |
Sergunb | 0:8918a71cdbe9 | 684 | //Fix length field |
Sergunb | 0:8918a71cdbe9 | 685 | record->length = htons(length); |
Sergunb | 0:8918a71cdbe9 | 686 | |
Sergunb | 0:8918a71cdbe9 | 687 | //Debug message |
Sergunb | 0:8918a71cdbe9 | 688 | TRACE_DEBUG("Record with padding (%" PRIuSIZE " bytes):\r\n", length); |
Sergunb | 0:8918a71cdbe9 | 689 | TRACE_DEBUG_ARRAY(" ", record, length + sizeof(TlsRecord)); |
Sergunb | 0:8918a71cdbe9 | 690 | |
Sergunb | 0:8918a71cdbe9 | 691 | //CBC encryption |
Sergunb | 0:8918a71cdbe9 | 692 | error = cbcEncrypt(context->cipherAlgo, context->writeCipherContext, |
Sergunb | 0:8918a71cdbe9 | 693 | context->writeIv, record->data, record->data, length); |
Sergunb | 0:8918a71cdbe9 | 694 | //Any error to report? |
Sergunb | 0:8918a71cdbe9 | 695 | if(error) |
Sergunb | 0:8918a71cdbe9 | 696 | return error; |
Sergunb | 0:8918a71cdbe9 | 697 | } |
Sergunb | 0:8918a71cdbe9 | 698 | else |
Sergunb | 0:8918a71cdbe9 | 699 | #endif |
Sergunb | 0:8918a71cdbe9 | 700 | #if (TLS_CCM_CIPHER_SUPPORT == ENABLED || TLS_CCM_8_CIPHER_SUPPORT == ENABLED || \ |
Sergunb | 0:8918a71cdbe9 | 701 | TLS_GCM_CIPHER_SUPPORT == ENABLED) |
Sergunb | 0:8918a71cdbe9 | 702 | //CCM or GCM AEAD cipher? |
Sergunb | 0:8918a71cdbe9 | 703 | if(context->cipherMode == CIPHER_MODE_CCM || |
Sergunb | 0:8918a71cdbe9 | 704 | context->cipherMode == CIPHER_MODE_GCM) |
Sergunb | 0:8918a71cdbe9 | 705 | { |
Sergunb | 0:8918a71cdbe9 | 706 | uint8_t *data; |
Sergunb | 0:8918a71cdbe9 | 707 | uint8_t *tag; |
Sergunb | 0:8918a71cdbe9 | 708 | size_t nonceLength; |
Sergunb | 0:8918a71cdbe9 | 709 | uint8_t nonce[12]; |
Sergunb | 0:8918a71cdbe9 | 710 | uint8_t a[13]; |
Sergunb | 0:8918a71cdbe9 | 711 | |
Sergunb | 0:8918a71cdbe9 | 712 | //Determine the total length of the nonce |
Sergunb | 0:8918a71cdbe9 | 713 | nonceLength = context->fixedIvLen + context->recordIvLen; |
Sergunb | 0:8918a71cdbe9 | 714 | //The salt is the implicit part of the nonce and is not sent in the packet |
Sergunb | 0:8918a71cdbe9 | 715 | memcpy(nonce, context->writeIv, context->fixedIvLen); |
Sergunb | 0:8918a71cdbe9 | 716 | |
Sergunb | 0:8918a71cdbe9 | 717 | //The explicit part of the nonce is chosen by the sender |
Sergunb | 0:8918a71cdbe9 | 718 | error = context->prngAlgo->read(context->prngContext, |
Sergunb | 0:8918a71cdbe9 | 719 | nonce + context->fixedIvLen, context->recordIvLen); |
Sergunb | 0:8918a71cdbe9 | 720 | //Any error to report? |
Sergunb | 0:8918a71cdbe9 | 721 | if(error) |
Sergunb | 0:8918a71cdbe9 | 722 | return error; |
Sergunb | 0:8918a71cdbe9 | 723 | |
Sergunb | 0:8918a71cdbe9 | 724 | //Make room for the explicit nonce at the beginning of the record |
Sergunb | 0:8918a71cdbe9 | 725 | memmove(record->data + context->recordIvLen, record->data, length); |
Sergunb | 0:8918a71cdbe9 | 726 | //The explicit part of the nonce is carried in each TLS record |
Sergunb | 0:8918a71cdbe9 | 727 | memcpy(record->data, nonce + context->fixedIvLen, context->recordIvLen); |
Sergunb | 0:8918a71cdbe9 | 728 | |
Sergunb | 0:8918a71cdbe9 | 729 | //Additional data to be authenticated |
Sergunb | 0:8918a71cdbe9 | 730 | memcpy(a, context->writeSeqNum, sizeof(TlsSequenceNumber)); |
Sergunb | 0:8918a71cdbe9 | 731 | memcpy(a + sizeof(TlsSequenceNumber), record, sizeof(TlsRecord)); |
Sergunb | 0:8918a71cdbe9 | 732 | |
Sergunb | 0:8918a71cdbe9 | 733 | //Point to the plaintext |
Sergunb | 0:8918a71cdbe9 | 734 | data = record->data + context->recordIvLen; |
Sergunb | 0:8918a71cdbe9 | 735 | //Point to the buffer where to store the authentication tag |
Sergunb | 0:8918a71cdbe9 | 736 | tag = data + length; |
Sergunb | 0:8918a71cdbe9 | 737 | |
Sergunb | 0:8918a71cdbe9 | 738 | #if (TLS_CCM_CIPHER_SUPPORT == ENABLED || TLS_CCM_8_CIPHER_SUPPORT == ENABLED) |
Sergunb | 0:8918a71cdbe9 | 739 | //CCM AEAD cipher? |
Sergunb | 0:8918a71cdbe9 | 740 | if(context->cipherMode == CIPHER_MODE_CCM) |
Sergunb | 0:8918a71cdbe9 | 741 | { |
Sergunb | 0:8918a71cdbe9 | 742 | //Authenticated encryption using CCM |
Sergunb | 0:8918a71cdbe9 | 743 | error = ccmEncrypt(context->cipherAlgo, context->writeCipherContext, |
Sergunb | 0:8918a71cdbe9 | 744 | nonce, nonceLength, a, 13, data, data, length, tag, context->authTagLen); |
Sergunb | 0:8918a71cdbe9 | 745 | } |
Sergunb | 0:8918a71cdbe9 | 746 | else |
Sergunb | 0:8918a71cdbe9 | 747 | #endif |
Sergunb | 0:8918a71cdbe9 | 748 | #if (TLS_GCM_CIPHER_SUPPORT == ENABLED) |
Sergunb | 0:8918a71cdbe9 | 749 | //GCM AEAD cipher? |
Sergunb | 0:8918a71cdbe9 | 750 | if(context->cipherMode == CIPHER_MODE_GCM) |
Sergunb | 0:8918a71cdbe9 | 751 | { |
Sergunb | 0:8918a71cdbe9 | 752 | //Authenticated encryption using GCM |
Sergunb | 0:8918a71cdbe9 | 753 | error = gcmEncrypt(context->writeGcmContext, nonce, nonceLength, |
Sergunb | 0:8918a71cdbe9 | 754 | a, 13, data, data, length, tag, context->authTagLen); |
Sergunb | 0:8918a71cdbe9 | 755 | } |
Sergunb | 0:8918a71cdbe9 | 756 | else |
Sergunb | 0:8918a71cdbe9 | 757 | #endif |
Sergunb | 0:8918a71cdbe9 | 758 | //Invalid cipher mode? |
Sergunb | 0:8918a71cdbe9 | 759 | { |
Sergunb | 0:8918a71cdbe9 | 760 | //The specified cipher mode is not supported |
Sergunb | 0:8918a71cdbe9 | 761 | error = ERROR_UNSUPPORTED_CIPHER_MODE; |
Sergunb | 0:8918a71cdbe9 | 762 | } |
Sergunb | 0:8918a71cdbe9 | 763 | |
Sergunb | 0:8918a71cdbe9 | 764 | //Failed to encrypt data? |
Sergunb | 0:8918a71cdbe9 | 765 | if(error) |
Sergunb | 0:8918a71cdbe9 | 766 | return error; |
Sergunb | 0:8918a71cdbe9 | 767 | |
Sergunb | 0:8918a71cdbe9 | 768 | //Compute the length of the resulting message |
Sergunb | 0:8918a71cdbe9 | 769 | length += context->recordIvLen + context->authTagLen; |
Sergunb | 0:8918a71cdbe9 | 770 | //Fix length field |
Sergunb | 0:8918a71cdbe9 | 771 | record->length = htons(length); |
Sergunb | 0:8918a71cdbe9 | 772 | |
Sergunb | 0:8918a71cdbe9 | 773 | //Increment sequence number |
Sergunb | 0:8918a71cdbe9 | 774 | tlsIncSequenceNumber(context->writeSeqNum); |
Sergunb | 0:8918a71cdbe9 | 775 | } |
Sergunb | 0:8918a71cdbe9 | 776 | else |
Sergunb | 0:8918a71cdbe9 | 777 | #endif |
Sergunb | 0:8918a71cdbe9 | 778 | #if (TLS_CHACHA20_POLY1305_SUPPORT == ENABLED) |
Sergunb | 0:8918a71cdbe9 | 779 | //ChaCha20Poly1305 AEAD cipher? |
Sergunb | 0:8918a71cdbe9 | 780 | if(context->cipherMode == CIPHER_MODE_CHACHA20_POLY1305) |
Sergunb | 0:8918a71cdbe9 | 781 | { |
Sergunb | 0:8918a71cdbe9 | 782 | size_t i; |
Sergunb | 0:8918a71cdbe9 | 783 | uint8_t *tag; |
Sergunb | 0:8918a71cdbe9 | 784 | uint8_t nonce[12]; |
Sergunb | 0:8918a71cdbe9 | 785 | uint8_t a[13]; |
Sergunb | 0:8918a71cdbe9 | 786 | |
Sergunb | 0:8918a71cdbe9 | 787 | //The 64-bit record sequence number is serialized as an 8-byte, |
Sergunb | 0:8918a71cdbe9 | 788 | //big-endian value and padded on the left with four 0x00 bytes |
Sergunb | 0:8918a71cdbe9 | 789 | memcpy(nonce + 4, context->writeSeqNum, 8); |
Sergunb | 0:8918a71cdbe9 | 790 | memset(nonce, 0, 4); |
Sergunb | 0:8918a71cdbe9 | 791 | |
Sergunb | 0:8918a71cdbe9 | 792 | //The padded sequence number is XORed with the write IV to form |
Sergunb | 0:8918a71cdbe9 | 793 | //the 96-bit nonce |
Sergunb | 0:8918a71cdbe9 | 794 | for(i = 0; i < context->fixedIvLen; i++) |
Sergunb | 0:8918a71cdbe9 | 795 | nonce[i] ^= context->writeIv[i]; |
Sergunb | 0:8918a71cdbe9 | 796 | |
Sergunb | 0:8918a71cdbe9 | 797 | //Additional data to be authenticated |
Sergunb | 0:8918a71cdbe9 | 798 | memcpy(a, context->writeSeqNum, sizeof(TlsSequenceNumber)); |
Sergunb | 0:8918a71cdbe9 | 799 | memcpy(a + sizeof(TlsSequenceNumber), record, sizeof(TlsRecord)); |
Sergunb | 0:8918a71cdbe9 | 800 | |
Sergunb | 0:8918a71cdbe9 | 801 | //Point to the buffer where to store the authentication tag |
Sergunb | 0:8918a71cdbe9 | 802 | tag = record->data + length; |
Sergunb | 0:8918a71cdbe9 | 803 | |
Sergunb | 0:8918a71cdbe9 | 804 | //Authenticated encryption using ChaCha20Poly1305 |
Sergunb | 0:8918a71cdbe9 | 805 | error = chacha20Poly1305Encrypt(context->writeEncKey, context->encKeyLen, |
Sergunb | 0:8918a71cdbe9 | 806 | nonce, 12, a, 13, record->data, record->data, length, tag, context->authTagLen); |
Sergunb | 0:8918a71cdbe9 | 807 | //Failed to encrypt data? |
Sergunb | 0:8918a71cdbe9 | 808 | if(error) |
Sergunb | 0:8918a71cdbe9 | 809 | return error; |
Sergunb | 0:8918a71cdbe9 | 810 | |
Sergunb | 0:8918a71cdbe9 | 811 | //Compute the length of the resulting message |
Sergunb | 0:8918a71cdbe9 | 812 | length += context->authTagLen; |
Sergunb | 0:8918a71cdbe9 | 813 | //Fix length field |
Sergunb | 0:8918a71cdbe9 | 814 | record->length = htons(length); |
Sergunb | 0:8918a71cdbe9 | 815 | |
Sergunb | 0:8918a71cdbe9 | 816 | //Increment sequence number |
Sergunb | 0:8918a71cdbe9 | 817 | tlsIncSequenceNumber(context->writeSeqNum); |
Sergunb | 0:8918a71cdbe9 | 818 | } |
Sergunb | 0:8918a71cdbe9 | 819 | else |
Sergunb | 0:8918a71cdbe9 | 820 | #endif |
Sergunb | 0:8918a71cdbe9 | 821 | //Invalid cipher mode? |
Sergunb | 0:8918a71cdbe9 | 822 | { |
Sergunb | 0:8918a71cdbe9 | 823 | //The specified cipher mode is not supported |
Sergunb | 0:8918a71cdbe9 | 824 | return ERROR_UNSUPPORTED_CIPHER_MODE; |
Sergunb | 0:8918a71cdbe9 | 825 | } |
Sergunb | 0:8918a71cdbe9 | 826 | |
Sergunb | 0:8918a71cdbe9 | 827 | //Debug message |
Sergunb | 0:8918a71cdbe9 | 828 | TRACE_DEBUG("Encrypted record (%" PRIuSIZE " bytes):\r\n", length); |
Sergunb | 0:8918a71cdbe9 | 829 | TRACE_DEBUG_ARRAY(" ", record, length + sizeof(TlsRecord)); |
Sergunb | 0:8918a71cdbe9 | 830 | } |
Sergunb | 0:8918a71cdbe9 | 831 | |
Sergunb | 0:8918a71cdbe9 | 832 | //Successful encryption |
Sergunb | 0:8918a71cdbe9 | 833 | return NO_ERROR; |
Sergunb | 0:8918a71cdbe9 | 834 | } |
Sergunb | 0:8918a71cdbe9 | 835 | |
Sergunb | 0:8918a71cdbe9 | 836 | |
Sergunb | 0:8918a71cdbe9 | 837 | /** |
Sergunb | 0:8918a71cdbe9 | 838 | * @brief Decrypt an incoming TLS record |
Sergunb | 0:8918a71cdbe9 | 839 | * @param[in] context Pointer to the TLS context |
Sergunb | 0:8918a71cdbe9 | 840 | * @param[in,out] record TLS record to be decrypted |
Sergunb | 0:8918a71cdbe9 | 841 | * @return Error code |
Sergunb | 0:8918a71cdbe9 | 842 | **/ |
Sergunb | 0:8918a71cdbe9 | 843 | |
Sergunb | 0:8918a71cdbe9 | 844 | error_t tlsDecryptRecord(TlsContext *context, TlsRecord *record) |
Sergunb | 0:8918a71cdbe9 | 845 | { |
Sergunb | 0:8918a71cdbe9 | 846 | error_t error; |
Sergunb | 0:8918a71cdbe9 | 847 | size_t length; |
Sergunb | 0:8918a71cdbe9 | 848 | |
Sergunb | 0:8918a71cdbe9 | 849 | //Convert the length field to host byte order |
Sergunb | 0:8918a71cdbe9 | 850 | length = ntohs(record->length); |
Sergunb | 0:8918a71cdbe9 | 851 | |
Sergunb | 0:8918a71cdbe9 | 852 | //Decrypt record if necessary |
Sergunb | 0:8918a71cdbe9 | 853 | if(context->cipherMode != CIPHER_MODE_NULL) |
Sergunb | 0:8918a71cdbe9 | 854 | { |
Sergunb | 0:8918a71cdbe9 | 855 | //Debug message |
Sergunb | 0:8918a71cdbe9 | 856 | TRACE_DEBUG("Record to be decrypted (%" PRIuSIZE " bytes):\r\n", length); |
Sergunb | 0:8918a71cdbe9 | 857 | TRACE_DEBUG_ARRAY(" ", record, length + sizeof(TlsRecord)); |
Sergunb | 0:8918a71cdbe9 | 858 | |
Sergunb | 0:8918a71cdbe9 | 859 | #if (TLS_STREAM_CIPHER_SUPPORT == ENABLED) |
Sergunb | 0:8918a71cdbe9 | 860 | //Stream cipher? |
Sergunb | 0:8918a71cdbe9 | 861 | if(context->cipherMode == CIPHER_MODE_STREAM) |
Sergunb | 0:8918a71cdbe9 | 862 | { |
Sergunb | 0:8918a71cdbe9 | 863 | //Decrypt record contents |
Sergunb | 0:8918a71cdbe9 | 864 | context->cipherAlgo->decryptStream(context->readCipherContext, |
Sergunb | 0:8918a71cdbe9 | 865 | record->data, record->data, length); |
Sergunb | 0:8918a71cdbe9 | 866 | } |
Sergunb | 0:8918a71cdbe9 | 867 | else |
Sergunb | 0:8918a71cdbe9 | 868 | #endif |
Sergunb | 0:8918a71cdbe9 | 869 | #if (TLS_CBC_CIPHER_SUPPORT == ENABLED) |
Sergunb | 0:8918a71cdbe9 | 870 | //CBC block cipher? |
Sergunb | 0:8918a71cdbe9 | 871 | if(context->cipherMode == CIPHER_MODE_CBC) |
Sergunb | 0:8918a71cdbe9 | 872 | { |
Sergunb | 0:8918a71cdbe9 | 873 | size_t i; |
Sergunb | 0:8918a71cdbe9 | 874 | size_t paddingLength; |
Sergunb | 0:8918a71cdbe9 | 875 | |
Sergunb | 0:8918a71cdbe9 | 876 | //The length of the data must be a multiple of the block size |
Sergunb | 0:8918a71cdbe9 | 877 | if((length % context->cipherAlgo->blockSize) != 0) |
Sergunb | 0:8918a71cdbe9 | 878 | return ERROR_DECODING_FAILED; |
Sergunb | 0:8918a71cdbe9 | 879 | |
Sergunb | 0:8918a71cdbe9 | 880 | //CBC decryption |
Sergunb | 0:8918a71cdbe9 | 881 | error = cbcDecrypt(context->cipherAlgo, context->readCipherContext, |
Sergunb | 0:8918a71cdbe9 | 882 | context->readIv, record->data, record->data, length); |
Sergunb | 0:8918a71cdbe9 | 883 | //Any error to report? |
Sergunb | 0:8918a71cdbe9 | 884 | if(error) |
Sergunb | 0:8918a71cdbe9 | 885 | return error; |
Sergunb | 0:8918a71cdbe9 | 886 | |
Sergunb | 0:8918a71cdbe9 | 887 | //Debug message |
Sergunb | 0:8918a71cdbe9 | 888 | TRACE_DEBUG("Record with padding (%" PRIuSIZE " bytes):\r\n", length); |
Sergunb | 0:8918a71cdbe9 | 889 | TRACE_DEBUG_ARRAY(" ", record, length + sizeof(TlsRecord)); |
Sergunb | 0:8918a71cdbe9 | 890 | |
Sergunb | 0:8918a71cdbe9 | 891 | #if (TLS_MAX_VERSION >= TLS_VERSION_1_1 && TLS_MIN_VERSION <= TLS_VERSION_1_2) |
Sergunb | 0:8918a71cdbe9 | 892 | //TLS 1.1 and 1.2 use an explicit IV |
Sergunb | 0:8918a71cdbe9 | 893 | if(context->version >= TLS_VERSION_1_1) |
Sergunb | 0:8918a71cdbe9 | 894 | { |
Sergunb | 0:8918a71cdbe9 | 895 | //Make sure the message length is acceptable |
Sergunb | 0:8918a71cdbe9 | 896 | if(length < context->recordIvLen) |
Sergunb | 0:8918a71cdbe9 | 897 | return ERROR_DECODING_FAILED; |
Sergunb | 0:8918a71cdbe9 | 898 | |
Sergunb | 0:8918a71cdbe9 | 899 | //Adjust the length of the message |
Sergunb | 0:8918a71cdbe9 | 900 | length -= context->recordIvLen; |
Sergunb | 0:8918a71cdbe9 | 901 | //Discard the first cipher block (corresponding to the explicit IV) |
Sergunb | 0:8918a71cdbe9 | 902 | memmove(record->data, record->data + context->recordIvLen, length); |
Sergunb | 0:8918a71cdbe9 | 903 | } |
Sergunb | 0:8918a71cdbe9 | 904 | #endif |
Sergunb | 0:8918a71cdbe9 | 905 | //Make sure the message length is acceptable |
Sergunb | 0:8918a71cdbe9 | 906 | if(length < context->cipherAlgo->blockSize) |
Sergunb | 0:8918a71cdbe9 | 907 | return ERROR_DECODING_FAILED; |
Sergunb | 0:8918a71cdbe9 | 908 | |
Sergunb | 0:8918a71cdbe9 | 909 | //Compute the length of the padding string |
Sergunb | 0:8918a71cdbe9 | 910 | paddingLength = record->data[length - 1]; |
Sergunb | 0:8918a71cdbe9 | 911 | //Erroneous padding length? |
Sergunb | 0:8918a71cdbe9 | 912 | if(paddingLength >= length) |
Sergunb | 0:8918a71cdbe9 | 913 | return ERROR_BAD_RECORD_MAC; |
Sergunb | 0:8918a71cdbe9 | 914 | |
Sergunb | 0:8918a71cdbe9 | 915 | //The receiver must check the padding |
Sergunb | 0:8918a71cdbe9 | 916 | for(i = 0; i <= paddingLength; i++) |
Sergunb | 0:8918a71cdbe9 | 917 | { |
Sergunb | 0:8918a71cdbe9 | 918 | //Each byte in the padding data must be filled |
Sergunb | 0:8918a71cdbe9 | 919 | //with the padding length value |
Sergunb | 0:8918a71cdbe9 | 920 | if(record->data[length - 1 - i] != paddingLength) |
Sergunb | 0:8918a71cdbe9 | 921 | return ERROR_BAD_RECORD_MAC; |
Sergunb | 0:8918a71cdbe9 | 922 | } |
Sergunb | 0:8918a71cdbe9 | 923 | |
Sergunb | 0:8918a71cdbe9 | 924 | //Remove padding bytes |
Sergunb | 0:8918a71cdbe9 | 925 | length -= paddingLength + 1; |
Sergunb | 0:8918a71cdbe9 | 926 | //Fix the length field of the TLS record |
Sergunb | 0:8918a71cdbe9 | 927 | record->length = htons(length); |
Sergunb | 0:8918a71cdbe9 | 928 | } |
Sergunb | 0:8918a71cdbe9 | 929 | else |
Sergunb | 0:8918a71cdbe9 | 930 | #endif |
Sergunb | 0:8918a71cdbe9 | 931 | #if (TLS_CCM_CIPHER_SUPPORT == ENABLED || TLS_CCM_8_CIPHER_SUPPORT == ENABLED || \ |
Sergunb | 0:8918a71cdbe9 | 932 | TLS_GCM_CIPHER_SUPPORT == ENABLED) |
Sergunb | 0:8918a71cdbe9 | 933 | //CCM or GCM AEAD cipher? |
Sergunb | 0:8918a71cdbe9 | 934 | if(context->cipherMode == CIPHER_MODE_CCM || |
Sergunb | 0:8918a71cdbe9 | 935 | context->cipherMode == CIPHER_MODE_GCM) |
Sergunb | 0:8918a71cdbe9 | 936 | { |
Sergunb | 0:8918a71cdbe9 | 937 | uint8_t *ciphertext; |
Sergunb | 0:8918a71cdbe9 | 938 | uint8_t *tag; |
Sergunb | 0:8918a71cdbe9 | 939 | size_t nonceLength; |
Sergunb | 0:8918a71cdbe9 | 940 | uint8_t nonce[12]; |
Sergunb | 0:8918a71cdbe9 | 941 | uint8_t a[13]; |
Sergunb | 0:8918a71cdbe9 | 942 | |
Sergunb | 0:8918a71cdbe9 | 943 | //Make sure the message length is acceptable |
Sergunb | 0:8918a71cdbe9 | 944 | if(length < (context->recordIvLen + context->authTagLen)) |
Sergunb | 0:8918a71cdbe9 | 945 | return ERROR_DECODING_FAILED; |
Sergunb | 0:8918a71cdbe9 | 946 | |
Sergunb | 0:8918a71cdbe9 | 947 | //Determine the total length of the nonce |
Sergunb | 0:8918a71cdbe9 | 948 | nonceLength = context->fixedIvLen + context->recordIvLen; |
Sergunb | 0:8918a71cdbe9 | 949 | //The salt is the implicit part of the nonce and is not sent in the packet |
Sergunb | 0:8918a71cdbe9 | 950 | memcpy(nonce, context->readIv, context->fixedIvLen); |
Sergunb | 0:8918a71cdbe9 | 951 | //The explicit part of the nonce is chosen by the sender |
Sergunb | 0:8918a71cdbe9 | 952 | memcpy(nonce + context->fixedIvLen, record->data, context->recordIvLen); |
Sergunb | 0:8918a71cdbe9 | 953 | |
Sergunb | 0:8918a71cdbe9 | 954 | //Calculate the length of the ciphertext |
Sergunb | 0:8918a71cdbe9 | 955 | length -= context->recordIvLen + context->authTagLen; |
Sergunb | 0:8918a71cdbe9 | 956 | //Fix the length field of the TLS record |
Sergunb | 0:8918a71cdbe9 | 957 | record->length = htons(length); |
Sergunb | 0:8918a71cdbe9 | 958 | |
Sergunb | 0:8918a71cdbe9 | 959 | //Additional data to be authenticated |
Sergunb | 0:8918a71cdbe9 | 960 | memcpy(a, context->readSeqNum, sizeof(TlsSequenceNumber)); |
Sergunb | 0:8918a71cdbe9 | 961 | memcpy(a + sizeof(TlsSequenceNumber), record, sizeof(TlsRecord)); |
Sergunb | 0:8918a71cdbe9 | 962 | |
Sergunb | 0:8918a71cdbe9 | 963 | //Point to the ciphertext |
Sergunb | 0:8918a71cdbe9 | 964 | ciphertext = record->data + context->recordIvLen; |
Sergunb | 0:8918a71cdbe9 | 965 | //Point to the authentication tag |
Sergunb | 0:8918a71cdbe9 | 966 | tag = ciphertext + length; |
Sergunb | 0:8918a71cdbe9 | 967 | |
Sergunb | 0:8918a71cdbe9 | 968 | #if (TLS_CCM_CIPHER_SUPPORT == ENABLED || TLS_CCM_8_CIPHER_SUPPORT == ENABLED) |
Sergunb | 0:8918a71cdbe9 | 969 | //CCM AEAD cipher? |
Sergunb | 0:8918a71cdbe9 | 970 | if(context->cipherMode == CIPHER_MODE_CCM) |
Sergunb | 0:8918a71cdbe9 | 971 | { |
Sergunb | 0:8918a71cdbe9 | 972 | //Authenticated decryption using CCM |
Sergunb | 0:8918a71cdbe9 | 973 | error = ccmDecrypt(context->cipherAlgo, context->readCipherContext, |
Sergunb | 0:8918a71cdbe9 | 974 | nonce, nonceLength, a, 13, ciphertext, ciphertext, length, tag, context->authTagLen); |
Sergunb | 0:8918a71cdbe9 | 975 | } |
Sergunb | 0:8918a71cdbe9 | 976 | else |
Sergunb | 0:8918a71cdbe9 | 977 | #endif |
Sergunb | 0:8918a71cdbe9 | 978 | #if (TLS_GCM_CIPHER_SUPPORT == ENABLED) |
Sergunb | 0:8918a71cdbe9 | 979 | //GCM AEAD cipher? |
Sergunb | 0:8918a71cdbe9 | 980 | if(context->cipherMode == CIPHER_MODE_GCM) |
Sergunb | 0:8918a71cdbe9 | 981 | { |
Sergunb | 0:8918a71cdbe9 | 982 | //Authenticated decryption using GCM |
Sergunb | 0:8918a71cdbe9 | 983 | error = gcmDecrypt(context->readGcmContext, nonce, nonceLength, |
Sergunb | 0:8918a71cdbe9 | 984 | a, 13, ciphertext, ciphertext, length, tag, context->authTagLen); |
Sergunb | 0:8918a71cdbe9 | 985 | } |
Sergunb | 0:8918a71cdbe9 | 986 | else |
Sergunb | 0:8918a71cdbe9 | 987 | #endif |
Sergunb | 0:8918a71cdbe9 | 988 | //Invalid cipher mode? |
Sergunb | 0:8918a71cdbe9 | 989 | { |
Sergunb | 0:8918a71cdbe9 | 990 | //The specified cipher mode is not supported |
Sergunb | 0:8918a71cdbe9 | 991 | error = ERROR_UNSUPPORTED_CIPHER_MODE; |
Sergunb | 0:8918a71cdbe9 | 992 | } |
Sergunb | 0:8918a71cdbe9 | 993 | |
Sergunb | 0:8918a71cdbe9 | 994 | //Wrong authentication tag? |
Sergunb | 0:8918a71cdbe9 | 995 | if(error) |
Sergunb | 0:8918a71cdbe9 | 996 | return ERROR_BAD_RECORD_MAC; |
Sergunb | 0:8918a71cdbe9 | 997 | |
Sergunb | 0:8918a71cdbe9 | 998 | //Discard the explicit part of the nonce |
Sergunb | 0:8918a71cdbe9 | 999 | memmove(record->data, record->data + context->recordIvLen, length); |
Sergunb | 0:8918a71cdbe9 | 1000 | |
Sergunb | 0:8918a71cdbe9 | 1001 | //Increment sequence number |
Sergunb | 0:8918a71cdbe9 | 1002 | tlsIncSequenceNumber(context->readSeqNum); |
Sergunb | 0:8918a71cdbe9 | 1003 | } |
Sergunb | 0:8918a71cdbe9 | 1004 | else |
Sergunb | 0:8918a71cdbe9 | 1005 | #endif |
Sergunb | 0:8918a71cdbe9 | 1006 | #if (TLS_CHACHA20_POLY1305_SUPPORT == ENABLED) |
Sergunb | 0:8918a71cdbe9 | 1007 | //ChaCha20Poly1305 AEAD cipher? |
Sergunb | 0:8918a71cdbe9 | 1008 | if(context->cipherMode == CIPHER_MODE_CHACHA20_POLY1305) |
Sergunb | 0:8918a71cdbe9 | 1009 | { |
Sergunb | 0:8918a71cdbe9 | 1010 | size_t i; |
Sergunb | 0:8918a71cdbe9 | 1011 | uint8_t *tag; |
Sergunb | 0:8918a71cdbe9 | 1012 | uint8_t nonce[12]; |
Sergunb | 0:8918a71cdbe9 | 1013 | uint8_t a[13]; |
Sergunb | 0:8918a71cdbe9 | 1014 | |
Sergunb | 0:8918a71cdbe9 | 1015 | //Make sure the message length is acceptable |
Sergunb | 0:8918a71cdbe9 | 1016 | if(length < context->authTagLen) |
Sergunb | 0:8918a71cdbe9 | 1017 | return ERROR_DECODING_FAILED; |
Sergunb | 0:8918a71cdbe9 | 1018 | |
Sergunb | 0:8918a71cdbe9 | 1019 | //The 64-bit record sequence number is serialized as an 8-byte, |
Sergunb | 0:8918a71cdbe9 | 1020 | //big-endian value and padded on the left with four 0x00 bytes |
Sergunb | 0:8918a71cdbe9 | 1021 | memcpy(nonce + 4, context->readSeqNum, 8); |
Sergunb | 0:8918a71cdbe9 | 1022 | memset(nonce, 0, 4); |
Sergunb | 0:8918a71cdbe9 | 1023 | |
Sergunb | 0:8918a71cdbe9 | 1024 | //The padded sequence number is XORed with the read IV to form |
Sergunb | 0:8918a71cdbe9 | 1025 | //the 96-bit nonce |
Sergunb | 0:8918a71cdbe9 | 1026 | for(i = 0; i < context->fixedIvLen; i++) |
Sergunb | 0:8918a71cdbe9 | 1027 | nonce[i] ^= context->readIv[i]; |
Sergunb | 0:8918a71cdbe9 | 1028 | |
Sergunb | 0:8918a71cdbe9 | 1029 | //Calculate the length of the ciphertext |
Sergunb | 0:8918a71cdbe9 | 1030 | length -= context->authTagLen; |
Sergunb | 0:8918a71cdbe9 | 1031 | //Fix the length field of the TLS record |
Sergunb | 0:8918a71cdbe9 | 1032 | record->length = htons(length); |
Sergunb | 0:8918a71cdbe9 | 1033 | |
Sergunb | 0:8918a71cdbe9 | 1034 | //Additional data to be authenticated |
Sergunb | 0:8918a71cdbe9 | 1035 | memcpy(a, context->readSeqNum, sizeof(TlsSequenceNumber)); |
Sergunb | 0:8918a71cdbe9 | 1036 | memcpy(a + sizeof(TlsSequenceNumber), record, sizeof(TlsRecord)); |
Sergunb | 0:8918a71cdbe9 | 1037 | |
Sergunb | 0:8918a71cdbe9 | 1038 | //Point to the authentication tag |
Sergunb | 0:8918a71cdbe9 | 1039 | tag = record->data + length; |
Sergunb | 0:8918a71cdbe9 | 1040 | |
Sergunb | 0:8918a71cdbe9 | 1041 | //Authenticated decryption using ChaCha20Poly1305 |
Sergunb | 0:8918a71cdbe9 | 1042 | error = chacha20Poly1305Decrypt(context->readEncKey, context->encKeyLen, |
Sergunb | 0:8918a71cdbe9 | 1043 | nonce, 12, a, 13, record->data, record->data, length, tag, context->authTagLen); |
Sergunb | 0:8918a71cdbe9 | 1044 | //Wrong authentication tag? |
Sergunb | 0:8918a71cdbe9 | 1045 | if(error) |
Sergunb | 0:8918a71cdbe9 | 1046 | return ERROR_BAD_RECORD_MAC; |
Sergunb | 0:8918a71cdbe9 | 1047 | |
Sergunb | 0:8918a71cdbe9 | 1048 | //Increment sequence number |
Sergunb | 0:8918a71cdbe9 | 1049 | tlsIncSequenceNumber(context->readSeqNum); |
Sergunb | 0:8918a71cdbe9 | 1050 | } |
Sergunb | 0:8918a71cdbe9 | 1051 | else |
Sergunb | 0:8918a71cdbe9 | 1052 | #endif |
Sergunb | 0:8918a71cdbe9 | 1053 | //Invalid cipher mode? |
Sergunb | 0:8918a71cdbe9 | 1054 | { |
Sergunb | 0:8918a71cdbe9 | 1055 | //The specified cipher mode is not supported |
Sergunb | 0:8918a71cdbe9 | 1056 | return ERROR_UNSUPPORTED_CIPHER_MODE; |
Sergunb | 0:8918a71cdbe9 | 1057 | } |
Sergunb | 0:8918a71cdbe9 | 1058 | |
Sergunb | 0:8918a71cdbe9 | 1059 | //Debug message |
Sergunb | 0:8918a71cdbe9 | 1060 | TRACE_DEBUG("Decrypted record (%" PRIuSIZE " bytes):\r\n", length); |
Sergunb | 0:8918a71cdbe9 | 1061 | TRACE_DEBUG_ARRAY(" ", record, length + sizeof(TlsRecord)); |
Sergunb | 0:8918a71cdbe9 | 1062 | } |
Sergunb | 0:8918a71cdbe9 | 1063 | |
Sergunb | 0:8918a71cdbe9 | 1064 | //Check message authentication code if necessary |
Sergunb | 0:8918a71cdbe9 | 1065 | if(context->hashAlgo != NULL) |
Sergunb | 0:8918a71cdbe9 | 1066 | { |
Sergunb | 0:8918a71cdbe9 | 1067 | //Make sure the message length is acceptable |
Sergunb | 0:8918a71cdbe9 | 1068 | if(length < context->hashAlgo->digestSize) |
Sergunb | 0:8918a71cdbe9 | 1069 | return ERROR_DECODING_FAILED; |
Sergunb | 0:8918a71cdbe9 | 1070 | |
Sergunb | 0:8918a71cdbe9 | 1071 | //Adjust the length of the message |
Sergunb | 0:8918a71cdbe9 | 1072 | length -= context->hashAlgo->digestSize; |
Sergunb | 0:8918a71cdbe9 | 1073 | //Fix the length field of the TLS record |
Sergunb | 0:8918a71cdbe9 | 1074 | record->length = htons(length); |
Sergunb | 0:8918a71cdbe9 | 1075 | |
Sergunb | 0:8918a71cdbe9 | 1076 | #if (TLS_MAX_VERSION >= SSL_VERSION_3_0 && TLS_MIN_VERSION <= SSL_VERSION_3_0) |
Sergunb | 0:8918a71cdbe9 | 1077 | //Check whether SSL 3.0 is currently used |
Sergunb | 0:8918a71cdbe9 | 1078 | if(context->version == SSL_VERSION_3_0) |
Sergunb | 0:8918a71cdbe9 | 1079 | { |
Sergunb | 0:8918a71cdbe9 | 1080 | //SSL 3.0 uses an older obsolete version of the HMAC construction |
Sergunb | 0:8918a71cdbe9 | 1081 | error = sslComputeMac(context, context->readMacKey, context->readSeqNum, |
Sergunb | 0:8918a71cdbe9 | 1082 | record, record->data, length, context->hmacContext.digest); |
Sergunb | 0:8918a71cdbe9 | 1083 | //Any error to report? |
Sergunb | 0:8918a71cdbe9 | 1084 | if(error) |
Sergunb | 0:8918a71cdbe9 | 1085 | return error; |
Sergunb | 0:8918a71cdbe9 | 1086 | } |
Sergunb | 0:8918a71cdbe9 | 1087 | else |
Sergunb | 0:8918a71cdbe9 | 1088 | #endif |
Sergunb | 0:8918a71cdbe9 | 1089 | #if (TLS_MAX_VERSION >= TLS_VERSION_1_0 && TLS_MIN_VERSION <= TLS_VERSION_1_2) |
Sergunb | 0:8918a71cdbe9 | 1090 | //Check whether TLS 1.0, TLS 1.1 or TLS 1.2 is currently used |
Sergunb | 0:8918a71cdbe9 | 1091 | if(context->version >= TLS_VERSION_1_0) |
Sergunb | 0:8918a71cdbe9 | 1092 | { |
Sergunb | 0:8918a71cdbe9 | 1093 | //TLS uses a HMAC construction |
Sergunb | 0:8918a71cdbe9 | 1094 | hmacInit(&context->hmacContext, context->hashAlgo, |
Sergunb | 0:8918a71cdbe9 | 1095 | context->readMacKey, context->macKeyLen); |
Sergunb | 0:8918a71cdbe9 | 1096 | |
Sergunb | 0:8918a71cdbe9 | 1097 | //Compute MAC over the sequence number and the record contents |
Sergunb | 0:8918a71cdbe9 | 1098 | hmacUpdate(&context->hmacContext, context->readSeqNum, sizeof(TlsSequenceNumber)); |
Sergunb | 0:8918a71cdbe9 | 1099 | hmacUpdate(&context->hmacContext, record, sizeof(TlsRecord)); |
Sergunb | 0:8918a71cdbe9 | 1100 | hmacUpdate(&context->hmacContext, record->data, length); |
Sergunb | 0:8918a71cdbe9 | 1101 | hmacFinal(&context->hmacContext, NULL); |
Sergunb | 0:8918a71cdbe9 | 1102 | } |
Sergunb | 0:8918a71cdbe9 | 1103 | else |
Sergunb | 0:8918a71cdbe9 | 1104 | #endif |
Sergunb | 0:8918a71cdbe9 | 1105 | //The negotiated TLS version is not valid... |
Sergunb | 0:8918a71cdbe9 | 1106 | { |
Sergunb | 0:8918a71cdbe9 | 1107 | //Report an error |
Sergunb | 0:8918a71cdbe9 | 1108 | return ERROR_INVALID_VERSION; |
Sergunb | 0:8918a71cdbe9 | 1109 | } |
Sergunb | 0:8918a71cdbe9 | 1110 | |
Sergunb | 0:8918a71cdbe9 | 1111 | //Debug message |
Sergunb | 0:8918a71cdbe9 | 1112 | TRACE_DEBUG("Read sequence number:\r\n"); |
Sergunb | 0:8918a71cdbe9 | 1113 | TRACE_DEBUG_ARRAY(" ", context->readSeqNum, sizeof(TlsSequenceNumber)); |
Sergunb | 0:8918a71cdbe9 | 1114 | TRACE_DEBUG("Computed MAC:\r\n"); |
Sergunb | 0:8918a71cdbe9 | 1115 | TRACE_DEBUG_ARRAY(" ", context->hmacContext.digest, context->hashAlgo->digestSize); |
Sergunb | 0:8918a71cdbe9 | 1116 | |
Sergunb | 0:8918a71cdbe9 | 1117 | //Check the message authentication code |
Sergunb | 0:8918a71cdbe9 | 1118 | if(memcmp(record->data + length, context->hmacContext.digest, context->hashAlgo->digestSize)) |
Sergunb | 0:8918a71cdbe9 | 1119 | return ERROR_BAD_RECORD_MAC; |
Sergunb | 0:8918a71cdbe9 | 1120 | |
Sergunb | 0:8918a71cdbe9 | 1121 | //Increment sequence number |
Sergunb | 0:8918a71cdbe9 | 1122 | tlsIncSequenceNumber(context->readSeqNum); |
Sergunb | 0:8918a71cdbe9 | 1123 | } |
Sergunb | 0:8918a71cdbe9 | 1124 | |
Sergunb | 0:8918a71cdbe9 | 1125 | //Successful decryption |
Sergunb | 0:8918a71cdbe9 | 1126 | return NO_ERROR; |
Sergunb | 0:8918a71cdbe9 | 1127 | } |
Sergunb | 0:8918a71cdbe9 | 1128 | |
Sergunb | 0:8918a71cdbe9 | 1129 | |
Sergunb | 0:8918a71cdbe9 | 1130 | /** |
Sergunb | 0:8918a71cdbe9 | 1131 | * @brief Increment sequence number |
Sergunb | 0:8918a71cdbe9 | 1132 | * @param[in] seqNum Sequence number to increment |
Sergunb | 0:8918a71cdbe9 | 1133 | **/ |
Sergunb | 0:8918a71cdbe9 | 1134 | |
Sergunb | 0:8918a71cdbe9 | 1135 | void tlsIncSequenceNumber(TlsSequenceNumber seqNum) |
Sergunb | 0:8918a71cdbe9 | 1136 | { |
Sergunb | 0:8918a71cdbe9 | 1137 | int_t i; |
Sergunb | 0:8918a71cdbe9 | 1138 | |
Sergunb | 0:8918a71cdbe9 | 1139 | //Sequence numbers are stored MSB first |
Sergunb | 0:8918a71cdbe9 | 1140 | for(i = 7; i >= 0; i--) |
Sergunb | 0:8918a71cdbe9 | 1141 | { |
Sergunb | 0:8918a71cdbe9 | 1142 | //Increment the current byte |
Sergunb | 0:8918a71cdbe9 | 1143 | seqNum[i]++; |
Sergunb | 0:8918a71cdbe9 | 1144 | //Propagate the carry if necessary |
Sergunb | 0:8918a71cdbe9 | 1145 | if(seqNum[i] != 0) |
Sergunb | 0:8918a71cdbe9 | 1146 | break; |
Sergunb | 0:8918a71cdbe9 | 1147 | } |
Sergunb | 0:8918a71cdbe9 | 1148 | } |
Sergunb | 0:8918a71cdbe9 | 1149 | |
Sergunb | 0:8918a71cdbe9 | 1150 | #endif |
Sergunb | 0:8918a71cdbe9 | 1151 |