Webserver+3d print
Diff: cyclone_ssl/tls_client_misc.c
- Revision:
- 0:8918a71cdbe9
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cyclone_ssl/tls_client_misc.c Sat Feb 04 18:15:49 2017 +0000 @@ -0,0 +1,840 @@ +/** + * @file tls_client_misc.c + * @brief Helper functions (TLS client) + * + * @section License + * + * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved. + * + * This file is part of CycloneSSL Open. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * @author Oryx Embedded SARL (www.oryx-embedded.com) + * @version 1.7.6 + **/ + +//Switch to the appropriate trace level +#define TRACE_LEVEL TLS_TRACE_LEVEL + +//Dependencies +#include <string.h> +#include "tls.h" +#include "tls_cipher_suites.h" +#include "tls_client.h" +#include "tls_client_misc.h" +#include "tls_common.h" +#include "tls_record.h" +#include "tls_cache.h" +#include "tls_misc.h" +#include "debug.h" + +//Check SSL library configuration +#if (TLS_SUPPORT == ENABLED && TLS_CLIENT_SUPPORT == ENABLED) + + +/** + * @brief Format PSK identity + * @param[in] context Pointer to the TLS context + * @param[in] p Output stream where to write the PSK identity hint + * @param[out] written Total number of bytes that have been written + * @return Error code + **/ + +error_t tlsFormatPskIdentity(TlsContext *context, + uint8_t *p, size_t *written) +{ + size_t n; + TlsPskIdentity *pskIdentity; + + //Point to the PSK identity + pskIdentity = (TlsPskIdentity *) p; + + //Initialize length field + n = 0; + +#if (TLS_PSK_SUPPORT == ENABLED || TLS_RSA_PSK_SUPPORT == ENABLED || \ + TLS_DHE_PSK_SUPPORT == ENABLED || TLS_ECDHE_PSK_SUPPORT == ENABLED) + //Any registered callback? + if(context->pskCallback != NULL) + { + error_t error; + + //Invoke user callback function + if(context->pskIdentityHint != NULL) + error = context->pskCallback(context, context->pskIdentityHint); + else + error = context->pskCallback(context, ""); + + //Any error to report? + if(error) + return ERROR_UNKNOWN_IDENTITY; + } + + //Any PSK identity defined? + if(context->pskIdentity != NULL) + { + //Determine the length of the PSK identity + n = strlen(context->pskIdentity); + //Copy PSK identity + memcpy(pskIdentity->value, context->pskIdentity, n); + } +#endif + + //The PSK identity is preceded by a 2-byte length field + pskIdentity->length = htons(n); + + //Total number of bytes that have been written + *written = sizeof(TlsPskIdentity) + n; + + //Successful processing + return NO_ERROR; +} + + +/** + * @brief Format client's key exchange parameters + * @param[in] context Pointer to the TLS context + * @param[in] p Output stream where to write the PSK identity hint + * @param[out] written Total number of bytes that have been written + * @return Error code + **/ + +error_t tlsFormatClientKeyParams(TlsContext *context, + uint8_t *p, size_t *written) +{ +#if (TLS_RSA_SUPPORT == ENABLED || TLS_RSA_PSK_SUPPORT == ENABLED) + //RSA key exchange method? + if(context->keyExchMethod == TLS_KEY_EXCH_RSA || + context->keyExchMethod == TLS_KEY_EXCH_RSA_PSK) + { + error_t error; + size_t n; + + //Sanity check + if(TLS_MAX_PREMASTER_SECRET_SIZE < 48) + return ERROR_BUFFER_OVERFLOW; + + //If RSA is being used for key agreement and authentication, the + //client generates a 48-byte premaster secret + context->premasterSecretLen = 48; + + //The first 2 bytes code the latest version supported by the client + STORE16BE(TLS_MAX_VERSION, context->premasterSecret); + + //The last 46 bytes contain securely-generated random bytes + error = context->prngAlgo->read(context->prngContext, + context->premasterSecret + 2, 46); + //Any error to report? + if(error) + return error; + + //The RSA-encrypted premaster secret in a ClientKeyExchange is preceded by + //two length bytes. SSL 3.0 implementations do not include these bytes + if(context->version > SSL_VERSION_3_0) + { + //Encrypt the premaster secret using the server public key + error = rsaesPkcs1v15Encrypt(context->prngAlgo, context->prngContext, + &context->peerRsaPublicKey, context->premasterSecret, 48, p + 2, &n); + //RSA encryption failed? + if(error) + return error; + + //Write the length field + STORE16BE(n, p); + + //Length of the resulting octet string + n += 2; + } + else + { + //Encrypt the premaster secret using the server public key + error = rsaesPkcs1v15Encrypt(context->prngAlgo, context->prngContext, + &context->peerRsaPublicKey, context->premasterSecret, 48, p, &n); + //RSA encryption failed? + if(error) + return error; + } + + //Total number of bytes that have been written + *written = n; + } + else +#endif +#if (TLS_DH_ANON_SUPPORT == ENABLED || TLS_DHE_RSA_SUPPORT == ENABLED || \ + TLS_DHE_DSS_SUPPORT == ENABLED || TLS_DHE_PSK_SUPPORT == ENABLED) + //Diffie-Hellman key exchange method? + if(context->keyExchMethod == TLS_KEY_EXCH_DH_ANON || + context->keyExchMethod == TLS_KEY_EXCH_DHE_RSA || + context->keyExchMethod == TLS_KEY_EXCH_DHE_DSS || + context->keyExchMethod == TLS_KEY_EXCH_DHE_PSK) + { + error_t error; + size_t n; + + //Generate an ephemeral key pair + error = dhGenerateKeyPair(&context->dhContext, + context->prngAlgo, context->prngContext); + //Any error to report? + if(error) + return error; + + //Encode the client's public value to an opaque vector + error = tlsWriteMpi(&context->dhContext.ya, p, &n); + //Any error to report? + if(error) + return error; + + //Total number of bytes that have been written + *written = n; + + //Calculate the negotiated key Z + error = dhComputeSharedSecret(&context->dhContext, context->premasterSecret, + TLS_MAX_PREMASTER_SECRET_SIZE, &context->premasterSecretLen); + //Any error to report? + if(error) + return error; + + //Leading bytes of Z that contain all zero bits are stripped before + //it is used as the premaster secret (RFC 4346, section 8.2.1) + for(n = 0; n < context->premasterSecretLen; n++) + { + if(context->premasterSecret[n] != 0x00) + break; + } + + //Any leading zero bytes? + if(n > 0) + { + //Strip leading zero bytes from the negotiated key + memmove(context->premasterSecret, context->premasterSecret + n, + context->premasterSecretLen - n); + + //Adjust the length of the premaster secret + context->premasterSecretLen -= n; + } + } + else +#endif +#if (TLS_ECDH_ANON_SUPPORT == ENABLED || TLS_ECDHE_RSA_SUPPORT == ENABLED || \ + TLS_ECDHE_ECDSA_SUPPORT == ENABLED || TLS_ECDHE_PSK_SUPPORT == ENABLED) + //ECDH key exchange method? + if(context->keyExchMethod == TLS_KEY_EXCH_ECDH_ANON || + context->keyExchMethod == TLS_KEY_EXCH_ECDHE_RSA || + context->keyExchMethod == TLS_KEY_EXCH_ECDHE_ECDSA || + context->keyExchMethod == TLS_KEY_EXCH_ECDHE_PSK) + { + error_t error; + size_t n; + + //Generate an ephemeral key pair + error = ecdhGenerateKeyPair(&context->ecdhContext, + context->prngAlgo, context->prngContext); + //Any error to report? + if(error) + return error; + + //Encode the client's public key to an opaque vector + error = tlsWriteEcPoint(&context->ecdhContext.params, + &context->ecdhContext.qa, p, &n); + //Any error to report? + if(error) + return error; + + //Total number of bytes that have been written + *written = n; + + //Calculate the negotiated key Z + error = ecdhComputeSharedSecret(&context->ecdhContext, context->premasterSecret, + TLS_MAX_PREMASTER_SECRET_SIZE, &context->premasterSecretLen); + //Any error to report? + if(error) + return error; + } + else +#endif + //Invalid key exchange method? + { + //The specified key exchange method is not supported + return ERROR_UNSUPPORTED_KEY_EXCH_METHOD; + } + + //Successful processing + return NO_ERROR; +} + + +/** + * @brief Parse PSK identity hint + * @param[in] context Pointer to the TLS context + * @param[in] p Input stream where to read the PSK identity hint + * @param[in] length Number of bytes available in the input stream + * @param[out] consumed Total number of bytes that have been consumed + * @return Error code + **/ + +error_t tlsParsePskIdentityHint(TlsContext *context, + const uint8_t *p, size_t length, size_t *consumed) +{ + size_t n; + TlsPskIdentityHint *pskIdentityHint; + + //Malformed ServerKeyExchange message? + if(length < sizeof(TlsPskIdentityHint)) + return ERROR_DECODING_FAILED; + + //Point to the PSK identity hint + pskIdentityHint = (TlsPskIdentityHint *) p; + + //Retrieve the length of the PSK identity hint + n = ntohs(pskIdentityHint->length); + + //Make sure the length field is valid + if(length < (sizeof(TlsPskIdentityHint) + n)) + return ERROR_DECODING_FAILED; + +#if (TLS_PSK_SUPPORT == ENABLED || TLS_RSA_PSK_SUPPORT == ENABLED || \ + TLS_DHE_PSK_SUPPORT == ENABLED || TLS_ECDHE_PSK_SUPPORT == ENABLED) + //Check whether the PSK identity hint has already been configured + if(context->pskIdentityHint != NULL) + { + //Release memory + tlsFreeMem(context->pskIdentityHint); + context->pskIdentityHint = NULL; + } + + //The PSK identity hint is optional + if(n > 0) + { + //Allocate a memory block to hold the PSK identity hint + context->pskIdentityHint = tlsAllocMem(n + 1); + //Failed to allocate memory? + if(context->pskIdentityHint == NULL) + return ERROR_OUT_OF_MEMORY; + + //Save the PSK identity hint + memcpy(context->pskIdentityHint, pskIdentityHint->value, n); + //Properly terminate the string + context->pskIdentityHint[n] = '\0'; + } +#endif + + //Total number of bytes that have been consumed + *consumed = sizeof(TlsPskIdentityHint) + n; + + //Successful processing + return NO_ERROR; +} + + +/** + * @brief Parse server's key exchange parameters + * @param[in] context Pointer to the TLS context + * @param[in] p Input stream where to read the server's key exchange parameters + * @param[in] length Number of bytes available in the input stream + * @param[out] consumed Total number of bytes that have been consumed + * @return Error code + **/ + +error_t tlsParseServerKeyParams(TlsContext *context, + const uint8_t *p, size_t length, size_t *consumed) +{ + error_t error; + const uint8_t *params; + + //Initialize status code + error = NO_ERROR; + + //Point to the server's key exchange parameters + params = p; + +#if (TLS_DH_ANON_SUPPORT == ENABLED || TLS_DHE_RSA_SUPPORT == ENABLED || \ + TLS_DHE_DSS_SUPPORT == ENABLED || TLS_DHE_PSK_SUPPORT == ENABLED) + //Diffie-Hellman key exchange method? + if(context->keyExchMethod == TLS_KEY_EXCH_DH_ANON || + context->keyExchMethod == TLS_KEY_EXCH_DHE_RSA || + context->keyExchMethod == TLS_KEY_EXCH_DHE_DSS || + context->keyExchMethod == TLS_KEY_EXCH_DHE_PSK) + { + uint_t k; + size_t n; + + //Convert the prime modulus to a multiple precision integer + error = tlsReadMpi(&context->dhContext.params.p, p, length, &n); + + //Check status code + if(!error) + { + //Get the length of the prime modulus, in bits + k = mpiGetBitLength(&context->dhContext.params.p); + + //Make sure the prime modulus is acceptable + if(k < TLS_MIN_DH_MODULUS_SIZE || k > TLS_MAX_DH_MODULUS_SIZE) + error = ERROR_ILLEGAL_PARAMETER; + } + + //Check status code + if(!error) + { + //Advance data pointer + p += n; + //Remaining bytes to process + length -= n; + + //Convert the generator to a multiple precision integer + error = tlsReadMpi(&context->dhContext.params.g, p, length, &n); + } + + //Check status code + if(!error) + { + //Advance data pointer + p += n; + //Remaining bytes to process + length -= n; + + //Convert the server's public value to a multiple precision integer + error = tlsReadMpi(&context->dhContext.yb, p, length, &n); + } + + //Check status code + if(!error) + { + //Advance data pointer + p += n; + //Remaining bytes to process + length -= n; + + //Verify peer's public value + error = dhCheckPublicKey(&context->dhContext.params, + &context->dhContext.yb); + } + + //Check status code + if(!error) + { + //Debug message + TRACE_DEBUG("Diffie-Hellman parameters:\r\n"); + TRACE_DEBUG(" Prime modulus:\r\n"); + TRACE_DEBUG_MPI(" ", &context->dhContext.params.p); + TRACE_DEBUG(" Generator:\r\n"); + TRACE_DEBUG_MPI(" ", &context->dhContext.params.g); + TRACE_DEBUG(" Server public value:\r\n"); + TRACE_DEBUG_MPI(" ", &context->dhContext.yb); + } + } + else +#endif +#if (TLS_ECDH_ANON_SUPPORT == ENABLED || TLS_ECDHE_RSA_SUPPORT == ENABLED || \ + TLS_ECDHE_ECDSA_SUPPORT == ENABLED || TLS_ECDHE_PSK_SUPPORT == ENABLED) + //ECDH key exchange method? + if(context->keyExchMethod == TLS_KEY_EXCH_ECDH_ANON || + context->keyExchMethod == TLS_KEY_EXCH_ECDHE_RSA || + context->keyExchMethod == TLS_KEY_EXCH_ECDHE_ECDSA || + context->keyExchMethod == TLS_KEY_EXCH_ECDHE_PSK) + { + size_t n; + uint8_t curveType; + uint16_t namedCurve; + const EcCurveInfo *curveInfo; + + //Malformed ServerKeyExchange message? + if(length < sizeof(curveType)) + error = ERROR_DECODING_FAILED; + + //Check status code + if(!error) + { + //Retrieve the type of the elliptic curve domain parameters + curveType = *p; + + //Advance data pointer + p += sizeof(curveType); + //Remaining bytes to process + length -= sizeof(curveType); + + //Only named curves are supported + if(curveType != TLS_EC_CURVE_TYPE_NAMED_CURVE) + error = ERROR_ILLEGAL_PARAMETER; + } + + //Check status code + if(!error) + { + //Malformed ServerKeyExchange message? + if(length < sizeof(namedCurve)) + error = ERROR_DECODING_FAILED; + } + + //Check status code + if(!error) + { + //Get elliptic curve identifier + namedCurve = LOAD16BE(p); + + //Advance data pointer + p += sizeof(namedCurve); + //Remaining bytes to process + length -= sizeof(namedCurve); + + //Retrieve the corresponding EC domain parameters + curveInfo = tlsGetCurveInfo(namedCurve); + + //Make sure the elliptic curve is supported + if(curveInfo == NULL) + error = ERROR_ILLEGAL_PARAMETER; + } + + //Check status code + if(!error) + { + //Load EC domain parameters + error = ecLoadDomainParameters(&context->ecdhContext.params, + curveInfo); + } + + //Check status code + if(!error) + { + //Read server's public key + error = tlsReadEcPoint(&context->ecdhContext.params, + &context->ecdhContext.qb, p, length, &n); + } + + //Check status code + if(!error) + { + //Advance data pointer + p += n; + //Remaining bytes to process + length -= n; + + //Verify peer's public key + error = ecdhCheckPublicKey(&context->ecdhContext.params, &context->ecdhContext.qb); + } + + //Check status code + if(!error) + { + //Debug message + TRACE_DEBUG(" Server public key X:\r\n"); + TRACE_DEBUG_MPI(" ", &context->ecdhContext.qb.x); + TRACE_DEBUG(" Server public key Y:\r\n"); + TRACE_DEBUG_MPI(" ", &context->ecdhContext.qb.y); + } + } + else +#endif + //Invalid key exchange method? + { + //It is not legal to send the ServerKeyExchange message when a key + //exchange method other than DHE_DSS, DHE_RSA, DH_anon, ECDHE_RSA, + //ECDHE_ECDSA or ECDH_anon is selected + error = ERROR_UNEXPECTED_MESSAGE; + } + + //Total number of bytes that have been consumed + *consumed = p - params; + + //Return status code + return error; +} + + +/** + * @brief Verify signature over the server's key exchange parameters + * @param[in] context Pointer to the TLS context + * @param[in] p Input stream where to read the signature + * @param[in] length Number of bytes available in the input stream + * @param[in] params Pointer to the server's key exchange parameters + * @param[in] paramsLen Length of the server's key exchange parameters + * @param[out] consumed Total number of bytes that have been consumed + * @return Error code + **/ + +error_t tlsVerifyServerKeySignature(TlsContext *context, const uint8_t *p, + size_t length, const uint8_t *params, size_t paramsLen, size_t *consumed) +{ + error_t error; + + //Initialize status code + error = NO_ERROR; + +#if (TLS_MAX_VERSION >= SSL_VERSION_3_0 && TLS_MIN_VERSION <= TLS_VERSION_1_1) + //SSL 3.0, TLS 1.0 or TLS 1.1 currently selected? + if(context->version <= TLS_VERSION_1_1) + { + TlsDigitalSignature *signature; + + //Point to the digitally-signed element + signature = (TlsDigitalSignature *) p; + + //Check the length of the digitally-signed element + if(length < sizeof(TlsDigitalSignature)) + return ERROR_DECODING_FAILED; + if(length < (sizeof(TlsDigitalSignature) + ntohs(signature->length))) + return ERROR_DECODING_FAILED; + +#if (TLS_DHE_RSA_SUPPORT == ENABLED || TLS_ECDHE_RSA_SUPPORT == ENABLED) + //Check whether DHE_RSA or ECDHE_RSA key exchange method is currently used + if(context->keyExchMethod == TLS_KEY_EXCH_DHE_RSA || + context->keyExchMethod == TLS_KEY_EXCH_ECDHE_RSA) + { + Md5Context *md5Context; + Sha1Context *sha1Context; + + //Allocate a memory buffer to hold the MD5 context + md5Context = tlsAllocMem(sizeof(Md5Context)); + + //Successful memory allocation? + if(md5Context != NULL) + { + //Compute MD5(ClientHello.random + ServerHello.random + ServerDhParams) + md5Init(md5Context); + md5Update(md5Context, context->random, 64); + md5Update(md5Context, params, paramsLen); + md5Final(md5Context, context->verifyData); + + //Release previously allocated memory + tlsFreeMem(md5Context); + } + else + { + //Failed to allocate memory + error = ERROR_OUT_OF_MEMORY; + } + + //Check status code + if(!error) + { + //Allocate a memory buffer to hold the SHA-1 context + sha1Context = tlsAllocMem(sizeof(Sha1Context)); + + //Successful memory allocation? + if(sha1Context != NULL) + { + //Compute SHA(ClientHello.random + ServerHello.random + ServerDhParams) + sha1Init(sha1Context); + sha1Update(sha1Context, context->random, 64); + sha1Update(sha1Context, params, paramsLen); + sha1Final(sha1Context, context->verifyData + MD5_DIGEST_SIZE); + + //Release previously allocated memory + tlsFreeMem(sha1Context); + } + else + { + //Failed to allocate memory + error = ERROR_OUT_OF_MEMORY; + } + } + + //Check status code + if(!error) + { + //RSA signature verification + error = tlsVerifyRsaSignature(&context->peerRsaPublicKey, + context->verifyData, signature->value, ntohs(signature->length)); + } + } + else +#endif +#if (TLS_DHE_DSS_SUPPORT == ENABLED) + //Check whether DHE_DSS key exchange method is currently used + if(context->keyExchMethod == TLS_KEY_EXCH_DHE_DSS) + { + Sha1Context *sha1Context; + + //Allocate a memory buffer to hold the SHA-1 context + sha1Context = tlsAllocMem(sizeof(Sha1Context)); + + //Successful memory allocation? + if(sha1Context != NULL) + { + //Compute SHA(ClientHello.random + ServerHello.random + ServerDhParams) + sha1Init(sha1Context); + sha1Update(sha1Context, context->random, 64); + sha1Update(sha1Context, params, paramsLen); + sha1Final(sha1Context, context->verifyData); + + //Release previously allocated memory + tlsFreeMem(sha1Context); + } + else + { + //Failed to allocate memory + error = ERROR_OUT_OF_MEMORY; + } + + //Check status code + if(!error) + { + //DSA signature verification + error = tlsVerifyDsaSignature(&context->peerDsaPublicKey, context->verifyData, + SHA1_DIGEST_SIZE, signature->value, ntohs(signature->length)); + } + } + else +#endif +#if (TLS_ECDHE_ECDSA_SUPPORT == ENABLED) + //Check whether ECDHE_ECDSA key exchange method is currently used + if(context->keyExchMethod == TLS_KEY_EXCH_ECDHE_ECDSA) + { + Sha1Context *sha1Context; + + //Allocate a memory buffer to hold the SHA-1 context + sha1Context = tlsAllocMem(sizeof(Sha1Context)); + + //Successful memory allocation? + if(sha1Context != NULL) + { + //Compute SHA(ClientHello.random + ServerHello.random + ServerDhParams) + sha1Init(sha1Context); + sha1Update(sha1Context, context->random, 64); + sha1Update(sha1Context, params, paramsLen); + sha1Final(sha1Context, context->verifyData); + + //Release previously allocated memory + tlsFreeMem(sha1Context); + } + + //Check status code + if(!error) + { + //ECDSA signature verification + error = tlsVerifyEcdsaSignature(&context->peerEcParams, + &context->peerEcPublicKey, context->verifyData, + SHA1_DIGEST_SIZE, signature->value, ntohs(signature->length)); + } + } + else +#endif + //Invalid signature algorithm? + { + //Report an error + error = ERROR_UNSUPPORTED_SIGNATURE_ALGO; + } + + //Total number of bytes that have been consumed + *consumed = sizeof(TlsDigitalSignature) + ntohs(signature->length); + } + else +#endif +#if (TLS_MAX_VERSION >= TLS_VERSION_1_2 && TLS_MIN_VERSION <= TLS_VERSION_1_2) + //TLS 1.2 currently selected? + if(context->version == TLS_VERSION_1_2) + { + TlsDigitalSignature2 *signature; + const HashAlgo *hashAlgo; + HashContext *hashContext; + + //Point to the digitally-signed element + signature = (TlsDigitalSignature2 *) p; + + //Check the length of the digitally-signed element + if(length < sizeof(TlsDigitalSignature2)) + return ERROR_DECODING_FAILED; + if(length < (sizeof(TlsDigitalSignature2) + ntohs(signature->length))) + return ERROR_DECODING_FAILED; + + //Retrieve the hash algorithm used for signing + hashAlgo = tlsGetHashAlgo(signature->algorithm.hash); + + //Make sure the hash algorithm is supported + if(hashAlgo != NULL) + { + //Allocate a memory buffer to hold the hash context + hashContext = tlsAllocMem(hashAlgo->contextSize); + + //Successful memory allocation? + if(hashContext != NULL) + { + //Compute SHA(ClientHello.random + ServerHello.random + ServerDhParams) + hashAlgo->init(hashContext); + hashAlgo->update(hashContext, context->random, 64); + hashAlgo->update(hashContext, params, paramsLen); + hashAlgo->final(hashContext, NULL); + +#if (TLS_DHE_RSA_SUPPORT == ENABLED || TLS_ECDHE_RSA_SUPPORT == ENABLED) + //Check whether DHE_RSA or ECDHE_RSA key exchange method is currently used + if((context->keyExchMethod == TLS_KEY_EXCH_DHE_RSA || + context->keyExchMethod == TLS_KEY_EXCH_ECDHE_RSA) && + signature->algorithm.signature == TLS_SIGN_ALGO_RSA) + { + //Use the signature verification algorithm defined in PKCS #1 v1.5 + error = rsassaPkcs1v15Verify(&context->peerRsaPublicKey, hashAlgo, + hashContext->digest, signature->value, ntohs(signature->length)); + } + else +#endif +#if (TLS_DHE_DSS_SUPPORT == ENABLED) + //Check whether DHE_DSS key exchange method is currently used + if(context->keyExchMethod == TLS_KEY_EXCH_DHE_DSS && + signature->algorithm.signature == TLS_SIGN_ALGO_DSA) + { + //DSA signature verification + error = tlsVerifyDsaSignature(&context->peerDsaPublicKey, hashContext->digest, + hashAlgo->digestSize, signature->value, ntohs(signature->length)); + } + else +#endif +#if (TLS_ECDHE_ECDSA_SUPPORT == ENABLED) + //Check whether DHE_ECDSA key exchange method is currently used + if(context->keyExchMethod == TLS_KEY_EXCH_ECDHE_ECDSA && + signature->algorithm.signature == TLS_SIGN_ALGO_ECDSA) + { + //ECDSA signature verification + error = tlsVerifyEcdsaSignature(&context->peerEcParams, &context->peerEcPublicKey, + hashContext->digest, hashAlgo->digestSize, signature->value, ntohs(signature->length)); + } + else +#endif + //Invalid signature algorithm? + { + //Report an error + error = ERROR_UNSUPPORTED_SIGNATURE_ALGO; + } + + //Release previously allocated memory + tlsFreeMem(hashContext); + } + else + { + //Failed to allocate memory + error = ERROR_OUT_OF_MEMORY; + } + } + else + { + //Hash algorithm not supported + error = ERROR_INVALID_SIGNATURE; + } + + //Total number of bytes that have been consumed + *consumed = sizeof(TlsDigitalSignature2) + ntohs(signature->length); + } + else +#endif + { + //The negotiated TLS version is not valid + error = ERROR_INVALID_VERSION; + } + + //Return status code + return error; +} + +#endif +