diff --git a/cyassl/internal.h b/cyassl/internal.h index 583b1cd6d..0f8d9d2a7 100644 --- a/cyassl/internal.h +++ b/cyassl/internal.h @@ -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 */ diff --git a/src/internal.c b/src/internal.c index 59d942669..5709f5f5d 100644 --- a/src/internal.c +++ b/src/internal.c @@ -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++) diff --git a/src/keys.c b/src/keys.c index 6f759756c..7617b004a 100644 --- a/src/keys.c +++ b/src/keys.c @@ -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);