Initial draft of AES GCM cipher suites. Missing SHA-384 support.

This commit is contained in:
John Safranek 2012-06-26 09:30:48 -07:00
parent 737cd127e8
commit 3a9a195683
3 changed files with 218 additions and 66 deletions

View File

@ -233,6 +233,11 @@ void c32to24(word32 in, word24 out);
#define BUILD_AES
#endif
#if defined(BUILD_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256) || \
defined(BUILD_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256)
#define BUILD_AESGCM
#endif
#if defined(BUILD_TLS_RSA_WITH_HC_128_CBC_SHA) || \
defined(BUILD_TLS_RSA_WITH_HC_128_CBC_MD5)
#define BUILD_HC128
@ -398,6 +403,8 @@ enum Misc {
AES_256_KEY_SIZE = 32, /* for 256 bit */
AES_192_KEY_SIZE = 24, /* for 192 bit */
AES_IV_SIZE = 16, /* always block size */
AES_GCM_IMPLICIT_IV_SIZE = 4, /* Implicit half of IV */
AES_GCM_EXPLICIT_IV_SIZE = 8, /* Explicit half of IV */
AES_128_KEY_SIZE = 16, /* for 128 bit */
HC_128_KEY_SIZE = 16, /* 128 bits */
@ -1167,6 +1174,9 @@ struct CYASSL {
Sha hashSha; /* sha hash of handshake msgs */
#ifndef NO_SHA256
Sha256 hashSha256; /* sha256 hash of handshake msgs */
#endif
#ifdef CYASSL_SHA384
Sha384 hashSha384; /* sha384 hash of handshake msgs */
#endif
Hashes verifyHashes;
Hashes certHashes; /* for cert verify */

View File

@ -886,6 +886,9 @@ int InitSSL(CYASSL* ssl, CYASSL_CTX* ctx)
InitSha(&ssl->hashSha);
#ifndef NO_SHA256
InitSha256(&ssl->hashSha256);
#endif
#ifdef CYASSL_SHA384
InitSha384(&ssl->hashSha384);
#endif
InitRsaKey(&ssl->peerRsaKey, ctx->heap);
@ -1177,10 +1180,14 @@ static void HashOutput(CYASSL* ssl, const byte* output, int sz, int ivSz)
Md5Update(&ssl->hashMd5, adj, sz);
ShaUpdate(&ssl->hashSha, adj, sz);
if (IsAtLeastTLSv1_2(ssl)) {
#ifndef NO_SHA256
if (IsAtLeastTLSv1_2(ssl))
Sha256Update(&ssl->hashSha256, adj, sz);
#endif
#ifdef CYASSL_SHA384
Sha384Update(&ssl->hashSha384, adj, sz);
#endif
}
}
@ -1199,10 +1206,14 @@ static void HashInput(CYASSL* ssl, const byte* input, int sz)
Md5Update(&ssl->hashMd5, adj, sz);
ShaUpdate(&ssl->hashSha, adj, sz);
if (IsAtLeastTLSv1_2(ssl)) {
#ifndef NO_SHA256
if (IsAtLeastTLSv1_2(ssl))
Sha256Update(&ssl->hashSha256, adj, sz);
#endif
#ifdef CYASSL_SHA384
Sha384Update(&ssl->hashSha384, adj, sz);
#endif
}
}
@ -1624,6 +1635,12 @@ static void BuildFinished(CYASSL* ssl, Hashes* hashes, const byte* sender)
if (IsAtLeastTLSv1_2(ssl))
sha256 = ssl->hashSha256;
#endif
#if CYASSL_SHA384
Sha384 sha384;
InitSha384(&sha384);
if (IsAtLeastTLSv1_2(ssl))
sha384 = ssl->hashSha384;
#endif
if (ssl->options.tls)
BuildTlsFinished(ssl, hashes, sender);
@ -1639,6 +1656,10 @@ static void BuildFinished(CYASSL* ssl, Hashes* hashes, const byte* sender)
if (IsAtLeastTLSv1_2(ssl))
ssl->hashSha256 = sha256;
#endif
#ifdef CYASSL_SHA384
if (IsAtLeastTLSv1_2(ssl))
ssl->hashSha384 = sha384;
#endif
}
@ -2017,24 +2038,30 @@ int DoFinished(CYASSL* ssl, const byte* input, word32* inOutIdx, int sniff)
}
}
ssl->hmac(ssl, verifyMAC, input + idx - headerSz, macSz,
handshake, 1);
idx += finishedSz;
if (ssl->specs.cipher_type != aead) {
ssl->hmac(ssl, verifyMAC, input + idx - headerSz, macSz,
handshake, 1);
idx += finishedSz;
/* read mac and fill */
mac = input + idx;
idx += ssl->specs.hash_size;
/* read mac and fill */
mac = input + idx;
idx += ssl->specs.hash_size;
if (ssl->options.tls1_1 && ssl->specs.cipher_type == block)
padSz -= ssl->specs.block_size;
if (ssl->options.tls1_1 && ssl->specs.cipher_type == block)
padSz -= ssl->specs.block_size;
idx += padSz;
idx += padSz;
/* verify mac */
if (XMEMCMP(mac, verifyMAC, ssl->specs.hash_size)) {
CYASSL_MSG("Verify finished error on mac");
return VERIFY_MAC_ERROR;
}
/* verify mac */
if (XMEMCMP(mac, verifyMAC, ssl->specs.hash_size)) {
CYASSL_MSG("Verify finished error on mac");
return VERIFY_MAC_ERROR;
}
}
else {
idx = idx + finishedSz + 16;
/* XXX the 16 should be from specs */
}
if (ssl->options.side == CLIENT_END) {
ssl->options.serverState = SERVER_FINISHED_COMPLETE;
@ -2156,6 +2183,15 @@ static int DoHandShakeMsg(CYASSL* ssl, byte* input, word32* inOutIdx,
}
static INLINE word32 GetSEQIncrement(CYASSL* ssl, int verify)
{
if (verify)
return ssl->keys.peer_sequence_number++;
else
return ssl->keys.sequence_number++;
}
static INLINE void Encrypt(CYASSL* ssl, byte* out, const byte* input, word32 sz)
{
switch (ssl->specs.bulk_cipher_algorithm) {
@ -2186,6 +2222,35 @@ static INLINE void Encrypt(CYASSL* ssl, byte* out, const byte* input, word32 sz)
break;
#endif
#ifdef BUILD_AESGCM
case aes_gcm:
{
byte additional[AES_BLOCK_SIZE];
byte nonce[AES_BLOCK_SIZE];
if (ssl->options.side == SERVER_END) {
XMEMCPY(nonce, ssl->keys.server_write_IV,
AES_GCM_IMPLICIT_IV_SIZE);
}
else {
XMEMCPY(nonce, ssl->keys.client_write_IV,
AES_GCM_IMPLICIT_IV_SIZE);
}
XMEMCPY(nonce + AES_GCM_IMPLICIT_IV_SIZE,
input, AES_GCM_EXPLICIT_IV_SIZE);
XMEMSET(nonce + AES_GCM_IMPLICIT_IV_SIZE +
AES_GCM_EXPLICIT_IV_SIZE, 0, 4);
AesSetIV(&ssl->encrypt.aes, nonce);
XMEMSET(additional, 0, 16);
c32toa(GetSEQIncrement(ssl, 0), additional + 4);
XMEMCPY(additional+8, input - 5, 5);
AesGcmEncrypt(&ssl->encrypt.aes, out+8, input+8, sz-24,
out + 8 + (sz - 24), 16, additional, 13);
}
break;
#endif
#ifdef HAVE_HC128
case hc128:
Hc128_Process(&ssl->encrypt.hc128, out, input, sz);
@ -2204,7 +2269,7 @@ static INLINE void Encrypt(CYASSL* ssl, byte* out, const byte* input, word32 sz)
}
static INLINE void Decrypt(CYASSL* ssl, byte* plain, const byte* input,
static INLINE int Decrypt(CYASSL* ssl, byte* plain, const byte* input,
word32 sz)
{
switch (ssl->specs.bulk_cipher_algorithm) {
@ -2226,6 +2291,41 @@ static INLINE void Decrypt(CYASSL* ssl, byte* plain, const byte* input,
break;
#endif
#ifdef BUILD_AESGCM
case aes_gcm:
{
byte additional[16];
byte nonce[16];
/* use the other side's IV */
if (ssl->options.side == SERVER_END) {
XMEMCPY(nonce, ssl->keys.client_write_IV,
AES_GCM_IMPLICIT_IV_SIZE);
}
else {
XMEMCPY(nonce, ssl->keys.server_write_IV,
AES_GCM_IMPLICIT_IV_SIZE);
}
XMEMCPY(nonce + AES_GCM_IMPLICIT_IV_SIZE,
input, AES_GCM_EXPLICIT_IV_SIZE);
XMEMSET(nonce + AES_GCM_IMPLICIT_IV_SIZE +
AES_GCM_EXPLICIT_IV_SIZE, 0, 4);
AesSetIV(&ssl->decrypt.aes, nonce);
XMEMSET(additional, 0, 4);
c32toa(GetSEQIncrement(ssl, 1), additional + 4);
additional[8] = ssl->curRL.type;
additional[9] = ssl->curRL.version.major;
additional[10] = ssl->curRL.version.minor;
c16toa(sz, additional + 11);
if (AesGcmDecrypt(&ssl->decrypt.aes, plain+8, input+8, sz-24,
input + 8 + (sz - 24), 16, additional, 13) < 0) {
SendAlert(ssl, alert_fatal, bad_record_mac);
return VERIFY_MAC_ERROR;
}
break;
}
#endif
#ifdef HAVE_HC128
case hc128:
Hc128_Process(&ssl->decrypt.hc128, plain, input, sz);
@ -2241,27 +2341,25 @@ static INLINE void Decrypt(CYASSL* ssl, byte* plain, const byte* input,
default:
CYASSL_MSG("CyaSSL Decrypt programming error");
}
return 0;
}
/* decrypt input message in place */
static int DecryptMessage(CYASSL* ssl, byte* input, word32 sz, word32* idx)
{
Decrypt(ssl, input, input, sz);
ssl->keys.encryptSz = sz;
if (ssl->options.tls1_1 && ssl->specs.cipher_type == block)
*idx += ssl->specs.block_size; /* go past TLSv1.1 IV */
int decryptResult = Decrypt(ssl, input, input, sz);
return 0;
}
if (decryptResult == 0)
{
ssl->keys.encryptSz = sz;
if (ssl->options.tls1_1 && ssl->specs.cipher_type == block)
*idx += ssl->specs.block_size; /* go past TLSv1.1 IV */
if (ssl->specs.cipher_type == aead)
*idx += AES_GCM_EXPLICIT_IV_SIZE;
}
static INLINE word32 GetSEQIncrement(CYASSL* ssl, int verify)
{
if (verify)
return ssl->keys.peer_sequence_number++;
else
return ssl->keys.sequence_number++;
return decryptResult;
}
@ -2288,6 +2386,10 @@ int DoApplicationData(CYASSL* ssl, byte* input, word32* inOutIdx)
pad = *(input + idx + msgSz - ivExtra - 1);
padByte = 1;
}
if (ssl->specs.cipher_type == aead) {
ivExtra = 8;
digestSz = 16;
}
dataSz = msgSz - ivExtra - digestSz - pad - padByte;
if (dataSz < 0) {
@ -2299,7 +2401,8 @@ int DoApplicationData(CYASSL* ssl, byte* input, word32* inOutIdx)
if (dataSz) {
int rawSz = dataSz; /* keep raw size for hmac */
ssl->hmac(ssl, verify, rawData, rawSz, application_data, 1);
if (ssl->specs.cipher_type != aead)
ssl->hmac(ssl, verify, rawData, rawSz, application_data, 1);
#ifdef HAVE_LIBZ
if (ssl->options.usingCompression) {
@ -2332,7 +2435,7 @@ int DoApplicationData(CYASSL* ssl, byte* input, word32* inOutIdx)
/* verify */
if (dataSz) {
if (XMEMCMP(mac, verify, digestSz)) {
if (ssl->specs.cipher_type != aead && XMEMCMP(mac, verify, digestSz)) {
CYASSL_MSG("App data verify mac error");
return VERIFY_MAC_ERROR;
}
@ -2368,24 +2471,30 @@ static int DoAlert(CYASSL* ssl, byte* input, word32* inOutIdx, int* type)
}
CYASSL_ERROR(*type);
if (ssl->keys.encryptionOn) {
int aSz = ALERT_SIZE;
const byte* mac;
byte verify[SHA256_DIGEST_SIZE];
int padSz = ssl->keys.encryptSz - aSz - ssl->specs.hash_size;
ssl->hmac(ssl, verify, input + *inOutIdx - aSz, aSz, alert, 1);
/* read mac and fill */
mac = input + *inOutIdx;
*inOutIdx += (ssl->specs.hash_size + padSz);
/* verify */
if (XMEMCMP(mac, verify, ssl->specs.hash_size)) {
CYASSL_MSG(" alert verify mac error");
return VERIFY_MAC_ERROR;
}
}
if (ssl->keys.encryptionOn) {
if (ssl->specs.cipher_type != aead) {
int aSz = ALERT_SIZE;
const byte* mac;
byte verify[SHA256_DIGEST_SIZE];
int padSz = ssl->keys.encryptSz - aSz - ssl->specs.hash_size;
ssl->hmac(ssl, verify, input + *inOutIdx - aSz, aSz, alert, 1);
/* read mac and fill */
mac = input + *inOutIdx;
*inOutIdx += (ssl->specs.hash_size + padSz);
/* verify */
if (XMEMCMP(mac, verify, ssl->specs.hash_size)) {
CYASSL_MSG(" alert verify mac error");
return VERIFY_MAC_ERROR;
}
}
else {
*inOutIdx += 16;
/* XXX this should be a value out of the cipher specs */
}
}
return level;
}
@ -2901,6 +3010,11 @@ static int BuildMessage(CYASSL* ssl, byte* output, const byte* input, int inSz,
sz += pad;
}
if (ssl->specs.cipher_type == aead) {
ivSz = AES_GCM_EXPLICIT_IV_SIZE;
sz = sz + ivSz + 16 - digestSz;
RNG_GenerateBlock(&ssl->rng, iv, ivSz);
}
size = (word16)(sz - headerSz); /* include mac and digest */
AddRecordHeader(output, size, (byte)type, ssl);
@ -2914,8 +3028,10 @@ static int BuildMessage(CYASSL* ssl, byte* output, const byte* input, int inSz,
if (type == handshake)
HashOutput(ssl, output, headerSz + inSz, ivSz);
ssl->hmac(ssl, output+idx, output + headerSz + ivSz, inSz, type, 0);
idx += digestSz;
if (ssl->specs.cipher_type != aead) {
ssl->hmac(ssl, output+idx, output + headerSz + ivSz, inSz, type, 0);
idx += digestSz;
}
if (ssl->specs.cipher_type == block)
for (i = 0; i <= pad; i++)

View File

@ -323,7 +323,7 @@ int SetCipherSpecs(CYASSL* ssl)
ssl->specs.static_ecdh = 0;
ssl->specs.key_size = AES_128_KEY_SIZE;
ssl->specs.block_size = AES_BLOCK_SIZE;
ssl->specs.iv_size = AES_IV_SIZE;
ssl->specs.iv_size = AES_GCM_IMPLICIT_IV_SIZE;
break;
#endif
@ -340,7 +340,7 @@ int SetCipherSpecs(CYASSL* ssl)
ssl->specs.static_ecdh = 0;
ssl->specs.key_size = AES_256_KEY_SIZE;
ssl->specs.block_size = AES_BLOCK_SIZE;
ssl->specs.iv_size = AES_IV_SIZE;
ssl->specs.iv_size = AES_GCM_IMPLICIT_IV_SIZE;
break;
#endif
@ -357,7 +357,7 @@ int SetCipherSpecs(CYASSL* ssl)
ssl->specs.static_ecdh = 0;
ssl->specs.key_size = AES_128_KEY_SIZE;
ssl->specs.block_size = AES_BLOCK_SIZE;
ssl->specs.iv_size = AES_IV_SIZE;
ssl->specs.iv_size = AES_GCM_IMPLICIT_IV_SIZE;
break;
#endif
@ -374,7 +374,7 @@ int SetCipherSpecs(CYASSL* ssl)
ssl->specs.static_ecdh = 0;
ssl->specs.key_size = AES_256_KEY_SIZE;
ssl->specs.block_size = AES_BLOCK_SIZE;
ssl->specs.iv_size = AES_IV_SIZE;
ssl->specs.iv_size = AES_GCM_IMPLICIT_IV_SIZE;
break;
#endif
@ -391,7 +391,7 @@ int SetCipherSpecs(CYASSL* ssl)
ssl->specs.static_ecdh = 1;
ssl->specs.key_size = AES_128_KEY_SIZE;
ssl->specs.block_size = AES_BLOCK_SIZE;
ssl->specs.iv_size = AES_IV_SIZE;
ssl->specs.iv_size = AES_GCM_IMPLICIT_IV_SIZE;
break;
#endif
@ -408,7 +408,7 @@ int SetCipherSpecs(CYASSL* ssl)
ssl->specs.static_ecdh = 1;
ssl->specs.key_size = AES_256_KEY_SIZE;
ssl->specs.block_size = AES_BLOCK_SIZE;
ssl->specs.iv_size = AES_IV_SIZE;
ssl->specs.iv_size = AES_GCM_IMPLICIT_IV_SIZE;
break;
#endif
@ -425,7 +425,7 @@ int SetCipherSpecs(CYASSL* ssl)
ssl->specs.static_ecdh = 1;
ssl->specs.key_size = AES_128_KEY_SIZE;
ssl->specs.block_size = AES_BLOCK_SIZE;
ssl->specs.iv_size = AES_IV_SIZE;
ssl->specs.iv_size = AES_GCM_IMPLICIT_IV_SIZE;
break;
#endif
@ -442,7 +442,7 @@ int SetCipherSpecs(CYASSL* ssl)
ssl->specs.static_ecdh = 1;
ssl->specs.key_size = AES_256_KEY_SIZE;
ssl->specs.block_size = AES_BLOCK_SIZE;
ssl->specs.iv_size = AES_IV_SIZE;
ssl->specs.iv_size = AES_GCM_IMPLICIT_IV_SIZE;
break;
#endif
@ -793,7 +793,7 @@ int SetCipherSpecs(CYASSL* ssl)
ssl->specs.static_ecdh = 0;
ssl->specs.key_size = AES_128_KEY_SIZE;
ssl->specs.block_size = AES_BLOCK_SIZE;
ssl->specs.iv_size = AES_IV_SIZE;
ssl->specs.iv_size = AES_GCM_IMPLICIT_IV_SIZE;
break;
#endif
@ -809,7 +809,7 @@ int SetCipherSpecs(CYASSL* ssl)
ssl->specs.static_ecdh = 0;
ssl->specs.key_size = AES_256_KEY_SIZE;
ssl->specs.block_size = AES_BLOCK_SIZE;
ssl->specs.iv_size = AES_IV_SIZE;
ssl->specs.iv_size = AES_GCM_IMPLICIT_IV_SIZE;
break;
#endif
@ -970,6 +970,27 @@ static int SetKeys(Ciphers* enc, Ciphers* dec, Keys* keys, CipherSpecs* specs,
}
#endif
#ifdef BUILD_AESGCM
if (specs->bulk_cipher_algorithm == aes_gcm) {
if (side == CLIENT_END) {
AesSetKey(&enc->aes, keys->client_write_key,
specs->key_size, keys->client_write_IV,
AES_ENCRYPTION);
AesSetKey(&dec->aes, keys->server_write_key,
specs->key_size, keys->server_write_IV,
AES_ENCRYPTION);
}
else {
AesSetKey(&enc->aes, keys->server_write_key,
specs->key_size, keys->server_write_IV,
AES_ENCRYPTION);
AesSetKey(&dec->aes, keys->client_write_key,
specs->key_size, keys->client_write_IV,
AES_ENCRYPTION);
}
}
#endif
keys->sequence_number = 0;
keys->peer_sequence_number = 0;
keys->encryptionOn = 0;
@ -983,10 +1004,15 @@ int StoreKeys(CYASSL* ssl, const byte* keyData)
{
int sz = ssl->specs.hash_size, i;
XMEMCPY(ssl->keys.client_write_MAC_secret, keyData, sz);
i = sz;
XMEMCPY(ssl->keys.server_write_MAC_secret,&keyData[i], sz);
i += sz;
if (ssl->specs.cipher_type != aead) {
XMEMCPY(ssl->keys.client_write_MAC_secret, keyData, sz);
i = sz;
XMEMCPY(ssl->keys.server_write_MAC_secret,&keyData[i], sz);
i += sz;
}
else {
sz = 0;
}
sz = ssl->specs.key_size;
XMEMCPY(ssl->keys.client_write_key, &keyData[i], sz);