asn1-data 0.4.2 → 0.4.3
raw patch · 5 files changed
+132/−24 lines, 5 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Data.ASN1.BER: decodeASN1EventsRepr :: [ASN1Event] -> Either ASN1Err [ASN1Repr]
+ Data.ASN1.BER: decodeASN1StreamRepr :: ByteString -> Either ASN1Err [ASN1Repr]
+ Data.ASN1.BER: enumReadRawRepr :: Monad m => Enumeratee ASN1Event ASN1Repr m a
+ Data.ASN1.BER: iterateByteStringRepr :: Monad m => ByteString -> Iteratee ASN1Repr m a -> m (Either SomeException a)
+ Data.ASN1.BER: iterateEventsRepr :: Monad m => [ASN1Event] -> Iteratee ASN1Repr m a -> m (Either SomeException a)
+ Data.ASN1.DER: decodeASN1EventsRepr :: [ASN1Event] -> Either ASN1Err [ASN1Repr]
+ Data.ASN1.DER: decodeASN1StreamRepr :: ByteString -> Either ASN1Err [ASN1Repr]
+ Data.ASN1.DER: enumReadBytesRepr :: Monad m => Enumeratee ByteString ASN1Repr m a
+ Data.ASN1.DER: enumReadRawRepr :: Monad m => Enumeratee ASN1Event ASN1Repr m a
+ Data.ASN1.DER: iterateByteStringRepr :: Monad m => ByteString -> Iteratee ASN1Repr m a -> m (Either SomeException a)
+ Data.ASN1.DER: iterateEventsRepr :: Monad m => [ASN1Event] -> Iteratee ASN1Repr m a -> m (Either SomeException a)
+ Data.ASN1.Stream: type ASN1Repr = (ASN1, [ASN1Event])
Files
- Data/ASN1/BER.hs +64/−20
- Data/ASN1/DER.hs +34/−1
- Data/ASN1/Stream.hs +6/−0
- Tests.hs +27/−2
- asn1-data.cabal +1/−1
Data/ASN1/BER.hs view
@@ -13,6 +13,7 @@ , ASN1ConstructionType(..) -- * enumeratee to transform between ASN1 and raw+ , enumReadRawRepr , enumReadRaw , enumWriteRaw @@ -23,12 +24,17 @@ -- * iterate over common representation to an ASN1 stream , iterateFile , iterateByteString+ , iterateByteStringRepr , iterateEvents+ , iterateEventsRepr -- * BER serialize functions+ , decodeASN1EventsRepr , decodeASN1Events , encodeASN1Events+ , decodeASN1Stream+ , decodeASN1StreamRepr , encodeASN1Stream -- * BER serialize functions, deprecated@@ -60,30 +66,47 @@ decodeConstruction (ASN1Header Universal 0x11 _ _) = Set decodeConstruction (ASN1Header c t _ _) = Container c t -{- | enumReadRaw is an enumeratee from raw events to asn1 -}-enumReadRaw :: Monad m => Enumeratee Raw.ASN1Event ASN1 m a-enumReadRaw = E.checkDone $ \k -> k (E.Chunks []) >>== loop []+{- | enumerate from 'Raw.ASN1Event' to an 'ASN1Repr' (ASN1 augmented by a list of raw asn1 events)+ -}+enumReadRawRepr :: Monad m => Enumeratee Raw.ASN1Event ASN1Repr m a+enumReadRawRepr = E.checkDone $ \k -> k (E.Chunks []) >>== loop [] where loop l = E.checkDone $ go l go l k = E.head >>= \x -> case x of- Nothing ->- if l == [] then k (E.Chunks []) >>== return else E.throwError (Raw.ASN1ParsingPartial)- Just Raw.ConstructionEnd ->- k (E.Chunks [head l]) >>== loop (tail l)- Just (Raw.Header hdr@(ASN1Header _ _ True _)) -> E.head >>= \z -> case z of- Nothing -> E.throwError (Raw.ASN1ParsingFail "expecting construction, got EOF")- Just Raw.ConstructionBegin ->- let ctype = decodeConstruction hdr in- k (E.Chunks [Start ctype]) >>== loop (End ctype : l)- Just _ -> E.throwError (Raw.ASN1ParsingFail "expecting construction")- Just (Raw.Header hdr@(ASN1Header _ _ False _)) -> E.head >>= \z -> case z of- Nothing -> E.throwError (Raw.ASN1ParsingFail "expecting primitive, got EOF")- Just (Raw.Primitive p) ->- let (Right pr) = decodePrimitive hdr p in- k (E.Chunks [pr]) >>== loop l- Just _ -> E.throwError (Raw.ASN1ParsingFail "expecting primitive")- Just _ -> E.throwError (Raw.ASN1ParsingFail "boundary not a header")+ Nothing -> if l == [] then k (E.Chunks []) >>== return else E.throwError (Raw.ASN1ParsingPartial)+ Just el -> p l k el + {- on construction end, we pop the list context -}+ p l k Raw.ConstructionEnd = k (E.Chunks [head l]) >>== loop (tail l)++ {- on header with construction, we pop the next element in the enumerator and+ - expect a ConstructionBegin. the list context is prepended by the new construction -}+ p l k el@(Raw.Header hdr@(ASN1Header _ _ True _)) = E.head >>= \z -> case z of+ Just el2@Raw.ConstructionBegin ->+ let ctype = decodeConstruction hdr in+ k (E.Chunks [(Start ctype, [el,el2])]) >>== loop ((End ctype,[Raw.ConstructionEnd]) : l)+ Just _ -> E.throwError (Raw.ASN1ParsingFail "expecting construction")+ Nothing -> E.throwError (Raw.ASN1ParsingFail "expecting construction, got EOF")++ {- on header with primtive, we pop the next element in the enumerator and+ - expect a Primitive -}+ p l k el@(Raw.Header hdr@(ASN1Header _ _ False _)) = E.head >>= \z -> case z of+ Just el2@(Raw.Primitive prim) ->+ let (Right pr) = decodePrimitive hdr prim in+ k (E.Chunks [(pr, [el,el2])]) >>== loop l+ Just _ -> E.throwError (Raw.ASN1ParsingFail "expecting primitive")+ Nothing -> E.throwError (Raw.ASN1ParsingFail "expecting primitive, got EOF")++ p _ _ _ = E.throwError (Raw.ASN1ParsingFail "boundary not a header")++{- | enumeratee from 'Raw.ASN1Event to 'ASN1'+ -+ - it's the enumerator equivalent:+ - @enumReadRaw = map fst . enumReadRawRepr@+ -}+enumReadRaw :: Monad m => Enumeratee Raw.ASN1Event ASN1 m a+enumReadRaw = \f -> E.joinI (enumReadRawRepr $$ (E.map fst f))+ {- | enumWriteRaw is an enumeratee from asn1 to raw events -} enumWriteRaw :: Monad m => Enumeratee ASN1 Raw.ASN1Event m a enumWriteRaw = \f -> E.joinI (enumWriteTree $$ (enumWriteTreeRaw f))@@ -139,6 +162,11 @@ enumReadBytes :: Monad m => Enumeratee ByteString ASN1 m a enumReadBytes = \f -> E.joinI (Raw.enumReadBytes $$ (enumReadRaw f)) +{-| enumReadBytes is an enumeratee converting from bytestring to ASN1+ it transforms chunks of bytestring into chunks of ASN1 objects -}+enumReadBytesRepr :: Monad m => Enumeratee ByteString ASN1Repr m a+enumReadBytesRepr = \f -> E.joinI (Raw.enumReadBytes $$ (enumReadRawRepr f))+ {-| enumWriteBytes is an enumeratee converting from ASN1 to bytestring. it transforms chunks of ASN1 objects into chunks of bytestring -} enumWriteBytes :: Monad m => Enumeratee ASN1 ByteString m a@@ -152,10 +180,18 @@ iterateByteString :: Monad m => L.ByteString -> Iteratee ASN1 m a -> m (Either SomeException a) iterateByteString bs p = E.run (E.enumList 1 (L.toChunks bs) $$ E.joinI $ enumReadBytes $$ p) +{-| iterate over a bytestring using a list enumerator over each chunks -}+iterateByteStringRepr :: Monad m => L.ByteString -> Iteratee ASN1Repr m a -> m (Either SomeException a)+iterateByteStringRepr bs p = E.run (E.enumList 1 (L.toChunks bs) $$ E.joinI $ enumReadBytesRepr $$ p)+ {-| iterate over asn1 events using a list enumerator over each chunks -} iterateEvents :: Monad m => [Raw.ASN1Event] -> Iteratee ASN1 m a -> m (Either SomeException a) iterateEvents evs p = E.run (E.enumList 8 evs $$ E.joinI $ enumReadRaw $$ p) +{-| iterate over asn1 events using a list enumerator over each chunks -}+iterateEventsRepr :: Monad m => [Raw.ASN1Event] -> Iteratee ASN1Repr m a -> m (Either SomeException a)+iterateEventsRepr evs p = E.run (E.enumList 8 evs $$ E.joinI $ enumReadRawRepr $$ p)+ {- helper to transform a Someexception from the enumerator to an ASN1Err if possible -} wrapASN1Err :: Either SomeException a -> Either ASN1Err a wrapASN1Err (Left err) = Left (maybe (ASN1ParsingFail "unknown") id $ fromException err)@@ -165,9 +201,17 @@ decodeASN1Events :: [Raw.ASN1Event] -> Either ASN1Err [ASN1] decodeASN1Events evs = wrapASN1Err $ runIdentity (iterateEvents evs E.consume) +{-| decode a list of raw ASN1Events into a stream of ASN1Repr types -}+decodeASN1EventsRepr :: [Raw.ASN1Event] -> Either ASN1Err [ASN1Repr]+decodeASN1EventsRepr evs = wrapASN1Err $ runIdentity (iterateEventsRepr evs E.consume)+ {-| decode a lazy bytestring as an ASN1 stream -} decodeASN1Stream :: L.ByteString -> Either ASN1Err [ASN1] decodeASN1Stream l = wrapASN1Err $ runIdentity (iterateByteString l E.consume)++{-| decode a lazy bytestring as an ASN1repr stream -}+decodeASN1StreamRepr :: L.ByteString -> Either ASN1Err [ASN1Repr]+decodeASN1StreamRepr l = wrapASN1Err $ runIdentity (iterateByteStringRepr l E.consume) {-| encode an ASN1 Stream as raw ASN1 Events -} encodeASN1Events :: [ASN1] -> Either ASN1Err [Raw.ASN1Event]
Data/ASN1/DER.hs view
@@ -13,22 +13,29 @@ , ASN1ConstructionType(..) -- * enumeratee to transform between ASN1 and raw+ , enumReadRawRepr , enumReadRaw , enumWriteRaw -- * enumeratee to transform between ASN1 and bytes , enumReadBytes+ , enumReadBytesRepr , enumWriteBytes -- * iterate over common representation to an ASN1 stream , iterateFile , iterateByteString+ , iterateByteStringRepr , iterateEvents+ , iterateEventsRepr -- * DER serialize functions+ , decodeASN1EventsRepr , decodeASN1Events , encodeASN1Events+ , decodeASN1Stream+ , decodeASN1StreamRepr , encodeASN1Stream -- * DER serialize functions, deprecated@@ -42,6 +49,7 @@ import qualified Data.ASN1.Raw as Raw import Data.ASN1.Prim+import Data.ASN1.Stream (ASN1Repr) import Data.ASN1.Types (ofStream, toStream, ASN1t) import qualified Data.ASN1.BER as BER@@ -83,6 +91,10 @@ enumReadRaw :: Monad m => Enumeratee Raw.ASN1Event ASN1 m a enumReadRaw = \f -> E.joinI (checkRawDER $$ BER.enumReadRaw f) +{- | enumReadRawRepr is an enumeratee from raw events to asn1repr -}+enumReadRawRepr :: Monad m => Enumeratee Raw.ASN1Event ASN1Repr m a+enumReadRawRepr = \f -> E.joinI (checkRawDER $$ BER.enumReadRawRepr f)+ {- | enumWriteRaw is an enumeratee from asn1 to raw events -} enumWriteRaw :: Monad m => Enumeratee ASN1 Raw.ASN1Event m a enumWriteRaw = BER.enumWriteRaw@@ -90,8 +102,13 @@ {-| enumReadBytes is an enumeratee converting from bytestring to ASN1 it transforms chunks of bytestring into chunks of ASN1 objects -} enumReadBytes :: Monad m => Enumeratee ByteString ASN1 m a-enumReadBytes = \f -> E.joinI (Raw.enumReadBytes $$ (BER.enumReadRaw f))+enumReadBytes = \f -> E.joinI (Raw.enumReadBytes $$ (enumReadRaw f)) +{-| enumReadBytes is an enumeratee converting from bytestring to ASN1+ it transforms chunks of bytestring into chunks of ASN1 objects -}+enumReadBytesRepr :: Monad m => Enumeratee ByteString ASN1Repr m a+enumReadBytesRepr = \f -> E.joinI (Raw.enumReadBytes $$ (enumReadRawRepr f))+ {-| enumWriteBytes is an enumeratee converting from ASN1 to bytestring. it transforms chunks of ASN1 objects into chunks of bytestring -} enumWriteBytes :: Monad m => Enumeratee ASN1 ByteString m a@@ -105,10 +122,18 @@ iterateByteString :: Monad m => L.ByteString -> Iteratee ASN1 m a -> m (Either SomeException a) iterateByteString bs p = E.run (E.enumList 1 (L.toChunks bs) $$ E.joinI $ enumReadBytes $$ p) +{-| iterate over a bytestring using a list enumerator over each chunks -}+iterateByteStringRepr :: Monad m => L.ByteString -> Iteratee ASN1Repr m a -> m (Either SomeException a)+iterateByteStringRepr bs p = E.run (E.enumList 1 (L.toChunks bs) $$ E.joinI $ enumReadBytesRepr $$ p)+ {-| iterate over asn1 events using a list enumerator over each chunks -} iterateEvents :: Monad m => [Raw.ASN1Event] -> Iteratee ASN1 m a -> m (Either SomeException a) iterateEvents evs p = E.run (E.enumList 8 evs $$ E.joinI $ enumReadRaw $$ p) +{-| iterate over asn1 events using a list enumerator over each chunks -}+iterateEventsRepr :: Monad m => [Raw.ASN1Event] -> Iteratee ASN1Repr m a -> m (Either SomeException a)+iterateEventsRepr evs p = E.run (E.enumList 8 evs $$ E.joinI $ enumReadRawRepr $$ p)+ {- helper to transform a Someexception from the enumerator to an ASN1Err if possible -} wrapASN1Err :: Either SomeException a -> Either ASN1Err a wrapASN1Err (Left err) = Left (maybe (ASN1ParsingFail "unknown") id $ fromException err)@@ -118,9 +143,17 @@ decodeASN1Events :: [Raw.ASN1Event] -> Either ASN1Err [ASN1] decodeASN1Events evs = wrapASN1Err $ runIdentity (iterateEvents evs E.consume) +{-| decode a list of raw ASN1Events into a stream of ASN1Repr types -}+decodeASN1EventsRepr :: [Raw.ASN1Event] -> Either ASN1Err [ASN1Repr]+decodeASN1EventsRepr evs = wrapASN1Err $ runIdentity (iterateEventsRepr evs E.consume)+ {-| decode a lazy bytestring as an ASN1 stream -} decodeASN1Stream :: L.ByteString -> Either ASN1Err [ASN1] decodeASN1Stream l = wrapASN1Err $ runIdentity (iterateByteString l E.consume)++{-| decode a lazy bytestring as an ASN1repr stream -}+decodeASN1StreamRepr :: L.ByteString -> Either ASN1Err [ASN1Repr]+decodeASN1StreamRepr l = wrapASN1Err $ runIdentity (iterateByteStringRepr l E.consume) {-| encode an ASN1 Stream as raw ASN1 Events -} encodeASN1Events :: [ASN1] -> Either ASN1Err [Raw.ASN1Event]
Data/ASN1/Stream.hs view
@@ -1,5 +1,6 @@ module Data.ASN1.Stream ( ASN1(..)+ , ASN1Repr , ASN1ConstructionType(..) , getConstructedEnd ) where@@ -42,6 +43,11 @@ | Start ASN1ConstructionType | End ASN1ConstructionType deriving (Show, Eq)++{- associate a list of asn1 event with an ASN1 type.+ - it's sometimes required to know the exact byte sequence leading to an ASN1 type:+ - eg: cryptographic signature -}+type ASN1Repr = (ASN1, [ASN1Event]) getConstructedEnd :: Int -> [ASN1] -> ([ASN1],[ASN1]) getConstructedEnd _ xs@[] = (xs, xs)
Tests.hs view
@@ -1,5 +1,3 @@---{-# LANGUAGE FlexibleInstances, OverlappingInstances #-}- import Test.QuickCheck import Text.Printf @@ -145,6 +143,24 @@ , liftM UniversalString arbitrary ] +newtype ASN1s = ASN1s [ASN1]++instance Show ASN1s where+ show (ASN1s x) = show x++instance Arbitrary ASN1s where+ arbitrary = do+ x <- choose (0,5) :: Gen Int+ z <- case x of+ 4 -> makeList Sequence+ 3 -> makeList Set+ _ -> resize 2 $ listOf1 arbitrary+ return $ ASN1s z+ where+ makeList str = do+ (ASN1s l) <- arbitrary+ return ([Start str] ++ l ++ [End str])+ instance Arbitrary T.ASN1t where arbitrary = oneof [ liftM T.Boolean arbitrary@@ -192,6 +208,14 @@ where enumWriteReadRaw = \f -> E.joinI (BER.enumWriteRaw $$ (BER.enumReadRaw f)) +prop_asn1_event_repr_id :: ASN1s -> Bool+prop_asn1_event_repr_id (ASN1s l) =+ case BER.encodeASN1Events l of+ Left _ -> False+ Right events -> case BER.decodeASN1EventsRepr events of+ Left _ -> False+ Right l2repr -> map fst l2repr == l && concat (map snd l2repr) == events+ prop_asn1_ber_marshalling_id :: T.ASN1t -> Bool prop_asn1_ber_marshalling_id v = (BER.decodeASN1 . BER.encodeASN1) v == Right v @@ -211,5 +235,6 @@ run_test "marshalling header = id" prop_header_marshalling_id run_test "marshalling event = id" prop_event_marshalling_id run_test "marshalling asn1 stream = id" prop_asn1_event_marshalling_id+ run_test "marshalling asn1 repr = id" prop_asn1_event_repr_id run_test "marshalling asn1 BER type = id" prop_asn1_ber_marshalling_id run_test "marshalling asn1 DER type = id" prop_asn1_der_marshalling_id
asn1-data.cabal view
@@ -1,5 +1,5 @@ Name: asn1-data-Version: 0.4.2+Version: 0.4.3 Description: ASN1 data reader and writer in raw form with supports for high level forms of ASN1 (BER, CER and DER). .