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 #define BUILD_AES
#endif #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) || \ #if defined(BUILD_TLS_RSA_WITH_HC_128_CBC_SHA) || \
defined(BUILD_TLS_RSA_WITH_HC_128_CBC_MD5) defined(BUILD_TLS_RSA_WITH_HC_128_CBC_MD5)
#define BUILD_HC128 #define BUILD_HC128
@ -398,6 +403,8 @@ enum Misc {
AES_256_KEY_SIZE = 32, /* for 256 bit */ AES_256_KEY_SIZE = 32, /* for 256 bit */
AES_192_KEY_SIZE = 24, /* for 192 bit */ AES_192_KEY_SIZE = 24, /* for 192 bit */
AES_IV_SIZE = 16, /* always block size */ 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 */ AES_128_KEY_SIZE = 16, /* for 128 bit */
HC_128_KEY_SIZE = 16, /* 128 bits */ HC_128_KEY_SIZE = 16, /* 128 bits */
@ -1167,6 +1174,9 @@ struct CYASSL {
Sha hashSha; /* sha hash of handshake msgs */ Sha hashSha; /* sha hash of handshake msgs */
#ifndef NO_SHA256 #ifndef NO_SHA256
Sha256 hashSha256; /* sha256 hash of handshake msgs */ Sha256 hashSha256; /* sha256 hash of handshake msgs */
#endif
#ifdef CYASSL_SHA384
Sha384 hashSha384; /* sha384 hash of handshake msgs */
#endif #endif
Hashes verifyHashes; Hashes verifyHashes;
Hashes certHashes; /* for cert verify */ Hashes certHashes; /* for cert verify */

View File

@ -886,6 +886,9 @@ int InitSSL(CYASSL* ssl, CYASSL_CTX* ctx)
InitSha(&ssl->hashSha); InitSha(&ssl->hashSha);
#ifndef NO_SHA256 #ifndef NO_SHA256
InitSha256(&ssl->hashSha256); InitSha256(&ssl->hashSha256);
#endif
#ifdef CYASSL_SHA384
InitSha384(&ssl->hashSha384);
#endif #endif
InitRsaKey(&ssl->peerRsaKey, ctx->heap); 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); Md5Update(&ssl->hashMd5, adj, sz);
ShaUpdate(&ssl->hashSha, adj, sz); ShaUpdate(&ssl->hashSha, adj, sz);
if (IsAtLeastTLSv1_2(ssl)) {
#ifndef NO_SHA256 #ifndef NO_SHA256
if (IsAtLeastTLSv1_2(ssl))
Sha256Update(&ssl->hashSha256, adj, sz); Sha256Update(&ssl->hashSha256, adj, sz);
#endif #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); Md5Update(&ssl->hashMd5, adj, sz);
ShaUpdate(&ssl->hashSha, adj, sz); ShaUpdate(&ssl->hashSha, adj, sz);
if (IsAtLeastTLSv1_2(ssl)) {
#ifndef NO_SHA256 #ifndef NO_SHA256
if (IsAtLeastTLSv1_2(ssl))
Sha256Update(&ssl->hashSha256, adj, sz); Sha256Update(&ssl->hashSha256, adj, sz);
#endif #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)) if (IsAtLeastTLSv1_2(ssl))
sha256 = ssl->hashSha256; sha256 = ssl->hashSha256;
#endif #endif
#if CYASSL_SHA384
Sha384 sha384;
InitSha384(&sha384);
if (IsAtLeastTLSv1_2(ssl))
sha384 = ssl->hashSha384;
#endif
if (ssl->options.tls) if (ssl->options.tls)
BuildTlsFinished(ssl, hashes, sender); BuildTlsFinished(ssl, hashes, sender);
@ -1639,6 +1656,10 @@ static void BuildFinished(CYASSL* ssl, Hashes* hashes, const byte* sender)
if (IsAtLeastTLSv1_2(ssl)) if (IsAtLeastTLSv1_2(ssl))
ssl->hashSha256 = sha256; ssl->hashSha256 = sha256;
#endif #endif
#ifdef CYASSL_SHA384
if (IsAtLeastTLSv1_2(ssl))
ssl->hashSha384 = sha384;
#endif
} }
@ -2017,6 +2038,7 @@ int DoFinished(CYASSL* ssl, const byte* input, word32* inOutIdx, int sniff)
} }
} }
if (ssl->specs.cipher_type != aead) {
ssl->hmac(ssl, verifyMAC, input + idx - headerSz, macSz, ssl->hmac(ssl, verifyMAC, input + idx - headerSz, macSz,
handshake, 1); handshake, 1);
idx += finishedSz; idx += finishedSz;
@ -2035,6 +2057,11 @@ int DoFinished(CYASSL* ssl, const byte* input, word32* inOutIdx, int sniff)
CYASSL_MSG("Verify finished error on mac"); CYASSL_MSG("Verify finished error on mac");
return VERIFY_MAC_ERROR; return VERIFY_MAC_ERROR;
} }
}
else {
idx = idx + finishedSz + 16;
/* XXX the 16 should be from specs */
}
if (ssl->options.side == CLIENT_END) { if (ssl->options.side == CLIENT_END) {
ssl->options.serverState = SERVER_FINISHED_COMPLETE; 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) static INLINE void Encrypt(CYASSL* ssl, byte* out, const byte* input, word32 sz)
{ {
switch (ssl->specs.bulk_cipher_algorithm) { switch (ssl->specs.bulk_cipher_algorithm) {
@ -2186,6 +2222,35 @@ static INLINE void Encrypt(CYASSL* ssl, byte* out, const byte* input, word32 sz)
break; break;
#endif #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 #ifdef HAVE_HC128
case hc128: case hc128:
Hc128_Process(&ssl->encrypt.hc128, out, input, sz); 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) word32 sz)
{ {
switch (ssl->specs.bulk_cipher_algorithm) { switch (ssl->specs.bulk_cipher_algorithm) {
@ -2226,6 +2291,41 @@ static INLINE void Decrypt(CYASSL* ssl, byte* plain, const byte* input,
break; break;
#endif #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 #ifdef HAVE_HC128
case hc128: case hc128:
Hc128_Process(&ssl->decrypt.hc128, plain, input, sz); Hc128_Process(&ssl->decrypt.hc128, plain, input, sz);
@ -2241,27 +2341,25 @@ static INLINE void Decrypt(CYASSL* ssl, byte* plain, const byte* input,
default: default:
CYASSL_MSG("CyaSSL Decrypt programming error"); CYASSL_MSG("CyaSSL Decrypt programming error");
} }
return 0;
} }
/* decrypt input message in place */ /* decrypt input message in place */
static int DecryptMessage(CYASSL* ssl, byte* input, word32 sz, word32* idx) static int DecryptMessage(CYASSL* ssl, byte* input, word32 sz, word32* idx)
{ {
Decrypt(ssl, input, input, sz); int decryptResult = Decrypt(ssl, input, input, sz);
if (decryptResult == 0)
{
ssl->keys.encryptSz = sz; ssl->keys.encryptSz = sz;
if (ssl->options.tls1_1 && ssl->specs.cipher_type == block) if (ssl->options.tls1_1 && ssl->specs.cipher_type == block)
*idx += ssl->specs.block_size; /* go past TLSv1.1 IV */ *idx += ssl->specs.block_size; /* go past TLSv1.1 IV */
if (ssl->specs.cipher_type == aead)
return 0; *idx += AES_GCM_EXPLICIT_IV_SIZE;
} }
return decryptResult;
static INLINE word32 GetSEQIncrement(CYASSL* ssl, int verify)
{
if (verify)
return ssl->keys.peer_sequence_number++;
else
return ssl->keys.sequence_number++;
} }
@ -2288,6 +2386,10 @@ int DoApplicationData(CYASSL* ssl, byte* input, word32* inOutIdx)
pad = *(input + idx + msgSz - ivExtra - 1); pad = *(input + idx + msgSz - ivExtra - 1);
padByte = 1; padByte = 1;
} }
if (ssl->specs.cipher_type == aead) {
ivExtra = 8;
digestSz = 16;
}
dataSz = msgSz - ivExtra - digestSz - pad - padByte; dataSz = msgSz - ivExtra - digestSz - pad - padByte;
if (dataSz < 0) { if (dataSz < 0) {
@ -2299,6 +2401,7 @@ int DoApplicationData(CYASSL* ssl, byte* input, word32* inOutIdx)
if (dataSz) { if (dataSz) {
int rawSz = dataSz; /* keep raw size for hmac */ int rawSz = dataSz; /* keep raw size for hmac */
if (ssl->specs.cipher_type != aead)
ssl->hmac(ssl, verify, rawData, rawSz, application_data, 1); ssl->hmac(ssl, verify, rawData, rawSz, application_data, 1);
#ifdef HAVE_LIBZ #ifdef HAVE_LIBZ
@ -2332,7 +2435,7 @@ int DoApplicationData(CYASSL* ssl, byte* input, word32* inOutIdx)
/* verify */ /* verify */
if (dataSz) { if (dataSz) {
if (XMEMCMP(mac, verify, digestSz)) { if (ssl->specs.cipher_type != aead && XMEMCMP(mac, verify, digestSz)) {
CYASSL_MSG("App data verify mac error"); CYASSL_MSG("App data verify mac error");
return VERIFY_MAC_ERROR; return VERIFY_MAC_ERROR;
} }
@ -2369,6 +2472,7 @@ static int DoAlert(CYASSL* ssl, byte* input, word32* inOutIdx, int* type)
CYASSL_ERROR(*type); CYASSL_ERROR(*type);
if (ssl->keys.encryptionOn) { if (ssl->keys.encryptionOn) {
if (ssl->specs.cipher_type != aead) {
int aSz = ALERT_SIZE; int aSz = ALERT_SIZE;
const byte* mac; const byte* mac;
byte verify[SHA256_DIGEST_SIZE]; byte verify[SHA256_DIGEST_SIZE];
@ -2386,6 +2490,11 @@ static int DoAlert(CYASSL* ssl, byte* input, word32* inOutIdx, int* type)
return VERIFY_MAC_ERROR; return VERIFY_MAC_ERROR;
} }
} }
else {
*inOutIdx += 16;
/* XXX this should be a value out of the cipher specs */
}
}
return level; return level;
} }
@ -2901,6 +3010,11 @@ static int BuildMessage(CYASSL* ssl, byte* output, const byte* input, int inSz,
sz += pad; 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 */ size = (word16)(sz - headerSz); /* include mac and digest */
AddRecordHeader(output, size, (byte)type, ssl); 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) if (type == handshake)
HashOutput(ssl, output, headerSz + inSz, ivSz); HashOutput(ssl, output, headerSz + inSz, ivSz);
if (ssl->specs.cipher_type != aead) {
ssl->hmac(ssl, output+idx, output + headerSz + ivSz, inSz, type, 0); ssl->hmac(ssl, output+idx, output + headerSz + ivSz, inSz, type, 0);
idx += digestSz; idx += digestSz;
}
if (ssl->specs.cipher_type == block) if (ssl->specs.cipher_type == block)
for (i = 0; i <= pad; i++) for (i = 0; i <= pad; i++)

View File

@ -323,7 +323,7 @@ int SetCipherSpecs(CYASSL* ssl)
ssl->specs.static_ecdh = 0; ssl->specs.static_ecdh = 0;
ssl->specs.key_size = AES_128_KEY_SIZE; ssl->specs.key_size = AES_128_KEY_SIZE;
ssl->specs.block_size = AES_BLOCK_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; break;
#endif #endif
@ -340,7 +340,7 @@ int SetCipherSpecs(CYASSL* ssl)
ssl->specs.static_ecdh = 0; ssl->specs.static_ecdh = 0;
ssl->specs.key_size = AES_256_KEY_SIZE; ssl->specs.key_size = AES_256_KEY_SIZE;
ssl->specs.block_size = AES_BLOCK_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; break;
#endif #endif
@ -357,7 +357,7 @@ int SetCipherSpecs(CYASSL* ssl)
ssl->specs.static_ecdh = 0; ssl->specs.static_ecdh = 0;
ssl->specs.key_size = AES_128_KEY_SIZE; ssl->specs.key_size = AES_128_KEY_SIZE;
ssl->specs.block_size = AES_BLOCK_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; break;
#endif #endif
@ -374,7 +374,7 @@ int SetCipherSpecs(CYASSL* ssl)
ssl->specs.static_ecdh = 0; ssl->specs.static_ecdh = 0;
ssl->specs.key_size = AES_256_KEY_SIZE; ssl->specs.key_size = AES_256_KEY_SIZE;
ssl->specs.block_size = AES_BLOCK_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; break;
#endif #endif
@ -391,7 +391,7 @@ int SetCipherSpecs(CYASSL* ssl)
ssl->specs.static_ecdh = 1; ssl->specs.static_ecdh = 1;
ssl->specs.key_size = AES_128_KEY_SIZE; ssl->specs.key_size = AES_128_KEY_SIZE;
ssl->specs.block_size = AES_BLOCK_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; break;
#endif #endif
@ -408,7 +408,7 @@ int SetCipherSpecs(CYASSL* ssl)
ssl->specs.static_ecdh = 1; ssl->specs.static_ecdh = 1;
ssl->specs.key_size = AES_256_KEY_SIZE; ssl->specs.key_size = AES_256_KEY_SIZE;
ssl->specs.block_size = AES_BLOCK_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; break;
#endif #endif
@ -425,7 +425,7 @@ int SetCipherSpecs(CYASSL* ssl)
ssl->specs.static_ecdh = 1; ssl->specs.static_ecdh = 1;
ssl->specs.key_size = AES_128_KEY_SIZE; ssl->specs.key_size = AES_128_KEY_SIZE;
ssl->specs.block_size = AES_BLOCK_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; break;
#endif #endif
@ -442,7 +442,7 @@ int SetCipherSpecs(CYASSL* ssl)
ssl->specs.static_ecdh = 1; ssl->specs.static_ecdh = 1;
ssl->specs.key_size = AES_256_KEY_SIZE; ssl->specs.key_size = AES_256_KEY_SIZE;
ssl->specs.block_size = AES_BLOCK_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; break;
#endif #endif
@ -793,7 +793,7 @@ int SetCipherSpecs(CYASSL* ssl)
ssl->specs.static_ecdh = 0; ssl->specs.static_ecdh = 0;
ssl->specs.key_size = AES_128_KEY_SIZE; ssl->specs.key_size = AES_128_KEY_SIZE;
ssl->specs.block_size = AES_BLOCK_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; break;
#endif #endif
@ -809,7 +809,7 @@ int SetCipherSpecs(CYASSL* ssl)
ssl->specs.static_ecdh = 0; ssl->specs.static_ecdh = 0;
ssl->specs.key_size = AES_256_KEY_SIZE; ssl->specs.key_size = AES_256_KEY_SIZE;
ssl->specs.block_size = AES_BLOCK_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; break;
#endif #endif
@ -970,6 +970,27 @@ static int SetKeys(Ciphers* enc, Ciphers* dec, Keys* keys, CipherSpecs* specs,
} }
#endif #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->sequence_number = 0;
keys->peer_sequence_number = 0; keys->peer_sequence_number = 0;
keys->encryptionOn = 0; keys->encryptionOn = 0;
@ -983,10 +1004,15 @@ int StoreKeys(CYASSL* ssl, const byte* keyData)
{ {
int sz = ssl->specs.hash_size, i; int sz = ssl->specs.hash_size, i;
if (ssl->specs.cipher_type != aead) {
XMEMCPY(ssl->keys.client_write_MAC_secret, keyData, sz); XMEMCPY(ssl->keys.client_write_MAC_secret, keyData, sz);
i = sz; i = sz;
XMEMCPY(ssl->keys.server_write_MAC_secret,&keyData[i], sz); XMEMCPY(ssl->keys.server_write_MAC_secret,&keyData[i], sz);
i += sz; i += sz;
}
else {
sz = 0;
}
sz = ssl->specs.key_size; sz = ssl->specs.key_size;
XMEMCPY(ssl->keys.client_write_key, &keyData[i], sz); XMEMCPY(ssl->keys.client_write_key, &keyData[i], sz);