MatrixSSL 3.8.3 Open
This commit is contained in:
471
matrixssl/hsHash.c
Normal file
471
matrixssl/hsHash.c
Normal file
@@ -0,0 +1,471 @@
|
||||
/**
|
||||
* @file hsHash.c
|
||||
* @version $Format:%h%d$
|
||||
*
|
||||
* "Native" handshake hash.
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2013-2016 INSIDE Secure Corporation
|
||||
* Copyright (c) PeerSec Networks, 2002-2011
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The latest version of this code is available at http://www.matrixssl.org
|
||||
*
|
||||
* This software is open source; 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 General Public License does NOT permit incorporating this software
|
||||
* into proprietary programs. If you are unable to comply with the GPL, a
|
||||
* commercial license for this software may be purchased from INSIDE at
|
||||
* http://www.insidesecure.com/
|
||||
*
|
||||
* This program is distributed in 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#include "matrixsslApi.h"
|
||||
|
||||
|
||||
#define FINISHED_LABEL_SIZE 15
|
||||
#define LABEL_CLIENT "client finished"
|
||||
#define LABEL_SERVER "server finished"
|
||||
/******************************************************************************/
|
||||
/**
|
||||
Initialize the SHA1 and MD5 hash contexts for the handshake messages.
|
||||
The handshake hashes are used in 3 messages in TLS:
|
||||
ClientFinished, ServerFinished and ClientCertificateVerify.
|
||||
The version of TLS affects which hashes are used for the Finished messages.
|
||||
TLS 1.2 allows a different hash algorithm for the CertificatVerify message
|
||||
than is used by the Finished messages, determined by the
|
||||
Signature Algorithms extension.
|
||||
Multiple handshake hash contexts must be maintained until the handshake has
|
||||
progressed enough to determine the negotiated TLS version and whether or
|
||||
not Client Authentication is to be performed. Also, if USE_ONLY_TLS_1_2 is
|
||||
defined at compile time, or USE_CLIENT_AUTH is undefined at compile time,
|
||||
the potential runtime combinations are reduced.
|
||||
The various algorithms are used as follows (+ means concatenation):
|
||||
Client and Server Finished messages
|
||||
< TLS 1.2 - MD5+SHA1
|
||||
TLS 1.2 - SHA256
|
||||
Client CertificateVerify message.
|
||||
< TLS 1.2 - MD5+SHA1
|
||||
TLS 1.2 - One of the hashes present in the union of the
|
||||
SignatureAlgorithms Client extension and the CertificateRequest
|
||||
message from the server. At most this is the set
|
||||
{SHA1,SHA256,SHA384,SHA512}.
|
||||
@return < 0 on failure.
|
||||
@param[in,out] ssl TLS context
|
||||
*/
|
||||
int32_t sslInitHSHash(ssl_t *ssl)
|
||||
{
|
||||
#ifdef USE_DTLS
|
||||
if (ssl->flags & SSL_FLAGS_DTLS) {
|
||||
/* Don't allow CLIENT_HELLO message retransmit to reset hash */
|
||||
if (ssl->retransmit) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif /* USE_DTLS */
|
||||
|
||||
#ifndef USE_ONLY_TLS_1_2
|
||||
psMd5Sha1Init(&ssl->sec.msgHashMd5Sha1);
|
||||
#endif
|
||||
|
||||
#ifdef USE_TLS_1_2
|
||||
psSha256Init(&ssl->sec.msgHashSha256);
|
||||
#ifdef USE_SHA1
|
||||
psSha1Init(&ssl->sec.msgHashSha1);
|
||||
#endif
|
||||
#ifdef USE_SHA384
|
||||
psSha384Init(&ssl->sec.msgHashSha384);
|
||||
#endif
|
||||
#ifdef USE_SHA512
|
||||
psSha512Init(&ssl->sec.msgHashSha512);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/**
|
||||
Add the given data to the running hash of the handshake messages.
|
||||
@param[in,out] ssl TLS context
|
||||
@param[in] in Pointer to handshake data to hash.
|
||||
@param[in] len Number of bytes of handshake data to hash.
|
||||
@return < 0 on failure.
|
||||
*/
|
||||
int32_t sslUpdateHSHash(ssl_t *ssl, const unsigned char *in, uint16_t len)
|
||||
{
|
||||
|
||||
#ifdef USE_DTLS
|
||||
if (ssl->flags & SSL_FLAGS_DTLS) {
|
||||
/* Don't update handshake hashes on resends. Already been through here */
|
||||
if (ssl->retransmit) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif /* USE_DTLS */
|
||||
|
||||
#ifdef USE_TLS_1_2
|
||||
/* Keep a running total of each for greatest RFC support when it comes
|
||||
to the CertificateVerify message. Although, trying to be smart
|
||||
about MD5 and SHA-2 based on protocol version. */
|
||||
if ((ssl->majVer == 0 && ssl->minVer == 0) ||
|
||||
#ifdef USE_DTLS
|
||||
ssl->minVer == DTLS_1_2_MIN_VER ||
|
||||
#endif
|
||||
ssl->minVer == TLS_1_2_MIN_VER) {
|
||||
psSha256Update(&ssl->sec.msgHashSha256, in, len);
|
||||
#ifdef USE_SHA1
|
||||
psSha1Update(&ssl->sec.msgHashSha1, in, len);
|
||||
#endif
|
||||
#ifdef USE_SHA384
|
||||
psSha384Update(&ssl->sec.msgHashSha384, in, len);
|
||||
#endif
|
||||
#ifdef USE_SHA512
|
||||
psSha512Update(&ssl->sec.msgHashSha512, in, len);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef USE_ONLY_TLS_1_2
|
||||
/* Below TLS 1.2, the hash is always the md5sha1 hash. If we negotiate
|
||||
to TLS 1.2 and need sha1, we use just that part of the md5Sha1. */
|
||||
//TODO if (ssl->reqMinVer == 0 || ssl->minVer != TLS_1_2_MIN_VER) {
|
||||
psMd5Sha1Update(&ssl->sec.msgHashMd5Sha1, in, len);
|
||||
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef USE_TLS_1_2
|
||||
/* Functions necessary to deal with needing to keep track of both SHA-1
|
||||
and SHA-256 handshake hash states. FINISHED message will always be
|
||||
SHA-256 but client might be sending SHA-1 CertificateVerify message */
|
||||
#if defined(USE_SERVER_SIDE_SSL) && defined(USE_CLIENT_AUTH)
|
||||
#ifdef USE_SHA1
|
||||
int32 sslSha1RetrieveHSHash(ssl_t *ssl, unsigned char *out)
|
||||
{
|
||||
memcpy(out, ssl->sec.sha1Snapshot, SHA1_HASH_SIZE);
|
||||
return SHA1_HASH_SIZE;
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_SHA384
|
||||
int32 sslSha384RetrieveHSHash(ssl_t *ssl, unsigned char *out)
|
||||
{
|
||||
memcpy(out, ssl->sec.sha384Snapshot, SHA384_HASH_SIZE);
|
||||
return SHA384_HASH_SIZE;
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_SHA512
|
||||
int32 sslSha512RetrieveHSHash(ssl_t *ssl, unsigned char *out)
|
||||
{
|
||||
memcpy(out, ssl->sec.sha512Snapshot, SHA512_HASH_SIZE);
|
||||
return SHA512_HASH_SIZE;
|
||||
}
|
||||
#endif
|
||||
#endif /* USE_SERVER_SIDE_SSL && USE_CLIENT_AUTH */
|
||||
|
||||
#if defined(USE_CLIENT_SIDE_SSL) && defined(USE_CLIENT_AUTH)
|
||||
#ifdef USE_SHA1
|
||||
/* It is possible the certificate verify message wants a non-SHA256 hash */
|
||||
void sslSha1SnapshotHSHash(ssl_t *ssl, unsigned char *out)
|
||||
{
|
||||
psSha1Final(&ssl->sec.msgHashSha1, out);
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_SHA384
|
||||
void sslSha384SnapshotHSHash(ssl_t *ssl, unsigned char *out)
|
||||
{
|
||||
psSha384_t sha384;
|
||||
|
||||
/* SHA384 must copy the context because it could be needed again for
|
||||
final handshake hash. SHA1 doesn't need this because it will
|
||||
not ever be used again after this client auth one-off */
|
||||
psSha384Sync(&ssl->sec.msgHashSha384, 0);
|
||||
sha384 = ssl->sec.msgHashSha384;
|
||||
psSha384Final(&sha384, out);
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_SHA512
|
||||
void sslSha512SnapshotHSHash(ssl_t *ssl, unsigned char *out)
|
||||
{
|
||||
psSha512_t sha512;
|
||||
|
||||
/* SHA512 must copy the context because it could be needed again for
|
||||
final handshake hash. SHA1 doesn't need this because it will
|
||||
not ever be used again after this client auth one-off */
|
||||
psSha512Sync(&ssl->sec.msgHashSha512, 0);
|
||||
sha512 = ssl->sec.msgHashSha512;
|
||||
psSha512Final(&sha512, out);
|
||||
}
|
||||
#endif
|
||||
#endif /* USE_CLIENT_SIDE_SSL && USE_CLIENT_AUTH */
|
||||
#endif /* USE_TLS_1_2 */
|
||||
|
||||
#ifdef USE_TLS
|
||||
/******************************************************************************/
|
||||
/*
|
||||
TLS handshake hash computation
|
||||
*/
|
||||
static int32_t tlsGenerateFinishedHash(ssl_t *ssl,
|
||||
#ifndef USE_ONLY_TLS_1_2
|
||||
psMd5Sha1_t *md5sha1,
|
||||
#endif
|
||||
#ifdef USE_TLS_1_2
|
||||
#ifdef USE_SHA1
|
||||
psSha1_t *sha1,
|
||||
#endif
|
||||
#ifdef USE_SHA256
|
||||
psSha256_t *sha256,
|
||||
#endif
|
||||
#ifdef USE_SHA384
|
||||
psSha384_t *sha384,
|
||||
#endif
|
||||
#ifdef USE_SHA512
|
||||
psSha512_t *sha512,
|
||||
#endif
|
||||
#endif /* USE_TLS_1_2 */
|
||||
unsigned char *masterSecret,
|
||||
unsigned char *out, int32 senderFlag)
|
||||
{
|
||||
unsigned char tmp[FINISHED_LABEL_SIZE + SHA384_HASH_SIZE];
|
||||
|
||||
#ifndef USE_ONLY_TLS_1_2
|
||||
psMd5Sha1_t md5sha1_backup;
|
||||
#endif
|
||||
#ifdef USE_SHA1
|
||||
psSha1_t sha1_backup;
|
||||
#endif
|
||||
#ifdef USE_SHA256
|
||||
psSha256_t sha256_backup;
|
||||
#endif
|
||||
#ifdef USE_SHA384
|
||||
psSha384_t sha384_backup;
|
||||
#endif
|
||||
#ifdef USE_SHA512
|
||||
psSha512_t sha512_backup;
|
||||
#endif
|
||||
/*
|
||||
In each branch: Use a backup of the message hash-to-date because we don't
|
||||
want to destroy the state of the handshaking until truly complete
|
||||
*/
|
||||
|
||||
if (senderFlag >= 0) {
|
||||
memcpy(tmp, (senderFlag & SSL_FLAGS_SERVER) ? LABEL_SERVER : LABEL_CLIENT,
|
||||
FINISHED_LABEL_SIZE);
|
||||
#ifdef USE_TLS_1_2
|
||||
if (ssl->flags & SSL_FLAGS_TLS_1_2) {
|
||||
if (ssl->cipher->flags & CRYPTO_FLAGS_SHA3) {
|
||||
#ifdef USE_SHA384
|
||||
psSha384Cpy(&sha384_backup, sha384);
|
||||
psSha384Final(&sha384_backup, tmp + FINISHED_LABEL_SIZE);
|
||||
return prf2(masterSecret, SSL_HS_MASTER_SIZE, tmp,
|
||||
FINISHED_LABEL_SIZE + SHA384_HASH_SIZE, out,
|
||||
TLS_HS_FINISHED_SIZE, CRYPTO_FLAGS_SHA3);
|
||||
#endif
|
||||
} else {
|
||||
psSha256Cpy(&sha256_backup, sha256);
|
||||
psSha256Final(&sha256_backup, tmp + FINISHED_LABEL_SIZE);
|
||||
return prf2(masterSecret, SSL_HS_MASTER_SIZE, tmp,
|
||||
FINISHED_LABEL_SIZE + SHA256_HASH_SIZE, out,
|
||||
TLS_HS_FINISHED_SIZE, CRYPTO_FLAGS_SHA2);
|
||||
}
|
||||
#ifndef USE_ONLY_TLS_1_2
|
||||
} else {
|
||||
psMd5Sha1Cpy(&md5sha1_backup, md5sha1);
|
||||
psMd5Sha1Final(&md5sha1_backup, tmp + FINISHED_LABEL_SIZE);
|
||||
return prf(masterSecret, SSL_HS_MASTER_SIZE, tmp,
|
||||
FINISHED_LABEL_SIZE + MD5SHA1_HASHLEN,
|
||||
out, TLS_HS_FINISHED_SIZE);
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
psMd5Sha1Cpy(&md5sha1_backup, md5sha1);
|
||||
psMd5Sha1Final(&md5sha1_backup, tmp + FINISHED_LABEL_SIZE);
|
||||
return prf(masterSecret, SSL_HS_MASTER_SIZE, tmp,
|
||||
FINISHED_LABEL_SIZE + MD5SHA1_HASHLEN,
|
||||
out, TLS_HS_FINISHED_SIZE);
|
||||
#endif
|
||||
} else {
|
||||
/* Overloading this function to handle the client auth needs of
|
||||
handshake hashing. */
|
||||
#ifdef USE_TLS_1_2
|
||||
if (ssl->flags & SSL_FLAGS_TLS_1_2) {
|
||||
psSha256Cpy(&sha256_backup, sha256);
|
||||
psSha256Final(&sha256_backup, out);
|
||||
#if defined(USE_SERVER_SIDE_SSL) && defined(USE_CLIENT_AUTH)
|
||||
/* Check to make sure we are a server because clients come
|
||||
through here as well and they do not need to snapshot any
|
||||
hashes because they are in a write state during the
|
||||
CERTIFICATE_VERIFY creation. So if they detect a non-default
|
||||
in digest, they just run the sslSha384SnapshotHSHash family
|
||||
of functions. Servers really do have to save aside the
|
||||
snapshots beause the CERTIFICATE_VERIFY is a parse and so the
|
||||
handshake hash is being set aside for all possible combos
|
||||
here so the sslSha384RetrieveHSHash can fetch. Previous
|
||||
versions were not testing for SERVER here so clients were
|
||||
running digest operations that were not needed in client auth */
|
||||
if (ssl->flags & SSL_FLAGS_SERVER) {
|
||||
#ifdef USE_SHA384
|
||||
psSha384Cpy(&sha384_backup, sha384);
|
||||
psSha384Final(&sha384_backup, ssl->sec.sha384Snapshot);
|
||||
#endif
|
||||
#ifdef USE_SHA512
|
||||
psSha512Cpy(&sha512_backup, sha512);
|
||||
psSha512Final(&sha512_backup, ssl->sec.sha512Snapshot);
|
||||
#endif
|
||||
#ifdef USE_SHA1
|
||||
psSha1Cpy(&sha1_backup, sha1);
|
||||
psSha1Final(&sha1_backup, ssl->sec.sha1Snapshot);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
return SHA256_HASH_SIZE;
|
||||
#ifndef USE_ONLY_TLS_1_2
|
||||
} else {
|
||||
psMd5Sha1Cpy(&md5sha1_backup, md5sha1);
|
||||
psMd5Sha1Final(&md5sha1_backup, out);
|
||||
return MD5SHA1_HASHLEN;
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
/*
|
||||
The handshake snapshot for client authentication is simply the
|
||||
appended MD5 and SHA1 hashes
|
||||
*/
|
||||
psMd5Sha1Cpy(&md5sha1_backup, md5sha1);
|
||||
psMd5Sha1Final(&md5sha1_backup, out);
|
||||
return MD5SHA1_HASHLEN;
|
||||
#endif /* USE_TLS_1_2 */
|
||||
}
|
||||
return PS_FAILURE; /* Should not reach this */
|
||||
}
|
||||
#endif /* USE_TLS */
|
||||
|
||||
|
||||
/* The extended master secret computation uses a handshake hash */
|
||||
int32_t extMasterSecretSnapshotHSHash(ssl_t *ssl, unsigned char *out,
|
||||
uint32 *outLen)
|
||||
{
|
||||
#ifndef USE_ONLY_TLS_1_2
|
||||
psMd5Sha1_t md5sha1;
|
||||
#endif
|
||||
#ifdef USE_SHA256
|
||||
psSha256_t sha256;
|
||||
#endif
|
||||
#ifdef USE_SHA384
|
||||
psSha384_t sha384;
|
||||
#endif
|
||||
|
||||
/*
|
||||
Use a backup of the message hash-to-date because we don't want
|
||||
to destroy the state of the handshaking until truly complete
|
||||
*/
|
||||
|
||||
*outLen = 0;
|
||||
|
||||
#ifdef USE_TLS_1_2
|
||||
if (ssl->flags & SSL_FLAGS_TLS_1_2) {
|
||||
if (ssl->cipher->flags & CRYPTO_FLAGS_SHA3) {
|
||||
#ifdef USE_SHA384
|
||||
psSha384Cpy(&sha384, &ssl->sec.msgHashSha384);
|
||||
psSha384Final(&sha384, out);
|
||||
*outLen = SHA384_HASH_SIZE;
|
||||
#endif
|
||||
} else {
|
||||
psSha256Cpy(&sha256, &ssl->sec.msgHashSha256);
|
||||
psSha256Final(&sha256, out);
|
||||
*outLen = SHA256_HASH_SIZE;
|
||||
}
|
||||
#ifndef USE_ONLY_TLS_1_2
|
||||
} else {
|
||||
psMd5Sha1Cpy(&md5sha1, &ssl->sec.msgHashMd5Sha1);
|
||||
psMd5Sha1Final(&md5sha1, out);
|
||||
*outLen = MD5SHA1_HASHLEN;
|
||||
#endif
|
||||
}
|
||||
#else /* no TLS 1.2 */
|
||||
psMd5Sha1Cpy(&md5sha1, &ssl->sec.msgHashMd5Sha1);
|
||||
psMd5Sha1Final(&md5sha1, out);
|
||||
*outLen = MD5SHA1_HASHLEN;
|
||||
#endif
|
||||
|
||||
return *outLen;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
Snapshot is called by the receiver of the finished message to produce
|
||||
a hash of the preceeding handshake messages for comparison to incoming
|
||||
message.
|
||||
*/
|
||||
int32_t sslSnapshotHSHash(ssl_t *ssl, unsigned char *out, int32 senderFlag)
|
||||
{
|
||||
int32 len = PS_FAILURE;
|
||||
|
||||
#ifdef USE_DTLS
|
||||
if (ssl->flags & SSL_FLAGS_DTLS) {
|
||||
/* Don't allow FINISHED message retransmit to re-calc hash */
|
||||
if (ssl->retransmit) {
|
||||
memcpy(out, ssl->hsSnapshot, ssl->hsSnapshotLen);
|
||||
return ssl->hsSnapshotLen;
|
||||
}
|
||||
}
|
||||
#endif /* USE_DTLS */
|
||||
|
||||
#ifdef USE_TLS
|
||||
if (ssl->flags & SSL_FLAGS_TLS) {
|
||||
len = tlsGenerateFinishedHash(ssl,
|
||||
#ifndef USE_ONLY_TLS_1_2
|
||||
&ssl->sec.msgHashMd5Sha1,
|
||||
#endif
|
||||
#ifdef USE_TLS_1_2
|
||||
#ifdef USE_SHA1
|
||||
&ssl->sec.msgHashSha1,
|
||||
#endif
|
||||
#ifdef USE_SHA256
|
||||
&ssl->sec.msgHashSha256,
|
||||
#endif
|
||||
#ifdef USE_SHA384
|
||||
&ssl->sec.msgHashSha384,
|
||||
#endif
|
||||
#ifdef USE_SHA512
|
||||
&ssl->sec.msgHashSha512,
|
||||
#endif
|
||||
#endif /* USE_TLS_1_2 */
|
||||
ssl->sec.masterSecret, out, senderFlag);
|
||||
|
||||
#ifndef DISABLE_SSLV3
|
||||
} else {
|
||||
len = sslGenerateFinishedHash(&ssl->sec.msgHashMd5Sha1,
|
||||
ssl->sec.masterSecret, out, senderFlag);
|
||||
#endif /* DISABLE_SSLV3 */
|
||||
}
|
||||
#endif /* USE_TLS */
|
||||
|
||||
#ifdef USE_DTLS
|
||||
if (ssl->flags & SSL_FLAGS_DTLS) {
|
||||
if (len > 0) {
|
||||
memcpy(ssl->hsSnapshot, out, len);
|
||||
ssl->hsSnapshotLen = len;
|
||||
}
|
||||
}
|
||||
#endif /* USE_DTLS */
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
Reference in New Issue
Block a user