packages feed

peyotls 0.0.0.21 → 0.0.0.22

raw patch · 20 files changed

+657/−649 lines, 20 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- Network.PeyoTLS.Client: data TlsHandleC h g
- Network.PeyoTLS.Client: instance (ValidateHandle h, CPRG g) => HandleLike (TlsHandleC h g)
- Network.PeyoTLS.Client: instance SecretKey PrivateKey
- Network.PeyoTLS.Client: instance Verify PublicKey
- Network.PeyoTLS.Client: type PeyotlsHandleC = TlsHandleC Handle SystemRNG
- Network.PeyoTLS.Server: data TlsHandleS h g
- Network.PeyoTLS.Server: instance (ValidateHandle h, CPRG g) => HandleLike (TlsHandleS h g)
- Network.PeyoTLS.Server: instance Show h => Show (TlsHandleS h g)
- Network.PeyoTLS.Server: type PeyotlsHandleS = TlsHandleS Handle SystemRNG
+ Network.PeyoTLS.Client: EcdsaKey :: PrivateKey -> CertSecretKey
+ Network.PeyoTLS.Client: RsaKey :: PrivateKey -> CertSecretKey
+ Network.PeyoTLS.Client: data TlsHandle h g
+ Network.PeyoTLS.Client: ecdsaKey :: CertSecretKey -> PrivateKey
+ Network.PeyoTLS.Client: instance (ValidateHandle h, CPRG g) => HandleLike (TlsHandle h g)
+ Network.PeyoTLS.Client: instance Show h => Show (TlsHandle h g)
+ Network.PeyoTLS.Client: rsaKey :: CertSecretKey -> PrivateKey
+ Network.PeyoTLS.Client: type PeyotlsHandle = TlsHandle Handle SystemRNG
+ Network.PeyoTLS.Server: EcdsaKey :: PrivateKey -> CertSecretKey
+ Network.PeyoTLS.Server: RsaKey :: PrivateKey -> CertSecretKey
+ Network.PeyoTLS.Server: data TlsHandle h g
+ Network.PeyoTLS.Server: ecdsaKey :: CertSecretKey -> PrivateKey
+ Network.PeyoTLS.Server: instance (ValidateHandle h, CPRG g) => HandleLike (TlsHandle h g)
+ Network.PeyoTLS.Server: instance Show h => Show (TlsHandle h g)
+ Network.PeyoTLS.Server: rsaKey :: CertSecretKey -> PrivateKey
+ Network.PeyoTLS.Server: type PeyotlsHandle = TlsHandle Handle SystemRNG
- Network.PeyoTLS.Client: names :: TlsHandleC h g -> [String]
+ Network.PeyoTLS.Client: names :: TlsHandle h g -> [String]
- Network.PeyoTLS.Client: open :: (ValidateHandle h, CPRG g) => h -> [CipherSuite] -> [(CertSecretKey, CertificateChain)] -> CertificateStore -> TlsM h g (TlsHandleC h g)
+ Network.PeyoTLS.Client: open :: (ValidateHandle h, CPRG g) => h -> [CipherSuite] -> [(CertSecretKey, CertificateChain)] -> CertificateStore -> TlsM h g (TlsHandle h g)
- Network.PeyoTLS.Client: renegotiate :: (ValidateHandle h, CPRG g) => TlsHandleC h g -> TlsM h g ()
+ Network.PeyoTLS.Client: renegotiate :: (ValidateHandle h, CPRG g) => TlsHandle h g -> TlsM h g ()
- Network.PeyoTLS.ReadFile: readCertificateChain :: FilePath -> IO CertificateChain
+ Network.PeyoTLS.ReadFile: readCertificateChain :: [FilePath] -> IO CertificateChain
- Network.PeyoTLS.Server: names :: TlsHandleS h g -> [String]
+ Network.PeyoTLS.Server: names :: TlsHandle h g -> [String]
- Network.PeyoTLS.Server: open :: (ValidateHandle h, CPRG g) => h -> [CipherSuite] -> [(CertSecretKey, CertificateChain)] -> Maybe CertificateStore -> TlsM h g (TlsHandleS h g)
+ Network.PeyoTLS.Server: open :: (ValidateHandle h, CPRG g) => h -> [CipherSuite] -> [(CertSecretKey, CertificateChain)] -> Maybe CertificateStore -> TlsM h g (TlsHandle h g)
- Network.PeyoTLS.Server: renegotiate :: (ValidateHandle h, CPRG g) => TlsHandleS h g -> TlsM h g ()
+ Network.PeyoTLS.Server: renegotiate :: (ValidateHandle h, CPRG g) => TlsHandle h g -> TlsM h g ()

Files

