Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
tls.c
00001 /** 00002 * @file tls.c 00003 * @brief TLS (Transport Layer Security) 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 * @section Description 00026 * 00027 * The TLS protocol provides communications security over the Internet. The 00028 * protocol allows client/server applications to communicate in a way that 00029 * is designed to prevent eavesdropping, tampering, or message forgery 00030 * 00031 * @author Oryx Embedded SARL (www.oryx-embedded.com) 00032 * @version 1.7.6 00033 **/ 00034 00035 //Switch to the appropriate trace level 00036 #define TRACE_LEVEL TLS_TRACE_LEVEL 00037 00038 //Dependencies 00039 #include <string.h> 00040 #include <ctype.h> 00041 #include "tls.h" 00042 #include "tls_client.h" 00043 #include "tls_server.h" 00044 #include "tls_common.h" 00045 #include "tls_record.h" 00046 #include "tls_misc.h" 00047 #include "x509.h" 00048 #include "pem.h" 00049 #include "debug.h" 00050 00051 //Check SSL library configuration 00052 #if (TLS_SUPPORT == ENABLED) 00053 00054 00055 /** 00056 * @brief TLS context initialization 00057 * @return Handle referencing the fully initialized TLS context 00058 **/ 00059 00060 TlsContext *tlsInit(void) 00061 { 00062 TlsContext *context; 00063 00064 //Allocate a memory buffer to hold the TLS context 00065 context = tlsAllocMem(sizeof(TlsContext)); 00066 00067 //Successful memory allocation? 00068 if(context != NULL) 00069 { 00070 //Clear TLS context 00071 memset(context, 0, sizeof(TlsContext)); 00072 00073 //Default state 00074 context->state = TLS_STATE_INIT; 00075 //Default operation mode 00076 context->entity = TLS_CONNECTION_END_CLIENT; 00077 //Default TLS version 00078 context->version = TLS_MIN_VERSION; 00079 //Default client authentication mode 00080 context->clientAuthMode = TLS_CLIENT_AUTH_NONE; 00081 00082 #if (TLS_DH_ANON_SUPPORT == ENABLED || TLS_DHE_RSA_SUPPORT == ENABLED || \ 00083 TLS_DHE_DSS_SUPPORT == ENABLED || TLS_DHE_PSK_SUPPORT == ENABLED) 00084 //Initialize Diffie-Hellman context 00085 dhInit(&context->dhContext); 00086 #endif 00087 00088 #if (TLS_ECDH_ANON_SUPPORT == ENABLED || TLS_ECDHE_RSA_SUPPORT == ENABLED || \ 00089 TLS_ECDHE_ECDSA_SUPPORT == ENABLED || TLS_ECDHE_PSK_SUPPORT == ENABLED) 00090 //Initialize ECDH context 00091 ecdhInit(&context->ecdhContext); 00092 #endif 00093 00094 #if (TLS_RSA_SIGN_SUPPORT == ENABLED || TLS_RSA_SUPPORT == ENABLED || \ 00095 TLS_DHE_RSA_SUPPORT == ENABLED || TLS_ECDHE_RSA_SUPPORT == ENABLED) 00096 //Initialize peer's RSA public key 00097 rsaInitPublicKey(&context->peerRsaPublicKey); 00098 #endif 00099 00100 #if (TLS_DSA_SIGN_SUPPORT == ENABLED || TLS_DHE_DSS_SUPPORT == ENABLED) 00101 //Initialize peer's DSA public key 00102 dsaInitPublicKey(&context->peerDsaPublicKey); 00103 #endif 00104 00105 #if (TLS_ECDSA_SIGN_SUPPORT == ENABLED || TLS_ECDHE_ECDSA_SUPPORT == ENABLED) 00106 //Initialize peer's EC domain parameters 00107 ecInitDomainParameters(&context->peerEcParams); 00108 //Initialize peer's EC public key 00109 ecInit(&context->peerEcPublicKey); 00110 #endif 00111 00112 //Set the maximum fragment length for outgoing TLS records 00113 context->txRecordMaxLen = TLS_MAX_RECORD_LENGTH; 00114 00115 //Compute the corresponding buffer size 00116 context->txBufferSize = TLS_MAX_RECORD_LENGTH + 00117 sizeof(TlsRecord) + TLS_MAX_RECORD_OVERHEAD; 00118 00119 //Save the maximum fragment length for incoming TLS records 00120 context->rxRecordMaxLen = TLS_MAX_RECORD_LENGTH; 00121 00122 //Compute the corresponding buffer size 00123 context->rxBufferSize = TLS_MAX_RECORD_LENGTH + 00124 sizeof(TlsRecord) + TLS_MAX_RECORD_OVERHEAD; 00125 } 00126 00127 //Return a pointer to the freshly created TLS context 00128 return context; 00129 } 00130 00131 00132 /** 00133 * @brief Set send and receive callbacks (I/O abstraction layer) 00134 * @param[in] context Pointer to the TLS context 00135 * @param[in] handle Handle for I/O operations 00136 * @param[in] sendCallback Send callback function 00137 * @param[in] receiveCallback Receive callback function 00138 * @return Error code 00139 **/ 00140 00141 error_t tlsSetIoCallbacks(TlsContext *context, TlsIoHandle handle, 00142 TlsIoSendCallback sendCallback, TlsIoReceiveCallback receiveCallback) 00143 { 00144 //Check parameters 00145 if(context == NULL || sendCallback == NULL || receiveCallback == NULL) 00146 return ERROR_INVALID_PARAMETER; 00147 00148 //Save I/O handle 00149 context->handle = handle; 00150 00151 //Save send and receive callback functions 00152 context->sendCallback = sendCallback; 00153 context->receiveCallback = receiveCallback; 00154 00155 //Successful processing 00156 return NO_ERROR; 00157 } 00158 00159 00160 /** 00161 * @brief Set operation mode (client or server) 00162 * @param[in] context Pointer to the TLS context 00163 * @param[in] entity Specifies whether this entity is considered a client or a server 00164 * @return Error code 00165 **/ 00166 00167 error_t tlsSetConnectionEnd(TlsContext *context, TlsConnectionEnd entity) 00168 { 00169 //Invalid TLS context? 00170 if(context == NULL) 00171 return ERROR_INVALID_PARAMETER; 00172 //Invalid parameter? 00173 if(entity != TLS_CONNECTION_END_CLIENT && entity != TLS_CONNECTION_END_SERVER) 00174 return ERROR_INVALID_PARAMETER; 00175 00176 //Check whether TLS operates as a client or a server 00177 context->entity = entity; 00178 00179 //Successful processing 00180 return NO_ERROR; 00181 } 00182 00183 00184 /** 00185 * @brief Set the pseudo-random number generator to be used 00186 * @param[in] context Pointer to the TLS context 00187 * @param[in] prngAlgo PRNG algorithm 00188 * @param[in] prngContext Pointer to the PRNG context 00189 * @return Error code 00190 **/ 00191 00192 error_t tlsSetPrng(TlsContext *context, const PrngAlgo *prngAlgo, void *prngContext) 00193 { 00194 //Invalid TLS context? 00195 if(context == NULL) 00196 return ERROR_INVALID_PARAMETER; 00197 //Invalid parameters? 00198 if(prngAlgo == NULL || prngContext == NULL) 00199 return ERROR_INVALID_PARAMETER; 00200 00201 //PRNG algorithm that will be used to generate random numbers 00202 context->prngAlgo = prngAlgo; 00203 //PRNG context 00204 context->prngContext = prngContext; 00205 00206 //Successful processing 00207 return NO_ERROR; 00208 } 00209 00210 00211 /** 00212 * @brief Set the name of the remote server 00213 * @param[in] context Pointer to the TLS context 00214 * @param[in] serverName Fully qualified domain name of the server 00215 * @return Error code 00216 **/ 00217 00218 error_t tlsSetServerName(TlsContext *context, const char_t *serverName) 00219 { 00220 size_t i; 00221 size_t length; 00222 00223 //Invalid parameters? 00224 if(context == NULL || serverName == NULL) 00225 return ERROR_INVALID_PARAMETER; 00226 00227 //Retrieve the length of the server name 00228 length = strlen(serverName); 00229 00230 //Check whether the server name has already been configured 00231 if(context->serverName != NULL) 00232 { 00233 //Release memory 00234 tlsFreeMem(context->serverName); 00235 context->serverName = NULL; 00236 } 00237 00238 //Valid server name? 00239 if(length > 0) 00240 { 00241 //Allocate a memory block to hold the hostname 00242 context->serverName = tlsAllocMem(length + 1); 00243 //Failed to allocate memory? 00244 if(context->serverName == NULL) 00245 return ERROR_OUT_OF_MEMORY; 00246 00247 //Convert the hostname into lowercase 00248 for(i = 0; i < length; i++) 00249 context->serverName[i] = tolower((uint8_t) serverName[i]); 00250 00251 //Properly terminate the string with a NULL character 00252 context->serverName[length] = '\0'; 00253 } 00254 00255 //Successful processing 00256 return NO_ERROR; 00257 } 00258 00259 00260 /** 00261 * @brief Set session cache 00262 * @param[in] context Pointer to the TLS context 00263 * @param[in] cache Session cache that will be used to save/resume TLS sessions 00264 * @return Error code 00265 **/ 00266 00267 error_t tlsSetCache(TlsContext *context, TlsCache *cache) 00268 { 00269 //Check parameters 00270 if(context == NULL || cache == NULL) 00271 return ERROR_INVALID_PARAMETER; 00272 00273 //The cache will be used to save/resume TLS sessions 00274 context->cache = cache; 00275 00276 //Successful processing 00277 return NO_ERROR; 00278 } 00279 00280 00281 /** 00282 * @brief Set client authentication mode 00283 * @param[in] context Pointer to the TLS context 00284 * @param[in] mode Client authentication mode 00285 * @return Error code 00286 **/ 00287 00288 error_t tlsSetClientAuthMode(TlsContext *context, TlsClientAuthMode mode) 00289 { 00290 //Invalid TLS context? 00291 if(context == NULL) 00292 return ERROR_INVALID_PARAMETER; 00293 00294 //Save client authentication mode 00295 context->clientAuthMode = mode; 00296 00297 //Successful processing 00298 return NO_ERROR; 00299 } 00300 00301 00302 /** 00303 * @brief Set TLS buffer size 00304 * @param[in] context Pointer to the TLS context 00305 * @param[in] txBufferSize TX buffer size 00306 * @param[in] rxBufferSize RX buffer size 00307 * @return Error code 00308 **/ 00309 00310 error_t tlsSetBufferSize(TlsContext *context, 00311 size_t txBufferSize, size_t rxBufferSize) 00312 { 00313 //Invalid TLS context? 00314 if(context == NULL) 00315 return ERROR_INVALID_PARAMETER; 00316 //Check parameters 00317 if(txBufferSize < 512 || rxBufferSize < 512) 00318 return ERROR_INVALID_PARAMETER; 00319 00320 //Save the maximum fragment length for outgoing TLS records 00321 context->txRecordMaxLen = txBufferSize; 00322 00323 //Compute the corresponding buffer size 00324 context->txBufferSize = txBufferSize + 00325 sizeof(TlsRecord) + TLS_MAX_RECORD_OVERHEAD; 00326 00327 //Save the maximum fragment length for incoming TLS records 00328 context->rxRecordMaxLen = rxBufferSize; 00329 00330 //Compute the corresponding buffer size 00331 context->rxBufferSize = rxBufferSize + 00332 sizeof(TlsRecord) + TLS_MAX_RECORD_OVERHEAD; 00333 00334 //Successful processing 00335 return NO_ERROR; 00336 } 00337 00338 00339 /** 00340 * @brief Specify the list of allowed cipher suites 00341 * @param[in] context Pointer to the TLS context 00342 * @param[in] cipherSuites Pointer to the cipher suite list 00343 * @param[in] length Number of cipher suites in the list 00344 * @return Error code 00345 **/ 00346 00347 error_t tlsSetCipherSuites(TlsContext *context, 00348 const uint16_t *cipherSuites, uint_t length) 00349 { 00350 //Invalid TLS context? 00351 if(context == NULL) 00352 return ERROR_INVALID_PARAMETER; 00353 //Check parameters 00354 if(cipherSuites == NULL && length != 0) 00355 return ERROR_INVALID_PARAMETER; 00356 00357 //Restrict the cipher suites that can be used 00358 context->cipherSuites = cipherSuites; 00359 context->numCipherSuites = length; 00360 00361 //Successful processing 00362 return NO_ERROR; 00363 } 00364 00365 00366 /** 00367 * @brief Import Diffie-Hellman parameters 00368 * @param[in] context Pointer to the TLS context 00369 * @param[in] params PEM structure that holds Diffie-Hellman parameters 00370 * @param[in] length Total length of the DER structure 00371 * @return Error code 00372 **/ 00373 00374 error_t tlsSetDhParameters(TlsContext *context, 00375 const char_t *params, size_t length) 00376 { 00377 #if (TLS_DH_ANON_SUPPORT == ENABLED || TLS_DHE_RSA_SUPPORT == ENABLED || \ 00378 TLS_DHE_DSS_SUPPORT == ENABLED || TLS_DHE_PSK_SUPPORT == ENABLED) 00379 //Invalid TLS context? 00380 if(context == NULL) 00381 return ERROR_INVALID_PARAMETER; 00382 //Check parameters 00383 if(params == NULL && length != 0) 00384 return ERROR_INVALID_PARAMETER; 00385 00386 //Decode the PEM structure that holds Diffie-Hellman parameters 00387 return pemReadDhParameters(params, length, &context->dhContext.params); 00388 #else 00389 //Diffie-Hellman is not implemented 00390 return ERROR_NOT_IMPLEMENTED; 00391 #endif 00392 } 00393 00394 00395 /** 00396 * @brief Set the list of supported ALPN protocols 00397 * @param[in] context Pointer to the TLS context 00398 * @param[in] protocolList Comma-delimited list of supported protocols 00399 * @return Error code 00400 **/ 00401 00402 error_t tlsSetAlpnProtocolList(TlsContext *context, const char_t *protocolList) 00403 { 00404 #if (TLS_ALPN_SUPPORT == ENABLED) 00405 size_t length; 00406 00407 //Invalid parameters? 00408 if(context == NULL || protocolList == NULL) 00409 return ERROR_INVALID_PARAMETER; 00410 00411 //Retrieve the length of the list 00412 length = strlen(protocolList); 00413 00414 //Check whether the list of supported protocols has already been configured 00415 if(context->protocolList != NULL) 00416 { 00417 //Release memory 00418 tlsFreeMem(context->protocolList); 00419 context->protocolList = NULL; 00420 } 00421 00422 //Check whether the list of protocols is valid 00423 if(length > 0) 00424 { 00425 //Allocate a memory block to hold the list 00426 context->protocolList = tlsAllocMem(length + 1); 00427 //Failed to allocate memory? 00428 if(context->protocolList == NULL) 00429 return ERROR_OUT_OF_MEMORY; 00430 00431 //Save the list of supported protocols 00432 strcpy(context->protocolList, protocolList); 00433 } 00434 00435 //Successful processing 00436 return NO_ERROR; 00437 #else 00438 //ALPN is not implemented 00439 return ERROR_NOT_IMPLEMENTED; 00440 #endif 00441 } 00442 00443 00444 /** 00445 * @brief Get the name of the negotiated ALPN protocol 00446 * @param[in] context Pointer to the TLS context 00447 * @return Pointer to the protocol name 00448 **/ 00449 00450 const char_t *tlsGetAlpnProtocol(TlsContext *context) 00451 { 00452 //Not implemented 00453 return NULL; 00454 } 00455 00456 00457 /** 00458 * @brief Set the pre-shared key to be used 00459 * @param[in] context Pointer to the TLS context 00460 * @param[in] psk Pointer to the pre-shared key 00461 * @param[in] pskLength Length of the pre-shared key, in bytes 00462 * @return Error code 00463 **/ 00464 00465 error_t tlsSetPsk(TlsContext *context, const uint8_t *psk, size_t pskLength) 00466 { 00467 #if (TLS_PSK_SUPPORT == ENABLED || TLS_RSA_PSK_SUPPORT == ENABLED || \ 00468 TLS_DHE_PSK_SUPPORT == ENABLED || TLS_ECDHE_PSK_SUPPORT == ENABLED) 00469 //Invalid TLS context? 00470 if(context == NULL) 00471 return ERROR_INVALID_PARAMETER; 00472 //Check parameters 00473 if(psk == NULL && pskLength != 0) 00474 return ERROR_INVALID_PARAMETER; 00475 00476 //Check whether the pre-shared key has already been configured 00477 if(context->psk != NULL) 00478 { 00479 //Release memory 00480 memset(context->psk, 0, context->pskLen); 00481 tlsFreeMem(context->psk); 00482 //Re-initialize length 00483 context->pskLen = 0; 00484 } 00485 00486 //Valid PSK? 00487 if(pskLength > 0) 00488 { 00489 //Allocate a memory block to hold the pre-shared key 00490 context->psk = tlsAllocMem(pskLength); 00491 //Failed to allocate memory? 00492 if(context->psk == NULL) 00493 return ERROR_OUT_OF_MEMORY; 00494 00495 //Save the pre-shared key 00496 memcpy(context->psk, psk, pskLength); 00497 //Save the length of the key 00498 context->pskLen = pskLength; 00499 } 00500 00501 //Successful processing 00502 return NO_ERROR; 00503 #else 00504 //PSK key exchange is not implemented 00505 return ERROR_NOT_IMPLEMENTED; 00506 #endif 00507 } 00508 00509 00510 /** 00511 * @brief Set the PSK identity to be used by the client 00512 * @param[in] context Pointer to the TLS context 00513 * @param[in] pskIdentity NULL-terminated string that contains the PSK identity 00514 * @return Error code 00515 **/ 00516 00517 error_t tlsSetPskIdentity(TlsContext *context, const char_t *pskIdentity) 00518 { 00519 #if (TLS_PSK_SUPPORT == ENABLED || TLS_RSA_PSK_SUPPORT == ENABLED || \ 00520 TLS_DHE_PSK_SUPPORT == ENABLED || TLS_ECDHE_PSK_SUPPORT == ENABLED) 00521 size_t length; 00522 00523 //Invalid parameters? 00524 if(context == NULL || pskIdentity == NULL) 00525 return ERROR_INVALID_PARAMETER; 00526 00527 //Retrieve the length of the PSK identity 00528 length = strlen(pskIdentity); 00529 00530 //Check whether the PSK identity has already been configured 00531 if(context->pskIdentity != NULL) 00532 { 00533 //Release memory 00534 tlsFreeMem(context->pskIdentity); 00535 context->pskIdentity = NULL; 00536 } 00537 00538 //Valid PSK identity? 00539 if(length > 0) 00540 { 00541 //Allocate a memory block to hold the PSK identity 00542 context->pskIdentity = tlsAllocMem(length + 1); 00543 //Failed to allocate memory? 00544 if(context->pskIdentity == NULL) 00545 return ERROR_OUT_OF_MEMORY; 00546 00547 //Save the PSK identity 00548 strcpy(context->pskIdentity, pskIdentity); 00549 } 00550 00551 //Successful processing 00552 return NO_ERROR; 00553 #else 00554 //PSK key exchange is not implemented 00555 return ERROR_NOT_IMPLEMENTED; 00556 #endif 00557 } 00558 00559 00560 /** 00561 * @brief Set the PSK identity hint to be used by the server 00562 * @param[in] context Pointer to the TLS context 00563 * @param[in] pskIdentityHint NULL-terminated string that contains the PSK identity hint 00564 * @return Error code 00565 **/ 00566 00567 error_t tlsSetPskIdentityHint(TlsContext *context, const char_t *pskIdentityHint) 00568 { 00569 #if (TLS_PSK_SUPPORT == ENABLED || TLS_RSA_PSK_SUPPORT == ENABLED || \ 00570 TLS_DHE_PSK_SUPPORT == ENABLED || TLS_ECDHE_PSK_SUPPORT == ENABLED) 00571 size_t length; 00572 00573 //Invalid parameters? 00574 if(context == NULL || pskIdentityHint == NULL) 00575 return ERROR_INVALID_PARAMETER; 00576 00577 //Retrieve the length of the PSK identity hint 00578 length = strlen(pskIdentityHint); 00579 00580 //Check whether the PSK identity hint has already been configured 00581 if(context->pskIdentityHint != NULL) 00582 { 00583 //Release memory 00584 tlsFreeMem(context->pskIdentityHint); 00585 context->pskIdentityHint = NULL; 00586 } 00587 00588 //Valid PSK identity hint? 00589 if(length > 0) 00590 { 00591 //Allocate a memory block to hold the PSK identity hint 00592 context->pskIdentityHint = tlsAllocMem(length + 1); 00593 //Failed to allocate memory? 00594 if(context->pskIdentityHint == NULL) 00595 return ERROR_OUT_OF_MEMORY; 00596 00597 //Save the PSK identity hint 00598 strcpy(context->pskIdentityHint, pskIdentityHint); 00599 } 00600 00601 //Successful processing 00602 return NO_ERROR; 00603 #else 00604 //PSK key exchange is not implemented 00605 return ERROR_NOT_IMPLEMENTED; 00606 #endif 00607 } 00608 00609 00610 /** 00611 * @brief Register the PSK callback function 00612 * @param[in] context Pointer to the TLS context 00613 * @param[in] pskCallback PSK callback function 00614 * @return Error code 00615 **/ 00616 00617 error_t tlsSetPskCallback(TlsContext *context, TlsPskCallback pskCallback) 00618 { 00619 #if (TLS_PSK_SUPPORT == ENABLED || TLS_RSA_PSK_SUPPORT == ENABLED || \ 00620 TLS_DHE_PSK_SUPPORT == ENABLED || TLS_ECDHE_PSK_SUPPORT == ENABLED) 00621 //Invalid parameters? 00622 if(context == NULL || pskCallback == NULL) 00623 return ERROR_INVALID_PARAMETER; 00624 00625 //Save the PSK callback function 00626 context->pskCallback = pskCallback; 00627 00628 //Successful processing 00629 return NO_ERROR; 00630 #else 00631 //PSK key exchange is not implemented 00632 return ERROR_NOT_IMPLEMENTED; 00633 #endif 00634 } 00635 00636 00637 /** 00638 * @brief Import a trusted CA list 00639 * @param[in] context Pointer to the TLS context 00640 * @param[in] trustedCaList List of trusted CA (PEM format) 00641 * @param[in] length Total length of the list 00642 * @return Error code 00643 **/ 00644 00645 error_t tlsSetTrustedCaList(TlsContext *context, 00646 const char_t *trustedCaList, size_t length) 00647 { 00648 //Invalid TLS context? 00649 if(context == NULL) 00650 return ERROR_INVALID_PARAMETER; 00651 //Check parameters 00652 if(trustedCaList == NULL && length != 0) 00653 return ERROR_INVALID_PARAMETER; 00654 00655 //Save the certificate chain 00656 context->trustedCaList = trustedCaList; 00657 context->trustedCaListLen = length; 00658 00659 //Successful processing 00660 return NO_ERROR; 00661 } 00662 00663 00664 /** 00665 * @brief Import a certificate and the corresponding private key 00666 * @param[in] context Pointer to the TLS context 00667 * @param[in] certChain Certificate chain (PEM format) 00668 * @param[in] certChainLength Total length of the certificate chain 00669 * @param[in] privateKey Private key (PEM format) 00670 * @param[in] privateKeyLength Total length of the private key 00671 * @return Error code 00672 **/ 00673 00674 error_t tlsAddCertificate(TlsContext *context, const char_t *certChain, 00675 size_t certChainLength, const char_t *privateKey, size_t privateKeyLength) 00676 { 00677 error_t error; 00678 const char_t *p; 00679 size_t n; 00680 uint8_t *derCert; 00681 size_t derCertSize; 00682 size_t derCertLength; 00683 X509CertificateInfo *certInfo; 00684 TlsCertificateType certType; 00685 TlsSignatureAlgo certSignAlgo; 00686 TlsHashAlgo certHashAlgo; 00687 TlsEcNamedCurve namedCurve; 00688 00689 //Invalid TLS context? 00690 if(context == NULL) 00691 return ERROR_INVALID_PARAMETER; 00692 00693 //Check parameters 00694 if(certChain == NULL || certChainLength == 0) 00695 return ERROR_INVALID_PARAMETER; 00696 if(privateKey == NULL || privateKeyLength == 0) 00697 return ERROR_INVALID_PARAMETER; 00698 00699 //Make sure there is enough room to add the certificate 00700 if(context->numCerts >= TLS_MAX_CERTIFICATES) 00701 return ERROR_OUT_OF_RESOURCES; 00702 00703 //Allocate a memory buffer to store X.509 certificate info 00704 certInfo = tlsAllocMem(sizeof(X509CertificateInfo)); 00705 //Failed to allocate memory? 00706 if(certInfo == NULL) 00707 return ERROR_OUT_OF_MEMORY; 00708 00709 //Point to the beginning of the certificate chain 00710 p = certChain; 00711 n = certChainLength; 00712 00713 //DER encoded certificate 00714 derCert = NULL; 00715 derCertSize = 0; 00716 derCertLength = 0; 00717 00718 //Start of exception handling block 00719 do 00720 { 00721 //Decode end entity certificate 00722 error = pemReadCertificate(&p, &n, &derCert, &derCertSize, &derCertLength); 00723 //Any error to report? 00724 if(error) 00725 break; 00726 00727 //Parse X.509 certificate 00728 error = x509ParseCertificate(derCert, derCertLength, certInfo); 00729 //Failed to parse the X.509 certificate? 00730 if(error) 00731 break; 00732 00733 //Retrieve the signature algorithm that has been used to sign the certificate 00734 error = tlsGetCertificateType(certInfo, &certType, 00735 &certSignAlgo, &certHashAlgo, &namedCurve); 00736 //The specified signature algorithm is not supported? 00737 if(error) 00738 break; 00739 00740 //End of exception handling block 00741 } while(0); 00742 00743 //Check whether the certificate is acceptable 00744 if(!error) 00745 { 00746 //Point to the structure that describes the certificate 00747 TlsCertDesc *cert = &context->certs[context->numCerts]; 00748 00749 //Save the certificate chain and the corresponding private key 00750 cert->certChain = certChain; 00751 cert->certChainLength = certChainLength; 00752 cert->privateKey = privateKey; 00753 cert->privateKeyLength = privateKeyLength; 00754 cert->type = certType; 00755 cert->signAlgo = certSignAlgo; 00756 cert->hashAlgo = certHashAlgo; 00757 cert->namedCurve = namedCurve; 00758 00759 //Update the number of certificates 00760 context->numCerts++; 00761 } 00762 00763 //Release previously allocated memory 00764 tlsFreeMem(derCert); 00765 tlsFreeMem(certInfo); 00766 00767 //Return status code 00768 return error; 00769 } 00770 00771 00772 /** 00773 * @brief Initiate the TLS handshake 00774 * @param[in] context Pointer to the TLS context 00775 * @return Error code 00776 **/ 00777 00778 error_t tlsConnect(TlsContext *context) 00779 { 00780 error_t error; 00781 00782 //Invalid TLS context? 00783 if(context == NULL) 00784 return ERROR_INVALID_PARAMETER; 00785 00786 //Ensure the I/O callback functions are properly registered 00787 if(context->sendCallback == NULL || context->receiveCallback == NULL) 00788 return ERROR_NOT_CONFIGURED; 00789 00790 //Verify that the PRNG is properly set 00791 if(context->prngAlgo == NULL || context->prngContext == NULL) 00792 return ERROR_NOT_CONFIGURED; 00793 00794 //Check current state 00795 if(context->state == TLS_STATE_INIT) 00796 { 00797 //Allocate send buffer if necessary 00798 if(context->txBuffer == NULL) 00799 { 00800 //Allocate TX buffer 00801 context->txBuffer = tlsAllocMem(context->txBufferSize); 00802 00803 //Failed to allocate memory? 00804 if(context->txBuffer == NULL) 00805 return ERROR_OUT_OF_MEMORY; 00806 00807 //Clear TX buffer 00808 memset(context->txBuffer, 0, context->txBufferSize); 00809 } 00810 00811 //Allocate receive buffer if necessary 00812 if(context->rxBuffer == NULL) 00813 { 00814 //Allocate RX buffer 00815 context->rxBuffer = tlsAllocMem(context->rxBufferSize); 00816 00817 //Failed to allocate memory? 00818 if(context->rxBuffer == NULL) 00819 { 00820 //Clean up side effects 00821 tlsFreeMem(context->txBuffer); 00822 context->txBuffer = NULL; 00823 //Report an error 00824 return ERROR_OUT_OF_MEMORY; 00825 } 00826 00827 //Clear RX buffer 00828 memset(context->rxBuffer, 0, context->rxBufferSize); 00829 } 00830 } 00831 00832 //Perform TLS handshake 00833 error = tlsHandshake(context); 00834 //Return status code 00835 return error; 00836 } 00837 00838 00839 /** 00840 * @brief Send application data to the remote host using TLS 00841 * @param[in] context Pointer to the TLS context 00842 * @param[in] data Pointer to a buffer containing the data to be transmitted 00843 * @param[in] length Number of bytes to be transmitted 00844 * @param[out] written Actual number of bytes written (optional parameter) 00845 * @param[in] flags Set of flags that influences the behavior of this function 00846 * @return Error code 00847 **/ 00848 00849 error_t tlsWrite(TlsContext *context, const void *data, 00850 size_t length, size_t *written, uint_t flags) 00851 { 00852 error_t error; 00853 size_t n; 00854 size_t totalLength; 00855 00856 //Invalid TLS context? 00857 if(context == NULL) 00858 return ERROR_INVALID_PARAMETER; 00859 00860 //Check parameters 00861 if(data == NULL && length != 0) 00862 return ERROR_INVALID_PARAMETER; 00863 00864 //Ensure the I/O callback functions are properly registered 00865 if(context->sendCallback == NULL || context->receiveCallback == NULL) 00866 return ERROR_NOT_CONFIGURED; 00867 00868 //Initialize status code 00869 error = NO_ERROR; 00870 00871 //Actual number of bytes written 00872 totalLength = 0; 00873 00874 //Send as much data as possible 00875 while(totalLength < length) 00876 { 00877 //Check current state 00878 if(context->state == TLS_STATE_APPLICATION_DATA) 00879 { 00880 //Calculate the number of bytes to write at a time 00881 n = MIN(length - totalLength, context->txRecordMaxLen); 00882 //The record length must not exceed 16384 bytes 00883 n = MIN(n, TLS_MAX_RECORD_LENGTH); 00884 00885 //Send application data 00886 error = tlsWriteProtocolData(context, data, n, TLS_TYPE_APPLICATION_DATA); 00887 00888 //Check status code 00889 if(!error) 00890 { 00891 //Advance data pointer 00892 data = (uint8_t *) data + n; 00893 //Update byte counter 00894 totalLength += n; 00895 } 00896 else 00897 { 00898 //Send an alert message to the peer, if applicable 00899 tlsProcessError(context, error); 00900 } 00901 } 00902 else 00903 { 00904 //The connection has not yet been established 00905 error = ERROR_NOT_CONNECTED; 00906 } 00907 00908 //Any error to report? 00909 if(error) 00910 break; 00911 } 00912 00913 //Total number of data that have been written 00914 if(written != NULL) 00915 *written = totalLength; 00916 00917 //Return status code 00918 return error; 00919 } 00920 00921 00922 /** 00923 * @brief Receive application data from a the remote host using TLS 00924 * @param[in] context Pointer to the TLS context 00925 * @param[out] data Buffer into which received data will be placed 00926 * @param[in] size Maximum number of bytes that can be received 00927 * @param[out] received Number of bytes that have been received 00928 * @param[in] flags Set of flags that influences the behavior of this function 00929 * @return Error code 00930 **/ 00931 00932 error_t tlsRead(TlsContext *context, void *data, 00933 size_t size, size_t *received, uint_t flags) 00934 { 00935 error_t error; 00936 size_t i; 00937 size_t n; 00938 uint8_t *p; 00939 TlsContentType contentType; 00940 00941 //Invalid TLS context? 00942 if(context == NULL) 00943 return ERROR_INVALID_PARAMETER; 00944 00945 //Check parameters 00946 if(data == NULL && received == NULL) 00947 return ERROR_INVALID_PARAMETER; 00948 00949 //Ensure the I/O callback functions are properly registered 00950 if(context->sendCallback == NULL || context->receiveCallback == NULL) 00951 return ERROR_NOT_CONFIGURED; 00952 00953 //Initialize status code 00954 error = NO_ERROR; 00955 00956 //No data has been read yet 00957 *received = 0; 00958 00959 //Read as much data as possible 00960 while(*received < size) 00961 { 00962 //Check current state 00963 if(context->state == TLS_STATE_APPLICATION_DATA) 00964 { 00965 //The TLS record layer receives uninterpreted data from higher layers 00966 error = tlsReadProtocolData(context, (void **) &p, &n, &contentType); 00967 00968 //Check status code 00969 if(!error) 00970 { 00971 //Application data received? 00972 if(contentType == TLS_TYPE_APPLICATION_DATA) 00973 { 00974 //Limit the number of bytes to read at a time 00975 n = MIN(n, size - *received); 00976 00977 //The TLS_FLAG_BREAK_CHAR flag causes the function to stop reading 00978 //data as soon as the specified break character is encountered 00979 if(flags & TLS_FLAG_BREAK_CHAR) 00980 { 00981 //Retrieve the break character code 00982 char_t c = LSB(flags); 00983 00984 //Search for the specified break character 00985 for(i = 0; i < n && p[i] != c; i++); 00986 //Adjust the number of data to read 00987 n = MIN(n, i + 1); 00988 00989 //Copy data to user buffer 00990 memcpy(data, p, n); 00991 //Total number of data that have been read 00992 *received += n; 00993 00994 //Advance data pointer 00995 context->rxBufferPos += n; 00996 //Number of bytes still pending in the receive buffer 00997 context->rxBufferLen -= n; 00998 00999 //Check whether a break character has been found 01000 if(n > 0 && p[n - 1] == c) 01001 break; 01002 } 01003 else 01004 { 01005 //Copy data to user buffer 01006 memcpy(data, p, n); 01007 //Total number of data that have been read 01008 *received += n; 01009 01010 //Advance data pointer 01011 context->rxBufferPos += n; 01012 //Number of bytes still pending in the receive buffer 01013 context->rxBufferLen -= n; 01014 01015 //The TLS_FLAG_WAIT_ALL flag causes the function to return 01016 //only when the requested number of bytes have been read 01017 if(!(flags & TLS_FLAG_WAIT_ALL)) 01018 break; 01019 } 01020 01021 //Advance data pointer 01022 data = (uint8_t *) data + n; 01023 } 01024 //Alert message received? 01025 else if(contentType == TLS_TYPE_ALERT) 01026 { 01027 //Parse Alert message 01028 error = tlsParseAlert(context, (TlsAlert *) p, n); 01029 01030 //Advance data pointer 01031 context->rxBufferPos += n; 01032 //Number of bytes still pending in the receive buffer 01033 context->rxBufferLen -= n; 01034 } 01035 //An inappropriate message was received? 01036 else 01037 { 01038 //Report an error 01039 error = ERROR_UNEXPECTED_MESSAGE; 01040 } 01041 } 01042 01043 //Any error to report? 01044 if(error) 01045 { 01046 //Send an alert message to the peer, if applicable 01047 tlsProcessError(context, error); 01048 } 01049 } 01050 else if(context->state == TLS_STATE_CLOSING || 01051 context->state == TLS_STATE_CLOSED) 01052 { 01053 //Check whether a fatal alert message has been sent or received 01054 if(context->fatalAlertSent || context->fatalAlertReceived) 01055 { 01056 //Alert messages with a level of fatal result in the immediate 01057 //termination of the connection 01058 error = ERROR_FAILURE; 01059 } 01060 else 01061 { 01062 //The user must be satisfied with data already on hand 01063 if(*received > 0) 01064 { 01065 //Some data are pending in the receive buffer 01066 error = NO_ERROR; 01067 break; 01068 } 01069 else 01070 { 01071 //The receive buffer is empty 01072 error = ERROR_END_OF_STREAM; 01073 } 01074 } 01075 } 01076 else 01077 { 01078 //The connection has not yet been established 01079 error = ERROR_NOT_CONNECTED; 01080 } 01081 01082 //Any error to report? 01083 if(error) 01084 break; 01085 } 01086 01087 //Return status code 01088 return error; 01089 } 01090 01091 01092 /** 01093 * @brief Gracefully close TLS session 01094 * @param[in] context Pointer to the TLS context 01095 **/ 01096 01097 error_t tlsShutdown(TlsContext *context) 01098 { 01099 //Either party may initiate a close by sending a close_notify alert 01100 return tlsShutdownEx(context, FALSE); 01101 } 01102 01103 01104 /** 01105 * @brief Gracefully close TLS session 01106 * @param[in] context Pointer to the TLS context 01107 * @param[in] waitForCloseNotify Wait for the close notify alert from the peer 01108 **/ 01109 01110 error_t tlsShutdownEx(TlsContext *context, bool_t waitForCloseNotify) 01111 { 01112 error_t error; 01113 size_t n; 01114 uint8_t *p; 01115 TlsContentType contentType; 01116 01117 //Invalid TLS context? 01118 if(context == NULL) 01119 return ERROR_INVALID_PARAMETER; 01120 01121 //Ensure the I/O callback functions are properly registered 01122 if(context->sendCallback == NULL || context->receiveCallback == NULL) 01123 return ERROR_NOT_CONFIGURED; 01124 01125 //Initialize status code 01126 error = NO_ERROR; 01127 01128 //Wait for the TLS session to be closed 01129 while(context->state != TLS_STATE_CLOSED) 01130 { 01131 //Check current state 01132 if(context->state == TLS_STATE_APPLICATION_DATA) 01133 { 01134 //Flush send buffer 01135 error = tlsWriteProtocolData(context, NULL, 0, TLS_TYPE_NONE); 01136 01137 //Check status code 01138 if(!error) 01139 { 01140 //Either party may initiate a close by sending a close_notify alert 01141 context->state = TLS_STATE_CLOSING; 01142 } 01143 } 01144 if(context->state == TLS_STATE_CLOSING) 01145 { 01146 //Flush send buffer 01147 error = tlsWriteProtocolData(context, NULL, 0, TLS_TYPE_NONE); 01148 01149 //Check status code 01150 if(!error) 01151 { 01152 //Unless some other fatal alert has been transmitted, each party 01153 //is required to send a close_notify alert before closing the 01154 //write side of the connection 01155 if(context->fatalAlertSent || context->fatalAlertReceived) 01156 { 01157 //Close the connection immediately 01158 context->state = TLS_STATE_CLOSED; 01159 } 01160 else if(!context->closeNotifySent) 01161 { 01162 //Notifies the recipient that the sender will not send any 01163 //more messages on this connection 01164 error = tlsSendAlert(context, TLS_ALERT_LEVEL_WARNING, 01165 TLS_ALERT_CLOSE_NOTIFY); 01166 } 01167 else if(!context->closeNotifyReceived && waitForCloseNotify) 01168 { 01169 //Wait for the responding close_notify alert 01170 error = tlsReadProtocolData(context, (void **) &p, &n, &contentType); 01171 01172 //Check status code 01173 if(!error) 01174 { 01175 //Application data received? 01176 if(contentType == TLS_TYPE_APPLICATION_DATA) 01177 { 01178 //Advance data pointer 01179 context->rxBufferPos += n; 01180 //Number of bytes still pending in the receive buffer 01181 context->rxBufferLen -= n; 01182 } 01183 //Alert message received? 01184 else if(contentType == TLS_TYPE_ALERT) 01185 { 01186 //Parse Alert message 01187 error = tlsParseAlert(context, (TlsAlert *) p, n); 01188 01189 //Advance data pointer 01190 context->rxBufferPos += n; 01191 //Number of bytes still pending in the receive buffer 01192 context->rxBufferLen -= n; 01193 } 01194 //An inappropriate message was received? 01195 else 01196 { 01197 //Report an error 01198 error = ERROR_UNEXPECTED_MESSAGE; 01199 } 01200 } 01201 } 01202 else 01203 { 01204 //The connection is closed 01205 context->state = TLS_STATE_CLOSED; 01206 } 01207 } 01208 } 01209 else 01210 { 01211 //Report an error 01212 error = ERROR_NOT_CONNECTED; 01213 } 01214 01215 //Any error to report? 01216 if(error) 01217 break; 01218 } 01219 01220 //Return status code 01221 return error; 01222 } 01223 01224 01225 /** 01226 * @brief Release TLS context 01227 * @param[in] context Pointer to the TLS context 01228 **/ 01229 01230 void tlsFree(TlsContext *context) 01231 { 01232 //Valid TLS context? 01233 if(context != NULL) 01234 { 01235 //Release server name 01236 if(context->serverName != NULL) 01237 tlsFreeMem(context->serverName); 01238 01239 #if (TLS_ALPN_SUPPORT == ENABLED) 01240 //Release the list of supported protocols 01241 if(context->protocolList != NULL) 01242 tlsFreeMem(context->protocolList); 01243 #endif 01244 01245 #if (TLS_PSK_SUPPORT == ENABLED || TLS_RSA_PSK_SUPPORT == ENABLED || \ 01246 TLS_DHE_PSK_SUPPORT == ENABLED || TLS_ECDHE_PSK_SUPPORT == ENABLED) 01247 //Release the pre-shared key 01248 if(context->psk != NULL) 01249 { 01250 memset(context->psk, 0, context->pskLen); 01251 tlsFreeMem(context->psk); 01252 } 01253 01254 //Release the PSK identity 01255 if(context->pskIdentity != NULL) 01256 tlsFreeMem(context->pskIdentity); 01257 01258 //Release the PSK identity hint 01259 if(context->pskIdentityHint != NULL) 01260 tlsFreeMem(context->pskIdentityHint); 01261 #endif 01262 01263 #if (TLS_DH_ANON_SUPPORT == ENABLED || TLS_DHE_RSA_SUPPORT == ENABLED || \ 01264 TLS_DHE_DSS_SUPPORT == ENABLED || TLS_DHE_PSK_SUPPORT == ENABLED) 01265 //Release Diffie-Hellman context 01266 dhFree(&context->dhContext); 01267 #endif 01268 01269 #if (TLS_ECDH_ANON_SUPPORT == ENABLED || TLS_ECDHE_RSA_SUPPORT == ENABLED || \ 01270 TLS_ECDHE_ECDSA_SUPPORT == ENABLED || TLS_ECDHE_PSK_SUPPORT == ENABLED) 01271 //Release ECDH context 01272 ecdhFree(&context->ecdhContext); 01273 #endif 01274 01275 #if (TLS_RSA_SIGN_SUPPORT == ENABLED || TLS_RSA_SUPPORT == ENABLED || \ 01276 TLS_DHE_RSA_SUPPORT == ENABLED || TLS_ECDHE_RSA_SUPPORT == ENABLED) 01277 //Release peer's RSA public key 01278 rsaFreePublicKey(&context->peerRsaPublicKey); 01279 #endif 01280 01281 #if (TLS_DSA_SIGN_SUPPORT == ENABLED || TLS_DHE_DSS_SUPPORT == ENABLED) 01282 //Release peer's DSA public key 01283 dsaFreePublicKey(&context->peerDsaPublicKey); 01284 #endif 01285 01286 #if (TLS_ECDSA_SIGN_SUPPORT == ENABLED || TLS_ECDHE_ECDSA_SUPPORT == ENABLED) 01287 //Release peer's EC domain parameters 01288 ecFreeDomainParameters(&context->peerEcParams); 01289 //Release peer's EC public key 01290 ecFree(&context->peerEcPublicKey); 01291 #endif 01292 01293 //Release send buffer 01294 if(context->txBuffer != NULL) 01295 { 01296 memset(context->txBuffer, 0, context->txBufferSize); 01297 tlsFreeMem(context->txBuffer); 01298 } 01299 01300 //Release receive buffer 01301 if(context->rxBuffer != NULL) 01302 { 01303 memset(context->rxBuffer, 0, context->rxBufferSize); 01304 tlsFreeMem(context->rxBuffer); 01305 } 01306 01307 //Release the MD5 context used to compute verify data 01308 if(context->handshakeMd5Context != NULL) 01309 { 01310 memset(context->handshakeMd5Context, 0, sizeof(Md5Context)); 01311 tlsFreeMem(context->handshakeMd5Context); 01312 } 01313 01314 //Release the SHA-1 context used to compute verify data 01315 if(context->handshakeSha1Context != NULL) 01316 { 01317 memset(context->handshakeSha1Context, 0, sizeof(Sha1Context)); 01318 tlsFreeMem(context->handshakeSha1Context); 01319 } 01320 01321 //Release the hash context used to compute verify data (TLS 1.2) 01322 if(context->handshakeHashContext != NULL) 01323 { 01324 memset(context->handshakeHashContext, 0, context->prfHashAlgo->contextSize); 01325 tlsFreeMem(context->handshakeHashContext); 01326 } 01327 01328 //Release the encryption context (TX path) 01329 if(context->writeCipherContext != NULL) 01330 { 01331 memset(context->writeCipherContext, 0, context->cipherAlgo->contextSize); 01332 tlsFreeMem(context->writeCipherContext); 01333 } 01334 01335 //Release the encryption context (RX path) 01336 if(context->readCipherContext != NULL) 01337 { 01338 memset(context->readCipherContext, 0, context->cipherAlgo->contextSize); 01339 tlsFreeMem(context->readCipherContext); 01340 } 01341 01342 #if (TLS_GCM_CIPHER_SUPPORT == ENABLED) 01343 //Release the GCM context (TX path) 01344 if(context->writeGcmContext != NULL) 01345 { 01346 memset(context->writeGcmContext, 0, sizeof(GcmContext)); 01347 tlsFreeMem(context->writeGcmContext); 01348 } 01349 01350 //Release the GCM context (RX path) 01351 if(context->readGcmContext != NULL) 01352 { 01353 memset(context->readGcmContext, 0, sizeof(GcmContext)); 01354 tlsFreeMem(context->readGcmContext); 01355 } 01356 #endif 01357 01358 //Clear the TLS context before freeing memory 01359 memset(context, 0, sizeof(TlsContext)); 01360 tlsFreeMem(context); 01361 } 01362 } 01363 01364 01365 /** 01366 * @brief Save TLS session 01367 * @param[in] context Pointer to the TLS context 01368 * @param[out] session Buffer where to store the current session parameters 01369 * @return Error code 01370 **/ 01371 01372 error_t tlsSaveSession(const TlsContext *context, TlsSession *session) 01373 { 01374 //Check parameters 01375 if(context == NULL || session == NULL) 01376 return ERROR_INVALID_PARAMETER; 01377 01378 //Invalid session parameters? 01379 if(!context->sessionIdLen || !context->cipherSuite) 01380 return ERROR_FAILURE; 01381 01382 //Save session identifier 01383 memcpy(session->id, context->sessionId, context->sessionIdLen); 01384 session->idLength = context->sessionIdLen; 01385 01386 //Get current time 01387 session->timestamp = osGetSystemTime(); 01388 01389 //Negotiated cipher suite and compression method 01390 session->cipherSuite = context->cipherSuite; 01391 session->compressionMethod = context->compressionMethod; 01392 01393 //Save master secret 01394 memcpy(session->masterSecret, context->masterSecret, 48); 01395 01396 //Successful processing 01397 return NO_ERROR; 01398 } 01399 01400 01401 /** 01402 * @brief Restore TLS session 01403 * @param[in] context Pointer to the TLS context 01404 * @param[in] session Pointer to the session to be restored 01405 * @return Error code 01406 **/ 01407 01408 error_t tlsRestoreSession(TlsContext *context, const TlsSession *session) 01409 { 01410 //Check parameters 01411 if(context == NULL || session == NULL) 01412 return ERROR_INVALID_PARAMETER; 01413 01414 //Restore session identifier 01415 memcpy(context->sessionId, session->id, session->idLength); 01416 context->sessionIdLen = session->idLength; 01417 01418 //Negotiated cipher suite and compression method 01419 context->cipherSuite = session->cipherSuite; 01420 context->compressionMethod = session->compressionMethod; 01421 01422 //Restore master secret 01423 memcpy(context->masterSecret, session->masterSecret, 48); 01424 01425 //Successful processing 01426 return NO_ERROR; 01427 } 01428 01429 #endif 01430
Generated on Tue Jul 12 2022 17:10:17 by
