Safe Haskell | Safe-Inferred |
---|---|
Language | Haskell2010 |
Partial implementation of https://www.w3.org/TR/xmldsig-core/. We use hsaml2, hxt, x509 and other dubious packages internally, but expose xml-types and cryptonite.
FUTUREWORK: other implementations that could be used for testing: https://www.aleksey.com/xmlsec/ (C); https://github.com/yaronn/xml-crypto (js)
Synopsis
- data SignCreds = SignCreds SignDigest SignKey
- data SignDigest = SignDigestSha256
- data SignKey = SignKeyRSA PublicKey
- data SignPrivCreds = SignPrivCreds SignDigest SignPrivKey
- data SignPrivKey = SignPrivKeyRSA KeyPair
- verifySelfSignature :: (HasCallStack, MonadError String m) => SignedCertificate -> m ()
- parseKeyInfo :: (HasCallStack, MonadError String m) => Bool -> LT -> m SignedCertificate
- renderKeyInfo :: HasCallStack => SignedCertificate -> LT
- certToCreds :: (HasCallStack, MonadError String m) => SignedCertificate -> m SignCreds
- certToPublicKey :: (HasCallStack, MonadError String m) => SignedCertificate -> m PublicKey
- mkSignCreds :: (MonadRandom m, MonadIO m) => Int -> m (SignPrivCreds, SignCreds)
- mkSignCredsWithCert :: forall m. (MonadRandom m, MonadIO m) => Maybe DateTime -> Int -> m (SignPrivCreds, SignCreds, SignedCertificate)
- verify :: forall m. MonadError String m => NonEmpty SignCreds -> LBS -> String -> m ()
- verifyRoot :: forall m. MonadError String m => NonEmpty SignCreds -> LBS -> m ()
- verifyIO :: NonEmpty SignCreds -> LBS -> String -> IO [(SignCreds, Either SignatureError ())]
- signRoot :: (MonadRandom m, MonadError String m) => SignPrivCreds -> Document -> m Document
- signRootAt :: (MonadRandom m, MonadError String m) => Int -> SignPrivCreds -> Document -> m Document
- type HasMonadSign = MonadIO
- newtype MonadSign a = MonadSign (ExceptT String IO a)
- runMonadSign :: MonadSign a -> IO (Either String a)
- signElementIO :: (HasCallStack, HasMonadSign m) => SignPrivCreds -> [Node] -> m [Node]
- signElementIOAt :: (HasCallStack, HasMonadSign m) => Int -> SignPrivCreds -> [Node] -> m [Node]
types
data SignDigest Source #
Instances
Bounded SignDigest Source # | |
Defined in Text.XML.DSig minBound :: SignDigest # maxBound :: SignDigest # | |
Enum SignDigest Source # | |
Defined in Text.XML.DSig succ :: SignDigest -> SignDigest # pred :: SignDigest -> SignDigest # toEnum :: Int -> SignDigest # fromEnum :: SignDigest -> Int # enumFrom :: SignDigest -> [SignDigest] # enumFromThen :: SignDigest -> SignDigest -> [SignDigest] # enumFromTo :: SignDigest -> SignDigest -> [SignDigest] # enumFromThenTo :: SignDigest -> SignDigest -> SignDigest -> [SignDigest] # | |
Show SignDigest Source # | |
Defined in Text.XML.DSig showsPrec :: Int -> SignDigest -> ShowS # show :: SignDigest -> String # showList :: [SignDigest] -> ShowS # | |
Eq SignDigest Source # | |
Defined in Text.XML.DSig (==) :: SignDigest -> SignDigest -> Bool # (/=) :: SignDigest -> SignDigest -> Bool # |
data SignPrivCreds Source #
Instances
Show SignPrivCreds Source # | |
Defined in Text.XML.DSig showsPrec :: Int -> SignPrivCreds -> ShowS # show :: SignPrivCreds -> String # showList :: [SignPrivCreds] -> ShowS # | |
Eq SignPrivCreds Source # | |
Defined in Text.XML.DSig (==) :: SignPrivCreds -> SignPrivCreds -> Bool # (/=) :: SignPrivCreds -> SignPrivCreds -> Bool # |
data SignPrivKey Source #
Instances
Show SignPrivKey Source # | |
Defined in Text.XML.DSig showsPrec :: Int -> SignPrivKey -> ShowS # show :: SignPrivKey -> String # showList :: [SignPrivKey] -> ShowS # | |
Eq SignPrivKey Source # | |
Defined in Text.XML.DSig (==) :: SignPrivKey -> SignPrivKey -> Bool # (/=) :: SignPrivKey -> SignPrivKey -> Bool # |
credential handling
verifySelfSignature :: (HasCallStack, MonadError String m) => SignedCertificate -> m () Source #
parseKeyInfo :: (HasCallStack, MonadError String m) => Bool -> LT -> m SignedCertificate Source #
Read the KeyInfo element of a meta file's IDPSSODescriptor into a public key that can be used for signing. Tested for KeyInfo elements that contain an x509 certificate.
Self-signatures are only verified if first argument is True
. The reason for this flag is
that some IdPs (e.g. centrify) sign their certificates with external CAs. Verification
against external cert needs to be done separately before calling this function.
renderKeyInfo :: HasCallStack => SignedCertificate -> LT Source #
certToCreds :: (HasCallStack, MonadError String m) => SignedCertificate -> m SignCreds Source #
certToPublicKey :: (HasCallStack, MonadError String m) => SignedCertificate -> m PublicKey Source #
mkSignCreds :: (MonadRandom m, MonadIO m) => Int -> m (SignPrivCreds, SignCreds) Source #
mkSignCredsWithCert :: forall m. (MonadRandom m, MonadIO m) => Maybe DateTime -> Int -> m (SignPrivCreds, SignCreds, SignedCertificate) Source #
If first argument validSince
is Nothing
, use cucrent system time.
signature verification
verify :: forall m. MonadError String m => NonEmpty SignCreds -> LBS -> String -> m () Source #
We sometimes get XML documents that are underspecific about which credentials they are going to
use later. As longs as all credentials are from the same authoritative source, it may be ok to
ask for *any* of them to match a signature. So here is an or
over verify
and a non-empty
list of SignCred
s.
NB: The call to unsafePerformIO
in this function is sound under the assumption that
verifyIO
has no effects in IO
other than throwing SomeException
(which are captured
by try
. Technically, it does have other effects, like opening temp files for capturing
stderr (if any), but we do not care about those. The only thing we care about is that the
conceptually pure function of validating a signature will either be called twice with the
same arguments and return the same result value, or not be called a second time with the
same arguments, in which case that same value will be used.
verifyRoot :: forall m. MonadError String m => NonEmpty SignCreds -> LBS -> m () Source #
verifyIO :: NonEmpty SignCreds -> LBS -> String -> IO [(SignCreds, Either SignatureError ())] Source #
Try a list of creds against a document. If all fail, return a list of errors for each cert; if *any* succeed, return the empty list.
signature creation
signRoot :: (MonadRandom m, MonadError String m) => SignPrivCreds -> Document -> m Document Source #
Make sure that root node node has ID attribute and sign it. This is similar to the more
primitive generateSignature
. Cons signature to the children list (left-most position).
signRootAt :: (MonadRandom m, MonadError String m) => Int -> SignPrivCreds -> Document -> m Document Source #
Like signRoot
, but insert signature at any given position in the children list. If the list
is too short for this position, throw an error.
testing
type HasMonadSign = MonadIO Source #
Instances
Applicative MonadSign Source # | |
Functor MonadSign Source # | |
Monad MonadSign Source # | |
MonadRandom MonadSign Source # | |
Defined in Text.XML.DSig | |
MonadError String MonadSign Source # | |
Defined in Text.XML.DSig throwError :: String -> MonadSign a # catchError :: MonadSign a -> (String -> MonadSign a) -> MonadSign a # |
signElementIO :: (HasCallStack, HasMonadSign m) => SignPrivCreds -> [Node] -> m [Node] Source #
signElementIOAt :: (HasCallStack, HasMonadSign m) => Int -> SignPrivCreds -> [Node] -> m [Node] Source #