examples/clcertClient.hs view
@@ -16,7 +16,7 @@ main = do 	d : _ <- getArgs 	rk <- readKey $ d ++ "/yoshikuni.sample_key"-	rc <- readCertificateChain $ d ++ "/yoshikuni.sample_crt"+	rc <- readCertificateChain [d ++ "/yoshikuni.sample_crt"] 	ca <- readCertificateStore [d ++ "/cacert.pem"] 	h <- connectTo "localhost" $ PortNumber 443 	g <- cprgCreate <$> createEntropyPool :: IO SystemRNG
examples/clcertEcdsaClient.hs view
@@ -16,9 +16,9 @@ main = do 	d : _ <- getArgs 	rk <- readKey $ d ++ "/yoshikuni.sample_key"-	rc <- readCertificateChain $ d ++ "/yoshikuni.sample_crt"+	rc <- readCertificateChain [d ++ "/yoshikuni.sample_crt"] 	ek <- readKey $ d ++ "/client_ecdsa.sample_key"-	ec <- readCertificateChain $ d ++ "/client_ecdsa.sample_crt"+	ec <- readCertificateChain [d ++ "/client_ecdsa.sample_crt"] 	ca <- readCertificateStore [d ++ "/cacert.pem"] 	h <- connectTo "localhost" $ PortNumber 443 	g <- cprgCreate <$> createEntropyPool :: IO SystemRNG
examples/clcertServer.hs view
@@ -18,7 +18,7 @@ main = do 	d : _ <- getArgs 	k <- readKey $ d ++ "/localhost.sample_key"-	c <- readCertificateChain $ d ++"/localhost.sample_crt"+	c <- readCertificateChain [d ++"/localhost.sample_crt"] 	ca <- readCertificateStore [d ++ "/cacert.pem"] 	g0 <- cprgCreate <$> createEntropyPool :: IO SystemRNG 	soc <- listenOn $ PortNumber 443
examples/debugServer.hs view
@@ -18,7 +18,7 @@ main = do 	d : _ <- getArgs 	k <- readKey $ d ++ "/localhost.sample_key"-	c <- readCertificateChain $ d ++ "/localhost.sample_crt"+	c <- readCertificateChain [d ++ "/localhost.sample_crt"] 	g0 <- cprgCreate <$> createEntropyPool :: IO SystemRNG 	soc <- listenOn $ PortNumber 443 	void . (`runStateT` g0) . forever $ do
examples/eccServer.hs view
@@ -29,9 +29,9 @@ main = do 	d : _ <- getArgs 	rk <- readKey $ d ++ "/localhost.sample_key"-	rc <- readCertificateChain $ d ++ "/localhost.sample_crt"+	rc <- readCertificateChain [d ++ "/localhost.sample_crt"] 	ek <- readKey $ d ++ "/localhost_ecdsa.sample_key"-	ec <- readCertificateChain $ d ++ "/localhost_ecdsa.sample_crt"+	ec <- readCertificateChain [d ++ "/localhost_ecdsa.sample_crt"] 	g0 <- cprgCreate <$> createEntropyPool :: IO SystemRNG 	soc <- listenOn $ PortNumber 443 	void . (`runStateT` g0) . forever $ do
examples/renegServer.hs view
@@ -18,7 +18,7 @@ main = do 	d : _ <- getArgs 	k <- readKey $ d ++ "/localhost.sample_key"-	c <- readCertificateChain $ d ++ "/localhost.sample_crt"+	c <- readCertificateChain [d ++ "/localhost.sample_crt"] 	g0 <- cprgCreate <$> createEntropyPool :: IO SystemRNG 	soc <- listenOn $ PortNumber 443 	void . (`runStateT` g0) . forever $ do
examples/simpleServer.hs view
@@ -18,7 +18,7 @@ main = do 	d : _ <- getArgs 	k <- readKey $ d ++ "/localhost.sample_key"-	c <- readCertificateChain $ d ++ "/localhost.sample_crt"+	c <- readCertificateChain [d ++ "/localhost.sample_crt"] 	g0 <- cprgCreate <$> createEntropyPool :: IO SystemRNG 	soc <- listenOn $ PortNumber 443 	void . (`runStateT` g0) . forever $ do
peyotls.cabal view
@@ -2,7 +2,7 @@ cabal-version:	>= 1.8  name:		peyotls-version:	0.0.0.21+version:	0.0.0.22 stability:	Experimental author:		Yoshikuni Jujo <PAF01143@nifty.ne.jp> maintainer:	Yoshikuni Jujo <PAF01143@nifty.ne.jp>@@ -33,11 +33,15 @@     .     * TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256     .+    implement the following curves+    .+    * SEC p256r1+    .     And support client certificate with the following algorithms.     .-    * RSA (SHA1 or SHA256 depending on the agreed cipher suite)+    * RSA with SHA256     .-    * ECDSA (SHA1 or SHA256 depending on the agreed cipher suite)+    * ECDSA with SHA256     .     And support secure renegotiation (RFC 5746)     .@@ -45,6 +49,8 @@     .     * session resumption (RFC 5077)     .+    * curves other than SEC p256r1+    .     Server sample     .     * file: examples/simpleServer.hs@@ -85,7 +91,7 @@     > main :: IO ()     > main = do     >	k <- readKey "localhost.key"-    >	c <- readCertificateChain "localhost.crt"+    >	c <- readCertificateChain ["localhost.crt"]     >	g0 <- cprgCreate <$> createEntropyPool :: IO SystemRNG     >	soc <- listenOn $ PortNumber 443     >	void . (`runStateT` g0) . forever $ do@@ -172,7 +178,7 @@     > % diff examples/simpleClient.hs examples/clcertClient.hs     > 15a16,17     > >	rk <- readKey "client_rsa.key"-    > >	rc <- readCertificateChain "client_rsa.crt"+    > >	rc <- readCertificateChain ["client_rsa.crt"]     > 20c22     > <		p <- open h ["TLS_RSA_WITH_AES_128_CBC_SHA"] [] ca     > ---@@ -185,7 +191,7 @@     > % diff examples/clcertClient.hs examples/clcertEcdsaClient.hs     > 17a18,19     > >	ek <- readKey "client_ecdsa.key"-    > >	ec <- readCertificateChain "client_ecdsa.crt"+    > >	ec <- readCertificateChain ["client_ecdsa.crt"]     > 22c24     > <		p <- open h ["TLS_RSA_WITH_AES_128_CBC_SHA"] [(rk, rc)] ca     > ---@@ -210,12 +216,12 @@     > >     > 18,19c29,32     > <       k <- readKey "localhost.key"-    > <       c <- readCertificateChain "localhost.crt"+    > <       c <- readCertificateChain ["localhost.crt"]     > ---     > >       rk <- readKey "localhost.key"-    > >       rc <- readCertificateChain "localhost.crt"+    > >       rc <- readCertificateChain ["localhost.crt"]     > >       ek <- readKey "localhost_ecdsa.key"-    > >       ec <- readCertificateChain "localhost_ecdsa.crt"+    > >       ec <- readCertificateChain ["localhost_ecdsa.crt"]     > 26c39     > <                       p <- open h ["TLS_RSA_WITH_AES_128_CBC_SHA"] [(k, c)]     > ---@@ -274,7 +280,7 @@ source-repository	this     type:	git     location:	git://github.com/YoshikuniJujo/peyotls.git-    tag:	peyotls-0.0.0.21+    tag:	peyotls-0.0.0.22  library     hs-source-dirs:	src
src/Network/PeyoTLS/Base.hs view
@@ -3,11 +3,14 @@ {-# OPTIONS_GHC -fno-warn-orphans #-}  module Network.PeyoTLS.Base ( Extension(..),+	makeEcdsaPubKey,+	ClSignPublicKey(..), ClSignSecretKey(..),+	SvSignPublicKey(..), 	PeyotlsM, eRenegoInfo, 	debug, generateKs, blindSign, HM.CertSecretKey(..), isEcdsaKey, isRsaKey, 	HM.TlsM, HM.run, HM.HandshakeM, HM.execHandshakeM, HM.rerunHandshakeM, 	HM.withRandom, HM.randomByteString,-	HM.TlsHandle, HM.names,+	HM.TlsHandle_, HM.names, 		readHandshake, getChangeCipherSpec, 		writeHandshake, putChangeCipherSpec, 		writeHandshakeNH,@@ -19,7 +22,7 @@ 		CipherSuite(..), KeyEx(..), BulkEnc(..), 		CompMethod(..), HashAlg(..), SignAlg(..), 		HM.getCipherSuite, HM.setCipherSuite,-	CertificateRequest(..), certificateRequest, ClientCertificateType(..), SecretKey(..),+	CertReq(..), certificateRequest, ClientCertificateType(..), SecretKey(..), 	ClientKeyExchange(..), Epms(..), 		HM.generateKeys, 		HM.encryptRsa, HM.decryptRsa, HM.rsaPadding, HM.debugCipherSuite,@@ -27,6 +30,8 @@ 	HM.Side(..), HM.RW(..), finishedHash, 	DhParam(..), dh3072Modp, secp256r1, HM.throwError, 	HM.getClientFinished, HM.getServerFinished,+	checkClientRenego, makeClientRenego,+	checkServerRenego, makeServerRenego, 	Finished(..), 	HM.ContentType(CTAlert, CTHandshake, CTAppData), 	Handshake(..),@@ -34,10 +39,13 @@ 	hlGetRn, hlGetLineRn_, hlGetLineRn, hlGetContentRn_, 	hlGetContentRn, -	HM.getSettings, HM.setSettings,+	HM.getSettings, HM.setSettings, HM.SettingsS,+	getSettingsC, setSettingsC, 	HM.flushAppData_, 	flushAppData, 	HM.pushAdBufH,++	validateAlert, 	) where  import Control.Applicative@@ -66,14 +74,19 @@ import qualified Crypto.Types.PubKey.ECC as ECC import qualified Crypto.PubKey.ECC.Prim as ECC import qualified Crypto.Types.PubKey.ECDSA as ECDSA+import qualified Crypto.PubKey.ECC.ECDSA as ECDSA +import qualified Data.X509 as X509+import qualified Data.X509.Validation as X509+import qualified Data.X509.CertificateStore as X509+ import Network.PeyoTLS.Types ( Extension(..), 	Handshake(..), HandshakeItem(..), 	ClientHello(..), ServerHello(..), SessionId(..), 		CipherSuite(..), KeyEx(..), BulkEnc(..), 		CompMethod(..), 	ServerKeyExchange(..), ServerKeyExDhe(..), ServerKeyExEcdhe(..),-	CertificateRequest(..), certificateRequest, ClientCertificateType(..),+	CertReq(..), certificateRequest, ClientCertificateType(..), 		SignAlg(..), HashAlg(..), 	ServerHelloDone(..), ClientKeyExchange(..), Epms(..), 	DigitallySigned(..), Finished(..) )@@ -81,7 +94,7 @@ 	TlsM, run, HandshakeM, execHandshakeM, rerunHandshakeM, 	withRandom, randomByteString, 	ValidateHandle(..), handshakeValidate,-	TlsHandle(..), ContentType(..),+	TlsHandle_(..), ContentType(..), 		names, 		getCipherSuite, setCipherSuite, flushCipherSuite, debugCipherSuite, 		tlsGetContentType, tlsGet, tlsPut, tlsPutNH,@@ -95,7 +108,8 @@ 	getServerFinished, setServerFinished, 	resetSequenceNumber, -	getSettings, setSettings,+	getSettings, setSettings, SettingsS,+	getSettingsC, setSettingsC, 	flushAppData_, 	getAdBuf, 	setAdBuf,@@ -182,52 +196,6 @@ encodeContent (CAlert al ad) = (HM.CTAlert, BS.pack [al, ad]) encodeContent (CHandshake hss) = (HM.CTHandshake, B.encode hss) -class SecretKey sk where-	type Blinder sk-	generateBlinder :: CPRG g => sk -> g -> (Blinder sk, g)-	sign :: HashAlg -> Blinder sk -> sk -> BS.ByteString -> BS.ByteString-	signatureAlgorithm :: sk -> SignAlg--instance SecretKey RSA.PrivateKey where-	type Blinder RSA.PrivateKey = RSA.Blinder-	generateBlinder sk rng =-		RSA.generateBlinder rng . RSA.public_n $ RSA.private_pub sk-	sign hs bl sk bs = let-		(h, oid) = first ($ bs) $ case hs of-			Sha1 -> (SHA1.hash,-				ASN1.OID [1, 3, 14, 3, 2, 26])-			Sha256 -> (SHA256.hash,-				ASN1.OID [2, 16, 840, 1, 101, 3, 4, 2, 1])-			_ -> error $ "HandshakeBase: " ++-				"not implemented bulk encryption type"-		a = [ASN1.Start ASN1.Sequence,-			ASN1.Start ASN1.Sequence,-				oid, ASN1.Null, ASN1.End ASN1.Sequence,-			ASN1.OctetString h, ASN1.End ASN1.Sequence]-		b = ASN1.encodeASN1' ASN1.DER a-		pd = BS.concat [ "\x00\x01",-			BS.replicate (ps - 3 - BS.length b) 0xff, "\NUL", b ]-		ps = RSA.public_size $ RSA.private_pub sk in-		RSA.dp (Just bl) sk pd-	signatureAlgorithm _ = Rsa--instance SecretKey ECDSA.PrivateKey where-	type Blinder ECDSA.PrivateKey = Integer-	generateBlinder _ rng = let-		(Right bl, rng') = first B.decode $ cprgGenerate 32 rng in-		(bl, rng')-	sign ha bl sk = B.encode .-		(($) <$> blindSign bl hs sk . generateKs (hs, bls) q x <*> id)-		where-		(hs, bls) = case ha of-			Sha1 -> (SHA1.hash, 64)-			Sha256 -> (SHA256.hash, 64)-			_ -> error $ "HandshakeBase: " ++-				"not implemented bulk encryption type"-		q = ECC.ecc_n . ECC.common_curve $ ECDSA.private_curve sk-		x = ECDSA.private_d sk-	signatureAlgorithm _ = Ecdsa- class DhParam b where 	type Secret b 	type Public b@@ -289,9 +257,9 @@ 		HM.Server -> HM.setServerFinished fh 	return fh -instance (HandleLike h, CPRG g) => HandleLike (HM.TlsHandle h g) where-	type HandleMonad (HM.TlsHandle h g) = HM.TlsM h g-	type DebugLevel (HM.TlsHandle h g) = DebugLevel h+instance (HandleLike h, CPRG g) => HandleLike (HM.TlsHandle_ h g) where+	type HandleMonad (HM.TlsHandle_ h g) = HM.TlsM h g+	type DebugLevel (HM.TlsHandle_ h g) = DebugLevel h 	hlPut = HM.hlPut_ 	hlGet = (.) <$> checkAppData <*> ((fst `liftM`) .) 		. HM.tlsGet__ . (, undefined)@@ -300,13 +268,13 @@ 	hlDebug = HM.hlDebug_ 	hlClose = HM.hlClose_ -checkAppData :: (HandleLike h, CPRG g) => HM.TlsHandle h g ->+checkAppData :: (HandleLike h, CPRG g) => HM.TlsHandle_ h g -> 	HM.TlsM h g (HM.ContentType, BS.ByteString) -> HM.TlsM h g BS.ByteString checkAppData t m = m >>= \cp -> case cp of 	(HM.CTAppData, ad) -> return ad 	(HM.CTAlert, "\SOH\NUL") -> do 		_ <- HM.tlsPut_ (t, undefined) HM.CTAlert "\SOH\NUL"-		E.throwError "TlsHandle.checkAppData: EOF"+		E.throwError "TlsHandle_.checkAppData: EOF" 	(HM.CTHandshake, hs) -> do 		lift . lift $ hlDebug (HM.tlsHandle t) "critical" "renegotiation?\n" 		lift . lift . hlDebug (HM.tlsHandle t) "critical" . BSC.pack@@ -315,20 +283,20 @@ 			. (++ "\n") $ show (B.decode hs :: Either String Handshake) 		return "" 	_ -> do	_ <- HM.tlsPut_ (t, undefined) HM.CTAlert "\2\10"-		E.throwError "TlsHandle.checkAppData: not application data"+		E.throwError "TlsHandle_.checkAppData: not application data" -hlGetRn_ :: (HM.ValidateHandle h, CPRG g) => (HM.TlsHandle h g -> HM.TlsM h g ()) ->-	HM.TlsHandle h g -> Int -> HM.TlsM h g BS.ByteString+hlGetRn_ :: (HM.ValidateHandle h, CPRG g) => (HM.TlsHandle_ h g -> HM.TlsM h g ()) ->+	HM.TlsHandle_ h g -> Int -> HM.TlsM h g BS.ByteString hlGetRn_ rh = (.) <$> checkAppData <*> ((fst `liftM`) .) . HM.tlsGet_ rh 	. (, undefined)  hlGetLineRn_, hlGetContentRn_ :: (HM.ValidateHandle h, CPRG g) =>-	(HM.TlsHandle h g -> HM.TlsM h g ()) -> HM.TlsHandle h g -> HM.TlsM h g BS.ByteString+	(HM.TlsHandle_ h g -> HM.TlsM h g ()) -> HM.TlsHandle_ h g -> HM.TlsM h g BS.ByteString hlGetLineRn_ rh = ($) <$> checkAppData <*> HM.tGetLine_ rh hlGetContentRn_ rh = ($) <$> checkAppData <*> HM.tGetContent_ rh -hlGetRn :: (HM.ValidateHandle h, CPRG g) => (HM.TlsHandle h g -> HM.TlsM h g ()) ->-	HM.TlsHandle h g -> Int -> HM.TlsM h g BS.ByteString+hlGetRn :: (HM.ValidateHandle h, CPRG g) => (HM.TlsHandle_ h g -> HM.TlsM h g ()) ->+	HM.TlsHandle_ h g -> Int -> HM.TlsM h g BS.ByteString hlGetRn rn t n = do 	bf <- HM.getAdBuf t 	if BS.length bf >= n@@ -338,7 +306,7 @@ 	else (bf `BS.append`) `liftM` hlGetRn_ rn t (n - BS.length bf)  hlGetLineRn :: (HM.ValidateHandle h, CPRG g) =>-	(HM.TlsHandle h g -> HM.TlsM h g ()) -> HM.TlsHandle h g ->+	(HM.TlsHandle_ h g -> HM.TlsM h g ()) -> HM.TlsHandle_ h g -> 	HM.TlsM h g BS.ByteString hlGetLineRn rn t = do 	bf <- HM.getAdBuf t@@ -361,8 +329,8 @@ 	_ -> bs  hlGetContentRn :: (HM.ValidateHandle h, CPRG g) =>-	(HM.TlsHandle h g -> HM.TlsM h g ()) ->-	HM.TlsHandle h g -> HM.TlsM h g BS.ByteString+	(HM.TlsHandle_ h g -> HM.TlsM h g ()) ->+	HM.TlsHandle_ h g -> HM.TlsM h g BS.ByteString hlGetContentRn rn t = do 	bf <- HM.getAdBuf t 	if BS.null bf@@ -384,3 +352,161 @@ eRenegoInfo :: Extension -> Maybe BS.ByteString eRenegoInfo (ERenegoInfo ri) = Just ri eRenegoInfo _ = Nothing++checkClientRenego, checkServerRenego ::+	HandleLike h => BS.ByteString -> HM.HandshakeM h g ()+checkClientRenego cf = (cf ==) `liftM` HM.getClientFinished >>= \ok ->+	E.unless ok . HM.throwError HM.ALFatal HM.ADHsFailure $+		"Network.PeyoTLS.Base.checkClientRenego: bad renegotiation"+checkServerRenego ri = do+	cf <- HM.getClientFinished+	sf <- HM.getServerFinished+	E.unless (ri == cf `BS.append` sf) $ HM.throwError+		HM.ALFatal HM.ADHsFailure+		"Network.PeyoTLS.Base.checkServerRenego: bad renegotiation"++makeClientRenego, makeServerRenego :: HandleLike h => HM.HandshakeM h g Extension+makeClientRenego = ERenegoInfo `liftM` HM.getClientFinished+makeServerRenego = ERenegoInfo `liftM`+	(BS.append `liftM` HM.getClientFinished `E.ap` HM.getServerFinished)++validateAlert :: [X509.FailedReason] -> HM.AlertDesc+validateAlert vr+	| X509.UnknownCA `elem` vr = HM.ADUnknownCa+	| X509.Expired `elem` vr = HM.ADCertificateExpired+	| X509.InFuture `elem` vr = HM.ADCertificateExpired+	| otherwise = HM.ADCertificateUnknown++type SettingsC = (+	[CipherSuite],+	[(HM.CertSecretKey, X509.CertificateChain)],+	X509.CertificateStore )++getSettingsC :: HandleLike h => HM.HandshakeM h g SettingsC+getSettingsC = do+	(css, crts, mcs) <- HM.getSettingsC+	case mcs of+		Just cs -> return (css, crts, cs)+		_ -> HM.throwError HM.ALFatal HM.ADInternalError+			"Network.PeyoTLS.Base.getSettingsC"++setSettingsC :: HandleLike h => SettingsC -> HM.HandshakeM h g ()+setSettingsC (css, crts, cs) = HM.setSettingsC (css, crts, Just cs)++moduleName :: String+moduleName = "Network.PeyoTLS.Base"++decodePoint :: BS.ByteString -> ECC.Point+decodePoint s = case BS.uncons s of+	Just (4, p) -> let (x, y) = BS.splitAt 32 p in ECC.Point+		(either error id $ B.decode x)+		(either error id $ B.decode y)+	_ -> error $ moduleName ++ ".decodePoint: not implemented point"++class SvSignPublicKey pk where+	svpAlgorithm :: pk -> SignAlg+	verify :: HashAlg -> pk -> BS.ByteString -> BS.ByteString -> Bool++instance SvSignPublicKey RSA.PublicKey where+	svpAlgorithm _ = Rsa+	verify = rsaVerify++rsaVerify :: HashAlg -> RSA.PublicKey -> BS.ByteString -> BS.ByteString -> Bool+rsaVerify ha pk sn m = let+	(hs, oid0) = case ha of+		Sha1 -> (SHA1.hash, ASN1.OID [1, 3, 14, 3, 2, 26])+		Sha256 -> (SHA256.hash, ASN1.OID [2, 16, 840, 1, 101, 3, 4, 2, 1])+		_ -> error "not implemented"+	(o, oid) = case ASN1.decodeASN1' ASN1.DER . BS.tail+		. BS.dropWhile (== 255) . BS.drop 2 $ RSA.ep pk sn of+		Right [ASN1.Start ASN1.Sequence,+			ASN1.Start ASN1.Sequence, oid_, ASN1.Null, ASN1.End ASN1.Sequence,+			ASN1.OctetString o_, ASN1.End ASN1.Sequence ] -> (o_, oid_)+		e -> error $ show e in+	oid == oid0 && o == hs m++instance SvSignPublicKey ECDSA.PublicKey where+	svpAlgorithm _ = Ecdsa+	verify Sha1 pk = ECDSA.verify SHA1.hash pk . either error id . B.decode+	verify Sha256 pk = ECDSA.verify SHA256.hash pk . either error id . B.decode+	verify _ _ = error "TlsClient: ECDSA.PublicKey.verify: not implemented"++class SecretKey sk where+	type Blinder sk+	generateBlinder :: CPRG g => sk -> g -> (Blinder sk, g)+	sign :: HashAlg -> Blinder sk -> sk -> BS.ByteString -> BS.ByteString+	signatureAlgorithm :: sk -> SignAlg++instance SecretKey RSA.PrivateKey where+	type Blinder RSA.PrivateKey = RSA.Blinder+	generateBlinder sk rng =+		RSA.generateBlinder rng . RSA.public_n $ RSA.private_pub sk+	sign hs bl sk bs = let+		(h, oid) = first ($ bs) $ case hs of+			Sha1 -> (SHA1.hash,+				ASN1.OID [1, 3, 14, 3, 2, 26])+			Sha256 -> (SHA256.hash,+				ASN1.OID [2, 16, 840, 1, 101, 3, 4, 2, 1])+			_ -> error $ "HandshakeBase: " +++				"not implemented bulk encryption type"+		a = [ASN1.Start ASN1.Sequence,+			ASN1.Start ASN1.Sequence,+				oid, ASN1.Null, ASN1.End ASN1.Sequence,+			ASN1.OctetString h, ASN1.End ASN1.Sequence]+		b = ASN1.encodeASN1' ASN1.DER a+		pd = BS.concat [ "\x00\x01",+			BS.replicate (ps - 3 - BS.length b) 0xff, "\NUL", b ]+		ps = RSA.public_size $ RSA.private_pub sk in+		RSA.dp (Just bl) sk pd+	signatureAlgorithm _ = Rsa++instance SecretKey ECDSA.PrivateKey where+	type Blinder ECDSA.PrivateKey = Integer+	generateBlinder _ rng = let+		(Right bl, rng') = first B.decode $ cprgGenerate 32 rng in+		(bl, rng')+	sign ha bl sk = B.encode .+		(($) <$> blindSign bl hs sk . generateKs (hs, bls) q x <*> id)+		where+		(hs, bls) = case ha of+			Sha1 -> (SHA1.hash, 64)+			Sha256 -> (SHA256.hash, 64)+			_ -> error $ "HandshakeBase: " +++				"not implemented bulk encryption type"+		q = ECC.ecc_n . ECC.common_curve $ ECDSA.private_curve sk+		x = ECDSA.private_d sk+	signatureAlgorithm _ = Ecdsa++class ClSignSecretKey sk where+	csSign :: sk -> BS.ByteString -> BS.ByteString+	csAlgorithm :: sk -> (HashAlg, SignAlg)++instance ClSignSecretKey RSA.PrivateKey where+	csSign sk m = let pd = HM.rsaPadding (RSA.private_pub sk) m in RSA.dp Nothing sk pd+	csAlgorithm _ = (Sha256, Rsa)++instance ClSignSecretKey ECDSA.PrivateKey where+	csSign sk m = enc $ blindSign 0 id sk (generateKs (SHA256.hash, 64) q x m) m+		where+		q = ECC.ecc_n . ECC.common_curve $ ECDSA.private_curve sk+		x = ECDSA.private_d sk+		enc (ECDSA.Signature r s) = ASN1.encodeASN1' ASN1.DER [+			ASN1.Start ASN1.Sequence,+				ASN1.IntVal r, ASN1.IntVal s,+				ASN1.End ASN1.Sequence]+	csAlgorithm _ = (Sha256, Ecdsa)++class ClSignPublicKey pk where+	cspAlgorithm :: pk -> SignAlg+	csVerify :: pk -> BS.ByteString -> BS.ByteString -> Bool++instance ClSignPublicKey RSA.PublicKey where+	cspAlgorithm _ = Rsa+	csVerify k s h = RSA.ep k s == HM.rsaPadding k h++instance ClSignPublicKey ECDSA.PublicKey where+	cspAlgorithm _ = Ecdsa+	csVerify k = ECDSA.verify id k . either error id . B.decode++makeEcdsaPubKey :: ECC.CurveName -> BS.ByteString -> ECDSA.PublicKey+makeEcdsaPubKey c xy = ECDSA.PublicKey (ECC.getCurveByName c) $ decodePoint xy
src/Network/PeyoTLS/Certificate.hs view
@@ -2,7 +2,7 @@ {-# OPTIONS_GHC -fno-warn-orphans #-}  module Network.PeyoTLS.Certificate (-	CertificateRequest(..), certificateRequest, ClientCertificateType(..),+	CertReq(..), certificateRequest, ClientCertificateType(..), 	ClientKeyExchange(..), DigitallySigned(..)) where  import Control.Applicative ((<$>), (<*>))@@ -25,7 +25,7 @@ 		. (\(X509.CertificateChainRaw ccr) -> ccr) 		. X509.encodeCertificateChain 		. (\(X509.CertificateChain cs) ->-			X509.CertificateChain $ reverse cs)+			X509.CertificateChain $ cs)  instance B.Parsable X509.CertificateChain where 	parse = do@@ -33,29 +33,26 @@ 			(flip B.list (B.take =<< B.take 3) =<< B.take 3) 		case ecc of 			Right (X509.CertificateChain cs) ->-				return . X509.CertificateChain $ reverse cs+				return . X509.CertificateChain $ cs 			Left (n, err) -> fail $ show n ++ " " ++ err -data CertificateRequest-	= CertificateRequest [ClientCertificateType]-		[(HashAlg, SignAlg)] [X509.DistinguishedName]-	| CertificateRequestRaw BS.ByteString+data CertReq = CertReq [ClientCertificateType] [(HashAlg, SignAlg)] [X509.DistinguishedName] 	deriving Show  certificateRequest :: [ClientCertificateType] -> [(HashAlg, SignAlg)] ->-	X509.CertificateStore -> CertificateRequest-certificateRequest t a = CertificateRequest t a+	X509.CertificateStore -> CertReq+certificateRequest t a = CertReq t a 	. map (X509.certIssuerDN . X509.signedObject . X509.getSigned) 	. X509.listCertificates -instance B.Bytable CertificateRequest where-	encode (CertificateRequest t a n) = BS.concat [+instance B.Bytable CertReq where+	encode (CertReq t a n) = BS.concat [ 		B.addLen w8 $ cmap B.encode t, 		B.addLen w16 . BS.concat $ 			concatMap (\(h, s) -> [B.encode h, B.encode s]) a, 		B.addLen w16 . flip cmap n $ B.addLen w16 . 			ASN1.encodeASN1' ASN1.DER . flip ASN1.toASN1 [] ]-	encode (CertificateRequestRaw bs) = bs+--	encode (CertReq bs) = bs 	decode = B.evalBytableM $ do 		t <- flip B.list (B.take 1) =<< B.take 1 		a <- flip B.list ((,) <$> B.take 1 <*> B.take 1) =<< B.take 2@@ -64,7 +61,7 @@ 			a1 <- either (fail . show) return $ 				ASN1.decodeASN1' ASN1.DER bs 			either (fail . show) (return . fst) $ ASN1.fromASN1 a1-		return $ CertificateRequest t a n+		return $ CertReq t a n  data ClientCertificateType = CTRsaSign | CTEcdsaSign | CTRaw Word8 	deriving (Show, Eq)
src/Network/PeyoTLS/Client.hs view
@@ -1,200 +1,179 @@-{-# LANGUAGE OverloadedStrings, TypeFamilies, FlexibleContexts,-	PackageImports, ScopedTypeVariables #-}+{-# LANGUAGE OverloadedStrings, TypeFamilies, FlexibleContexts, PackageImports #-}  module Network.PeyoTLS.Client (-	PeyotlsM, PeyotlsHandleC,-	TlsM, TlsHandleC,-	run, open, renegotiate, names,+	PeyotlsM, PeyotlsHandle, TlsM, TlsHandle, run, open, renegotiate, names, 	CipherSuite(..), KeyEx(..), BulkEnc(..),-	ValidateHandle(..), CertSecretKey ) where+	ValidateHandle(..), CertSecretKey(..) ) where  import Control.Applicative ((<$>), (<*>))-import Control.Arrow (first)-import Control.Monad (when, unless, liftM)+import Control.Monad (when, unless, liftM, ap)+import Data.Maybe (fromMaybe, listToMaybe, mapMaybe) import Data.List (find, intersect) import Data.HandleLike (HandleLike(..)) import System.IO (Handle) import "crypto-random" Crypto.Random (CPRG, SystemRNG) -import qualified "monads-tf" Control.Monad.Error as E-import qualified "monads-tf" Control.Monad.Error.Class as E import qualified Data.ByteString as BS-import qualified Data.ASN1.Types as ASN1-import qualified Data.ASN1.Encoding as ASN1-import qualified Data.ASN1.BinaryEncoding as ASN1 import qualified Data.X509 as X509 import qualified Data.X509.CertificateStore as X509 import qualified Codec.Bytable.BigEndian as B-import qualified Crypto.Hash.SHA1 as SHA1-import qualified Crypto.Hash.SHA256 as SHA256 import qualified Crypto.PubKey.DH as DH-import qualified Crypto.PubKey.RSA as RSA-import qualified Crypto.PubKey.RSA.Prim as RSA import qualified Crypto.Types.PubKey.ECC as ECC-import qualified Crypto.PubKey.ECC.ECDSA as ECDSA -import qualified Network.PeyoTLS.Base as HB-import Network.PeyoTLS.Base ( flushAppData,-	Extension(..), getClientFinished,-	getSettings, setSettings,-	getClientFinished, getServerFinished,-	PeyotlsM,-	TlsM, run, HandshakeM, execHandshakeM, rerunHandshakeM,-		CertSecretKey(..),-		withRandom, randomByteString,-	TlsHandle,-		readHandshake, getChangeCipherSpec,-		writeHandshake, putChangeCipherSpec,-	ValidateHandle(..), handshakeValidate,-	ServerKeyExEcdhe(..), ServerKeyExDhe(..), ServerHelloDone(..),-	ClientHello(..), ServerHello(..), SessionId(..),+import qualified Network.PeyoTLS.Base as BASE (names)+import Network.PeyoTLS.Base ( debug,+	PeyotlsM, TlsM, run,+		getSettingsC, setSettingsC,+		hlGetRn, hlGetLineRn, hlGetContentRn,+	HandshakeM, execHandshakeM, rerunHandshakeM,+		withRandom, randomByteString, flushAppData,+		AlertLevel(..), AlertDesc(..), throwError,+	ValidateHandle(..), handshakeValidate, validateAlert,+	TlsHandle_, CertSecretKey(..),+		readHandshake, writeHandshake,+		getChangeCipherSpec, putChangeCipherSpec,+	ClientHello(..), ServerHello(..), SessionId(..), eRenegoInfo, 		CipherSuite(..), KeyEx(..), BulkEnc(..), 		CompMethod(..), HashAlg(..), SignAlg(..), 		setCipherSuite,-	CertificateRequest(..), ClientCertificateType(..),-	ClientKeyExchange(..), Epms(..),-		generateKeys, encryptRsa, rsaPadding,-	DigitallySigned(..), handshakeHash, flushCipherSuite,-	Side(..), RW(..), finishedHash,-	DhParam(..), generateKs, blindSign,+		checkServerRenego, makeClientRenego,+	ServerKeyExEcdhe(..), ServerKeyExDhe(..), SvSignPublicKey(..),+	CertReq(..), ClientCertificateType(..),+	ServerHelloDone(..),+	ClientKeyExchange(..), Epms(..), generateKeys, encryptRsa,+	DigitallySigned(..), ClSignSecretKey(..), handshakeHash,+	Side(..), RW(..), finishedHash, flushCipherSuite,+	DhParam(..), makeEcdsaPubKey ) -	hlGetRn, hlGetLineRn, hlGetContentRn,-	)+type PeyotlsHandle = TlsHandle Handle SystemRNG -names :: TlsHandleC h g -> [String]-names = HB.names . tlsHandleC+newtype TlsHandle h g = TlsHandleC { tlsHandleC :: TlsHandle_ h g } deriving Show +instance (ValidateHandle h, CPRG g) => HandleLike (TlsHandle h g) where+	type HandleMonad (TlsHandle h g) = TlsM h g+	type DebugLevel (TlsHandle h g) = DebugLevel h+	hlPut (TlsHandleC t) = hlPut t+	hlGet = hlGetRn rehandshake . tlsHandleC+	hlGetLine = hlGetLineRn rehandshake . tlsHandleC+	hlGetContent = hlGetContentRn rehandshake . tlsHandleC+	hlDebug (TlsHandleC t) = hlDebug t+	hlClose (TlsHandleC t) = hlClose t++moduleName :: String+moduleName = "Network.PeyoTLS.Client"++names :: TlsHandle h g -> [String]+names = BASE.names . tlsHandleC+ open :: (ValidateHandle h, CPRG g) => h -> [CipherSuite] -> 	[(CertSecretKey, X509.CertificateChain)] -> X509.CertificateStore ->-	TlsM h g (TlsHandleC h g)+	TlsM h g (TlsHandle h g) open h cscl crts ca = (TlsHandleC `liftM`) . execHandshakeM h $ do-	setSettings (cscl, rcrt, ecrt, Just ca)-	cr <- clientHello cscl-	handshake rcrt ecrt ca cr-	where-	rcrt = first rsaKey <$> find (HB.isRsaKey . fst) crts-	ecrt = first ecdsaKey <$> find (HB.isEcdsaKey . fst) crts+	setSettingsC (cscl, crts, ca)+	handshake crts ca =<< clientHello cscl -renegotiate :: (ValidateHandle h, CPRG g) => TlsHandleC h g -> TlsM h g ()+renegotiate :: (ValidateHandle h, CPRG g) => TlsHandle h g -> TlsM h g () renegotiate (TlsHandleC t) = rerunHandshakeM t $ do-	(cscl, rcrt, ecrt, Just ca) <- getSettings-	cr <- clientHello cscl-	HB.debug "critical" ("CLIENT HASH AFTER CLIENTHELLO" :: String)-	HB.debug "critical" =<< handshakeHash-	ne <- flushAppData-	when ne $ handshake rcrt ecrt ca cr+	(cscl, crts, ca) <- getSettingsC+	clientHello cscl >>= \cr ->+		flushAppData >>= flip when (handshake crts ca cr) -rehandshake :: (ValidateHandle h, CPRG g) => TlsHandle h g -> TlsM h g ()+rehandshake :: (ValidateHandle h, CPRG g) => TlsHandle_ h g -> TlsM h g () rehandshake t = rerunHandshakeM t $ do-	(cscl, rcrt, ecrt, Just ca) <- getSettings-	cr <- clientHello cscl-	handshake rcrt ecrt ca cr--handshake :: (ValidateHandle h, CPRG g) =>-	Maybe (RSA.PrivateKey, X509.CertificateChain) ->-	Maybe (ECDSA.PrivateKey, X509.CertificateChain) ->-	X509.CertificateStore -> BS.ByteString -> HandshakeM h g ()-handshake rcrt ecrt ca cr = do-	(sr, cs@(CipherSuite ke _)) <- serverHello-	setCipherSuite cs-	HB.debug "critical" ("CLIENT HASH AFTER SERVERHELLO" :: String)-	HB.debug "critical" =<< handshakeHash-	case ke of-		RSA -> rsaHandshake cr sr crts ca-		DHE_RSA -> dheHandshake dhType cr sr crts ca-		ECDHE_RSA -> dheHandshake curveType cr sr crts ca-		ECDHE_ECDSA -> dheHandshake curveType cr sr crts ca-		_ -> error "not implemented"-	where-	dhType :: DH.Params; dhType = undefined-	curveType :: ECC.Curve; curveType = undefined-	crts = case (rcrt, ecrt) of-		(Just (rsk, rcc), Just (esk, ecc)) -> [-			(RsaKey rsk, rcc), (EcdsaKey esk, ecc)]-		(Just (rsk, rcc), _) -> [(RsaKey rsk, rcc)]-		(_, Just (esk, ecc)) -> [(EcdsaKey esk, ecc)]-		_ -> []--getRenegoInfo :: Maybe [Extension] -> Maybe BS.ByteString-getRenegoInfo Nothing = Nothing-getRenegoInfo (Just []) = Nothing-getRenegoInfo (Just (ERenegoInfo rn : _)) = Just rn-getRenegoInfo (Just (_ : es)) = getRenegoInfo $ Just es+	(cscl, crts, ca) <- getSettingsC+	handshake crts ca =<< clientHello cscl  clientHello :: (HandleLike h, CPRG g) => 	[CipherSuite] -> HandshakeM h g BS.ByteString clientHello cscl = do 	cr <- randomByteString 32-	cf <- getClientFinished-	writeHandshake . ClientHello (3, 3) cr (SessionId "") cscl-		[CompMethodNull] $ Just [ERenegoInfo cf]+	((>>) <$> writeHandshake <*> debug "low")+		. ClientHello (3, 3) cr (SessionId "") cscl [CompMethodNull]+		. Just . (: []) =<< makeClientRenego 	return cr -serverHello :: (HandleLike h, CPRG g) =>-	HandshakeM h g (BS.ByteString, CipherSuite)+handshake :: (ValidateHandle h, CPRG g) =>+	[(CertSecretKey, X509.CertificateChain)] ->+	X509.CertificateStore -> BS.ByteString -> HandshakeM h g ()+handshake crts ca cr = do+	(sr, ke) <- serverHello+	($ ca) . ($ crts) . ($ (cr, sr)) $ case ke of+		RSA -> rsaHandshake+		DHE_RSA -> dheHandshake (undefined :: DH.Params)+		ECDHE_RSA -> dheHandshake (undefined :: ECC.Curve)+		ECDHE_ECDSA -> dheHandshake (undefined :: ECC.Curve)+		_ -> \_ _ _ -> throwError ALFatal ADHsFailure $+			moduleName ++ ".handshake: not implemented"++serverHello :: (HandleLike h, CPRG g) => HandshakeM h g (BS.ByteString, KeyEx) serverHello = do-	cf <- getClientFinished-	sf <- getServerFinished-	ServerHello _v sr _sid cs _cm e <- readHandshake-	let	Just rn = getRenegoInfo e-		rn0 = cf `BS.append` sf-	unless (rn == rn0) $ E.throwError "Network.PeyoTLS.Client.hello"-	return (sr, cs)+	ServerHello v sr _sid cs@(CipherSuite ke _) cm e <- readHandshake+	case v of+		(3, 3) -> return ()+		_ -> throwError ALFatal ADProtocolVersion $+			moduleName ++ ".serverHello: only TLS 1.2"+	case cm of+		CompMethodNull -> return ()+		_ -> throwError ALFatal ADHsFailure $+			moduleName ++ ".serverHello: only compression method null"+	case listToMaybe . mapMaybe eRenegoInfo $ fromMaybe [] e of+		Just ri -> checkServerRenego ri+		_ -> throwError ALFatal ADInsufficientSecurity $+			moduleName ++ ".serverHello: require secure renegotiation"+	setCipherSuite cs+	return (sr, ke) -rsaHandshake :: (ValidateHandle h, CPRG g) =>- 	BS.ByteString -> BS.ByteString ->+rsaHandshake :: (ValidateHandle h, CPRG g) => (BS.ByteString, BS.ByteString) -> 	[(CertSecretKey, X509.CertificateChain)] -> X509.CertificateStore -> 	HandshakeM h g ()-rsaHandshake cr sr crts ca = do+rsaHandshake rs crts ca = do 	cc@(X509.CertificateChain (c : _)) <- readHandshake 	vr <- handshakeValidate ca cc-	unless (null vr) $ E.throwError "TlsClient.rsaHandshake: validate failure"-	let X509.PubKeyRSA pk =-		X509.certPubKey . X509.signedObject $ X509.getSigned c+	unless (null vr) . throwError ALFatal (validateAlert vr) $+		moduleName ++ ".rsaHandshake: validate failure"+	pk <- case X509.certPubKey . X509.signedObject $ X509.getSigned c of+		X509.PubKeyRSA k -> return k+		_ -> throwError ALFatal ADIllegalParameter $+			moduleName ++ ".rsaHandshake: require RSA public key" 	crt <- clientCertificate crts 	pms <- ("\x03\x03" `BS.append`) `liftM` randomByteString 46-	generateKeys Client (cr, sr) pms+	generateKeys Client rs pms 	writeHandshake . Epms =<< encryptRsa pk pms 	finishHandshake crt -dheHandshake :: (ValidateHandle h, CPRG g, KeyExchangeClass ke, Show (Secret ke),-	Show (Public ke)) =>-	ke -> BS.ByteString -> BS.ByteString ->+dheHandshake :: (ValidateHandle h, CPRG g,+		KeyExchangeClass ke, Show (Secret ke), Show (Public ke)) =>+	ke -> (BS.ByteString, BS.ByteString) -> 	[(CertSecretKey, X509.CertificateChain)] -> X509.CertificateStore -> 	HandshakeM h g ()-dheHandshake t cr sr crts ca = do+dheHandshake t rs crts ca = do 	cc@(X509.CertificateChain cs) <- readHandshake-	let c = last cs-	case X509.certPubKey . X509.signedObject $ X509.getSigned c of-		X509.PubKeyRSA pk -> succeedHandshake t pk cr sr cc crts ca-		X509.PubKeyECDSA cv pnt ->-			succeedHandshake t (ek cv pnt) cr sr cc crts ca-		_ -> E.throwError "TlsClient.dheHandshake: not implemented"-	where-	ek cv pnt = ECDSA.PublicKey (ECC.getCurveByName cv) (point pnt)-	point s = let (x, y) = BS.splitAt 32 $ BS.drop 1 s in ECC.Point-		(either error id $ B.decode x)-		(either error id $ B.decode y)--succeedHandshake ::-	(ValidateHandle h, CPRG g, Verify pk, KeyExchangeClass ke, Show (Secret ke),-		Show (Public ke)) =>-	ke -> pk -> BS.ByteString -> BS.ByteString -> X509.CertificateChain ->-	[(CertSecretKey, X509.CertificateChain)] -> X509.CertificateStore ->-	HandshakeM h g ()-succeedHandshake t pk cr sr cc crts ca = do 	vr <- handshakeValidate ca cc-	unless (null vr) $-		E.throwError "TlsClient.succeedHandshake: validate failure"-	(ps, pv, ha, _sa, sn) <- serverKeyExchange+	unless (null vr) . throwError ALFatal (validateAlert vr) $+		moduleName ++ ".succeed: validate failure"+	case X509.certPubKey . X509.signedObject . X509.getSigned $ head cs of+		X509.PubKeyRSA pk -> succeed t pk rs crts+		X509.PubKeyECDSA cv pt -> succeed t (makeEcdsaPubKey cv pt) rs crts+		_ -> throwError ALFatal ADHsFailure $+			moduleName ++ ".dheHandshake: not implemented"++succeed :: (ValidateHandle h, CPRG g, SvSignPublicKey pk,+		KeyExchangeClass ke, Show (Secret ke), Show (Public ke)) =>+	ke -> pk -> (BS.ByteString, BS.ByteString) ->+	[(CertSecretKey, X509.CertificateChain)] -> HandshakeM h g ()+succeed t pk rs@(cr, sr) crts = do+	(ps, pv, ha, sa, sn) <- serverKeyExchange 	let _ = ps `asTypeOf` t-	unless (verify ha pk sn $ BS.concat [cr, sr, B.encode ps, B.encode pv]) $-		E.throwError "TlsClient.succeedHandshake: verify failure"+	unless (sa == svpAlgorithm pk) . throwError ALFatal ADHsFailure $+		pre ++ "sign algorithm unmatch"+	unless (verify ha pk sn $ BS.concat [cr, sr, B.encode ps, B.encode pv]) .+		throwError ALFatal ADDecryptError $ pre ++ "verify failure" 	crt <- clientCertificate crts 	sv <- withRandom $ generateSecret ps-	generateKeys Client (cr, sr) $ calculateShared ps sv pv+	generateKeys Client rs $ calculateShared ps sv pv 	writeHandshake . ClientKeyExchange . B.encode $ calculatePublic ps sv 	finishHandshake crt+	where pre = moduleName ++ ".succeed: "  class (DhParam bs, B.Bytable bs, B.Bytable (Public bs)) => KeyExchangeClass bs where 	serverKeyExchange :: (HandleLike h, CPRG g) => HandshakeM h g@@ -210,123 +189,45 @@ 		ServerKeyExDhe ps pv ha sa sn <- readHandshake 		return (ps, pv, ha, sa, sn) -class Verify pk where-	verify :: HashAlg -> pk -> BS.ByteString -> BS.ByteString -> Bool--instance Verify RSA.PublicKey where-	verify = rsaVerify--rsaVerify :: HashAlg -> RSA.PublicKey -> BS.ByteString -> BS.ByteString -> Bool-rsaVerify ha pk sn m = let-	(hs, oid0) = case ha of-		Sha1 -> (SHA1.hash, ASN1.OID [1, 3, 14, 3, 2, 26])-		Sha256 -> (SHA256.hash, ASN1.OID [2, 16, 840, 1, 101, 3, 4, 2, 1])-		_ -> error "not implemented"-	(o, oid) = case ASN1.decodeASN1' ASN1.DER . BS.tail-		. BS.dropWhile (== 255) . BS.drop 2 $ RSA.ep pk sn of-		Right [ASN1.Start ASN1.Sequence,-			ASN1.Start ASN1.Sequence, oid_, ASN1.Null, ASN1.End ASN1.Sequence,-			ASN1.OctetString o_, ASN1.End ASN1.Sequence ] -> (o_, oid_)-		e -> error $ show e in-	oid == oid0 && o == hs m--instance Verify ECDSA.PublicKey where-	verify Sha1 pk = ECDSA.verify SHA1.hash pk . either error id . B.decode-	verify Sha256 pk = ECDSA.verify SHA256.hash pk . either error id . B.decode-	verify _ _ = error "TlsClient: ECDSA.PublicKey.verify: not implemented"- clientCertificate :: (HandleLike h, CPRG g) => 	[(CertSecretKey, X509.CertificateChain)] -> 	HandshakeM h g (Maybe (CertSecretKey, X509.CertificateChain)) clientCertificate crts = do-	shd <- readHandshake-	case shd of-		Left (CertificateRequest ca hsa dn) -> do-			ServerHelloDone <- readHandshake-			case find (isMatchedCert ca hsa dn) crts of-				Just (sk, rcc) -> do-					writeHandshake rcc-					return $ Just (sk, rcc)-				_ -> E.throwError . E.strMsg $-					"TlsClient.clientCertificate: " ++-						"no certificate"-		Right ServerHelloDone -> return Nothing-		_ -> E.throwError "TlsClient.clientCertificate"+	h <- readHandshake+	(\p -> either p (\SHDone -> return Nothing) h) $ \(CertReq cct a dn) -> do+		SHDone <- readHandshake+		case find (isMatchedCert cct a dn) crts of+			Just c ->+				(>>) <$> writeHandshake . snd <*> return . Just $ c+			_ -> throwError ALFatal ADUnknownCa $ moduleName +++				".clientCertificate: no certificate"  isMatchedCert :: [ClientCertificateType] -> [(HashAlg, SignAlg)] -> 	[X509.DistinguishedName] -> (CertSecretKey, X509.CertificateChain) -> Bool isMatchedCert ct hsa dn = (&&) <$> csk . fst <*> ccrt . snd 	where-	csk (RsaKey _) = CTRsaSign `elem` ct || Rsa `elem` map snd hsa-	csk (EcdsaKey _) = CTEcdsaSign `elem` ct || Ecdsa `elem` map snd hsa-	ccrt (X509.CertificateChain cs@(c : _)) =-		cpk pk && not (null $ intersect dn issr)-		where-		obj = X509.signedObject . X509.getSigned-		pk = X509.certPubKey $ obj c-		issr = map (X509.certIssuerDN . obj) cs-	ccrt _ = error "TlsClient.certIsOk: empty certificate chain"-	cpk X509.PubKeyRSA {} = CTRsaSign `elem` ct || Rsa `elem` map snd hsa-	cpk X509.PubKeyECDSA {} = CTEcdsaSign `elem` ct || Ecdsa `elem` map snd hsa-	cpk _ = False+	obj = X509.signedObject . X509.getSigned+	rsa = CTRsaSign `elem` ct || Rsa `elem` map snd hsa+	ecdsa = CTEcdsaSign `elem` ct || Ecdsa `elem` map snd hsa+	csk (RsaKey _) = rsa; csk (EcdsaKey _) = ecdsa+	ccrt (X509.CertificateChain cs) =+		cpk (X509.certPubKey . obj $ head cs) &&+		not (null . intersect dn $ map (X509.certIssuerDN . obj) cs)+	cpk X509.PubKeyRSA{} = rsa; cpk X509.PubKeyECDSA{} = ecdsa; cpk _ = False  finishHandshake :: (HandleLike h, CPRG g) => 	Maybe (CertSecretKey, X509.CertificateChain) -> HandshakeM h g () finishHandshake crt = do 	hs <- handshakeHash-	case crt of-		Just (RsaKey sk, X509.CertificateChain (c : _)) ->-			writeHandshake $ digitallySigned sk (pubKey sk c) hs-		Just (EcdsaKey sk, X509.CertificateChain (c : _)) ->-			writeHandshake $ digitallySigned sk (pubKey sk c) hs+	case fst <$> crt of+		Just (RsaKey sk) -> writeHandshake $+			DigitallySigned (csAlgorithm sk) $ csSign sk hs+		Just (EcdsaKey sk) -> writeHandshake $+			DigitallySigned (csAlgorithm sk) $ csSign sk hs 		_ -> return () 	putChangeCipherSpec >> flushCipherSuite Write-	fc <- finishedHash Client-	writeHandshake fc+	writeHandshake =<< finishedHash Client 	getChangeCipherSpec >> flushCipherSuite Read-	fs <- finishedHash Server-	(fs ==) `liftM` readHandshake >>= flip unless-		(E.throwError "TlsClient.finishHandshake: finished hash failure")-	where-	digitallySigned sk pk hs = DigitallySigned (algorithm sk) $ sign sk pk hs--class SecretKey sk where-	type PubKey sk-	pubKey :: sk -> X509.SignedCertificate -> PubKey sk-	sign :: sk -> PubKey sk -> BS.ByteString -> BS.ByteString-	algorithm :: sk -> (HashAlg, SignAlg)--instance SecretKey RSA.PrivateKey where-	type PubKey RSA.PrivateKey = RSA.PublicKey-	pubKey _ c = case X509.certPubKey . X509.signedObject $ X509.getSigned c of-		X509.PubKeyRSA pk -> pk-		_ -> error "TlsClient: RSA.PrivateKey.pubKey"-	sign sk pk m = let pd = rsaPadding pk m in RSA.dp Nothing sk pd-	algorithm _ = (Sha256, Rsa)--instance SecretKey ECDSA.PrivateKey where-	type PubKey ECDSA.PrivateKey = ()-	pubKey _ _ = ()-	sign sk _ m = enc $ blindSign 0 id sk (generateKs (SHA256.hash, 64) q x m) m-		where-		q = ECC.ecc_n . ECC.common_curve $ ECDSA.private_curve sk-		x = ECDSA.private_d sk-		enc (ECDSA.Signature r s) = ASN1.encodeASN1' ASN1.DER [-			ASN1.Start ASN1.Sequence,-				ASN1.IntVal r, ASN1.IntVal s,-				ASN1.End ASN1.Sequence]-	algorithm _ = (Sha256, Ecdsa)--newtype TlsHandleC h g = TlsHandleC { tlsHandleC :: TlsHandle h g }--instance (ValidateHandle h, CPRG g) => HandleLike (TlsHandleC h g) where-	type HandleMonad (TlsHandleC h g) = TlsM h g-	type DebugLevel (TlsHandleC h g) = DebugLevel h-	hlPut (TlsHandleC t) = hlPut t-	hlGet = hlGetRn rehandshake . tlsHandleC-	hlGetLine = hlGetLineRn rehandshake . tlsHandleC-	hlGetContent = hlGetContentRn rehandshake . tlsHandleC-	hlDebug (TlsHandleC t) = hlDebug t-	hlClose (TlsHandleC t) = hlClose t--type PeyotlsHandleC = TlsHandleC Handle SystemRNG+	(==) `liftM` finishedHash Server `ap` readHandshake >>= flip unless+		(throwError ALFatal ADDecryptError $+			moduleName ++ ".finishHandshake: finished hash failure")
src/Network/PeyoTLS/Handle.hs view
@@ -3,7 +3,7 @@ module Network.PeyoTLS.Handle ( 	TlsM, Alert(..), AlertLevel(..), AlertDesc(..), 		run, withRandom, randomByteString,-	TlsHandle(..), RW(..), Side(..), ContentType(..), CipherSuite(..),+	TlsHandle_(..), RW(..), Side(..), ContentType(..), CipherSuite(..), 		newHandle, getContentType, tlsGet, tlsPut, generateKeys, 		debugCipherSuite, 		getCipherSuiteSt, setCipherSuiteSt, flushCipherSuiteSt,@@ -13,8 +13,10 @@ 	getClientFinishedT, setClientFinishedT, 	getServerFinishedT, setServerFinishedT, +	Settings,+	getSettingsT, setSettingsT, 	getInitSetT, setInitSetT,-	InitialSettings,+	SettingsS,  	resetSequenceNumber, 	tlsGet_,@@ -54,20 +56,21 @@ 	PartnerId, newPartnerId, Keys(..), 	getClientFinished, setClientFinished, 	getServerFinished, setServerFinished,-	InitialSettings,+	Settings, getSettings, setSettings,+	SettingsS, 	getInitSet, setInitSet, 	CertSecretKey(..), 	) import qualified Network.PeyoTLS.Crypto as CT ( 	makeKeys, encrypt, decrypt, hashSha1, hashSha256, finishedHash ) -data TlsHandle h g = TlsHandle {+data TlsHandle_ h g = TlsHandle_ { 	clientId :: PartnerId, 	tlsHandle :: h, 	names :: [String] } 	deriving Show -type HandleHash h g = (TlsHandle h g, SHA256.Ctx)+type HandleHash h g = (TlsHandle_ h g, SHA256.Ctx)  data Side = Server | Client deriving (Show, Eq) @@ -78,15 +81,15 @@ 		Right r -> return r 		Left a -> error $ show a -newHandle :: HandleLike h => h -> TlsM h g (TlsHandle h g)+newHandle :: HandleLike h => h -> TlsM h g (TlsHandle_ h g) newHandle h = do 	s <- get 	let (i, s') = newPartnerId s 	put s'-	return TlsHandle {+	return TlsHandle_ { 		clientId = i, tlsHandle = h, names = [] } -getContentType :: (HandleLike h, CPRG g) => TlsHandle h g -> TlsM h g ContentType+getContentType :: (HandleLike h, CPRG g) => TlsHandle_ h g -> TlsM h g ContentType getContentType t = do 	ct <- fst `liftM` getBuf (clientId t) 	(\gt -> case ct of CTNull -> gt; _ -> return ct) $ do@@ -95,7 +98,7 @@ 		return ct'  flushAppData :: (HandleLike h, CPRG g) =>-	TlsHandle h g -> TlsM h g (BS.ByteString, Bool)+	TlsHandle_ h g -> TlsM h g (BS.ByteString, Bool) flushAppData t = do 	ct <- getContentType t 	case ct of@@ -123,13 +126,13 @@ 			| otherwise -> updateHash hh bs 		_ -> return hh -tlsGet_ :: (HandleLike h, CPRG g) => (TlsHandle h g -> TlsM h g ()) ->+tlsGet_ :: (HandleLike h, CPRG g) => (TlsHandle_ h g -> TlsM h g ()) -> 	HandleHash h g -> Int -> 	TlsM h g ((ContentType, BS.ByteString), HandleHash h g) tlsGet_ rn hh@(t, _) n = (, hh) `liftM` buffered_ rn t n  buffered :: (HandleLike h, CPRG g) =>-	TlsHandle h g -> Int -> TlsM h g (ContentType, BS.ByteString)+	TlsHandle_ h g -> Int -> TlsM h g (ContentType, BS.ByteString) buffered t n = do 	(ct, b) <- getBuf $ clientId t; let rl = n - BS.length b 	if rl <= 0@@ -144,8 +147,8 @@ 		setBuf (clientId t) (ct', b') 		second (b `BS.append`) `liftM` buffered t rl -buffered_ :: (HandleLike h, CPRG g) => (TlsHandle h g -> TlsM h g ()) ->-	TlsHandle h g -> Int -> TlsM h g (ContentType, BS.ByteString)+buffered_ :: (HandleLike h, CPRG g) => (TlsHandle_ h g -> TlsM h g ()) ->+	TlsHandle_ h g -> Int -> TlsM h g (ContentType, BS.ByteString) buffered_ rn t n = do 	ct0 <- getContentType t 	case ct0 of@@ -161,7 +164,7 @@ 				second (b `BS.append`) `liftM` buffered_ rn t rl  splitRetBuf :: HandleLike h =>-	TlsHandle h g -> Int -> ContentType -> BS.ByteString ->+	TlsHandle_ h g -> Int -> ContentType -> BS.ByteString -> 	TlsM h g (ContentType, BS.ByteString) splitRetBuf t n ct b = do 	let (ret, b') = BS.splitAt n b@@ -169,33 +172,33 @@ 	return (ct, ret)  getWholeWithCt :: (HandleLike h, CPRG g) =>-	TlsHandle h g -> TlsM h g (ContentType, BS.ByteString)+	TlsHandle_ h g -> TlsM h g (ContentType, BS.ByteString) getWholeWithCt t = do 	flush t 	ct <- (either (throwError . strMsg) return . B.decode) =<< read t 1 	[_vmj, _vmn] <- BS.unpack `liftM` read t 2 	e <- read t =<< either (throwError . strMsg) return . B.decode =<< read t 2-	when (BS.null e) $ throwError "TlsHandle.getWholeWithCt: e is null"+	when (BS.null e) $ throwError "TlsHandle_.getWholeWithCt: e is null" 	p <- decrypt t ct e 	thlDebug (tlsHandle t) "medium" . BSC.pack . (++ ": ") $ show ct 	thlDebug (tlsHandle t) "medium" . BSC.pack . (++  "\n") . show $ BS.head p 	thlDebug (tlsHandle t) "low" . BSC.pack . (++ "\n") $ show p 	return (ct, p) -read :: (HandleLike h, CPRG g) => TlsHandle h g -> Int -> TlsM h g BS.ByteString+read :: (HandleLike h, CPRG g) => TlsHandle_ h g -> Int -> TlsM h g BS.ByteString read t n = do 	r <- thlGet (tlsHandle t) n 	unless (BS.length r == n) . throwError . strMsg $-		"TlsHandle.read: can't read " ++ show (BS.length r) ++ " " ++ show n+		"TlsHandle_.read: can't read " ++ show (BS.length r) ++ " " ++ show n 	return r  decrypt :: HandleLike h =>-	TlsHandle h g -> ContentType -> BS.ByteString -> TlsM h g BS.ByteString+	TlsHandle_ h g -> ContentType -> BS.ByteString -> TlsM h g BS.ByteString decrypt t ct e = do 	ks <- getKeys $ clientId t 	decrypt_ t ks ct e -decrypt_ :: HandleLike h => TlsHandle h g ->+decrypt_ :: HandleLike h => TlsHandle_ h g -> 	Keys -> ContentType -> BS.ByteString -> TlsM h g BS.ByteString decrypt_ _ Keys{ kReadCS = CipherSuite _ BE_NULL } _ e = return e decrypt_ t ks ct e = do@@ -206,7 +209,7 @@ 	hs <- case be of 		AES_128_CBC_SHA -> return CT.hashSha1 		AES_128_CBC_SHA256 -> return CT.hashSha256-		_ -> throwError "TlsHandle.decrypt: not implement bulk encryption"+		_ -> throwError "TlsHandle_.decrypt: not implement bulk encryption" 	either (throwError . strMsg) return $ 		CT.decrypt hs wk mk sn (B.encode ct `BS.append` "\x03\x03") e @@ -223,7 +226,7 @@ 		(CTHandshake, True) -> updateHash hh p 		_ -> return hh -flush :: (HandleLike h, CPRG g) => TlsHandle h g -> TlsM h g ()+flush :: (HandleLike h, CPRG g) => TlsHandle_ h g -> TlsM h g () flush t = do 	(bct, bp) <- getWBuf $ clientId t 	setWBuf (clientId t) (CTNull, "")@@ -233,12 +236,12 @@ 			B.encode bct, "\x03\x03", B.addLen (undefined :: Word16) e ]  encrypt :: (HandleLike h, CPRG g) =>-	TlsHandle h g -> ContentType -> BS.ByteString -> TlsM h g BS.ByteString+	TlsHandle_ h g -> ContentType -> BS.ByteString -> TlsM h g BS.ByteString encrypt t ct p = do 	ks <- getKeys $ clientId t 	encrypt_ t ks ct p -encrypt_ :: (HandleLike h, CPRG g) => TlsHandle h g ->+encrypt_ :: (HandleLike h, CPRG g) => TlsHandle_ h g -> 	Keys -> ContentType -> BS.ByteString -> TlsM h g BS.ByteString encrypt_ _ Keys{ kWriteCS = CipherSuite _ BE_NULL } _ p = return p encrypt_ t ks ct p = do@@ -249,14 +252,14 @@ 	hs <- case be of 		AES_128_CBC_SHA -> return CT.hashSha1 		AES_128_CBC_SHA256 -> return CT.hashSha256-		_ -> throwError "TlsHandle.encrypt: not implemented bulk encryption"+		_ -> throwError "TlsHandle_.encrypt: not implemented bulk encryption" 	withRandom $ CT.encrypt hs wk mk sn (B.encode ct `BS.append` "\x03\x03") p  updateHash :: 	HandleLike h => HandleHash h g -> BS.ByteString -> TlsM h g (HandleHash h g) updateHash (th, ctx') bs = return (th, SHA256.update ctx' bs) -updateSequenceNumber :: HandleLike h => TlsHandle h g -> RW -> TlsM h g Word64+updateSequenceNumber :: HandleLike h => TlsHandle_ h g -> RW -> TlsM h g Word64 updateSequenceNumber t rw = do 	ks <- getKeys $ clientId t 	(sn, cs) <- case rw of@@ -269,12 +272,12 @@ 			Write -> succWriteSn $ clientId t 	return sn -resetSequenceNumber :: HandleLike h => TlsHandle h g -> RW -> TlsM h g ()+resetSequenceNumber :: HandleLike h => TlsHandle_ h g -> RW -> TlsM h g () resetSequenceNumber t rw = case rw of 	Read -> resetReadSn $ clientId t 	Write -> resetWriteSn $ clientId t -generateKeys :: HandleLike h => TlsHandle h g -> Side -> CipherSuite ->+generateKeys :: HandleLike h => TlsHandle_ h g -> Side -> CipherSuite -> 	BS.ByteString -> BS.ByteString -> BS.ByteString -> TlsM h g Keys generateKeys t p cs cr sr pms = do 	let CipherSuite _ be = cs@@ -304,7 +307,7 @@ 	Read -> flushCipherSuiteRead 	Write -> flushCipherSuiteWrite -debugCipherSuite :: HandleLike h => TlsHandle h g -> String -> TlsM h g ()+debugCipherSuite :: HandleLike h => TlsHandle_ h g -> String -> TlsM h g () debugCipherSuite t a = do 	k <- getKeys $ clientId t 	thlDebug (tlsHandle t) "high" . BSC.pack@@ -321,19 +324,19 @@ 	sha256 <- handshakeHash (t, ctx) 	return $ CT.finishedHash (partner == Client) ms sha256 -hlPut_ :: (HandleLike h, CPRG g) => TlsHandle h g -> BS.ByteString -> TlsM h g ()+hlPut_ :: (HandleLike h, CPRG g) => TlsHandle_ h g -> BS.ByteString -> TlsM h g () hlPut_ = ((>> return ()) .) . flip (tlsPut True) CTAppData . (, undefined)  hlDebug_ :: HandleLike h =>-	TlsHandle h g -> DebugLevel h -> BS.ByteString -> TlsM h g ()+	TlsHandle_ h g -> DebugLevel h -> BS.ByteString -> TlsM h g () hlDebug_ t l = lift . lift . hlDebug (tlsHandle t) l -hlClose_ :: (HandleLike h, CPRG g) => TlsHandle h g -> TlsM h g ()+hlClose_ :: (HandleLike h, CPRG g) => TlsHandle_ h g -> TlsM h g () hlClose_ t = tlsPut True (t, undefined) CTAlert "\SOH\NUL" >> 	flush t >> thlClose (tlsHandle t)  tGetLine :: (HandleLike h, CPRG g) =>-	TlsHandle h g -> TlsM h g (ContentType, BS.ByteString)+	TlsHandle_ h g -> TlsM h g (ContentType, BS.ByteString) tGetLine t = do 	(bct, bp) <- getBuf $ clientId t 	case splitLine bp of@@ -342,8 +345,8 @@ 			setBuf (clientId t) cp 			second (bp `BS.append`) `liftM` tGetLine t -tGetLine_ :: (HandleLike h, CPRG g) => (TlsHandle h g -> TlsM h g ()) ->-	TlsHandle h g -> TlsM h g (ContentType, BS.ByteString)+tGetLine_ :: (HandleLike h, CPRG g) => (TlsHandle_ h g -> TlsM h g ()) ->+	TlsHandle_ h g -> TlsM h g (ContentType, BS.ByteString) tGetLine_ rn t = do 	ct <- getContentType t 	case ct of@@ -372,30 +375,36 @@ 	_ -> Nothing  tGetContent :: (HandleLike h, CPRG g) =>-	TlsHandle h g -> TlsM h g (ContentType, BS.ByteString)+	TlsHandle_ h g -> TlsM h g (ContentType, BS.ByteString) tGetContent t = do 	bcp@(_, bp) <- getBuf $ clientId t 	if BS.null bp then getWholeWithCt t else 		setBuf (clientId t) (CTNull, BS.empty) >> return bcp  getClientFinishedT, getServerFinishedT ::-	HandleLike h => TlsHandle h g -> TlsM h g BS.ByteString+	HandleLike h => TlsHandle_ h g -> TlsM h g BS.ByteString getClientFinishedT = getClientFinished . clientId getServerFinishedT = getServerFinished . clientId  setClientFinishedT, setServerFinishedT ::-	HandleLike h => TlsHandle h g -> BS.ByteString -> TlsM h g ()+	HandleLike h => TlsHandle_ h g -> BS.ByteString -> TlsM h g () setClientFinishedT = setClientFinished . clientId setServerFinishedT = setServerFinished . clientId -getInitSetT :: HandleLike h => TlsHandle h g -> TlsM h g InitialSettings+getSettingsT :: HandleLike h => TlsHandle_ h g -> TlsM h g Settings+getSettingsT = getSettings . clientId++getInitSetT :: HandleLike h => TlsHandle_ h g -> TlsM h g SettingsS getInitSetT = getInitSet . clientId -setInitSetT :: HandleLike h => TlsHandle h g -> InitialSettings -> TlsM h g ()+setSettingsT :: HandleLike h => TlsHandle_ h g -> Settings -> TlsM h g ()+setSettingsT = setSettings . clientId++setInitSetT :: HandleLike h => TlsHandle_ h g -> SettingsS -> TlsM h g () setInitSetT = setInitSet . clientId -getAdBufT :: HandleLike h => TlsHandle h g -> TlsM h g BS.ByteString+getAdBufT :: HandleLike h => TlsHandle_ h g -> TlsM h g BS.ByteString getAdBufT = getAdBuf . clientId -setAdBufT :: HandleLike h => TlsHandle h g -> BS.ByteString -> TlsM h g ()+setAdBufT :: HandleLike h => TlsHandle_ h g -> BS.ByteString -> TlsM h g () setAdBufT = setAdBuf . clientId
src/Network/PeyoTLS/Monad.hs view
@@ -10,7 +10,8 @@ 		resetReadSn, resetWriteSn, 		getCipherSuiteSt, setCipherSuiteSt, 		flushCipherSuiteRead, flushCipherSuiteWrite, setKeys, getKeys,-		getInitSet, setInitSet, S.InitialSettings,+		getSettings, setSettings,+		getInitSet, setInitSet, S.SettingsS, S.Settings, 	S.Alert(..), S.AlertLevel(..), S.AlertDesc(..), 	S.ContentType(..), 	S.CipherSuite(..), S.KeyEx(..), S.BulkEnc(..),@@ -41,11 +42,12 @@ 	getReadSN, getWriteSN, succReadSN, succWriteSN, resetReadSN, resetWriteSN, 	getCipherSuite, setCipherSuite, 	flushCipherSuiteRead, flushCipherSuiteWrite, setKeys, getKeys,+	getSettings, setSettings, 	getInitSet, setInitSet, 	getClientFinished, setClientFinished, 	getServerFinished, setServerFinished, -	InitialSettings,+	SettingsS, Settings, 	CertSecretKey(..), 	) @@ -90,11 +92,17 @@ getKeys :: HandleLike h => S.PartnerId -> TlsM h g S.Keys getKeys = gets . S.getKeys -getInitSet :: HandleLike h => S.PartnerId -> TlsM h g S.InitialSettings+getInitSet :: HandleLike h => S.PartnerId -> TlsM h g S.SettingsS getInitSet = gets . S.getInitSet -setInitSet :: HandleLike h => S.PartnerId -> S.InitialSettings -> TlsM h g ()+getSettings :: HandleLike h => S.PartnerId -> TlsM h g S.Settings+getSettings = gets . S.getSettings++setInitSet :: HandleLike h => S.PartnerId -> S.SettingsS -> TlsM h g () setInitSet = (modify .) . S.setInitSet++setSettings :: HandleLike h => S.PartnerId -> S.Settings -> TlsM h g ()+setSettings = (modify .) . S.setSettings  getClientFinished, getServerFinished :: 	HandleLike h => S.PartnerId -> TlsM h g BS.ByteString
src/Network/PeyoTLS/ReadFile.hs view
@@ -1,11 +1,11 @@-{-# LANGUAGE OverloadedStrings, TypeFamilies, TupleSections #-}+{-# LANGUAGE TupleSections #-}  module Network.PeyoTLS.ReadFile ( 	CertSecretKey, readKey, readCertificateChain, readCertificateStore) where  import Control.Applicative ((<$>), (<*>)) import Control.Arrow ((***))-import Control.Monad (unless)+import Control.Monad (unless, forM)  import qualified Data.ByteString as BS import qualified Data.ASN1.Types as ASN1@@ -17,30 +17,26 @@ import qualified Data.X509.File as X509 import qualified Data.X509.CertificateStore as X509 import qualified Codec.Bytable.BigEndian as B-import Codec.Bytable.BigEndian () import qualified Crypto.PubKey.ECC.Prim as ECC import qualified Crypto.Types.PubKey.ECC as ECC import qualified Crypto.Types.PubKey.ECDSA as ECDSA -import Network.PeyoTLS.CertSecretKey+import Network.PeyoTLS.CertSecretKey (CertSecretKey(..))  readKey :: FilePath -> IO CertSecretKey-readKey fp = do-	rk <- readRsaKey fp-	maybe (readEcdsaKey fp) return rk+readKey fp = maybe (readEcdsaKey fp) return =<< readRsaKey fp  readRsaKey :: FilePath -> IO (Maybe CertSecretKey)-readRsaKey fp = do-	ks <- X509.readKeyFile fp-	case ks of-		[X509.PrivKeyRSA sk] -> return . Just $ RsaKey sk-		_ -> return Nothing -- error "ReadFile.readRsaKey: not single RSA key"+readRsaKey fp = X509.readKeyFile fp >>= \ks -> case ks of+	[X509.PrivKeyRSA sk] -> return . Just $ RsaKey sk+	_ -> return Nothing  readEcdsaKey :: FilePath -> IO CertSecretKey readEcdsaKey = (EcdsaKey . either error id . decodeEcdsaKey <$>) . BS.readFile -readCertificateChain :: FilePath -> IO X509.CertificateChain-readCertificateChain = (X509.CertificateChain <$>) . X509.readSignedObject+readCertificateChain :: [FilePath] -> IO X509.CertificateChain+readCertificateChain fps =+	X509.CertificateChain . concat <$> forM fps X509.readSignedObject  readCertificateStore :: [FilePath] -> IO X509.CertificateStore readCertificateStore =@@ -51,9 +47,11 @@ 	pms <- either (Left . show) return $ PEM.pemParseBS bs 	pm <- fromSinglePem pms 	pmc <- case pm of-		PEM.PEM { PEM.pemName = "EC PRIVATE KEY", PEM.pemHeader = [],+		PEM.PEM {+			PEM.pemName = "EC PRIVATE KEY",+			PEM.pemHeader = [], 			PEM.pemContent = c } -> return c-		_ -> Left $ msgp ++ "bad PEM structure"+		_ -> Left $ pre ++ "bad PEM structure" 	asn <- either (Left . show) return $ ASN1.decodeASN1' ASN1.DER pmc 	(sk, oid, pk) <- case asn of 		[ASN1.Start ASN1.Sequence,@@ -65,20 +63,20 @@ 				ASN1.BitString (ASN1.BitArray _pl p), 				ASN1.End (ASN1.Container ASN1.Context 1), 			ASN1.End ASN1.Sequence] -> (, o, p) <$> B.decode s-		_ -> Left $ msgp ++ "bad ASN.1 structure"-	unless (oid == oidSecp256r1) . Left $ msgp ++ "not implemented curve"+		_ -> Left $ pre ++ "bad ASN.1 structure"+	unless (oid == oidSecp256r1) . Left $ pre ++ "not implemented curve" 	tpk <- case BS.uncons pk of 		Just (4, t) -> return t-		_ -> Left $ msgp ++ "not implemented point format"+		_ -> Left $ pre ++ "not implemented point format" 	(x, y) <- (\(ex, ey) -> (,) <$> ex <*> ey) . 			(B.decode *** B.decode) $ BS.splitAt 32 tpk 	unless (ECC.Point x y == ECC.pointMul secp256r1 sk g) .-		Left $ msgp ++ "the public key not match"+		Left $ pre ++ "the public key not match" 	return $ ECDSA.PrivateKey secp256r1 sk 	where-	msgp = "ReadFile.decodeEcdsaKey: "+	pre = "ReadFile.decodeEcdsaKey: " 	fromSinglePem [x] = return x-	fromSinglePem _ = Left $ msgp ++ "not single PEM"+	fromSinglePem _ = Left $ pre ++ "not single PEM" 	g = ECC.ecc_g $ ECC.common_curve secp256r1 	secp256r1 = ECC.getCurveByName ECC.SEC_p256r1 	oidSecp256r1 = ASN1.OID [1, 2, 840, 10045, 3, 1, 7]
src/Network/PeyoTLS/Run.hs view
@@ -4,7 +4,7 @@ 	TH.TlsM, TH.run, HandshakeM, execHandshakeM, rerunHandshakeM, 	withRandom, randomByteString, 	ValidateHandle(..), handshakeValidate,-	TH.TlsHandle(..), TH.ContentType(..),+	TH.TlsHandle_(..), TH.ContentType(..), 		getCipherSuite, setCipherSuite, flushCipherSuite, debugCipherSuite, 		tlsGetContentType, tlsGet, tlsPut, tlsPutNH, 		generateKeys, encryptRsa, decryptRsa, rsaPadding,@@ -18,7 +18,8 @@  	resetSequenceNumber, -	getSettings, setSettings,+	getSettings, setSettings, TH.SettingsS,+	getSettingsC, setSettingsC, TH.Settings, 	flushAppData_,  	getAdBuf, setAdBuf,@@ -54,7 +55,7 @@ import qualified Network.PeyoTLS.Handle as TH ( 	TlsM, Alert(..), AlertLevel(..), AlertDesc(..), 		run, withRandom, randomByteString,-	TlsHandle(..), ContentType(..),+	TlsHandle_(..), ContentType(..), 		newHandle, getContentType, tlsGet, tlsPut, generateKeys, 		debugCipherSuite, 		getCipherSuiteSt, setCipherSuiteSt, flushCipherSuiteSt, setKeys,@@ -65,7 +66,8 @@  	resetSequenceNumber, -	getInitSetT, setInitSetT, InitialSettings,+	getSettingsT, setSettingsT, Settings,+	getInitSetT, setInitSetT, SettingsS, 	tlsGet_, 	flushAppData, 	getAdBufT,@@ -78,17 +80,17 @@ resetSequenceNumber rw = gets fst >>= lift . flip TH.resetSequenceNumber rw  tlsGet_ :: (HandleLike h, CPRG g) =>-	(TH.TlsHandle h g -> TH.TlsM h g ()) ->-	(TH.TlsHandle h g, SHA256.Ctx) -> Int -> TH.TlsM h g ((TH.ContentType, BS.ByteString), (TH.TlsHandle h g, SHA256.Ctx))+	(TH.TlsHandle_ h g -> TH.TlsM h g ()) ->+	(TH.TlsHandle_ h g, SHA256.Ctx) -> Int -> TH.TlsM h g ((TH.ContentType, BS.ByteString), (TH.TlsHandle_ h g, SHA256.Ctx)) tlsGet_ = TH.tlsGet_  tlsGet__ :: (HandleLike h, CPRG g) =>-	(TH.TlsHandle h g, SHA256.Ctx) -> Int -> TH.TlsM h g ((TH.ContentType, BS.ByteString), (TH.TlsHandle h g, SHA256.Ctx))+	(TH.TlsHandle_ h g, SHA256.Ctx) -> Int -> TH.TlsM h g ((TH.ContentType, BS.ByteString), (TH.TlsHandle_ h g, SHA256.Ctx)) tlsGet__ = TH.tlsGet True  tGetLine_, tGetContent_ :: (HandleLike h, CPRG g) =>-	(TH.TlsHandle h g -> TH.TlsM h g ()) ->-	TH.TlsHandle h g -> TH.TlsM h g (TH.ContentType, BS.ByteString)+	(TH.TlsHandle_ h g -> TH.TlsM h g ()) ->+	TH.TlsHandle_ h g -> TH.TlsM h g (TH.ContentType, BS.ByteString) tGetLine_ = TH.tGetLine_  flushAppData_ :: (HandleLike h, CPRG g) => HandshakeM h g (BS.ByteString, Bool)@@ -101,22 +103,22 @@ 		_ -> TH.tGetContent t  tlsPut_ :: (HandleLike h, CPRG g) =>-	(TH.TlsHandle h g, SHA256.Ctx) -> TH.ContentType -> BS.ByteString -> TH.TlsM h g (TH.TlsHandle h g, SHA256.Ctx)+	(TH.TlsHandle_ h g, SHA256.Ctx) -> TH.ContentType -> BS.ByteString -> TH.TlsM h g (TH.TlsHandle_ h g, SHA256.Ctx) tlsPut_ = TH.tlsPut True  throwError :: HandleLike h => 	TH.AlertLevel -> TH.AlertDesc -> String -> HandshakeM h g a throwError al ad m = E.throwError $ TH.Alert al ad m -type HandshakeM h g = StateT (TH.TlsHandle h g, SHA256.Ctx) (TH.TlsM h g)+type HandshakeM h g = StateT (TH.TlsHandle_ h g, SHA256.Ctx) (TH.TlsM h g)  execHandshakeM :: HandleLike h =>-	h -> HandshakeM h g () -> TH.TlsM h g (TH.TlsHandle h g)+	h -> HandshakeM h g () -> TH.TlsM h g (TH.TlsHandle_ h g) execHandshakeM h = 	liftM fst . ((, SHA256.init) `liftM` TH.newHandle h >>=) . execStateT  rerunHandshakeM ::-	HandleLike h => TH.TlsHandle h g -> HandshakeM h g a -> TH.TlsM h g a+	HandleLike h => TH.TlsHandle_ h g -> HandshakeM h g a -> TH.TlsM h g a rerunHandshakeM t hm = evalStateT hm (t, SHA256.init)  withRandom :: HandleLike h => (g -> (a, g)) -> HandshakeM h g a@@ -154,7 +156,7 @@ 	X509.CertificateStore -> X509.CertificateChain -> 	HandshakeM h g [X509.FailedReason] handshakeValidate cs cc@(X509.CertificateChain c) = gets fst >>= \t -> do-	modify . first $ const t { TH.names = certNames . X509.getCertificate $ last c }+	modify . first $ const t { TH.names = certNames . X509.getCertificate $ head c } 	lift . lift . lift $ validate (TH.tlsHandle t) cs cc  setCipherSuite :: HandleLike h => TH.CipherSuite -> HandshakeM h g ()@@ -224,17 +226,23 @@ setClientFinished cf = gets fst >>= lift . flip TH.setClientFinishedT cf setServerFinished cf = gets fst >>= lift . flip TH.setServerFinishedT cf -getSettings :: HandleLike h => HandshakeM h g TH.InitialSettings+getSettings :: HandleLike h => HandshakeM h g TH.SettingsS getSettings = gets fst >>= lift . TH.getInitSetT -setSettings :: HandleLike h => TH.InitialSettings -> HandshakeM h g ()+getSettingsC :: HandleLike h => HandshakeM h g TH.Settings+getSettingsC = gets fst >>= lift . TH.getSettingsT++setSettings :: HandleLike h => TH.SettingsS -> HandshakeM h g () setSettings is = gets fst >>= lift . flip TH.setInitSetT is -getAdBuf :: HandleLike h => TH.TlsHandle h g -> TH.TlsM h g BS.ByteString+setSettingsC :: HandleLike h => TH.Settings -> HandshakeM h g ()+setSettingsC is = gets fst >>= lift . flip TH.setSettingsT is++getAdBuf :: HandleLike h => TH.TlsHandle_ h g -> TH.TlsM h g BS.ByteString getAdBuf = TH.getAdBufT  setAdBuf :: HandleLike h =>-	TH.TlsHandle h g -> BS.ByteString -> TH.TlsM h g ()+	TH.TlsHandle_ h g -> BS.ByteString -> TH.TlsM h g () setAdBuf = TH.setAdBufT  getAdBufH :: HandleLike h => HandshakeM h g BS.ByteString
src/Network/PeyoTLS/Server.hs view
@@ -1,9 +1,9 @@-{-# LANGUAGE OverloadedStrings, TypeFamilies, FlexibleContexts, PackageImports, TupleSections #-}+{-# LANGUAGE OverloadedStrings, TypeFamilies, FlexibleContexts, PackageImports #-}  module Network.PeyoTLS.Server (-	PeyotlsM, PeyotlsHandleS, TlsM, TlsHandleS, run, open, renegotiate, names,-	CipherSuite(..), KeyEx(..), BulkEnc(..), ValidateHandle(..), CertSecretKey-	) where+	PeyotlsM, PeyotlsHandle, TlsM, TlsHandle, run, open, renegotiate, names,+	CipherSuite(..), KeyEx(..), BulkEnc(..),+	ValidateHandle(..), CertSecretKey(..) ) where  import Control.Applicative ((<$>), (<*>)) import Control.Arrow (first)@@ -18,52 +18,44 @@  import qualified Data.ByteString as BS import qualified Data.X509 as X509-import qualified Data.X509.Validation as X509 import qualified Data.X509.CertificateStore as X509 import qualified Codec.Bytable.BigEndian as B import qualified Crypto.PubKey.RSA as RSA-import qualified Crypto.PubKey.RSA.Prim as RSA-import qualified Crypto.Types.PubKey.ECC as ECC-import qualified Crypto.Types.PubKey.ECDSA as ECDSA-import qualified Crypto.PubKey.ECC.ECDSA as ECDSA -import qualified Network.PeyoTLS.Base as HB (names)+import qualified Network.PeyoTLS.Base as BASE (names) import Network.PeyoTLS.Base ( 	PeyotlsM, TlsM, run,+		SettingsS, getSettings, setSettings,+		hlGetRn, hlGetLineRn, hlGetContentRn, 	HandshakeM, execHandshakeM, rerunHandshakeM,-		throwError, debug, debugCipherSuite,-		withRandom, randomByteString,-	ValidateHandle(..), handshakeValidate,-	TlsHandle, CertSecretKey(..), isRsaKey, isEcdsaKey,-		readHandshake, getChangeCipherSpec,-		writeHandshake, putChangeCipherSpec,-		writeHandshakeNH,-	AlertLevel(..), AlertDesc(..),-	ClientHello(..), ServerHello(..), SessionId(..), Extension(..),+		withRandom, randomByteString, flushAppData,+		AlertLevel(..), AlertDesc(..), throwError, debugCipherSuite,+	ValidateHandle(..), handshakeValidate, validateAlert,+	TlsHandle_, CertSecretKey(..), isRsaKey, isEcdsaKey,+		readHandshake, writeHandshake, writeHandshakeNH,+		getChangeCipherSpec, putChangeCipherSpec,+	Handshake(HHelloReq),+	ClientHello(..), ServerHello(..), SessionId(..), Extension(..), eRenegoInfo, 		CipherSuite(..), KeyEx(..), BulkEnc(..), 		CompMethod(..), HashAlg(..), SignAlg(..), 		getCipherSuite, setCipherSuite,-		getClientFinished, getServerFinished,-	ServerKeyExchange(..),-	certificateRequest, ClientCertificateType(..), SecretKey(..),+		checkClientRenego, makeServerRenego,+	ServerKeyExchange(..), SecretKey(..),+	certificateRequest, ClientCertificateType(..), 	ServerHelloDone(..),-	ClientKeyExchange(..), Epms(..),-		generateKeys, decryptRsa, rsaPadding,-	DigitallySigned(..), handshakeHash,+	ClientKeyExchange(..), Epms(..), generateKeys, decryptRsa,+	DigitallySigned(..), ClSignPublicKey(..), handshakeHash, 	RW(..), flushCipherSuite, 	Side(..), finishedHash,-	DhParam(..), dh3072Modp, secp256r1,--	Handshake(HHelloReq), eRenegoInfo, getSettings, setSettings, flushAppData,-	hlGetRn, hlGetLineRn, hlGetContentRn )+	DhParam(..), makeEcdsaPubKey, dh3072Modp, secp256r1 ) -type PeyotlsHandleS = TlsHandleS Handle SystemRNG+type PeyotlsHandle = TlsHandle Handle SystemRNG -newtype TlsHandleS h g = TlsHandleS { tlsHandleS :: TlsHandle h g } deriving Show+newtype TlsHandle h g = TlsHandleS { tlsHandleS :: TlsHandle_ h g } deriving Show -instance (ValidateHandle h, CPRG g) => HandleLike (TlsHandleS h g) where-	type HandleMonad (TlsHandleS h g) = TlsM h g-	type DebugLevel (TlsHandleS h g) = DebugLevel h+instance (ValidateHandle h, CPRG g) => HandleLike (TlsHandle h g) where+	type HandleMonad (TlsHandle h g) = TlsM h g+	type DebugLevel (TlsHandle h g) = DebugLevel h 	hlPut (TlsHandleS t) = hlPut t 	hlGet = hlGetRn rehandshake . tlsHandleS 	hlGetLine = hlGetLineRn rehandshake . tlsHandleS@@ -72,21 +64,19 @@ 	hlClose (TlsHandleS t) = hlClose t  type Version = (Word8, Word8)-type Settings = (-	[CipherSuite],-	Maybe (RSA.PrivateKey, X509.CertificateChain),-	Maybe (ECDSA.PrivateKey, X509.CertificateChain),-	Maybe X509.CertificateStore )  version :: Version version = (3, 3) -names :: TlsHandleS h g -> [String]-names = HB.names . tlsHandleS+moduleName :: String+moduleName = "Network.PeyoTLS.Server" -open :: (ValidateHandle h, CPRG g) => h ->-	[CipherSuite] -> [(CertSecretKey, X509.CertificateChain)] ->-	Maybe X509.CertificateStore -> TlsM h g (TlsHandleS h g)+names :: TlsHandle h g -> [String]+names = BASE.names . tlsHandleS++open :: (ValidateHandle h, CPRG g) => h -> [CipherSuite] ->+	[(CertSecretKey, X509.CertificateChain)] -> Maybe X509.CertificateStore ->+	TlsM h g (TlsHandle h g) open h cssv crts mcs = liftM TlsHandleS . execHandshakeM h $ 	((>>) <$> setSettings <*> handshake) (cssv', 		first rsaKey <$> find (isRsaKey . fst) crts,@@ -101,215 +91,143 @@ 	iscs EMPTY_RENEGOTIATION_INFO = False 	iscs _ = True -renegotiate :: (ValidateHandle h, CPRG g) => TlsHandleS h g -> TlsM h g ()+renegotiate :: (ValidateHandle h, CPRG g) => TlsHandle h g -> TlsM h g () renegotiate (TlsHandleS t) = rerunHandshakeM t $ writeHandshakeNH HHelloReq >> 		flushAppData >>= flip when (handshake =<< getSettings) -rehandshake :: (ValidateHandle h, CPRG g) => TlsHandle h g -> TlsM h g ()+rehandshake :: (ValidateHandle h, CPRG g) => TlsHandle_ h g -> TlsM h g () rehandshake t = rerunHandshakeM t $ handshake =<< getSettings -handshake :: (ValidateHandle h, CPRG g) => Settings -> HandshakeM h g ()+handshake :: (ValidateHandle h, CPRG g) => SettingsS -> HandshakeM h g () handshake (cssv, rcrt, ecrt, mcs) = do-	(ke, be, cr, cv, rn) <- clientHello cssv-	sr <- serverHello (snd <$> rcrt) (snd <$> ecrt) rn+	(ke, be, cr, cv) <- clientHello cssv+	sr <- serverHello (snd <$> rcrt) (snd <$> ecrt) 	ha <- case be of 		AES_128_CBC_SHA -> return Sha1 		AES_128_CBC_SHA256 -> return Sha256 		_ -> throwError ALFatal ADInternalError $ 			pre ++ "not implemented bulk encryption type"-	mpk <- ($ mcs) . ($ (cr, sr)) $ case (ke, rcrt, ecrt) of-		(RSA, Just (rsk, _), _) -> rsaKeyExchange rsk cv-		(DHE_RSA, Just (rsk, _), _) -> dhKeyExchange ha dh3072Modp rsk-		(ECDHE_RSA, Just (rsk, _), _) -> dhKeyExchange ha secp256r1 rsk-		(ECDHE_ECDSA, _, Just (esk, _)) -> dhKeyExchange ha secp256r1 esk+	mpk <- ($ mcs) . ($ (cr, sr)) $ case (ke, fst <$> rcrt, fst <$> ecrt) of+		(RSA, Just rsk, _) -> rsaKeyExchange rsk cv+		(DHE_RSA, Just rsk, _) -> dhKeyExchange ha dh3072Modp rsk+		(ECDHE_RSA, Just rsk, _) -> dhKeyExchange ha secp256r1 rsk+		(ECDHE_ECDSA, _, Just esk) -> dhKeyExchange ha secp256r1 esk 		_ -> \_ _ -> throwError ALFatal ADInternalError $ 			pre ++ "no implemented key exchange type or " ++ 				"no applicable certificate files"-	maybe (return ()) certificateVerify mpk+	flip (maybe $ return ()) mpk $ \pk -> case pk of+		X509.PubKeyRSA rpk -> certVerify rpk+		X509.PubKeyECDSA c xy -> certVerify $ makeEcdsaPubKey c xy+		_ -> throwError ALFatal ADUnsupportedCertificate $+			pre ++ "not implement: " ++ show pk 	getChangeCipherSpec >> flushCipherSuite Read-	(==) `liftM` finishedHash Client `ap` readHandshake >>= \ok ->-		unless ok . throwError ALFatal ADDecryptError $-			pre ++ "wrong finished hash"+	(==) `liftM` finishedHash Client `ap` readHandshake >>= \ok -> unless ok .+		throwError ALFatal ADDecryptError $ pre ++ "wrong finished hash" 	putChangeCipherSpec >> flushCipherSuite Write 	writeHandshake =<< finishedHash Server-	where pre = "Network.PeyoTLS.Server.handshake: "+	where pre = moduleName ++ ".handshake: "  clientHello :: (HandleLike h, CPRG g) => [CipherSuite] ->-	HandshakeM h g (KeyEx, BulkEnc, BS.ByteString, Version, Bool)+	HandshakeM h g (KeyEx, BulkEnc, BS.ByteString, Version) clientHello cssv = do 	ClientHello cv cr _sid cscl cms me <- readHandshake-	checkRenegotiation cscl me+	checkRenegoInfo cscl me 	unless (cv >= version) . throwError ALFatal ADProtocolVersion $-		pre ++ "client version should 3.3 or more"+		pre ++ "only implement TLS 1.2" 	unless (CompMethodNull `elem` cms) . throwError ALFatal ADDecodeError $ 		pre ++ "compression method NULL must be supported" 	(ke, be) <- case find (`elem` cscl) cssv of 		Just cs@(CipherSuite k b) -> setCipherSuite cs >> return (k, b)-		_ -> throwError ALFatal ADHandshakeFailure $-			pre ++ "no acceptable set of security parameters"-	return (ke, be, cr, cv, True)-	where pre = "Network.PeyoTLS.Server.clientHello: "+		_ -> throwError ALFatal ADHsFailure $+			pre ++ "no acceptable set of security parameters: \n\t" +++			"cscl: " ++ show cscl ++ "\n\t" +++			"cssv: " ++ show cssv ++ "\n"+	return (ke, be, cr, cv)+	where pre = moduleName ++ ".clientHello: " -checkRenegotiation ::+checkRenegoInfo :: 	HandleLike h => [CipherSuite] -> Maybe [Extension] -> HandshakeM h g ()-checkRenegotiation cscl me = do-	case mcf of-		Just cf -> (cf ==) `liftM` getClientFinished >>= \ok -> unless ok .-			throwError ALFatal ADHandshakeFailure $-				pre ++ "bad renegotiation"-		_ -> throwError ALFatal ADInsufficientSecurity $-			pre ++ "require secure renegotiation"-	where-	pre = "Network.PeyoTLS.Server.checkRenegotiation: "-	mcf = case (EMPTY_RENEGOTIATION_INFO `elem` cscl, me) of+checkRenegoInfo cscl me = (\n -> maybe n checkClientRenego mcf) . throwError+	ALFatal ADInsufficientSecurity $+	moduleName ++ ".checkRenego: require secure renegotiation"+	where mcf = case (EMPTY_RENEGOTIATION_INFO `elem` cscl, me) of 		(True, _) -> Just "" 		(_, Just e) -> listToMaybe $ mapMaybe eRenegoInfo e 		(_, _) -> Nothing  serverHello :: (HandleLike h, CPRG g) =>-	Maybe X509.CertificateChain -> Maybe X509.CertificateChain -> Bool ->+	Maybe X509.CertificateChain -> Maybe X509.CertificateChain -> 	HandshakeM h g BS.ByteString-serverHello rcc ecc rn = do-	cs@(CipherSuite ke _) <- getCipherSuite+serverHello rcc ecc = do+	cs <- getCipherSuite+	ke <- case cs of+		CipherSuite k _ -> return k+		_ -> throwError ALFatal ADInternalError $+			moduleName ++ ".serverHello: never occur" 	sr <- randomByteString 32-	cf <- getClientFinished-	sf <- getServerFinished-	writeHandshake . ServerHello-		version sr (SessionId "") cs CompMethodNull $ if rn-			then Just [ERenegoInfo $ cf `BS.append` sf]-			else Nothing-	debug "critical" ("SERVER HASH AFTER SERVERHELLO" :: String)-	debug "critical" =<< handshakeHash-	writeHandshake $ case (ke, rcc, ecc) of-		(ECDHE_ECDSA, _, Just c) -> c-		(_, Just c, _) -> c-		_ -> error "serverHello"+	writeHandshake+		. ServerHello version sr (SessionId "") cs CompMethodNull+		. Just . (: []) =<< makeServerRenego+	writeHandshake =<< case (ke, rcc, ecc) of+		(ECDHE_ECDSA, _, Just c) -> return c+		(_, Just c, _) -> return c+		_ -> throwError ALFatal ADInternalError $+			moduleName ++ ".serverHello: cert files not match" 	return sr-	{--serverHello _ _ _ _ = throwError ALFatal ADInternalError-	"Network.PeyoTLS.Server.serverHello: never occur"-	-}  rsaKeyExchange :: (ValidateHandle h, CPRG g) => RSA.PrivateKey -> Version -> 	(BS.ByteString, BS.ByteString) -> Maybe X509.CertificateStore -> 	HandshakeM h g (Maybe X509.PubKey)-rsaKeyExchange rsk cv rs mcs = return const-	`ap` requestAndCertificate mcs-	`ap` rsaClientKeyExchange rsk cv rs+rsaKeyExchange sk (vj, vn) rs mcs = const `liftM` reqAndCert mcs `ap` do+	Epms epms <- readHandshake+	generateKeys Server rs =<< mkpms epms `catchError` const+		((BS.cons vj . BS.cons vn) `liftM` randomByteString 46)+	where mkpms epms = do+		pms <- decryptRsa sk epms+		unless (BS.length pms == 48) $ throwError ALFatal ADHsFailure ""+		let [pvj, pvn] = BS.unpack $ BS.take 2 pms+		unless (pvj == vj && pvn == vn) $ throwError ALFatal ADHsFailure ""+		return pms -dhKeyExchange :: (ValidateHandle h, CPRG g, SecretKey sk, Show (Secret dp),-		Show (Public dp),+dhKeyExchange :: (ValidateHandle h, CPRG g, SecretKey sk, 		DhParam dp, B.Bytable dp, B.Bytable (Public dp)) =>-	HashAlg -> dp -> sk ->-	(BS.ByteString, BS.ByteString) -> Maybe X509.CertificateStore ->-	HandshakeM h g (Maybe X509.PubKey)-dhKeyExchange ha dp ssk rs mcs = do+	HashAlg -> dp -> sk -> (BS.ByteString, BS.ByteString) ->+	Maybe X509.CertificateStore -> HandshakeM h g (Maybe X509.PubKey)+dhKeyExchange ha dp sk rs@(cr, sr) mcs = do 	sv <- withRandom $ generateSecret dp-	serverKeyExchange ha dp sv ssk rs-	return const-		`ap` requestAndCertificate mcs-		`ap` dhClientKeyExchange dp sv rs--serverKeyExchange :: (HandleLike h, CPRG g, SecretKey sk,-		DhParam dp, B.Bytable dp, B.Bytable (Public dp)) =>-	HashAlg -> dp -> Secret dp -> sk ->-	(BS.ByteString, BS.ByteString) -> HandshakeM h g ()-serverKeyExchange ha dp sv ssk (cr, sr) = do-	bl <- withRandom $ generateBlinder ssk+	bl <- withRandom $ generateBlinder sk+	let pv = B.encode $ calculatePublic dp sv 	writeHandshake-		. ServerKeyEx edp pv ha (signatureAlgorithm ssk)-		. sign ha bl ssk $ BS.concat [cr, sr, edp, pv]-	where-	edp = B.encode dp-	pv = B.encode $ calculatePublic dp sv+		. ServerKeyEx (B.encode dp) pv ha (signatureAlgorithm sk)+		. sign ha bl sk $ BS.concat [cr, sr, B.encode dp, pv]+	const `liftM` reqAndCert mcs `ap` do+		ClientKeyExchange cke <- readHandshake+		generateKeys Server rs . calculateShared dp sv =<<+			either (throwError ALFatal ADInternalError .+					(moduleName ++) . (".dhKeyExchange: " ++))+				return (B.decode cke) -requestAndCertificate :: (ValidateHandle h, CPRG g) =>+reqAndCert :: (ValidateHandle h, CPRG g) => 	Maybe X509.CertificateStore -> HandshakeM h g (Maybe X509.PubKey)-requestAndCertificate mcs = do+reqAndCert mcs = do 	flip (maybe $ return ()) mcs $ writeHandshake . certificateRequest 		[CTRsaSign, CTEcdsaSign] [(Sha256, Rsa), (Sha256, Ecdsa)]-	writeHandshake ServerHelloDone-	debug "high" ("SERVER HASH AFTER SERVERHELLODONE" :: String)-	debug "high" =<< handshakeHash-	maybe (return Nothing) (liftM Just . clientCertificate) mcs--clientCertificate :: (ValidateHandle h, CPRG g) =>-	X509.CertificateStore -> HandshakeM h g X509.PubKey-clientCertificate cs = do-	cc@(X509.CertificateChain (c : _)) <- readHandshake-	chk cc-	return . X509.certPubKey $ X509.getCertificate c-	where-	chk cc = do-		rs <- handshakeValidate cs cc-		unless (null rs) . throwError ALFatal (selectAlert rs) $-			"TlsServer.clientCertificate: " ++ show rs-	selectAlert rs-		| X509.UnknownCA `elem` rs = ADUnknownCa-		| X509.Expired `elem` rs = ADCertificateExpired-		| X509.InFuture `elem` rs = ADCertificateExpired-		| otherwise = ADCertificateUnknown--rsaClientKeyExchange :: (HandleLike h, CPRG g) => RSA.PrivateKey ->-	Version -> (BS.ByteString, BS.ByteString) -> HandshakeM h g ()-rsaClientKeyExchange sk (cvj, cvn) rs = do-	Epms epms <- readHandshake-	debug "low" ("EPMS" :: String)-	debug "low" epms-	generateKeys Server rs =<< mkpms epms `catchError` const-		((BS.cons cvj . BS.cons cvn) `liftM` randomByteString 46)-	where-	mkpms epms = do-		pms <- decryptRsa sk epms-		unless (BS.length pms == 48) $-			throwError ALFatal ADHandshakeFailure ""-		case BS.unpack $ BS.take 2 pms of-			[pvj, pvn] -> unless (pvj == cvj && pvn == cvn) $-				throwError ALFatal ADHandshakeFailure ""-			_ -> error $ "Network.PeyoTLS.Server." ++-				"rsaClientKeyExchange: never occur"-		debug "low" ("PMS" :: String)-		debug "low" pms-		return pms--dhClientKeyExchange :: (HandleLike h, CPRG g, DhParam dp, B.Bytable (Public dp),-	Show (Public dp)) =>-	dp -> Secret dp -> (BS.ByteString, BS.ByteString) -> HandshakeM h g ()-dhClientKeyExchange dp sv rs = do-	ClientKeyExchange cke <- readHandshake-	let Right pv = B.decode cke-	generateKeys Server rs =<< case Right $ calculateShared dp sv pv of-		Left em -> throwError ALFatal ADInternalError $-			"Network.PeyoTLS.Server.dhClientKeyExchange: " ++ em-		Right sh -> return sh+	writeHandshake SHDone+	flip (maybe $ return Nothing) mcs $ liftM Just . \cs -> do+		cc@(X509.CertificateChain (c : _)) <- readHandshake+		vr <- handshakeValidate cs cc+		unless (null vr) . throwError ALFatal (validateAlert vr) $+			moduleName ++ ".reqAndCert: " ++ show vr+		return . X509.certPubKey $ X509.getCertificate c -certificateVerify :: (HandleLike h, CPRG g) => X509.PubKey -> HandshakeM h g ()-certificateVerify (X509.PubKeyRSA pk) = do-	debugCipherSuite "RSA"-	hs0 <- rsaPadding pk `liftM` handshakeHash-	DigitallySigned a s <- readHandshake-	case a of-		(Sha256, Rsa) -> return ()-		_ -> throwError ALFatal ADDecodeError $-			"TlsServer.certificateVEerify: not implement: " ++ show a-	unless (RSA.ep pk s == hs0) $ throwError ALFatal ADDecryptError-		"TlsServer.certificateVerify: client auth failed "-certificateVerify (X509.PubKeyECDSA ECC.SEC_p256r1 xy) = do-	debugCipherSuite "ECDSA"+certVerify :: (HandleLike h, CPRG g, ClSignPublicKey pk) => pk -> HandshakeM h g ()+certVerify pk = do+	debugCipherSuite . show $ cspAlgorithm pk 	hs0 <- handshakeHash 	DigitallySigned a s <- readHandshake 	case a of-		(Sha256, Ecdsa) -> return ()+		(Sha256, sa) | sa == cspAlgorithm pk -> return () 		_ -> throwError ALFatal ADDecodeError $-			"TlsServer.certificateverify: not implement: " ++ show a-	unless (ECDSA.verify id-		(ECDSA.PublicKey secp256r1 $ pnt xy)-		(either error id $ B.decode s) hs0) $ throwError-			ALFatal ADDecryptError-			"TlsServer.certificateverify: client auth failed"-	where-	pnt s = let (x, y) = BS.splitAt 32 $ BS.drop 1 s in ECC.Point-		(either error id $ B.decode x)-		(either error id $ B.decode y)-certificateVerify p = throwError ALFatal ADUnsupportedCertificate $-	"TlsServer.certificateVerify: not implement: " ++ show p+			moduleName ++ ".certVerify: not implement: " ++ show a+	unless (csVerify pk s hs0) . throwError ALFatal ADDecryptError $+		moduleName ++ ".certVerify: client auth failed "
src/Network/PeyoTLS/State.hs view
@@ -10,16 +10,20 @@ 	getReadSN, getWriteSN, succReadSN, succWriteSN, resetReadSN, resetWriteSN, 	getCipherSuite, setCipherSuite, flushCipherSuiteRead, flushCipherSuiteWrite, 	getKeys, setKeys,+	getSettings, setSettings, 	getInitSet, setInitSet, 	getClientFinished, setClientFinished, 	getServerFinished, setServerFinished, -	InitialSettings,+	SettingsS, Settings, 	CertSecretKey(..), ) where +import Control.Applicative ((<$>))+import Control.Arrow (first) import "monads-tf" Control.Monad.Error.Class (Error(strMsg))-import Data.Maybe (fromJust)+import Data.Maybe (fromJust, maybeToList)+import Data.List (find) import Data.Word (Word8, Word64) import Data.String (IsString(..)) @@ -57,16 +61,39 @@ 		radBuffer = "", 		readSN = 0, writeSN = 0, 		rnClientFinished = "", rnServerFinished = "",-		initialSettings = ([], Nothing, Nothing, Nothing)+		initialSettings = ([], [], Nothing) 		} 	sos = states s -type InitialSettings = (+type SettingsS = ( 	[CipherSuite], 	Maybe (RSA.PrivateKey, X509.CertificateChain), 	Maybe (ECDSA.PrivateKey, X509.CertificateChain),-	Maybe X509.CertificateStore)+	Maybe X509.CertificateStore ) +type Settings = (+	[CipherSuite],+	[(CertSecretKey, X509.CertificateChain)],+	Maybe X509.CertificateStore )++convertSettings :: Settings -> SettingsS+convertSettings (cs, crts, mcs) = (cs,+	first rsaKey <$> find (isRsaKey . fst) crts,+	first ecdsaKey <$> find (isEcdsaKey . fst) crts, mcs)++revertSettings :: SettingsS -> Settings+revertSettings (cs, rcrt, ecrt, mcs) = (cs,+	maybeToList (first RsaKey <$> rcrt) +++	maybeToList (first EcdsaKey <$> ecrt), mcs)++isEcdsaKey :: CertSecretKey -> Bool+isEcdsaKey (EcdsaKey _) = True+isEcdsaKey _ = False++isRsaKey :: CertSecretKey -> Bool+isRsaKey (RsaKey _) = True+isRsaKey _ = False+ data StateOne g = StateOne { 	sKeys :: Keys, 	rBuffer :: (ContentType, BS.ByteString),@@ -76,7 +103,7 @@ 	writeSN :: Word64, 	rnClientFinished :: BS.ByteString, 	rnServerFinished :: BS.ByteString,-	initialSettings :: InitialSettings+	initialSettings :: Settings 	}  getState :: PartnerId -> HandshakeState h g -> StateOne g@@ -136,7 +163,7 @@  data AlertDesc 	= ADCloseNotify            | ADUnexpectedMessage    | ADBadRecordMac-	| ADRecordOverflow         | ADDecompressionFailure | ADHandshakeFailure+	| ADRecordOverflow         | ADDecompressionFailure | ADHsFailure 	| ADUnsupportedCertificate | ADCertificateExpired   | ADCertificateUnknown 	| ADIllegalParameter       | ADUnknownCa            | ADDecodeError 	| ADDecryptError           | ADProtocolVersion      | ADInsufficientSecurity@@ -179,11 +206,19 @@ setKeys :: PartnerId -> Keys -> Modify (HandshakeState h g) setKeys i = modifyState i . \k st -> st { sKeys = k } -getInitSet :: PartnerId -> HandshakeState h g -> InitialSettings-getInitSet i = initialSettings . fromJust' "getInitSet" . lookup i . states+getSettings :: PartnerId -> HandshakeState h g -> Settings+getSettings i = initialSettings . fromJust' "getSettings" . lookup i . states -setInitSet :: PartnerId -> InitialSettings -> Modify (HandshakeState h g)-setInitSet i = modifyState i . \is st -> st { initialSettings = is }+getInitSet :: PartnerId -> HandshakeState h g -> SettingsS+getInitSet i = convertSettings .+	initialSettings . fromJust' "getInitSet" . lookup i . states++setSettings :: PartnerId -> Settings -> Modify (HandshakeState h g)+setSettings i = modifyState i . \is st -> st { initialSettings = is }++setInitSet :: PartnerId -> SettingsS -> Modify (HandshakeState h g)+setInitSet i = modifyState i . \is st -> st+	{ initialSettings = revertSettings is }  getClientFinished, getServerFinished :: 	PartnerId -> HandshakeState h g -> BS.ByteString
src/Network/PeyoTLS/Types.hs view
@@ -7,7 +7,7 @@ 		CipherSuite(..), KeyEx(..), BulkEnc(..), 		CompMethod(..), 	ServerKeyExchange(..), ServerKeyExDhe(..), ServerKeyExEcdhe(..),-	CertificateRequest(..), certificateRequest, ClientCertificateType(..),+	CertReq(..), certificateRequest, ClientCertificateType(..), 		SignAlg(..), HashAlg(..), 	ServerHelloDone(..), ClientKeyExchange(..), Epms(..), 	DigitallySigned(..), Finished(..) ) where@@ -28,14 +28,14 @@ 	CipherSuite(..), KeyEx(..), BulkEnc(..), 	CompMethod(..), HashAlg(..), SignAlg(..) ) import Network.PeyoTLS.Certificate (-	CertificateRequest(..), certificateRequest, ClientCertificateType(..),+	CertReq(..), certificateRequest, ClientCertificateType(..), 	ClientKeyExchange(..), DigitallySigned(..) )  data Handshake 	= HHelloReq 	| HClientHello ClientHello           | HServerHello ServerHello 	| HCertificate X509.CertificateChain | HServerKeyEx BS.ByteString-	| HCertificateReq CertificateRequest | HServerHelloDone+	| HCertificateReq CertReq | HServerHelloDone 	| HCertVerify DigitallySigned        | HClientKeyEx ClientKeyExchange 	| HFinished BS.ByteString            | HRaw Type BS.ByteString 	deriving Show@@ -163,13 +163,13 @@ hasasn :: B.BytableM (HashAlg, SignAlg, BS.ByteString) hasasn = (,,) <$> B.parse <*> B.parse <*> (B.take =<< B.take 2) -instance HandshakeItem CertificateRequest where+instance HandshakeItem CertReq where 	fromHandshake (HCertificateReq cr) = Just cr 	fromHandshake _ = Nothing 	toHandshake = HCertificateReq  instance HandshakeItem ServerHelloDone where-	fromHandshake HServerHelloDone = Just ServerHelloDone+	fromHandshake HServerHelloDone = Just SHDone 	fromHandshake _ = Nothing 	toHandshake _ = HServerHelloDone @@ -205,7 +205,7 @@ 	fromHandshake _ = Nothing 	toHandshake (Finished f) = HFinished f -data ServerHelloDone = ServerHelloDone deriving Show+data ServerHelloDone = SHDone deriving Show  data Type 	= THelloRequest | TClientHello | TServerHello
test/testCIRenego.hs view
@@ -32,7 +32,8 @@  ]  randomFrom :: [a] -> IO [a]-randomFrom [] = return []+randomFrom [] = error "bad"+randomFrom [x] = return [x] randomFrom (x : xs) = do 	b <- randomIO 	(if b then (x :) else id) <$> randomFrom xs
test/testDebug.hs view
@@ -33,7 +33,8 @@  ]  randomFrom :: [a] -> IO [a]-randomFrom [] = return []+randomFrom [] = error "bad"+randomFrom [x] = return [x] randomFrom (x : xs) = do 	b <- randomIO 	(if b then (x :) else id) <$> randomFrom xs