From 4dd9f290e5fc0f22f90752b86b445214289f8428 Mon Sep 17 00:00:00 2001 From: Todd A Ouska Date: Mon, 28 Feb 2011 12:21:06 -0800 Subject: [PATCH] TLS 1.2 updates for hash/sig id --- .gitignore | 5 +++ include/cyassl_int.h | 10 +++++ src/cyassl_int.c | 98 +++++++++++++++++++++++++++++++++++++------- src/keys.c | 8 ++-- src/ssl.c | 8 ++++ src/tls.c | 12 ++++-- 6 files changed, 119 insertions(+), 22 deletions(-) diff --git a/.gitignore b/.gitignore index a708848bf..1e85cbc58 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ Makefile depcomp missing libtool +tags benchmark test client @@ -22,3 +23,7 @@ server snifftest output testsuite +diff +*.gz +*.zip +*.bak diff --git a/include/cyassl_int.h b/include/cyassl_int.h index 857ad4056..6f8c712a3 100644 --- a/include/cyassl_int.h +++ b/include/cyassl_int.h @@ -36,6 +36,9 @@ #ifdef HAVE_ECC #include "ctc_ecc.h" #endif +#ifndef NO_SHA256 + #include "sha256.h" +#endif #ifdef CYASSL_CALLBACKS #include "cyassl_callbacks.h" @@ -333,6 +336,10 @@ enum Misc { NO_SNIFF = 0, /* not sniffing */ SNIFF = 1, /* currently sniffing */ + HASH_SIG_SIZE = 2, /* default SHA1 RSA */ + SHA1_ID = 2, /* hash id */ + RSA_ID = 1, /* sig id */ + NO_COPY = 0, /* should we copy static buffer for write */ COPY = 1 /* should we copy static buffer for write */ }; @@ -949,6 +956,9 @@ struct SSL { RNG rng; Md5 hashMd5; /* md5 hash of handshake msgs */ Sha hashSha; /* sha hash of handshake msgs */ +#ifndef NO_SHA256 + Sha256 hashSha256; /* sha256 hash of handshake msgs */ +#endif Hashes verifyHashes; Hashes certHashes; /* for cert verify */ Signer* caList; /* SSL_CTX owns */ diff --git a/src/cyassl_int.c b/src/cyassl_int.c index 2558958c5..522803e64 100644 --- a/src/cyassl_int.c +++ b/src/cyassl_int.c @@ -621,6 +621,9 @@ int InitSSL(SSL* ssl, SSL_CTX* ctx) InitMd5(&ssl->hashMd5); InitSha(&ssl->hashSha); +#ifndef NO_SHA256 + InitSha256(&ssl->hashSha256); +#endif InitRsaKey(&ssl->peerRsaKey, ctx->heap); ssl->peerRsaKeyPresent = 0; @@ -904,6 +907,10 @@ static void HashOutput(SSL* ssl, const byte* output, int sz, int ivSz) Md5Update(&ssl->hashMd5, buffer, sz); ShaUpdate(&ssl->hashSha, buffer, sz); +#ifndef NO_SHA256 + if (IsAtLeastTLSv1_2(ssl)) + Sha256Update(&ssl->hashSha256, buffer, sz); +#endif } @@ -922,6 +929,10 @@ static void HashInput(SSL* ssl, const byte* input, int sz) Md5Update(&ssl->hashMd5, buffer, sz); ShaUpdate(&ssl->hashSha, buffer, sz); +#ifndef NO_SHA256 + if (IsAtLeastTLSv1_2(ssl)) + Sha256Update(&ssl->hashSha256, buffer, sz); +#endif } @@ -1322,6 +1333,11 @@ static void BuildFinished(SSL* ssl, Hashes* hashes, const byte* sender) /* store current states, building requires get_digest which resets state */ Md5 md5 = ssl->hashMd5; Sha sha = ssl->hashSha; +#ifndef NO_SHA256 + Sha256 sha256; + if (IsAtLeastTLSv1_2(ssl)) + sha256 = ssl->hashSha256; +#endif if (ssl->options.tls) BuildTlsFinished(ssl, hashes, sender); @@ -1333,6 +1349,10 @@ static void BuildFinished(SSL* ssl, Hashes* hashes, const byte* sender) /* restore */ ssl->hashMd5 = md5; ssl->hashSha = sha; +#ifndef NO_SHA256 + if (IsAtLeastTLSv1_2(ssl)) + ssl->hashSha256 = sha256; +#endif } @@ -2311,6 +2331,11 @@ static void BuildCertHashes(SSL* ssl, Hashes* hashes) /* store current states, building requires get_digest which resets state */ Md5 md5 = ssl->hashMd5; Sha sha = ssl->hashSha; +#ifndef NO_SHA256 /* for possible future changes */ + Sha256 sha256; + if (IsAtLeastTLSv1_2(ssl)) + sha256 = ssl->hashSha256; +#endif if (ssl->options.tls) { Md5Final(&ssl->hashMd5, hashes->md5); @@ -2324,6 +2349,10 @@ static void BuildCertHashes(SSL* ssl, Hashes* hashes) /* restore */ ssl->hashMd5 = md5; ssl->hashSha = sha; +#ifndef NO_SHA256 + if (IsAtLeastTLSv1_2(ssl)) + ssl->hashSha256 = sha256; +#endif } @@ -2528,6 +2557,9 @@ int SendCertificateRequest(SSL* ssl) int typeTotal = 1; /* only rsa for now */ int reqSz = ENUM_LEN + typeTotal + REQ_HEADER_SZ; /* add auth later */ + if (IsAtLeastTLSv1_2(ssl)) + reqSz += LENGTH_SZ + HASH_SIG_SIZE; + if (ssl->options.usingPSK_cipher) return 0; /* not needed */ sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ + reqSz; @@ -2551,6 +2583,15 @@ int SendCertificateRequest(SSL* ssl) output[i++] = typeTotal; /* # of types */ output[i++] = rsa_sign; + /* supported hash/sig */ + if (IsAtLeastTLSv1_2(ssl)) { + c16toa(HASH_SIG_SIZE, &output[i]); + i += LENGTH_SZ; + + output[i++] = SHA1_ID; /* hash */ + output[i++] = RSA_ID; /* sig */ + } + c16toa(0, &output[i]); /* auth's */ i += REQ_HEADER_SZ; @@ -3573,14 +3614,15 @@ int SetCipherList(SSL_CTX* ctx, const char* list) if (XMEMCMP(ssl->arrays.sessionID, ssl->session.sessionID, ID_LEN) == 0) { if (SetCipherSpecs(ssl) == 0) { + int ret; XMEMCPY(ssl->arrays.masterSecret, ssl->session.masterSecret, SECRET_LEN); if (ssl->options.tls) - DeriveTlsKeys(ssl); + ret = DeriveTlsKeys(ssl); else - DeriveKeys(ssl); + ret = DeriveKeys(ssl); ssl->options.serverState = SERVER_HELLODONE_COMPLETE; - return 0; + return ret; } else return UNSUPPORTED_SUITE; @@ -3612,6 +3654,13 @@ int SetCipherList(SSL_CTX* ctx, const char* list) ato16(&input[*inOutIdx], &len); *inOutIdx += LENGTH_SZ; + if (IsAtLeastTLSv1_2(ssl)) { + /* hash sig format */ + *inOutIdx += len; + ato16(&input[*inOutIdx], &len); + *inOutIdx += LENGTH_SZ; + } + /* authorities */ while (len) { word16 dnSz; @@ -3755,6 +3804,11 @@ int SetCipherList(SSL_CTX* ctx, const char* list) return BUFFER_ERROR; XMEMCPY(messageVerify, &input[*inOutIdx - verifySz], verifySz); + if (IsAtLeastTLSv1_2(ssl)) { + /* just advance for now TODO: validate hash algo params */ + *inOutIdx += LENGTH_SZ; + } + /* signature */ ato16(&input[*inOutIdx], &length); *inOutIdx += LENGTH_SZ; @@ -4071,14 +4125,20 @@ int SetCipherList(SSL_CTX* ctx, const char* list) HANDSHAKE_HEADER_SZ]; byte* signBuffer = ssl->certHashes.md5; word32 signSz = sizeof(Hashes); - byte encodedSig[MAX_ENCODED_SIG_SZ]; + byte encodedSig[MAX_ENCODED_SIG_SZ]; + word32 extraSz = 0; /* tls 1.2 hash/sig */ #ifdef CYASSL_DTLS if (ssl->options.dtls) verify += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; #endif length = RsaEncryptSize(&key); - c16toa((word16)length, verify); /* prepend verify header */ + if (IsAtLeastTLSv1_2(ssl)) { + verify[0] = SHA1_ID; + verify[1] = RSA_ID; + extraSz = HASH_SIG_SIZE; + } + c16toa((word16)length, verify + extraSz); /* prepend verify header*/ if (IsAtLeastTLSv1_2(ssl)) { byte* digest; @@ -4094,17 +4154,17 @@ int SetCipherList(SSL_CTX* ctx, const char* list) signBuffer = encodedSig; } - ret = RsaSSL_Sign(signBuffer, signSz, verify + + ret = RsaSSL_Sign(signBuffer, signSz, verify + extraSz + VERIFY_HEADER, ENCRYPT_LEN, &key, &ssl->rng); if (ret > 0) { ret = 0; /* reset */ - AddHeaders(output, length + VERIFY_HEADER, certificate_verify, - ssl); + AddHeaders(output, length + extraSz + VERIFY_HEADER, + certificate_verify, ssl); sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ + length + - VERIFY_HEADER; + extraSz + VERIFY_HEADER; #ifdef CYASSL_DTLS if (ssl->options.dtls) sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; @@ -4514,6 +4574,10 @@ int SetCipherList(SSL_CTX* ctx, const char* list) /* manually hash input since different format */ Md5Update(&ssl->hashMd5, input + idx, sz); ShaUpdate(&ssl->hashSha, input + idx, sz); +#ifndef NO_SHA256 + if (IsAtLeastTLSv1_2(ssl)) + Sha256Update(&ssl->hashSha256, input + idx, sz); +#endif /* does this value mean client_hello? */ idx++; @@ -4589,6 +4653,7 @@ int SetCipherList(SSL_CTX* ctx, const char* list) /* DoClientHello uses same resume code */ while (ssl->options.resuming) { /* let's try */ + int ret; SSL_SESSION* session = GetSession(ssl, ssl->arrays.masterSecret); if (!session) { ssl->options.resuming = 0; @@ -4599,12 +4664,12 @@ int SetCipherList(SSL_CTX* ctx, const char* list) RNG_GenerateBlock(&ssl->rng, ssl->arrays.serverRandom, RAN_LEN); if (ssl->options.tls) - DeriveTlsKeys(ssl); + ret = DeriveTlsKeys(ssl); else - DeriveKeys(ssl); + ret = DeriveKeys(ssl); ssl->options.clientState = CLIENT_KEYEXCHANGE_COMPLETE; - return 0; + return ret; } return MatchSuite(ssl, &clSuites); @@ -4719,6 +4784,7 @@ int SetCipherList(SSL_CTX* ctx, const char* list) /* ProcessOld uses same resume code */ while (ssl->options.resuming) { /* let's try */ + int ret; SSL_SESSION* session = GetSession(ssl, ssl->arrays.masterSecret); if (!session) { ssl->options.resuming = 0; @@ -4729,12 +4795,12 @@ int SetCipherList(SSL_CTX* ctx, const char* list) RNG_GenerateBlock(&ssl->rng, ssl->arrays.serverRandom, RAN_LEN); if (ssl->options.tls) - DeriveTlsKeys(ssl); + ret = DeriveTlsKeys(ssl); else - DeriveKeys(ssl); + ret = DeriveKeys(ssl); ssl->options.clientState = CLIENT_KEYEXCHANGE_COMPLETE; - return 0; + return ret; } return MatchSuite(ssl, &clSuites); } @@ -4759,6 +4825,8 @@ int SetCipherList(SSL_CTX* ctx, const char* list) if ( (i + VERIFY_HEADER) > totalSz) return INCOMPLETE_DATA; + if (IsAtLeastTLSv1_2(ssl)) + i += HASH_SIG_SIZE; ato16(&input[i], &sz); i += VERIFY_HEADER; diff --git a/src/keys.c b/src/keys.c index 2fc4c710a..3a51f7fb2 100644 --- a/src/keys.c +++ b/src/keys.c @@ -431,7 +431,7 @@ int SetCipherSpecs(SSL* ssl) #ifndef NO_TLS ssl->options.tls = 1; ssl->hmac = TLS_hmac; - if (ssl->version.minor == 2) + if (ssl->version.minor >= 2) ssl->options.tls1_1 = 1; #endif } @@ -678,7 +678,7 @@ int MakeMasterSecret(SSL* ssl) byte shaOutput[SHA_DIGEST_SIZE]; byte md5Input[ENCRYPT_LEN + SHA_DIGEST_SIZE]; byte shaInput[PREFIX + ENCRYPT_LEN + 2 * RAN_LEN]; - int i; + int i, ret; word32 idx; word32 pmsSz = ssl->arrays.preMasterSz; @@ -740,10 +740,10 @@ int MakeMasterSecret(SSL* ssl) } #endif - DeriveKeys(ssl); + ret = DeriveKeys(ssl); CleanPreMaster(ssl); - return 0; + return ret; } diff --git a/src/ssl.c b/src/ssl.c index 18d0a9988..10d69f705 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -999,6 +999,10 @@ int SSL_CTX_set_cipher_list(SSL_CTX* ctx, const char* list) /* re-init hashes, exclude first hello and verify request */ InitMd5(&ssl->hashMd5); InitSha(&ssl->hashSha); + #ifndef NO_SHA256 + if (IsAtLeastTLSv1_2(ssl)) + InitSha256(&ssl->hashSha256); + #endif if ( (ssl->error = SendClientHello(ssl)) != 0) { CYASSL_ERROR(ssl->error); return SSL_FATAL_ERROR; @@ -1196,6 +1200,10 @@ int SSL_CTX_set_cipher_list(SSL_CTX* ctx, const char* list) /* re-init hashes, exclude first hello and verify request */ InitMd5(&ssl->hashMd5); InitSha(&ssl->hashSha); + #ifndef NO_SHA256 + if (IsAtLeastTLSv1_2(ssl)) + InitSha256(&ssl->hashSha256); + #endif while (ssl->options.clientState < CLIENT_HELLO_COMPLETE) if ( (ssl->error = ProcessReply(ssl)) < 0) { diff --git a/src/tls.c b/src/tls.c index 4d823115a..d6dd003e5 100644 --- a/src/tls.c +++ b/src/tls.c @@ -136,10 +136,17 @@ static void PRF(byte* digest, word32 digLen, const byte* secret, word32 secLen, void BuildTlsFinished(SSL* ssl, Hashes* hashes, const byte* sender) { const byte* side; - byte handshake_hash[FINISHED_SZ]; + byte handshake_hash[FINISHED_SZ]; + word32 hashSz = FINISHED_SZ; Md5Final(&ssl->hashMd5, handshake_hash); ShaFinal(&ssl->hashSha, &handshake_hash[MD5_DIGEST_SIZE]); +#ifndef NO_SHA256 + if (IsAtLeastTLSv1_2(ssl)) { + Sha256Final(&ssl->hashSha256, handshake_hash); + hashSz = SHA256_DIGEST_SIZE; + } +#endif if ( XSTRNCMP((const char*)sender, (const char*)client, SIZEOF_SENDER) == 0) side = tls_client; @@ -147,8 +154,7 @@ void BuildTlsFinished(SSL* ssl, Hashes* hashes, const byte* sender) side = tls_server; PRF(hashes->md5, TLS_FINISHED_SZ, ssl->arrays.masterSecret, SECRET_LEN, - side, FINISHED_LABEL_SZ, handshake_hash, FINISHED_SZ, - IsAtLeastTLSv1_2(ssl)); + side, FINISHED_LABEL_SZ, handshake_hash, hashSz, IsAtLeastTLSv1_2(ssl)); }