diff --git a/ctaocrypt/src/aes.c b/ctaocrypt/src/aes.c index ea815bc63..91268a0fa 100644 --- a/ctaocrypt/src/aes.c +++ b/ctaocrypt/src/aes.c @@ -1475,10 +1475,29 @@ static void GMULT(byte* X, byte* Y) } +static INLINE void FlattenSzInBits(byte* buf, word32 sz) +{ + /* Multiply the sz by 8 */ + word32 szHi = (sz >> (8*sizeof(sz) - 3)); + sz <<= 3; + + /* copy over the words of the sz into the destination buffer */ + buf[0] = (szHi >> 24) & 0xff; + buf[1] = (szHi >> 16) & 0xff; + buf[2] = (szHi >> 8) & 0xff; + buf[3] = szHi & 0xff; + buf[4] = (sz >> 24) & 0xff; + buf[5] = (sz >> 16) & 0xff; + buf[6] = (sz >> 8) & 0xff; + buf[7] = sz & 0xff; +} + + static void GHASH(byte* h, const byte* a, word32 aSz, const byte* c, word32 cSz, byte* s, word32 sSz) { byte x[AES_BLOCK_SIZE]; + byte scratch[AES_BLOCK_SIZE]; word32 blocks, partial; XMEMSET(x, 0, AES_BLOCK_SIZE); @@ -1493,7 +1512,6 @@ static void GHASH(byte* h, const byte* a, word32 aSz, a += AES_BLOCK_SIZE; } if (partial != 0) { - byte scratch[AES_BLOCK_SIZE]; XMEMSET(scratch, 0, AES_BLOCK_SIZE); XMEMCPY(scratch, a, partial); xorbuf(x, scratch, AES_BLOCK_SIZE); @@ -1511,7 +1529,6 @@ static void GHASH(byte* h, const byte* a, word32 aSz, c += AES_BLOCK_SIZE; } if (partial != 0) { - byte scratch[AES_BLOCK_SIZE]; XMEMSET(scratch, 0, AES_BLOCK_SIZE); XMEMCPY(scratch, c, partial); xorbuf(x, scratch, AES_BLOCK_SIZE); @@ -1519,24 +1536,13 @@ static void GHASH(byte* h, const byte* a, word32 aSz, } } - /* Hash in the lengths in bits of A and C */ - { - byte len[AES_BLOCK_SIZE]; - XMEMSET(len, 0, AES_BLOCK_SIZE); - len[3] = aSz >> 29; - len[4] = aSz >> 21; - len[5] = aSz >> 13; - len[6] = aSz >> 5; - len[7] = aSz << 3; + /* Hash in the lengths of A and C in bits */ + FlattenSzInBits(&scratch[0], aSz); + FlattenSzInBits(&scratch[8], cSz); + xorbuf(x, scratch, AES_BLOCK_SIZE); + GMULT(x, h); - len[11] = cSz >> 29; - len[12] = cSz >> 21; - len[13] = cSz >> 13; - len[14] = cSz >> 5; - len[15] = cSz << 3; - xorbuf(x, len, AES_BLOCK_SIZE); - GMULT(x, h); - } + /* Copy the result into s. */ XMEMCPY(s, x, sSz); } diff --git a/cyassl/internal.h b/cyassl/internal.h index 6294598e5..02d33f52f 100644 --- a/cyassl/internal.h +++ b/cyassl/internal.h @@ -381,7 +381,10 @@ enum Misc { CERT_HEADER_SZ = 3, /* always 3 bytes */ REQ_HEADER_SZ = 2, /* cert request header sz */ HINT_LEN_SZ = 2, /* length of hint size field */ - HELLO_EXT_SZ = 14, /* length of the lazy hello extensions */ + HELLO_EXT_SZ = 14, /* total length of the lazy hello extensions */ + HELLO_EXT_LEN = 12, /* length of the lazy hello extensions */ + HELLO_EXT_SIGALGO_SZ = 8, /* length of signature algo extension */ + HELLO_EXT_SIGALGO_LEN = 6, /* number of items in the signature algo list */ DTLS_HANDSHAKE_HEADER_SZ = 12, /* normal + seq(2) + offset(3) + length(3) */ DTLS_RECORD_HEADER_SZ = 13, /* normal + epoch(2) + seq_num(6) */ @@ -405,10 +408,19 @@ 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_GCM_IMP_IV_SZ = 4, /* Implicit part of IV */ + AES_GCM_EXP_IV_SZ = 8, /* Explicit part of IV */ + AES_GCM_CTR_IV_SZ = 4, /* Counter part of IV */ AES_128_KEY_SIZE = 16, /* for 128 bit */ + AEAD_SEQ_OFFSET = 4, /* Auth Data: Sequence number */ + AEAD_TYPE_OFFSET = 8, /* Auth Data: Type */ + AEAD_VMAJ_OFFSET = 9, /* Auth Data: Major Version */ + AEAD_VMIN_OFFSET = 10, /* Auth Data: Minor Version */ + AEAD_LEN_OFFSET = 11, /* Auth Data: Length */ + AEAD_AUTH_TAG_SZ = 16, /* Size of the authentication tag */ + AEAD_AUTH_DATA_SZ = 13, /* Size of the data to authenticate */ + HC_128_KEY_SIZE = 16, /* 128 bits */ HC_128_IV_SIZE = 16, /* also 128 bits */ diff --git a/src/internal.c b/src/internal.c index cb74aebf3..df3584320 100644 --- a/src/internal.c +++ b/src/internal.c @@ -2064,8 +2064,7 @@ int DoFinished(CYASSL* ssl, const byte* input, word32* inOutIdx, int sniff) } } else { - idx = idx + finishedSz + 16; - /* XXX the 16 should be from specs */ + idx += (finishedSz + AEAD_AUTH_TAG_SZ); } if (ssl->options.side == CLIENT_END) { @@ -2233,26 +2232,40 @@ static INLINE void Encrypt(CYASSL* ssl, byte* out, const byte* input, word32 sz) byte additional[AES_BLOCK_SIZE]; byte nonce[AES_BLOCK_SIZE]; + /* use this side's IV */ if (ssl->options.side == SERVER_END) { XMEMCPY(nonce, ssl->keys.server_write_IV, - AES_GCM_IMPLICIT_IV_SIZE); + AES_GCM_IMP_IV_SZ); } else { XMEMCPY(nonce, ssl->keys.client_write_IV, - AES_GCM_IMPLICIT_IV_SIZE); + AES_GCM_IMP_IV_SZ); } - 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); + XMEMCPY(nonce + AES_GCM_IMP_IV_SZ, + input, AES_GCM_EXP_IV_SZ); + XMEMSET(nonce + AES_GCM_IMP_IV_SZ + AES_GCM_EXP_IV_SZ, + 0, AES_GCM_CTR_IV_SZ); AesSetIV(&ssl->encrypt.aes, nonce); - - XMEMSET(additional, 0, 16); - c32toa(GetSEQIncrement(ssl, 0), additional + 4); - XMEMCPY(additional+8, input - 5, 5); - c16toa(sz - 24, additional+11); - AesGcmEncrypt(&ssl->encrypt.aes, out+8, input+8, sz-24, - out + sz - 16, 16, additional, 13); + + XMEMSET(additional, 0, AES_BLOCK_SIZE); + + /* sequence number field is 64-bits, we only use 32-bits */ + c32toa(GetSEQIncrement(ssl, 0), + additional + AEAD_SEQ_OFFSET); + + /* Store the type, version. Unfortunately, they are in + * the input buffer ahead of the plaintext. */ + XMEMCPY(additional + AEAD_TYPE_OFFSET, input - 5, 3); + + /* Store the length of the plain text minus the explicit + * IV length minus the authentication tag size. */ + c16toa(sz - AES_GCM_EXP_IV_SZ - AEAD_AUTH_TAG_SZ, + additional + AEAD_LEN_OFFSET); + AesGcmEncrypt(&ssl->encrypt.aes, + out + AES_GCM_EXP_IV_SZ, input + AES_GCM_EXP_IV_SZ, + sz - AES_GCM_EXP_IV_SZ - AEAD_AUTH_TAG_SZ, + out + sz - AEAD_AUTH_TAG_SZ, AEAD_AUTH_TAG_SZ, + additional, AEAD_AUTH_DATA_SZ); } break; #endif @@ -2300,31 +2313,41 @@ static INLINE int Decrypt(CYASSL* ssl, byte* plain, const byte* input, #ifdef BUILD_AESGCM case aes_gcm: { - byte additional[16]; - byte nonce[16]; + byte additional[AES_BLOCK_SIZE]; + byte nonce[AES_BLOCK_SIZE]; /* use the other side's IV */ if (ssl->options.side == SERVER_END) { XMEMCPY(nonce, ssl->keys.client_write_IV, - AES_GCM_IMPLICIT_IV_SIZE); + AES_GCM_IMP_IV_SZ); } else { XMEMCPY(nonce, ssl->keys.server_write_IV, - AES_GCM_IMPLICIT_IV_SIZE); + AES_GCM_IMP_IV_SZ); } - 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); + XMEMCPY(nonce + AES_GCM_IMP_IV_SZ, + input, AES_GCM_EXP_IV_SZ); + XMEMSET(nonce + AES_GCM_IMP_IV_SZ + AES_GCM_EXP_IV_SZ, + 0, AES_GCM_CTR_IV_SZ); 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-24, additional + 11); - if (AesGcmDecrypt(&ssl->decrypt.aes, plain+8, input+8, sz-24, - input + 8 + (sz - 24), 16, additional, 13) < 0) { + + XMEMSET(additional, 0, AES_BLOCK_SIZE); + + /* sequence number field is 64-bits, we only use 32-bits */ + c32toa(GetSEQIncrement(ssl, 1), additional + AEAD_SEQ_OFFSET); + + additional[AEAD_TYPE_OFFSET] = ssl->curRL.type; + additional[AEAD_VMAJ_OFFSET] = ssl->curRL.version.major; + additional[AEAD_VMIN_OFFSET] = ssl->curRL.version.minor; + + c16toa(sz - AES_GCM_EXP_IV_SZ - AEAD_AUTH_TAG_SZ, + additional + AEAD_LEN_OFFSET); + if (AesGcmDecrypt(&ssl->decrypt.aes, + plain + AES_GCM_EXP_IV_SZ, + input + AES_GCM_EXP_IV_SZ, + sz - AES_GCM_EXP_IV_SZ - AEAD_AUTH_TAG_SZ, + input + sz - AEAD_AUTH_TAG_SZ, AEAD_AUTH_TAG_SZ, + additional, AEAD_AUTH_DATA_SZ) < 0) { SendAlert(ssl, alert_fatal, bad_record_mac); return VERIFY_MAC_ERROR; } @@ -2362,7 +2385,7 @@ static int DecryptMessage(CYASSL* ssl, byte* input, word32 sz, word32* idx) 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; + *idx += AES_GCM_EXP_IV_SZ; } return decryptResult; @@ -2393,8 +2416,8 @@ int DoApplicationData(CYASSL* ssl, byte* input, word32* inOutIdx) padByte = 1; } if (ssl->specs.cipher_type == aead) { - ivExtra = 8; - digestSz = 16; + ivExtra = AES_GCM_EXP_IV_SZ; + digestSz = AEAD_AUTH_TAG_SZ; } dataSz = msgSz - ivExtra - digestSz - pad - padByte; @@ -2497,8 +2520,7 @@ static int DoAlert(CYASSL* ssl, byte* input, word32* inOutIdx, int* type) } } else { - *inOutIdx += 16; - /* XXX this should be a value out of the cipher specs */ + *inOutIdx += AEAD_AUTH_TAG_SZ; } } @@ -3017,8 +3039,8 @@ static int BuildMessage(CYASSL* ssl, byte* output, const byte* input, int inSz, } if (ssl->specs.cipher_type == aead) { - ivSz = AES_GCM_EXPLICIT_IV_SIZE; - sz = sz + ivSz + 16 - digestSz; + ivSz = AES_GCM_EXP_IV_SZ; + sz += (ivSz + 16 - digestSz); RNG_GenerateBlock(&ssl->rng, iv, ivSz); } size = (word16)(sz - headerSz); /* include mac and digest */ @@ -4457,15 +4479,16 @@ int SetCipherList(Suites* s, const char* list) if (IsAtLeastTLSv1_2(ssl)) { /* add in the extensions length */ - c16toa(HELLO_EXT_SZ-2, output + idx); + c16toa(HELLO_EXT_LEN, output + idx); idx += 2; c16toa(HELLO_EXT_SIG_ALGO, output + idx); idx += 2; - c16toa(HELLO_EXT_SZ-6, output + idx); + c16toa(HELLO_EXT_SIGALGO_SZ, output + idx); idx += 2; - - c16toa(HELLO_EXT_SZ-8, output + idx); + /* This is a lazy list setup. Eventually, we'll need to support + * using other hash types or even other extensions. */ + c16toa(HELLO_EXT_SIGALGO_LEN, output + idx); idx += 2; output[idx++] = sha_mac; output[idx++] = rsa_sa_algo; diff --git a/src/keys.c b/src/keys.c index 846345af8..2c471b92b 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_GCM_IMPLICIT_IV_SIZE; + ssl->specs.iv_size = AES_GCM_IMP_IV_SZ; 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_GCM_IMPLICIT_IV_SIZE; + ssl->specs.iv_size = AES_GCM_IMP_IV_SZ; 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_GCM_IMPLICIT_IV_SIZE; + ssl->specs.iv_size = AES_GCM_IMP_IV_SZ; 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_GCM_IMPLICIT_IV_SIZE; + ssl->specs.iv_size = AES_GCM_IMP_IV_SZ; 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_GCM_IMPLICIT_IV_SIZE; + ssl->specs.iv_size = AES_GCM_IMP_IV_SZ; 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_GCM_IMPLICIT_IV_SIZE; + ssl->specs.iv_size = AES_GCM_IMP_IV_SZ; 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_GCM_IMPLICIT_IV_SIZE; + ssl->specs.iv_size = AES_GCM_IMP_IV_SZ; 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_GCM_IMPLICIT_IV_SIZE; + ssl->specs.iv_size = AES_GCM_IMP_IV_SZ; break; #endif @@ -794,7 +794,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_GCM_IMPLICIT_IV_SIZE; + ssl->specs.iv_size = AES_GCM_IMP_IV_SZ; break; #endif @@ -811,7 +811,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_GCM_IMPLICIT_IV_SIZE; + ssl->specs.iv_size = AES_GCM_IMP_IV_SZ; break; #endif @@ -828,7 +828,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_GCM_IMPLICIT_IV_SIZE; + ssl->specs.iv_size = AES_GCM_IMP_IV_SZ; break; #endif @@ -845,7 +845,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_GCM_IMPLICIT_IV_SIZE; + ssl->specs.iv_size = AES_GCM_IMP_IV_SZ; break; #endif