packages feed

u2f 0.1.0.1 → 0.1.0.2

raw patch · 4 files changed

+34/−31 lines, 4 filesdep ~aesondep ~basedep ~cryptonite

Dependency ranges changed: aeson, base, cryptonite, hspec

Files

README.md view
@@ -1,3 +1,5 @@ # U2F -Haskell library for conveniently processing U2F registration/sign-in requests.+[![Hackage](https://img.shields.io/hackage/v/u2f.svg)](https://hackage.haskell.org/package/u2f) [![Build Status](https://travis-ci.org/EButlerIV/u2f.svg?branch=master)](https://travis-ci.org/EButlerIV/u2f)++Haskell library for conveniently processing U2F registration/sign-in requests consistent with the FIDO U2F standard. (https://fidoalliance.org/download/)
src/U2F.hs view
@@ -104,17 +104,16 @@ pubKeyShape (BitString (BitArray len _)) = len == 520 pubKeyShape _ = False -getSignatureBase :: BS.ByteString -> BS.ByteString -> BS.ByteString -> BS.ByteString -> BS.ByteString-getSignatureBase appId clientData keyHandle publicKey = sigBase-  where sigBase = BS.concat([BS.pack "\NUL", SHA256.hash(appId), SHA256.hash(decodeLenient clientData), keyHandle, publicKey])+formatSignatureBase :: BS.ByteString -> BS.ByteString -> BS.ByteString -> BS.ByteString -> BS.ByteString+formatSignatureBase _appId clientData _keyHandle publicKey = sigBase+  where sigBase = BS.concat([BS.pack "\NUL", SHA256.hash(_appId), SHA256.hash(decodeLenient clientData), _keyHandle, publicKey]) -getSignatureBaseFromRegistration :: Registration -> RegistrationData -> Either U2FError BS.ByteString-getSignatureBaseFromRegistration registration registrationData = do-  appId <- pure $ BS.pack $ T.unpack $ registration_appId registration-  clientData <- pure $ BS.pack $ T.unpack $ registration_clientData registration-  keyHandle <- pure $ registrationData_keyHandle registrationData-  publicKey <- pure $ registrationData_publicKey registrationData-  pure $ getSignatureBase appId clientData keyHandle publicKey+getSignatureBaseFromRegistration :: Registration -> RegistrationData -> BS.ByteString+getSignatureBaseFromRegistration registration registrationData = formatSignatureBase aId clientData kH publicKey+  where aId = encodeUtf8 $ registration_appId registration+        clientData = encodeUtf8 $ registration_clientData registration+        kH = registrationData_keyHandle registrationData+        publicKey = registrationData_publicKey registrationData  -- | Verifies that Registration is a valid response to the Request verifyRegistration :: Request -> Registration -> Either U2FError Request@@ -123,7 +122,7 @@   registrationData <- parseRegistrationData $ encodeUtf8 $ registration_registrationData registration   pkey <- getPubKeyFromCertificate $ registrationData_certificate registrationData   signature <- parseSignature $ registrationData_signature registrationData-  signatureBase <- getSignatureBaseFromRegistration registration registrationData+  let signatureBase = getSignatureBaseFromRegistration registration registrationData   case (verifySignature signatureBase pkey signature) of     True -> Right (request {keyHandle = Just $ formatOutputBase64 $ registrationData_keyHandle registrationData})     False -> Left FailedVerificationError@@ -140,15 +139,18 @@   Just clientData -> Right clientData   Nothing -> Left ClientDataParseError --- | Verifies that Signin response is valid given saved pubkey bytestring, request+-- | Verifies that Signin response is valid given saved pubkey bytestring, request.+--   Warning!: Expects uncompressed public key. verifySignin :: BS.ByteString -> Request -> Signin -> Either U2FError Bool verifySignin savedPubkey request signin = do   clientData <- parseClientData $ encodeUtf8 $ signin_clientData signin   _ <- u2fComparator (challenge request) (clientData_challenge clientData) ChallengeMismatchError   signatureData <- parseSignatureData $ encodeUtf8 $ signin_signatureData signin   signature <- parseSignature $ signatureData_signature signatureData-  signatureBase <- getSigninSignatureBase request signin signatureData-  -- So Gross. TODO: write function that checks first byte for compression state, parses each pubkey format+  let signatureBase = getSigninSignatureBase request signin signatureData+  -- TODO: write function that checks first byte for compression state, parses each pubkey format+  -- Technically, only uncompressed keys are allowed by the FIDO U2F spec, but it's possible that+  -- a compressed key could be added to user data via other means.   publicKey <- case (parsePublicKey $ BS.tail $ savedPubkey) of     Just key -> Right key     Nothing -> Left PubKeyParsingError@@ -164,13 +166,12 @@   Right ([_, IntVal r, IntVal s, _]) -> Right $ ECDSA.Signature r s   _ -> Left SignatureParseError -getSigninSignatureBase :: Request -> Signin -> SignatureData -> Either U2FError BS.ByteString-getSigninSignatureBase request signin signatureData = do-  appId <- pure $ encodeUtf8 $ appId request-  userPresenceFlag <- pure $ signatureData_userPresenceFlag signatureData-  counter <- pure $ signatureData_counter signatureData-  clientData <- pure $ encodeUtf8 $ signin_clientData signin-  Right $ BS.concat([SHA256.hash(appId), userPresenceFlag, counter, SHA256.hash(decodeLenient clientData)])+getSigninSignatureBase :: Request -> Signin -> SignatureData -> BS.ByteString+getSigninSignatureBase request signin signatureData = BS.concat([SHA256.hash(aId), userPresenceFlag, counter, SHA256.hash(decodeLenient clientData)])+  where aId = encodeUtf8 $ appId request+        userPresenceFlag = signatureData_userPresenceFlag signatureData+        counter = signatureData_counter signatureData+        clientData = encodeUtf8 $ signin_clientData signin  parsePublicKey :: BS.ByteString -> Maybe ECDSA.PublicKey parsePublicKey keyByteString = case P256.pointFromBinary keyByteString of@@ -195,10 +196,10 @@   reserved <- getByteString 1   publicKey <- getByteString 65   keyHandleLen <- getWord8-  keyHandle <- getByteString $ fromIntegral keyHandleLen+  kH <- getByteString $ fromIntegral keyHandleLen   cert <- unpackASN1   sign <- unpackASN1-  return $ RegistrationData reserved publicKey keyHandle cert sign+  return $ RegistrationData reserved publicKey kH cert sign  unpackSignatureData :: Get SignatureData unpackSignatureData = do
src/U2F/Types.hs view
@@ -5,8 +5,8 @@ import GHC.Generics import qualified Data.Text as T import qualified Data.ByteString.Char8 as BS-import Data.Aeson ((.:), (.:?), decode, FromJSON(..),-  ToJSON(..), Value(..), genericParseJSON, genericToJSON,  defaultOptions)+import Data.Aeson (FromJSON(..),+  ToJSON(..), genericParseJSON, genericToJSON,  defaultOptions) import Data.Aeson.Types (fieldLabelModifier)  data U2FError =
u2f.cabal view
@@ -2,7 +2,7 @@ -- see http://haskell.org/cabal/users-guide/  name:                u2f-version:             0.1.0.1+version:             0.1.0.2 synopsis:            Haskell Universal Two Factor helper toolbox library thing description:         Library useful for server-side U2F Registration and Signin flows. homepage:            https://github.com/EButlerIV/u2f@@ -23,15 +23,15 @@   ghc-options: -Wall   -- other-modules:   -- other-extensions:-  build-depends:       base >= 4.8 && < 4.11-                       , cryptonite >= 0.17 && < 0.21+  build-depends:       base >= 4.8 && < 5+                       , cryptonite >= 0.17 && <= 0.25                        , binary >= 0.8.4.0 && < 0.9                        , text >= 1.2 && < 1.3                        , asn1-encoding >= 0.9 && < 0.10                        , asn1-types >= 0.3.2 && < 0.4                        , base64-bytestring >= 1.0.0.1 && < 1.0.1.0                        , cryptohash >= 0.11 && < 0.12-                       , aeson >= 1.0 && < 1.1+                       , aeson >= 1.0 && <= 1.4.0.0                        , bytestring >= 0.10 && < 0.11   hs-source-dirs:      src   default-language:    Haskell2010@@ -43,7 +43,7 @@   hs-source-dirs: tests   default-language:    Haskell2010   build-depends:  base-                , hspec >= 2.2 && < 2.3+                , hspec >= 2.2 && < 2.6                 , u2f                 , text                 , either-unwrap