From 7d71d756f33eb51f3dfa3a21b66ce395572c8378 Mon Sep 17 00:00:00 2001 From: Jacob Barthelmeh Date: Wed, 27 Jan 2016 14:03:05 -0700 Subject: [PATCH] update ChaCha20-Poly1305 to most recent RFCs --- examples/client/client.c | 10 -- src/internal.c | 331 +++++++++++++++++++++-------------- src/keys.c | 75 +++++++- src/ssl.c | 15 +- tests/test.conf | 58 +++--- wolfcrypt/src/poly1305.c | 86 +++++++++ wolfcrypt/test/test.c | 64 +++++++ wolfssl/internal.h | 29 ++- wolfssl/wolfcrypt/poly1305.h | 7 +- 9 files changed, 487 insertions(+), 188 deletions(-) diff --git a/examples/client/client.c b/examples/client/client.c index 23bbbf176..586f773b0 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -1071,16 +1071,6 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) #endif tcp_connect(&sockfd, host, port, doDTLS, ssl); - -#ifdef HAVE_POLY1305 - /* use old poly to connect with google and wolfssl.com server */ - if (!XSTRNCMP(domain, "www.google.com", 14) || - !XSTRNCMP(domain, "www.wolfssl.com", 15)) { - if (wolfSSL_use_old_poly(ssl, 1) != 0) - err_sys("unable to set to old poly"); - } -#endif - wolfSSL_set_fd(ssl, sockfd); #ifdef HAVE_CRL if (disableCRL == 0) { diff --git a/src/internal.c b/src/internal.c index b3e3c7a92..96a315f7a 100644 --- a/src/internal.c +++ b/src/internal.c @@ -1263,6 +1263,28 @@ void InitSuites(Suites* suites, ProtocolVersion pv, word16 haveRSA, } #endif +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_CHACHA20_OLD_POLY1305_SHA256 + if (tls1_2 && haveECDSAsig) { + suites->suites[idx++] = CHACHA_BYTE; + suites->suites[idx++] = + TLS_ECDHE_ECDSA_WITH_CHACHA20_OLD_POLY1305_SHA256; + } +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256 + if (tls1_2 && haveRSA) { + suites->suites[idx++] = CHACHA_BYTE; + suites->suites[idx++] = TLS_ECDHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256; + } +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256 + if (tls1_2 && haveRSA) { + suites->suites[idx++] = CHACHA_BYTE; + suites->suites[idx++] = TLS_DHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256; + } +#endif + #ifdef BUILD_TLS_RSA_WITH_NULL_SHA if (tls && haveRSA) { suites->suites[idx++] = 0; @@ -3726,6 +3748,23 @@ static int BuildFinished(WOLFSSL* ssl, Hashes* hashes, const byte* sender) if (requirement == REQUIRES_DHE) return 1; break; + + case TLS_ECDHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256 : + if (requirement == REQUIRES_RSA) + return 1; + break; + + case TLS_ECDHE_ECDSA_WITH_CHACHA20_OLD_POLY1305_SHA256 : + if (requirement == REQUIRES_ECC_DSA) + return 1; + break; + + case TLS_DHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256 : + if (requirement == REQUIRES_RSA) + return 1; + if (requirement == REQUIRES_DHE) + return 1; + break; } } @@ -5999,65 +6038,6 @@ static INLINE void AeadIncrementExpIV(WOLFSSL* ssl) #if defined(HAVE_POLY1305) && defined(HAVE_CHACHA) -/*more recent rfc's concatonate input for poly1305 differently*/ -static int Poly1305Tag(WOLFSSL* ssl, byte* additional, const byte* out, - byte* cipher, word16 sz, byte* tag) -{ - int ret = 0; - int paddingSz = 0; - int msglen = (sz - ssl->specs.aead_mac_size); - word32 keySz = 32; - int blockSz = 16; - byte padding[16]; - - if (msglen < 0) - return INPUT_CASE_ERROR; - - XMEMSET(padding, 0, sizeof(padding)); - - if ((ret = wc_Poly1305SetKey(ssl->auth.poly1305, cipher, keySz)) != 0) - return ret; - - /* additional input to poly1305 */ - if ((ret = wc_Poly1305Update(ssl->auth.poly1305, additional, blockSz)) != 0) - return ret; - - /* cipher input */ - if ((ret = wc_Poly1305Update(ssl->auth.poly1305, out, msglen)) != 0) - return ret; - - /* handle padding for cipher input to make it 16 bytes long */ - if (msglen % 16 != 0) { - paddingSz = (16 - (sz - ssl->specs.aead_mac_size) % 16); - if (paddingSz < 0) - return INPUT_CASE_ERROR; - - if ((ret = wc_Poly1305Update(ssl->auth.poly1305, padding, paddingSz)) - != 0) - return ret; - } - - /* add size of AD and size of cipher to poly input */ - XMEMSET(padding, 0, sizeof(padding)); - padding[0] = blockSz; - - /* 32 bit size of cipher to 64 bit endian */ - padding[8] = msglen & 0xff; - padding[9] = (msglen >> 8) & 0xff; - padding[10] = (msglen >>16) & 0xff; - padding[11] = (msglen >>24) & 0xff; - if ((ret = wc_Poly1305Update(ssl->auth.poly1305, padding, sizeof(padding))) - != 0) - return ret; - - /* generate tag */ - if ((ret = wc_Poly1305Final(ssl->auth.poly1305, tag)) != 0) - return ret; - - return ret; -} - - /* Used for the older version of creating AEAD tags with Poly1305 */ static int Poly1305TagOld(WOLFSSL* ssl, byte* additional, const byte* out, byte* cipher, word16 sz, byte* tag) @@ -6077,9 +6057,6 @@ static int Poly1305TagOld(WOLFSSL* ssl, byte* additional, const byte* out, if ((ret = wc_Poly1305SetKey(ssl->auth.poly1305, cipher, keySz)) != 0) return ret; - /* add TLS compressed length and additional input to poly1305 */ - additional[AEAD_AUTH_DATA_SZ - 2] = (msglen >> 8) & 0xff; - additional[AEAD_AUTH_DATA_SZ - 1] = msglen & 0xff; if ((ret = wc_Poly1305Update(ssl->auth.poly1305, additional, AEAD_AUTH_DATA_SZ)) != 0) return ret; @@ -6118,42 +6095,49 @@ static int ChachaAEADEncrypt(WOLFSSL* ssl, byte* out, const byte* input, word16 sz) { const byte* additionalSrc = input - RECORD_HEADER_SZ; - int ret = 0; + int ret = 0; + word32 msgLen = (sz - ssl->specs.aead_mac_size); byte tag[POLY1305_AUTH_SZ]; - byte additional[CHACHA20_BLOCK_SIZE]; - byte nonce[AEAD_NONCE_SZ]; - byte cipher[CHACHA20_256_KEY_SIZE]; /* generated key for poly1305 */ + byte add[AEAD_AUTH_DATA_SZ]; + byte nonce[CHACHA20_IV_SIZE]; + byte poly[CHACHA20_256_KEY_SIZE]; /* generated key for poly1305 */ #ifdef CHACHA_AEAD_TEST int i; #endif - XMEMSET(tag, 0, sizeof(tag)); - XMEMSET(nonce, 0, AEAD_NONCE_SZ); - XMEMSET(cipher, 0, sizeof(cipher)); - XMEMSET(additional, 0, CHACHA20_BLOCK_SIZE); + XMEMSET(tag, 0, sizeof(tag)); + XMEMSET(nonce, 0, sizeof(nonce)); + XMEMSET(poly, 0, sizeof(poly)); + XMEMSET(add, 0, sizeof(add)); - /* get nonce */ - c32toa(ssl->keys.sequence_number, nonce + AEAD_IMP_IV_SZ - + AEAD_SEQ_OFFSET); + if (ssl->options.oldPoly != 0) { + /* get nonce */ + c32toa(ssl->keys.sequence_number, nonce + AEAD_IMP_IV_SZ + + AEAD_SEQ_OFFSET); + } /* opaque SEQ number stored for AD */ - c32toa(GetSEQIncrement(ssl, 0), additional + AEAD_SEQ_OFFSET); + c32toa(GetSEQIncrement(ssl, 0), add + AEAD_SEQ_OFFSET); /* Store the type, version. Unfortunately, they are in * the input buffer ahead of the plaintext. */ #ifdef WOLFSSL_DTLS if (ssl->options.dtls) { - c16toa(ssl->keys.dtls_epoch, additional); + c16toa(ssl->keys.dtls_epoch, add); additionalSrc -= DTLS_HANDSHAKE_EXTRA; } #endif - XMEMCPY(additional + AEAD_TYPE_OFFSET, additionalSrc, 3); + /* add TLS message size to additional data */ + add[AEAD_AUTH_DATA_SZ - 2] = (msgLen >> 8) & 0xff; + add[AEAD_AUTH_DATA_SZ - 1] = msgLen & 0xff; + + XMEMCPY(add + AEAD_TYPE_OFFSET, additionalSrc, 3); #ifdef CHACHA_AEAD_TEST printf("Encrypt Additional : "); - for (i = 0; i < CHACHA20_BLOCK_SIZE; i++) { - printf("%02x", additional[i]); + for (i = 0; i < AEAD_AUTH_DATA_SZ; i++) { + printf("%02x", add[i]); } printf("\n\n"); printf("input before encryption :\n"); @@ -6165,36 +6149,65 @@ static int ChachaAEADEncrypt(WOLFSSL* ssl, byte* out, const byte* input, printf("\n"); #endif - /* set the nonce for chacha and get poly1305 key */ - if ((ret = wc_Chacha_SetIV(ssl->encrypt.chacha, nonce, 0)) != 0) - return ret; + if (ssl->options.oldPoly == 0) { + /* nonce is formed by 4 0x00 byte padded to the left followed by 8 byte + * record sequence number XORed with client_write_IV/server_write_IV */ + XMEMCPY(nonce, ssl->keys.aead_enc_imp_IV, CHACHA20_IV_SIZE); + nonce[4] ^= add[0]; + nonce[5] ^= add[1]; + nonce[6] ^= add[2]; + nonce[7] ^= add[3]; + nonce[8] ^= add[4]; + nonce[9] ^= add[5]; + nonce[10] ^= add[6]; + nonce[11] ^= add[7]; + } - if ((ret = wc_Chacha_Process(ssl->encrypt.chacha, cipher, - cipher, sizeof(cipher))) != 0) + /* set the nonce for chacha and get poly1305 key */ + if ((ret = wc_Chacha_SetIV(ssl->encrypt.chacha, nonce, 0)) != 0) { + ForceZero(nonce, AEAD_NONCE_SZ); + return ret; + } + + ForceZero(nonce, AEAD_NONCE_SZ); /* done with nonce, clear it */ + /* create Poly1305 key using chacha20 keystream */ + if ((ret = wc_Chacha_Process(ssl->encrypt.chacha, poly, + poly, sizeof(poly))) != 0) return ret; /* encrypt the plain text */ - if ((ret = wc_Chacha_Process(ssl->encrypt.chacha, out, input, - sz - ssl->specs.aead_mac_size)) != 0) + if ((ret = wc_Chacha_Process(ssl->encrypt.chacha, out, + input, msgLen)) != 0) { + ForceZero(poly, sizeof(poly)); return ret; + } - /* get the tag : future use of hmac could go here*/ - if (ssl->options.oldPoly == 1) { - if ((ret = Poly1305TagOld(ssl, additional, (const byte* )out, - cipher, sz, tag)) != 0) + /* get the poly1305 tag using either old padding scheme or more recent */ + if (ssl->options.oldPoly != 0) { + if ((ret = Poly1305TagOld(ssl, add, (const byte* )out, + poly, sz, tag)) != 0) { + ForceZero(poly, sizeof(poly)); return ret; + } } else { - if ((ret = Poly1305Tag(ssl, additional, (const byte* )out, - cipher, sz, tag)) != 0) + if ((ret = wc_Poly1305SetKey(ssl->auth.poly1305, poly, + sizeof(poly))) != 0) { + ForceZero(poly, sizeof(poly)); return ret; + } + if ((ret = wc_Poly1305_MAC(ssl->auth.poly1305, add, + sizeof(add), out, msgLen, tag, sizeof(tag))) != 0) { + ForceZero(poly, sizeof(poly)); + return ret; + } } + ForceZero(poly, sizeof(poly)); /* done with poly1305 key, clear it */ /* append tag to ciphertext */ - XMEMCPY(out + sz - ssl->specs.aead_mac_size, tag, sizeof(tag)); + XMEMCPY(out + msgLen, tag, sizeof(tag)); AeadIncrementExpIV(ssl); - ForceZero(nonce, AEAD_NONCE_SZ); #ifdef CHACHA_AEAD_TEST printf("mac tag :\n"); @@ -6219,16 +6232,12 @@ static int ChachaAEADEncrypt(WOLFSSL* ssl, byte* out, const byte* input, static int ChachaAEADDecrypt(WOLFSSL* ssl, byte* plain, const byte* input, word16 sz) { - byte additional[CHACHA20_BLOCK_SIZE]; - byte nonce[AEAD_NONCE_SZ]; + byte add[AEAD_AUTH_DATA_SZ]; + byte nonce[CHACHA20_IV_SIZE]; byte tag[POLY1305_AUTH_SZ]; - byte cipher[CHACHA20_256_KEY_SIZE]; /* generated key for mac */ - int ret = 0; - - XMEMSET(tag, 0, sizeof(tag)); - XMEMSET(cipher, 0, sizeof(cipher)); - XMEMSET(nonce, 0, AEAD_NONCE_SZ); - XMEMSET(additional, 0, CHACHA20_BLOCK_SIZE); + byte poly[CHACHA20_256_KEY_SIZE]; /* generated key for mac */ + int ret = 0; + int msgLen = (sz - ssl->specs.aead_mac_size); #ifdef CHACHA_AEAD_TEST int i; @@ -6241,64 +6250,100 @@ static int ChachaAEADDecrypt(WOLFSSL* ssl, byte* plain, const byte* input, printf("\n"); #endif - /* get nonce */ - c32toa(ssl->keys.peer_sequence_number, nonce + AEAD_IMP_IV_SZ - + AEAD_SEQ_OFFSET); + XMEMSET(tag, 0, sizeof(tag)); + XMEMSET(poly, 0, sizeof(poly)); + XMEMSET(nonce, 0, sizeof(nonce)); + XMEMSET(add, 0, sizeof(add)); + + if (ssl->options.oldPoly != 0) { + /* get nonce */ + c32toa(ssl->keys.peer_sequence_number, nonce + AEAD_IMP_IV_SZ + + AEAD_SEQ_OFFSET); + } /* sequence number field is 64-bits, we only use 32-bits */ - c32toa(GetSEQIncrement(ssl, 1), additional + AEAD_SEQ_OFFSET); + c32toa(GetSEQIncrement(ssl, 1), add + AEAD_SEQ_OFFSET); /* get AD info */ - additional[AEAD_TYPE_OFFSET] = ssl->curRL.type; - additional[AEAD_VMAJ_OFFSET] = ssl->curRL.pvMajor; - additional[AEAD_VMIN_OFFSET] = ssl->curRL.pvMinor; + add[AEAD_TYPE_OFFSET] = ssl->curRL.type; + add[AEAD_VMAJ_OFFSET] = ssl->curRL.pvMajor; + add[AEAD_VMIN_OFFSET] = ssl->curRL.pvMinor; /* Store the type, version. */ #ifdef WOLFSSL_DTLS if (ssl->options.dtls) - c16toa(ssl->keys.dtls_state.curEpoch, additional); + c16toa(ssl->keys.dtls_state.curEpoch, add); #endif + /* add TLS message size to additional data */ + add[AEAD_AUTH_DATA_SZ - 2] = (msgLen >> 8) & 0xff; + add[AEAD_AUTH_DATA_SZ - 1] = msgLen & 0xff; + #ifdef CHACHA_AEAD_TEST printf("Decrypt Additional : "); - for (i = 0; i < CHACHA20_BLOCK_SIZE; i++) { - printf("%02x", additional[i]); + for (i = 0; i < AEAD_AUTH_DATA_SZ; i++) { + printf("%02x", add[i]); } printf("\n\n"); #endif + if (ssl->options.oldPoly == 0) { + /* nonce is formed by 4 0x00 byte padded to the left followed by 8 byte + * record sequence number XORed with client_write_IV/server_write_IV */ + XMEMCPY(nonce, ssl->keys.aead_dec_imp_IV, CHACHA20_IV_SIZE); + nonce[4] ^= add[0]; + nonce[5] ^= add[1]; + nonce[6] ^= add[2]; + nonce[7] ^= add[3]; + nonce[8] ^= add[4]; + nonce[9] ^= add[5]; + nonce[10] ^= add[6]; + nonce[11] ^= add[7]; + } + /* set nonce and get poly1305 key */ - if ((ret = wc_Chacha_SetIV(ssl->decrypt.chacha, nonce, 0)) != 0) + if ((ret = wc_Chacha_SetIV(ssl->decrypt.chacha, nonce, 0)) != 0) { + ForceZero(nonce, AEAD_NONCE_SZ); + return ret; + } + + ForceZero(nonce, AEAD_NONCE_SZ); /* done with nonce, clear it */ + /* use chacha20 keystream to get poly1305 key for tag */ + if ((ret = wc_Chacha_Process(ssl->decrypt.chacha, poly, + poly, sizeof(poly))) != 0) return ret; - if ((ret = wc_Chacha_Process(ssl->decrypt.chacha, cipher, - cipher, sizeof(cipher))) != 0) - return ret; - - /* get the tag : future use of hmac could go here*/ - if (ssl->options.oldPoly == 1) { - if ((ret = Poly1305TagOld(ssl, additional, input, cipher, - sz, tag)) != 0) + /* get the tag using Poly1305 */ + if (ssl->options.oldPoly != 0) { + if ((ret = Poly1305TagOld(ssl, add, input, poly, sz, tag)) != 0) { + ForceZero(poly, sizeof(poly)); return ret; + } } else { - if ((ret = Poly1305Tag(ssl, additional, input, cipher, - sz, tag)) != 0) + if ((ret = wc_Poly1305SetKey(ssl->auth.poly1305, poly, + sizeof(poly))) != 0) { + ForceZero(poly, sizeof(poly)); return ret; + } + if ((ret = wc_Poly1305_MAC(ssl->auth.poly1305, add, + sizeof(add), (byte*)input, msgLen, tag, sizeof(tag))) != 0) { + ForceZero(poly, sizeof(poly)); + return ret; + } } + ForceZero(poly, sizeof(poly)); /* done with poly1305 key, clear it */ - /* check mac sent along with packet */ - if (ConstantCompare(input + sz - ssl->specs.aead_mac_size, tag, - ssl->specs.aead_mac_size) != 0) { - WOLFSSL_MSG("Mac did not match"); + /* check tag sent along with packet */ + if (ConstantCompare(input + msgLen, tag, ssl->specs.aead_mac_size) != 0) { + WOLFSSL_MSG("MAC did not match"); SendAlert(ssl, alert_fatal, bad_record_mac); - ForceZero(nonce, AEAD_NONCE_SZ); return VERIFY_MAC_ERROR; } - /* if mac was good decrypt message */ - if ((ret = wc_Chacha_Process(ssl->decrypt.chacha, plain, input, - sz - ssl->specs.aead_mac_size)) != 0) + /* if the tag was good decrypt message */ + if ((ret = wc_Chacha_Process(ssl->decrypt.chacha, plain, + input, msgLen)) != 0) return ret; #ifdef CHACHA_AEAD_TEST @@ -9837,6 +9882,18 @@ static const char* const cipher_names[] = "DHE-RSA-CHACHA20-POLY1305", #endif +#ifdef BUILD_TLS_ECDHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256 + "ECDHE-RSA-CHACHA20-POLY1305-OLD", +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_CHACHA20_OLD_POLY1305_SHA256 + "ECDHE-ECDSA-CHACHA20-POLY1305-OLD", +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256 + "DHE-RSA-CHACHA20-POLY1305-OLD", +#endif + #ifdef BUILD_TLS_DH_anon_WITH_AES_128_CBC_SHA "ADH-AES128-SHA", #endif @@ -10239,6 +10296,18 @@ static int cipher_name_idx[] = TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256, #endif +#ifdef BUILD_TLS_ECDHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256 + TLS_ECDHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256, +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_CHACHA20_OLD_POLY1305_SHA256 + TLS_ECDHE_ECDSA_WITH_CHACHA20_OLD_POLY1305_SHA256, +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256 + TLS_DHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256, +#endif + #ifdef BUILD_TLS_DH_anon_WITH_AES_128_CBC_SHA TLS_DH_anon_WITH_AES_128_CBC_SHA, #endif diff --git a/src/keys.c b/src/keys.c index 3545a5e1c..65529efeb 100644 --- a/src/keys.c +++ b/src/keys.c @@ -60,6 +60,62 @@ int SetCipherSpecs(WOLFSSL* ssl) if (ssl->options.cipherSuite0 == CHACHA_BYTE) { switch (ssl->options.cipherSuite) { +#ifdef BUILD_TLS_ECDHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256 + case TLS_ECDHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256: + ssl->specs.bulk_cipher_algorithm = wolfssl_chacha; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = CHACHA20_256_KEY_SIZE; + ssl->specs.block_size = CHACHA20_BLOCK_SIZE; + ssl->specs.iv_size = CHACHA20_IV_SIZE; + ssl->specs.aead_mac_size = POLY1305_AUTH_SZ; + ssl->options.oldPoly = 1; /* use old poly1305 padding */ + + break; +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_CHACHA20_OLD_POLY1305_SHA256 + case TLS_ECDHE_ECDSA_WITH_CHACHA20_OLD_POLY1305_SHA256: + ssl->specs.bulk_cipher_algorithm = wolfssl_chacha; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = ecc_dsa_sa_algo; + ssl->specs.hash_size = SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = CHACHA20_256_KEY_SIZE; + ssl->specs.block_size = CHACHA20_BLOCK_SIZE; + ssl->specs.iv_size = CHACHA20_IV_SIZE; + ssl->specs.aead_mac_size = POLY1305_AUTH_SZ; + ssl->options.oldPoly = 1; /* use old poly1305 padding */ + + break; +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256 + case TLS_DHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256: + ssl->specs.bulk_cipher_algorithm = wolfssl_chacha; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = CHACHA20_256_KEY_SIZE; + ssl->specs.block_size = CHACHA20_BLOCK_SIZE; + ssl->specs.iv_size = CHACHA20_IV_SIZE; + ssl->specs.aead_mac_size = POLY1305_AUTH_SZ; + ssl->options.oldPoly = 1; /* use old poly1305 padding */ + + break; +#endif #ifdef BUILD_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: ssl->specs.bulk_cipher_algorithm = wolfssl_chacha; @@ -74,6 +130,7 @@ int SetCipherSpecs(WOLFSSL* ssl) ssl->specs.block_size = CHACHA20_BLOCK_SIZE; ssl->specs.iv_size = CHACHA20_IV_SIZE; ssl->specs.aead_mac_size = POLY1305_AUTH_SZ; + ssl->options.oldPoly = 0; /* use recent padding RFC */ break; #endif @@ -92,6 +149,7 @@ int SetCipherSpecs(WOLFSSL* ssl) ssl->specs.block_size = CHACHA20_BLOCK_SIZE; ssl->specs.iv_size = CHACHA20_IV_SIZE; ssl->specs.aead_mac_size = POLY1305_AUTH_SZ; + ssl->options.oldPoly = 0; /* use recent padding RFC */ break; #endif @@ -110,6 +168,7 @@ int SetCipherSpecs(WOLFSSL* ssl) ssl->specs.block_size = CHACHA20_BLOCK_SIZE; ssl->specs.iv_size = CHACHA20_IV_SIZE; ssl->specs.aead_mac_size = POLY1305_AUTH_SZ; + ssl->options.oldPoly = 0; /* use recent padding RFC */ break; #endif @@ -1916,14 +1975,14 @@ static int SetKeys(Ciphers* enc, Ciphers* dec, Keys* keys, CipherSpecs* specs, chachaRet = wc_Chacha_SetKey(enc->chacha, keys->client_write_key, specs->key_size); XMEMCPY(keys->aead_enc_imp_IV, keys->client_write_IV, - AEAD_IMP_IV_SZ); + CHACHA20_IV_SIZE); if (chachaRet != 0) return chachaRet; } if (dec) { chachaRet = wc_Chacha_SetKey(dec->chacha, keys->server_write_key, specs->key_size); XMEMCPY(keys->aead_dec_imp_IV, keys->server_write_IV, - AEAD_IMP_IV_SZ); + CHACHA20_IV_SIZE); if (chachaRet != 0) return chachaRet; } } @@ -1932,14 +1991,14 @@ static int SetKeys(Ciphers* enc, Ciphers* dec, Keys* keys, CipherSpecs* specs, chachaRet = wc_Chacha_SetKey(enc->chacha, keys->server_write_key, specs->key_size); XMEMCPY(keys->aead_enc_imp_IV, keys->server_write_IV, - AEAD_IMP_IV_SZ); + CHACHA20_IV_SIZE); if (chachaRet != 0) return chachaRet; } if (dec) { chachaRet = wc_Chacha_SetKey(dec->chacha, keys->client_write_key, specs->key_size); XMEMCPY(keys->aead_dec_imp_IV, keys->client_write_IV, - AEAD_IMP_IV_SZ); + CHACHA20_IV_SIZE); if (chachaRet != 0) return chachaRet; } } @@ -2489,10 +2548,10 @@ int SetKeysSide(WOLFSSL* ssl, enum encrypt_side side) /* Initialize encrypt implicit IV by encrypt side */ if (ssl->options.side == WOLFSSL_CLIENT_END) { XMEMCPY(ssl->keys.aead_enc_imp_IV, - keys->client_write_IV, AEAD_IMP_IV_SZ); + keys->client_write_IV, AEAD_NONCE_SZ); } else { XMEMCPY(ssl->keys.aead_enc_imp_IV, - keys->server_write_IV, AEAD_IMP_IV_SZ); + keys->server_write_IV, AEAD_NONCE_SZ); } } #endif @@ -2504,10 +2563,10 @@ int SetKeysSide(WOLFSSL* ssl, enum encrypt_side side) /* Initialize decrypt implicit IV by decrypt side */ if (ssl->options.side == WOLFSSL_SERVER_END) { XMEMCPY(ssl->keys.aead_dec_imp_IV, - keys->client_write_IV, AEAD_IMP_IV_SZ); + keys->client_write_IV, AEAD_NONCE_SZ); } else { XMEMCPY(ssl->keys.aead_dec_imp_IV, - keys->server_write_IV, AEAD_IMP_IV_SZ); + keys->server_write_IV, AEAD_NONCE_SZ); } } #endif diff --git a/src/ssl.c b/src/ssl.c index ed989932f..a83923c84 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -235,6 +235,8 @@ void wolfSSL_free(WOLFSSL* ssl) int wolfSSL_use_old_poly(WOLFSSL* ssl, int value) { WOLFSSL_ENTER("SSL_use_old_poly"); + WOLFSSL_MSG("Warning SSL connection auto detects old/new and this function" + "is depriciated"); ssl->options.oldPoly = value; WOLFSSL_LEAVE("SSL_use_old_poly", 0); return 0; @@ -423,7 +425,7 @@ int wolfSSL_GetObjectSize(void) printf(" sizeof rabbit = %lu\n", sizeof(Rabbit)); #endif #ifdef HAVE_CHACHA - printf(" sizeof chacha = %lu\n", sizeof(Chacha)); + printf(" sizeof chacha = %lu\n", sizeof(ChaCha)); #endif printf("sizeof cipher specs = %lu\n", sizeof(CipherSpecs)); printf("sizeof keys = %lu\n", sizeof(Keys)); @@ -10169,16 +10171,25 @@ const char* wolfSSL_CIPHER_get_name(const WOLFSSL_CIPHER* cipher) if (cipher->ssl->options.cipherSuite0 == CHACHA_BYTE) { /* ChaCha suites */ switch (cipher->ssl->options.cipherSuite) { -#ifdef HAVE_CHACHA +#ifdef HAVE_POLY1305 #ifndef NO_RSA case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 : return "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256"; case TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 : return "TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256"; + + case TLS_ECDHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256 : + return "TLS_ECDHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256"; + + case TLS_DHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256 : + return "TLS_DHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256"; #endif case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 : return "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256"; + + case TLS_ECDHE_ECDSA_WITH_CHACHA20_OLD_POLY1305_SHA256 : + return "TLS_ECDHE_ECDSA_WITH_CHACHA20_OLD_POLY1305_SHA256"; #endif } } diff --git a/tests/test.conf b/tests/test.conf index 5dda708b3..a7d2f5169 100644 --- a/tests/test.conf +++ b/tests/test.conf @@ -1,30 +1,3 @@ -# server TLSv1 DHE-RSA-CHACHA20-POLY1305 --v 1 --l DHE-RSA-CHACHA20-POLY1305 - -# client TLSv1 DHE-RSA-CHACHA20-POLY1305 --v 1 --l DHE-RSA-CHACHA20-POLY1305 - -# server TLSv1 ECDHE-EDCSA-CHACHA20-POLY1305 --v 1 --l ECDHE-ECDSA-CHACHA20-POLY1305 --c ./certs/server-ecc.pem --k ./certs/ecc-key.pem - -# client TLSv1 ECDHE-ECDSA-CHACHA20-POLY1305 --v 1 --l ECDHE-ECDSA-CHACHA20-POLY1305 --A ./certs/server-ecc.pem - -# server TLSv1 ECDHE-RSA-CHACHA20-POLY1305 --v 1 --l ECDHE-RSA-CHACHA20-POLY1305 - -# client TLSv1 ECDHE-RSA-CHACHA20-POLY1305 --v 1 --l ECDHE-RSA-CHACHA20-POLY1305 - # server TLSv1.1 DHE-RSA-CHACHA20-POLY1305 -v 2 -l DHE-RSA-CHACHA20-POLY1305 @@ -34,7 +7,7 @@ -l DHE-RSA-CHACHA20-POLY1305 # server TLSv1.1 ECDHE-RSA-CHACHA20-POLY1305 --v 2 +-v 2 -l ECDHE-RSA-CHACHA20-POLY1305 # client TLSv1.1 ECDHE-RSA-CHACHA20-POLY1305 @@ -61,7 +34,7 @@ -l DHE-RSA-CHACHA20-POLY1305 # server TLSv1.2 ECDHE-RSA-CHACHA20-POLY1305 --v 3 +-v 3 -l ECDHE-RSA-CHACHA20-POLY1305 # client TLSv1.2 ECDHE-RSA-CHACHA20-POLY1305 @@ -79,6 +52,33 @@ -l ECDHE-ECDSA-CHACHA20-POLY1305 -A ./certs/server-ecc.pem +# server TLSv1.2 DHE-RSA-CHACHA20-POLY1305-OLD +-v 3 +-l DHE-RSA-CHACHA20-POLY1305-OLD + +# client TLSv1.2 DHE-RSA-CHACHA20-POLY1305-OLD +-v 3 +-l DHE-RSA-CHACHA20-POLY1305-OLD + +# server TLSv1.2 ECDHE-RSA-CHACHA20-POLY1305-OLD +-v 3 +-l ECDHE-RSA-CHACHA20-POLY1305-OLD + +# client TLSv1.2 ECDHE-RSA-CHACHA20-POLY1305-OLD +-v 3 +-l ECDHE-RSA-CHACHA20-POLY1305-OLD + +# server TLSv1.2 ECDHE-EDCSA-CHACHA20-POLY1305-OLD +-v 3 +-l ECDHE-ECDSA-CHACHA20-POLY1305-OLD +-c ./certs/server-ecc.pem +-k ./certs/ecc-key.pem + +# client TLSv1.2 ECDHE-ECDSA-CHACHA20-POLY1305-OLD +-v 3 +-l ECDHE-ECDSA-CHACHA20-POLY1305-OLD +-A ./certs/server-ecc.pem + # server SSLv3 RC4-SHA -v 0 -l RC4-SHA diff --git a/wolfcrypt/src/poly1305.c b/wolfcrypt/src/poly1305.c index 3cc86e1bb..0bb2697f5 100644 --- a/wolfcrypt/src/poly1305.c +++ b/wolfcrypt/src/poly1305.c @@ -127,6 +127,16 @@ } #endif + +static void U32TO64(word32 v, byte* p) { + XMEMSET(p, 0, 8); + p[0] = (v & 0xFF); + p[1] = (v >> 8) & 0xFF; + p[2] = (v >> 16) & 0xFF; + p[3] = (v >> 24) & 0xFF; +} + + static void poly1305_blocks(Poly1305* ctx, const unsigned char *m, size_t bytes) { @@ -550,5 +560,81 @@ int wc_Poly1305Update(Poly1305* ctx, const byte* m, word32 bytes) { } return 0; } + + +/* Takes in an initialized Poly1305 struct that has a key loaded and creates + a MAC (tag) using recent TLS AEAD padding scheme. + ctx : Initialized Poly1305 struct to use + additional : Additional data to use + addSz : Size of additional buffer + input : Input buffer to create tag from + sz : Size of input buffer + tag : Buffer to hold created tag + tagSz : Size of input tag buffer (must be at least + WC_POLY1305_MAC_SZ(16)) + */ +int wc_Poly1305_MAC(Poly1305* ctx, byte* additional, word32 addSz, + byte* input, word32 sz, byte* tag, word32 tagSz) +{ + int ret; + byte padding[WC_POLY1305_PAD_SZ - 1]; + word32 paddingLen; + byte little64[8]; + + XMEMSET(padding, 0, sizeof(padding)); + + /* sanity check on arguments */ + if (ctx == NULL || input == NULL || tag == NULL || + tagSz < WC_POLY1305_MAC_SZ) { + return BAD_FUNC_ARG; + } + + if (additional == NULL && addSz > 0) { + return BAD_FUNC_ARG; + } + + /* additional data plus padding */ + if ((ret = wc_Poly1305Update(ctx, additional, addSz)) != 0) { + return ret; + } + paddingLen = -addSz & (WC_POLY1305_PAD_SZ - 1); + if (paddingLen) { + if ((ret = wc_Poly1305Update(ctx, padding, paddingLen)) != 0) { + return ret; + } + } + + /* input plus padding */ + if ((ret = wc_Poly1305Update(ctx, input, sz)) != 0) { + return ret; + } + paddingLen = -sz & (WC_POLY1305_PAD_SZ - 1); + if (paddingLen) { + if ((ret = wc_Poly1305Update(ctx, padding, paddingLen)) != 0) { + return ret; + } + } + + /* size of additional data and input as little endian 64 bit types */ + U32TO64(addSz, little64); + ret = wc_Poly1305Update(ctx, little64, sizeof(little64)); + if (ret) + { + return ret; + } + + U32TO64(sz, little64); + ret = wc_Poly1305Update(ctx, little64, sizeof(little64)); + if (ret) + { + return ret; + } + + /* Finalize the auth tag */ + ret = wc_Poly1305Final(ctx, tag); + + return ret; + +} #endif /* HAVE_POLY1305 */ diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index c14ce259e..acbe5aac2 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -2090,6 +2090,31 @@ int poly1305_test(void) 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; + const byte msg4[] = + { + 0xd3,0x1a,0x8d,0x34,0x64,0x8e,0x60,0xdb, + 0x7b,0x86,0xaf,0xbc,0x53,0xef,0x7e,0xc2, + 0xa4,0xad,0xed,0x51,0x29,0x6e,0x08,0xfe, + 0xa9,0xe2,0xb5,0xa7,0x36,0xee,0x62,0xd6, + 0x3d,0xbe,0xa4,0x5e,0x8c,0xa9,0x67,0x12, + 0x82,0xfa,0xfb,0x69,0xda,0x92,0x72,0x8b, + 0x1a,0x71,0xde,0x0a,0x9e,0x06,0x0b,0x29, + 0x05,0xd6,0xa5,0xb6,0x7e,0xcd,0x3b,0x36, + 0x92,0xdd,0xbd,0x7f,0x2d,0x77,0x8b,0x8c, + 0x98,0x03,0xae,0xe3,0x28,0x09,0x1b,0x58, + 0xfa,0xb3,0x24,0xe4,0xfa,0xd6,0x75,0x94, + 0x55,0x85,0x80,0x8b,0x48,0x31,0xd7,0xbc, + 0x3f,0xf4,0xde,0xf0,0x8e,0x4b,0x7a,0x9d, + 0xe5,0x76,0xd2,0x65,0x86,0xce,0xc6,0x4b, + 0x61,0x16 + }; + + byte additional[] = + { + 0x50,0x51,0x52,0x53,0xc0,0xc1,0xc2,0xc3, + 0xc4,0xc5,0xc6,0xc7 + }; + const byte correct[] = { 0xa8,0x06,0x1d,0xc1,0x30,0x51,0x36,0xc6, @@ -2109,6 +2134,12 @@ int poly1305_test(void) 0xc2,0x6b,0x33,0xb9,0x1c,0xcc,0x03,0x07 }; + const byte correct4[] = + { + 0x1a,0xe1,0x0b,0x59,0x4f,0x09,0xe2,0x6a, + 0x7e,0x90,0x2e,0xcb,0xd0,0x60,0x06,0x91 + }; + const byte key[] = { 0x85,0xd6,0xbe,0x78,0x57,0x55,0x6d,0x33, 0x7f,0x44,0x52,0xfe,0x42,0xd5,0x06,0xa8, @@ -2123,6 +2154,13 @@ int poly1305_test(void) 0x50,0x6f,0x6c,0x79,0x31,0x33,0x30,0x35 }; + const byte key4[] = { + 0x7b,0xac,0x2b,0x25,0x2d,0xb4,0x47,0xaf, + 0x09,0xb6,0x7a,0x55,0xa4,0xe9,0x55,0x84, + 0x0a,0xe1,0xd6,0x73,0x10,0x75,0xd9,0xeb, + 0x2a,0x93,0x75,0x78,0x3e,0xd5,0x53,0xff + }; + const byte* msgs[] = {msg, msg2, msg3}; word32 szm[] = {sizeof(msg),sizeof(msg2),sizeof(msg3)}; const byte* keys[] = {key, key2, key2}; @@ -2145,6 +2183,32 @@ int poly1305_test(void) return -61; } + /* Check TLS MAC function from 2.8.2 https://tools.ietf.org/html/rfc7539 */ + XMEMSET(tag, 0, sizeof(tag)); + ret = wc_Poly1305SetKey(&enc, key4, sizeof(key4)); + if (ret != 0) + return -62; + + ret = wc_Poly1305_MAC(&enc, additional, sizeof(additional), + (byte*)msg4, sizeof(msg4), tag, sizeof(tag)); + if (ret != 0) + return -63; + + if (memcmp(tag, correct4, sizeof(tag))) + return -64; + + /* Check fail of TLS MAC function if altering additional data */ + XMEMSET(tag, 0, sizeof(tag)); + additional[0] = additional[0] + 1; + ret = wc_Poly1305_MAC(&enc, additional, sizeof(additional), + (byte*)msg4, sizeof(msg4), tag, sizeof(tag)); + if (ret != 0) + return -65; + + if (memcmp(tag, correct4, sizeof(tag)) == 0) + return -66; + + return 0; } #endif /* HAVE_POLY1305 */ diff --git a/wolfssl/internal.h b/wolfssl/internal.h index b36af64d8..c0de16edc 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -521,6 +521,18 @@ typedef byte word24[3]; #endif /* NO_SHA */ #endif #endif + #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) && !defined(NO_SHA256) \ + && !defined(NO_OLD_POLY1305) + #ifdef HAVE_ECC + #define BUILD_TLS_ECDHE_ECDSA_WITH_CHACHA20_OLD_POLY1305_SHA256 + #ifndef NO_RSA + #define BUILD_TLS_ECDHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256 + #endif + #endif + #if !defined(NO_DH) && !defined(NO_RSA) + #define BUILD_TLS_DHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256 + #endif + #endif #endif /* !WOLFSSL_MAX_STRENGTH */ @@ -787,9 +799,14 @@ enum { TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 = 0xc4, /* chacha20-poly1305 suites first byte is 0xCC (CHACHA_BYTE) */ - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = 0x13, - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = 0x14, - TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = 0x15, + TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = 0xa8, + TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = 0xa9, + TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = 0xaa, + + /* chacha20-poly1305 earlier version of nonce and padding (CHACHA_BYTE) */ + TLS_ECDHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256 = 0x13, + TLS_ECDHE_ECDSA_WITH_CHACHA20_OLD_POLY1305_SHA256 = 0x14, + TLS_DHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256 = 0x15, /* Renegotiation Indication Extension Special Suite */ TLS_EMPTY_RENEGOTIATION_INFO_SCSV = 0xff @@ -933,7 +950,7 @@ enum Misc { CHACHA20_256_KEY_SIZE = 32, /* for 256 bit */ CHACHA20_128_KEY_SIZE = 16, /* for 128 bit */ - CHACHA20_IV_SIZE = 8, /* 64 bits for iv */ + CHACHA20_IV_SIZE = 12, /* 96 bits for iv */ POLY1305_AUTH_SZ = 16, /* 128 bits */ @@ -1448,8 +1465,8 @@ typedef struct Keys { byte server_write_IV[AES_IV_SIZE]; #ifdef HAVE_AEAD byte aead_exp_IV[AEAD_EXP_IV_SZ]; - byte aead_enc_imp_IV[AEAD_IMP_IV_SZ]; - byte aead_dec_imp_IV[AEAD_IMP_IV_SZ]; + byte aead_enc_imp_IV[AEAD_NONCE_SZ]; /* full size needed for chacha-poly */ + byte aead_dec_imp_IV[AEAD_NONCE_SZ]; #endif word32 peer_sequence_number; diff --git a/wolfssl/wolfcrypt/poly1305.h b/wolfssl/wolfcrypt/poly1305.h index 0e76d063d..55369cb4a 100644 --- a/wolfssl/wolfcrypt/poly1305.h +++ b/wolfssl/wolfcrypt/poly1305.h @@ -46,9 +46,11 @@ enum { POLY1305 = 7, POLY1305_BLOCK_SIZE = 16, POLY1305_DIGEST_SIZE = 16, - POLY1305_PAD_SIZE = 56 }; +#define WC_POLY1305_PAD_SZ 16 +#define WC_POLY1305_MAC_SZ 16 + /* Poly1305 state */ typedef struct Poly1305 { #if defined(POLY130564) @@ -71,7 +73,8 @@ typedef struct Poly1305 { WOLFSSL_API int wc_Poly1305SetKey(Poly1305* poly1305, const byte* key, word32 kySz); WOLFSSL_API int wc_Poly1305Update(Poly1305* poly1305, const byte*, word32); WOLFSSL_API int wc_Poly1305Final(Poly1305* poly1305, byte* tag); - +WOLFSSL_API int wc_Poly1305_MAC(Poly1305* ctx, byte* additional, word32 addSz, + byte* input, word32 sz, byte* tag, word32 tagSz); #ifdef __cplusplus } /* extern "C" */ #endif