packages feed

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 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).     .