quic 0.2.22 → 0.2.23
raw patch · 8 files changed
+176/−68 lines, 8 filesdep ~crypton
Dependency ranges changed: crypton
Files
- ChangeLog.md +5/−0
- Network/QUIC/Config.hs +16/−2
- Network/QUIC/Connection/Crypto.hs +7/−3
- Network/QUIC/Crypto/Fusion.hs +5/−5
- Network/QUIC/Crypto/Nite.hs +54/−48
- Network/QUIC/Crypto/Utils.hs +2/−0
- quic.cabal +9/−2
- test/TLSSpec.hs +78/−8
ChangeLog.md view
@@ -1,5 +1,10 @@ # ChangeLog +## 0.2.23++* Supporting ChaCha20Poly1305 for crypton (not for Fusion)+ [#89](https://github.com/kazu-yamamoto/quic/pull/89)+ ## 0.2.22 * Using tls v2.2 and crypton-x509* v1.8.
Network/QUIC/Config.hs view
@@ -16,6 +16,7 @@ defaultSupported, ) import Network.TLS.QUIC+import Network.TLS.Extra.Cipher import Network.QUIC.Imports import Network.QUIC.Parameters@@ -53,6 +54,19 @@ , onConnectionEstablished = \_ -> return () } +defaultCiphers :: [Cipher]+defaultCiphers =+#ifdef USE_FUSION+ [ cipher13_AES_256_GCM_SHA384+ , cipher13_AES_128_GCM_SHA256+ ]+#else+ [ cipher13_CHACHA20_POLY1305_SHA256+ , cipher13_AES_256_GCM_SHA384+ , cipher13_AES_128_GCM_SHA256+ ]+#endif+ ---------------------------------------------------------------- -- | Client configuration.@@ -122,7 +136,7 @@ ClientConfig { ccVersion = Version1 , ccVersions = [Version2, Version1]- , ccCiphers = supportedCiphers defaultSupported+ , ccCiphers = defaultCiphers , ccGroups = supportedGroups defaultSupported , ccParameters = defaultParameters #if MIN_VERSION_tls(2,1,10)@@ -189,7 +203,7 @@ defaultServerConfig = ServerConfig { scVersions = [Version2, Version1]- , scCiphers = supportedCiphers defaultSupported+ , scCiphers = defaultCiphers , scGroups = supportedGroups defaultSupported , scParameters = defaultParameters #if MIN_VERSION_tls(2,1,10)
Network/QUIC/Connection/Crypto.hs view
@@ -25,6 +25,7 @@ ) where import Control.Concurrent.STM+import Network.TLS.Extra.Cipher import Network.TLS.QUIC import Network.QUIC.Connection.Misc@@ -105,6 +106,9 @@ ---------------------------------------------------------------- +fusionCiphers :: [Cipher]+fusionCiphers = [cipher13_AES_128_GCM_SHA256, cipher13_AES_256_GCM_SHA384]+ initializeCoder :: Connection -> EncryptionLevel -> TrafficSecrets a -> IO () initializeCoder conn lvl sec = do ver <-@@ -114,7 +118,7 @@ cipher <- getCipher conn lvl avail <- isFusionAvailable (coder, protector) <-- if useFusion && avail+ if useFusion && avail && cipher `elem` fusionCiphers then genFusionCoder (isClient conn) ver cipher sec else genNiteCoder (isClient conn) ver cipher sec writeArray (coders conn) lvl coder@@ -126,7 +130,7 @@ cipher <- getCipher conn RTT1Level avail <- isFusionAvailable (coder, protector) <-- if useFusion && avail+ if useFusion && avail && cipher `elem` fusionCiphers then genFusionCoder (isClient conn) ver cipher sec else genNiteCoder (isClient conn) ver cipher sec let coder1 = Coder1RTT coder sec@@ -142,7 +146,7 @@ let secN1 = updateSecret ver cipher secN avail <- isFusionAvailable coderN1 <-- if useFusion && avail+ if useFusion && avail && cipher `elem` fusionCiphers then genFusionCoder1RTT (isClient conn) ver cipher secN1 coder else genNiteCoder1RTT (isClient conn) ver cipher secN1 coder let nextCoder = Coder1RTT coderN1 secN1
Network/QUIC/Crypto/Fusion.hs view
@@ -36,9 +36,9 @@ fusionSetup :: Cipher -> FusionContext -> Key -> IV -> IO () fusionSetup cipher- | cipher == cipher_TLS13_AES128GCM_SHA256 = fusionSetupAES128- | cipher == cipher_TLS13_AES256GCM_SHA384 = fusionSetupAES256- | otherwise = error "fusionSetup"+ | cipher == cipher13_AES_128_GCM_SHA256 = fusionSetupAES128+ | cipher == cipher13_AES_256_GCM_SHA384 = fusionSetupAES256+ | otherwise = error "fusionSetup" fusionSetupAES128 :: FusionContext -> Key -> IV -> IO () fusionSetupAES128 (FC fctx) (Key key) (IV iv) = withForeignPtr fctx $ \pctx ->@@ -88,8 +88,8 @@ SP <$> (c_supplement_new hpkeyp keylen >>= newForeignPtr p_supplement_free) where keylen- | cipher == cipher_TLS13_AES128GCM_SHA256 = 16- | otherwise = 32+ | cipher == cipher13_AES_128_GCM_SHA256 = 16+ | otherwise = 32 fusionSetSample :: Supplement -> Buffer -> IO () fusionSetSample (SP fsupp) p = withForeignPtr fsupp $ \psupp ->
Network/QUIC/Crypto/Nite.hs view
@@ -15,6 +15,8 @@ ) where import Crypto.Cipher.AES+import qualified Crypto.Cipher.ChaCha as ChaCha+import Crypto.Cipher.ChaChaPoly1305 (aeadChacha20poly1305Init) import Crypto.Cipher.Types hiding (Cipher, IV) import Crypto.Error (maybeCryptoError) import qualified Data.ByteArray as Byte (convert)@@ -39,66 +41,60 @@ -- it's impossible. cipherEncrypt :: Cipher -> Key -> Nonce -> PlainText -> AssDat -> Maybe (CipherText, CipherText)-cipherEncrypt cipher- | cipher == cipher13_AES_128_GCM_SHA256 = aes128gcmEncrypt+cipherEncrypt cipher (Key key) (Nonce nonce)+ | cipher == cipher13_AES_128_GCM_SHA256 =+ quicAeadEncrypt (aesGCMInit key nonce :: Maybe (AEAD AES128)) 16 | cipher == cipher13_AES_128_CCM_SHA256 = error "cipher13_AES_128_CCM_SHA256"- | cipher == cipher13_AES_256_GCM_SHA384 = aes256gcmEncrypt+ | cipher == cipher13_AES_256_GCM_SHA384 =+ quicAeadEncrypt (aesGCMInit key nonce :: Maybe (AEAD AES256)) 16+ | cipher == cipher13_CHACHA20_POLY1305_SHA256 =+ quicAeadEncrypt (maybeCryptoError $ aeadChacha20poly1305Init key nonce) 16 | otherwise = error "cipherEncrypt" cipherDecrypt :: Cipher -> Key -> Nonce -> CipherText -> AssDat -> Maybe PlainText-cipherDecrypt cipher- | cipher == cipher13_AES_128_GCM_SHA256 = aes128gcmDecrypt+cipherDecrypt cipher (Key key) (Nonce nonce)+ | cipher == cipher13_AES_128_GCM_SHA256 =+ quicAeadDecrypt (aesGCMInit key nonce :: Maybe (AEAD AES128)) 16 | cipher == cipher13_AES_128_CCM_SHA256 = error "cipher13_AES_128_CCM_SHA256"- | cipher == cipher13_AES_256_GCM_SHA384 = aes256gcmDecrypt+ | cipher == cipher13_AES_256_GCM_SHA384 =+ quicAeadDecrypt (aesGCMInit key nonce :: Maybe (AEAD AES256)) 16+ | cipher == cipher13_CHACHA20_POLY1305_SHA256 =+ quicAeadDecrypt (maybeCryptoError $ aeadChacha20poly1305Init key nonce) 16 | otherwise = error "cipherDecrypt" -- IMPORTANT: Using 'let' so that parameters can be memorized.-aes128gcmEncrypt- :: Key -> (Nonce -> PlainText -> AssDat -> Maybe (CipherText, CipherText))-aes128gcmEncrypt (Key key) = case maybeCryptoError $ cipherInit key of- Nothing -> \_ _ _ -> Nothing- Just (aes :: AES128) -> \(Nonce nonce) plaintext (AssDat ad) ->- case maybeCryptoError $ aeadInit AEAD_GCM aes nonce of- Nothing -> Nothing- Just aead ->- let (AuthTag tag0, ciphertext) = aeadSimpleEncrypt aead ad plaintext 16- tag = Byte.convert tag0- in Just (ciphertext, tag)+quicAeadEncrypt+ :: Maybe (AEAD cipher)+ -> Int+ -> PlainText+ -> AssDat+ -> Maybe (CipherText, CipherText)+quicAeadEncrypt Nothing _ = \_ _ -> Nothing+quicAeadEncrypt (Just aead) tagLen = \plaintext (AssDat ad) ->+ let (AuthTag tag0, ciphertext) = aeadSimpleEncrypt aead ad plaintext tagLen+ tag = Byte.convert tag0+ in Just (ciphertext, tag) -aes128gcmDecrypt :: Key -> (Nonce -> CipherText -> AssDat -> Maybe PlainText)-aes128gcmDecrypt (Key key) = case maybeCryptoError $ cipherInit key of- Nothing -> \_ _ _ -> Nothing- Just (aes :: AES128) -> \(Nonce nonce) ciphertag (AssDat ad) ->- case maybeCryptoError $ aeadInit AEAD_GCM aes nonce of- Nothing -> Nothing- Just aead ->- let (ciphertext, tag) = BS.splitAt (BS.length ciphertag - 16) ciphertag- authtag = AuthTag $ Byte.convert tag- in aeadSimpleDecrypt aead ad ciphertext authtag+quicAeadDecrypt+ :: Maybe (AEAD cipher) -> Int -> CipherText -> AssDat -> Maybe PlainText+quicAeadDecrypt Nothing _ = \_ _ -> Nothing+quicAeadDecrypt (Just aead) tagLen = \ciphertag (AssDat ad) ->+ let (ciphertext, tag) = BS.splitAt (BS.length ciphertag - tagLen) ciphertag+ authtag = AuthTag $ Byte.convert tag+ in aeadSimpleDecrypt aead ad ciphertext authtag -aes256gcmEncrypt- :: Key -> (Nonce -> PlainText -> AssDat -> Maybe (CipherText, CipherText))-aes256gcmEncrypt (Key key) = case maybeCryptoError $ cipherInit key of- Nothing -> \_ _ _ -> Nothing- Just (aes :: AES256) -> \(Nonce nonce) plaintext (AssDat ad) ->- case maybeCryptoError $ aeadInit AEAD_GCM aes nonce of- Nothing -> Nothing- Just aead ->- let (AuthTag tag0, ciphertext) = aeadSimpleEncrypt aead ad plaintext 16- tag = Byte.convert tag0- in Just (ciphertext, tag)+aesGCMInit+ :: BlockCipher cipher => ByteString -> ByteString -> Maybe (AEAD cipher)+aesGCMInit key nonce =+ case maybeCryptoError $ cipherInit key of+ Nothing -> Nothing+ Just aes -> maybeCryptoError $ aeadInit AEAD_GCM aes nonce -aes256gcmDecrypt :: Key -> (Nonce -> CipherText -> AssDat -> Maybe PlainText)-aes256gcmDecrypt (Key key) = case maybeCryptoError $ cipherInit key of- Nothing -> \_ _ _ -> Nothing- Just (aes :: AES256) -> \(Nonce nonce) ciphertag (AssDat ad) ->- case maybeCryptoError $ aeadInit AEAD_GCM aes nonce of- Nothing -> Nothing- Just aead ->- let (ciphertext, tag) = BS.splitAt (BS.length ciphertag - 16) ciphertag- authtag = AuthTag $ Byte.convert tag- in aeadSimpleDecrypt aead ad ciphertext authtag+aes128gcmEncrypt+ :: Key -> Nonce -> PlainText -> AssDat -> Maybe (CipherText, CipherText)+aes128gcmEncrypt (Key key) (Nonce nonce) =+ quicAeadEncrypt (aesGCMInit key nonce :: Maybe (AEAD AES128)) 16 ---------------------------------------------------------------- @@ -228,6 +224,7 @@ | cipher == cipher13_AES_128_GCM_SHA256 = aes128ecbEncrypt key | cipher == cipher13_AES_128_CCM_SHA256 = error "cipher13_AES_128_CCM_SHA256 " | cipher == cipher13_AES_256_GCM_SHA384 = aes256ecbEncrypt key+ | cipher == cipher13_CHACHA20_POLY1305_SHA256 = chacha20HeaderProtection key | otherwise = error "cipherHeaderProtection" @@ -248,6 +245,15 @@ in \(Sample sample) -> let mask = encrypt sample in Mask mask++chacha20HeaderProtection :: Key -> (Sample -> Mask)+chacha20HeaderProtection (Key key) (Sample sample) =+ Mask $ fst $ ChaCha.combine st "\x00\x00\x00\x00\x00"+ where+ st = ChaCha.setCounter32 counter $ ChaCha.initialize 20 key nonce+ nonce = BS.drop 4 sample+ counter = idx 0 + idx 1 * 256 + idx 2 * 65536 + idx 3 * 16777216+ idx i = fromIntegral (sample `BS.index` i) ----------------------------------------------------------------
Network/QUIC/Crypto/Utils.hs view
@@ -30,6 +30,7 @@ | cipher == cipher13_AES_128_GCM_SHA256 = 16 | cipher == cipher13_AES_128_CCM_SHA256 = 16 | cipher == cipher13_AES_256_GCM_SHA384 = 16+ | cipher == cipher13_CHACHA20_POLY1305_SHA256 = 16 | otherwise = error "tagLength" sampleLength :: Cipher -> Int@@ -37,6 +38,7 @@ | cipher == cipher13_AES_128_GCM_SHA256 = 16 | cipher == cipher13_AES_128_CCM_SHA256 = 16 | cipher == cipher13_AES_256_GCM_SHA384 = 16+ | cipher == cipher13_CHACHA20_POLY1305_SHA256 = 16 | otherwise = error "sampleLength" ----------------------------------------------------------------
quic.cabal view
@@ -1,6 +1,6 @@ cabal-version: >=1.10 name: quic-version: 0.2.22+version: 0.2.23 license: BSD3 license-file: LICENSE maintainer: kazu@iij.ad.jp@@ -135,7 +135,7 @@ bytestring >=0.10, containers, crypto-token >=0.1.2 && <0.2,- crypton >=0.34,+ crypton >=1.0.5, crypton-x509 >=1.8.0 && <1.9, crypton-x509-store >=1.8.0 && <1.9, crypton-x509-system >=1.8.0 && <1.9,@@ -266,3 +266,10 @@ if os(windows) ghc-options: -with-rtsopts=--io-manager=native++ if (flag(fusion) && arch(x86_64))+ cpp-options: -DUSE_FUSION+ cc-options: -mavx2 -maes -mpclmul -mvaes -mvpclmulqdq+ c-sources:+ cbits/fusion.c+ cbits/picotls.c
test/TLSSpec.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP #-} {-# LANGUAGE OverloadedStrings #-} {-# OPTIONS_GHC -fno-warn-orphans #-} @@ -6,6 +7,7 @@ import Data.Bits import qualified Data.ByteString as BS import Data.Maybe+import Network.TLS.Extra.Cipher import Test.Hspec import Network.QUIC.Internal@@ -22,9 +24,12 @@ spec :: Spec spec = do+ ----------------------------------------------------------------+ -- RFC 9001+ -- describe "test vector for version 1" $ do let ver = Version1- it "describes the examples of Keys" $ do+ it "describes the examples of Keys (RFC 9001: A.1)" $ do ---------------------------------------------------------------- -- shared keys let dcID = makeCID (dec16s "8394c8f03e515708")@@ -49,7 +54,7 @@ let shp = headerProtectionKey ver defaultCipher (Secret sis) shp `shouldBe` Key (dec16 "c206b8d9b9f0f37644430b490eeaa314") - it "describes the examples of Client Initial" $ do+ it "describes the examples of Client Initial (RFC 9001: A.2)" $ do let dcID = makeCID (dec16s "8394c8f03e515708") ClientTrafficSecret cis = clientInitialSecret ver dcID ckey = aeadKey ver defaultCipher (Secret cis)@@ -91,7 +96,7 @@ let Mask mask = protectionMask defaultCipher chp sample BS.take 5 mask `shouldBe` dec16 "437b9aec36" - it "describes the examples of Server Initial" $ do+ it "describes the examples of Server Initial (RFC 9001: A.3)" $ do let dcID = makeCID (dec16s "8394c8f03e515708") ServerTrafficSecret sis = serverInitialSecret ver dcID skey = aeadKey ver defaultCipher (Secret sis)@@ -132,7 +137,7 @@ let Mask mask = protectionMask defaultCipher shp sample BS.take 5 mask `shouldBe` dec16 "2ec0d8356a" - it "describes the examples of Retry" $ do+ it "describes the examples of Retry (RFC 9001: A.4)" $ do let wire0 = dec16 "ff000000010008f067a5502a4262b5746f6b656e04a265ba2eff4d829058fb3f0f2496ba" (ipkt, rest) <- decodePacket wire0 True@@ -146,7 +151,41 @@ r0 `shouldBe` r1 _ -> error "Retry version 1" - describe "test vector for version 2" $ do+{- FOURMOLU_DISABLE -}+#ifndef USE_FUSION+ it+ "describes the examples of ChaCha20-Poly1305 Short Header Packet (RFC 9001: A.5)"+ $ do+ let cipher = cipher13_CHACHA20_POLY1305_SHA256+ secret =+ Secret $+ dec16 "9ac312a7f877468ebe69422748ad00a15443f18203a07d6060f688f30f21632b"+ key = aeadKey ver cipher secret+ iv = initialVector ver cipher secret+ hp = headerProtectionKey ver cipher secret+ ku = nextSecret ver cipher secret+ payloadCipherText = niteEncrypt cipher key iv (dec16 "01") (AssDat $ dec16 "4200bff4") 654360564+ sample = Sample $ dec16 "5e5cd55c41f69080575d7999c25a5bfb"+ mask = protectionMask cipher hp sample+ key+ `shouldBe` Key (dec16 "c6d98ff3441c3fe1b2182094f69caa2ed4b716b65488960a7a984979fb23e1c8")+ iv+ `shouldBe` IV (dec16 "e0459b3474bdd0e44a41c144")+ hp+ `shouldBe` Key (dec16 "25a282b9e82f06f21f488917a4fc8f1b73573685608597d0efcb076b0ab7a7a4")+ ku+ `shouldBe` Secret+ (dec16 "1223504755036d556342ee9361d253421a826c9ecdf3c7148684b36b714881f9")+ payloadCipherText+ `shouldBe` Just (dec16 "65", dec16 "5e5cd55c41f69080575d7999c25a5bfb")+ mask `shouldBe` Mask (dec16 "aefefe7d03")+#endif+{- FOURMOLU_ENSABLE -}++ ----------------------------------------------------------------+ -- RFC 9369+ --+ describe "test vector for version 2 (RFC 9369: A1)" $ do let ver = Version2 it "describes the examples of Keys" $ do ----------------------------------------------------------------@@ -173,7 +212,7 @@ let shp = headerProtectionKey ver defaultCipher (Secret sis) shp `shouldBe` Key (dec16 "edf6d05c83121201b436e16877593c3a") - it "describes the examples of Client Initial" $ do+ it "describes the examples of Client Initial (RFC 9369: A2)" $ do let dcID = makeCID (dec16s "8394c8f03e515708") ClientTrafficSecret cis = clientInitialSecret ver dcID ckey = aeadKey ver defaultCipher (Secret cis)@@ -215,7 +254,7 @@ let Mask mask = protectionMask defaultCipher chp sample BS.take 5 mask `shouldBe` dec16 "94a0c95e80" - it "describes the examples of Server Initial" $ do+ it "describes the examples of Server Initial (RFC 9369: A3)" $ do let dcID = makeCID (dec16s "8394c8f03e515708") ServerTrafficSecret sis = serverInitialSecret ver dcID skey = aeadKey ver defaultCipher (Secret sis)@@ -256,7 +295,7 @@ let Mask mask = protectionMask defaultCipher shp sample BS.take 5 mask `shouldBe` dec16 "4dd92e91ea" - it "describes the examples of Retry" $ do+ it "describes the examples of Retry (RFC 9369: A4)" $ do let wire0 = dec16 "cf6b3343cf0008f067a5502a4262b5746f6b656ec8646ce8bfe33952d955543665dcc7b6" (ipkt, rest) <- decodePacket wire0 True@@ -269,6 +308,37 @@ f0 .&. 0xf0 `shouldBe` f1 .&. 0xf0 r0 `shouldBe` r1 _ -> error "Retry version 2"++{- FOURMOLU_DISABLE -}+#ifndef USE_FUSION+ it+ "describes the examples of ChaCha20-Poly1305 Short Header Packet (RFC 9369: A.5)"+ $ do+ let cipher = cipher13_CHACHA20_POLY1305_SHA256+ secret =+ Secret $+ dec16 "9ac312a7f877468ebe69422748ad00a15443f18203a07d6060f688f30f21632b"+ key = aeadKey ver cipher secret+ iv = initialVector ver cipher secret+ hp = headerProtectionKey ver cipher secret+ ku = nextSecret ver cipher secret+ payloadCipherText = niteEncrypt cipher key iv (dec16 "01") (AssDat $ dec16 "4200bff4") 654360564+ sample = Sample $ dec16 "e7b6b932bc27d786f4bc2bb20f2162ba"+ mask = protectionMask cipher hp sample+ key+ `shouldBe` Key (dec16 "3bfcddd72bcf02541d7fa0dd1f5f9eeea817e09a6963a0e6c7df0f9a1bab90f2")+ iv+ `shouldBe` IV (dec16 "a6b5bc6ab7dafce30ffff5dd")+ hp+ `shouldBe` Key (dec16 "d659760d2ba434a226fd37b35c69e2da8211d10c4f12538787d65645d5d1b8e2")+ ku+ `shouldBe` Secret+ (dec16 "c69374c49e3d2a9466fa689e49d476db5d0dfbc87d32ceeaa6343fd0ae4c7d88")+ payloadCipherText+ `shouldBe` Just (dec16 "0a", dec16 "e7b6b932bc27d786f4bc2bb20f2162ba")+ mask `shouldBe` Mask (dec16 "97580e32bf")+#endif+{- FOURMOLU_ENABLE -} serverCRYPTOframe :: BS.ByteString serverCRYPTOframe =