packages feed

asn1-data 0.3.0 → 0.4.0

raw patch · 11 files changed

+937/−528 lines, 11 filesdep +attoparsecdep +attoparsec-enumeratordep +enumeratordep −binarydep ~basePVP ok

version bump matches the API change (PVP)

Dependencies added: attoparsec, attoparsec-enumerator, enumerator

Dependencies removed: binary

Dependency ranges changed: base

API changes (from Hackage documentation)

- Data.ASN1.BER: EOC :: ASN1
- Data.ASN1.BER: data TagClass
- Data.ASN1.BER: decodeASN1Get :: Get (Either ASN1Err ASN1)
- Data.ASN1.BER: decodeASN1State :: ByteString -> Either ASN1Err (ASN1, ByteString, Int64)
- Data.ASN1.BER: encodeASN1Put :: ASN1 -> Put
- Data.ASN1.BER: encodeASN1sPut :: [ASN1] -> Put
- Data.ASN1.BER: ofRaw :: Value -> Either ASN1Err ASN1
- Data.ASN1.BER: toRaw :: ASN1 -> Value
- Data.ASN1.CER: EOC :: ASN1
- Data.ASN1.CER: Sequence :: [ASN1] -> ASN1
- Data.ASN1.CER: Set :: [ASN1] -> ASN1
- Data.ASN1.CER: data TagClass
- Data.ASN1.CER: decodeASN1Get :: Get (Either ASN1Err ASN1)
- Data.ASN1.CER: encodeASN1Put :: ASN1 -> Put
- Data.ASN1.DER: EOC :: ASN1
- Data.ASN1.DER: data TagClass
- Data.ASN1.DER: decodeASN1Get :: Get (Either ASN1Err ASN1)
- Data.ASN1.DER: decodeASN1State :: ByteString -> Either ASN1Err (ASN1, ByteString, Int64)
- Data.ASN1.DER: encodeASN1Put :: ASN1 -> Put
- Data.ASN1.DER: encodeASN1sPut :: [ASN1] -> Put
- Data.ASN1.Raw: Constructed :: [Value] -> ValStruct
- Data.ASN1.Raw: Value :: TagClass -> TagNumber -> ValStruct -> Value
- Data.ASN1.Raw: data GetErr a
- Data.ASN1.Raw: data TagClass
- Data.ASN1.Raw: data ValLength
- Data.ASN1.Raw: data ValStruct
- Data.ASN1.Raw: data Value
- Data.ASN1.Raw: getValue :: GetErr Value
- Data.ASN1.Raw: getValueCheck :: CheckFn -> GetErr Value
- Data.ASN1.Raw: instance Eq TagClass
- Data.ASN1.Raw: instance Eq ValLength
- Data.ASN1.Raw: instance Eq ValStruct
- Data.ASN1.Raw: instance Eq Value
- Data.ASN1.Raw: instance Error ASN1Err
- Data.ASN1.Raw: instance Functor GetErr
- Data.ASN1.Raw: instance Monad GetErr
- Data.ASN1.Raw: instance MonadError ASN1Err GetErr
- Data.ASN1.Raw: instance Show TagClass
- Data.ASN1.Raw: instance Show ValLength
- Data.ASN1.Raw: instance Show ValStruct
- Data.ASN1.Raw: instance Show Value
- Data.ASN1.Raw: putValue :: Value -> Put
- Data.ASN1.Raw: putValuePolicy :: (Value -> Int -> ValLength) -> Value -> Put
- Data.ASN1.Raw: runGetErr :: GetErr a -> ByteString -> Either ASN1Err a
- Data.ASN1.Raw: runGetErrInGet :: GetErr a -> Get (Either ASN1Err a)
- Data.ASN1.Raw: runGetErrState :: GetErr a -> ByteString -> Int64 -> Either ASN1Err (a, ByteString, Int64)
- Data.ASN1.Raw: type CheckFn = (TagClass, Bool, TagNumber) -> ValLength -> Maybe ASN1Err
- Data.ASN1.Raw: type TagNumber = Int
+ Data.ASN1.BER: Container :: ASN1Class -> ASN1Tag -> ASN1ConstructionType
+ Data.ASN1.BER: End :: ASN1ConstructionType -> ASN1
+ Data.ASN1.BER: Start :: ASN1ConstructionType -> ASN1
+ Data.ASN1.BER: data ASN1Class
+ Data.ASN1.BER: data ASN1ConstructionType
+ Data.ASN1.BER: decodeASN1Stream :: ByteString -> Either ASN1Err [ASN1]
+ Data.ASN1.BER: encodeASN1Stream :: Monad m => [ASN1] -> Iteratee ByteString m a -> m (Either SomeException a)
+ Data.ASN1.BER: enumReadBytes :: Monad m => Enumeratee ByteString ASN1 m a
+ Data.ASN1.BER: enumReadRaw :: Monad m => Enumeratee ASN1Event ASN1 m a
+ Data.ASN1.BER: enumWriteBytes :: Monad m => Enumeratee ASN1 ByteString m a
+ Data.ASN1.BER: enumWriteRaw :: Monad m => Enumeratee ASN1 ASN1Event m a
+ Data.ASN1.BER: iterateByteString :: Monad m => ByteString -> Iteratee ASN1 m a -> m (Either SomeException a)
+ Data.ASN1.BER: iterateFile :: FilePath -> Iteratee ASN1 IO a -> IO (Either SomeException a)
+ Data.ASN1.CER: End :: ASN1ConstructionType -> ASN1
+ Data.ASN1.CER: Start :: ASN1ConstructionType -> ASN1
+ Data.ASN1.CER: data ASN1Class
+ Data.ASN1.CER: decodeASN1s :: ByteString -> Either ASN1Err [ASN1t]
+ Data.ASN1.CER: encodeASN1s :: [ASN1t] -> ByteString
+ Data.ASN1.DER: Container :: ASN1Class -> ASN1Tag -> ASN1ConstructionType
+ Data.ASN1.DER: End :: ASN1ConstructionType -> ASN1
+ Data.ASN1.DER: Start :: ASN1ConstructionType -> ASN1
+ Data.ASN1.DER: data ASN1Class
+ Data.ASN1.DER: data ASN1ConstructionType
+ Data.ASN1.DER: decodeASN1Stream :: ByteString -> Either ASN1Err [ASN1]
+ Data.ASN1.DER: encodeASN1Stream :: Monad m => [ASN1] -> Iteratee ByteString m a -> m (Either SomeException a)
+ Data.ASN1.DER: enumReadBytes :: Monad m => Enumeratee ByteString ASN1 m a
+ Data.ASN1.DER: enumReadRaw :: Monad m => Enumeratee ASN1Event ASN1 m a
+ Data.ASN1.DER: enumWriteBytes :: Monad m => Enumeratee ASN1 ByteString m a
+ Data.ASN1.DER: enumWriteRaw :: Monad m => Enumeratee ASN1 ASN1Event m a
+ Data.ASN1.DER: iterateByteString :: Monad m => ByteString -> Iteratee ASN1 m a -> m (Either SomeException a)
+ Data.ASN1.DER: iterateFile :: FilePath -> Iteratee ASN1 IO a -> IO (Either SomeException a)
+ Data.ASN1.Raw: ASN1Header :: !ASN1Class -> !ASN1Tag -> !Bool -> !ASN1Length -> ASN1Header
+ Data.ASN1.Raw: ASN1ParsingFail :: String -> ASN1Err
+ Data.ASN1.Raw: ASN1ParsingPartial :: ASN1Err
+ Data.ASN1.Raw: ASN1WritingUnexpectedConstructionEnd :: ASN1Err
+ Data.ASN1.Raw: ASN1WritingUnexpectedInputEOF :: ASN1Err
+ Data.ASN1.Raw: ConstructionBegin :: ASN1Event
+ Data.ASN1.Raw: ConstructionEnd :: ASN1Event
+ Data.ASN1.Raw: Header :: ASN1Header -> ASN1Event
+ Data.ASN1.Raw: data ASN1Class
+ Data.ASN1.Raw: data ASN1Event
+ Data.ASN1.Raw: data ASN1Header
+ Data.ASN1.Raw: data ASN1Length
+ Data.ASN1.Raw: enumReadBytes :: Monad m => Enumeratee ByteString ASN1Event m a
+ Data.ASN1.Raw: enumWriteBytes :: Monad m => Enumeratee ASN1Event ByteString m a
+ Data.ASN1.Raw: getHeader :: ByteString -> Either ASN1Err ASN1Header
+ Data.ASN1.Raw: instance Enum ASN1Class
+ Data.ASN1.Raw: instance Eq ASN1Class
+ Data.ASN1.Raw: instance Eq ASN1Event
+ Data.ASN1.Raw: instance Eq ASN1Header
+ Data.ASN1.Raw: instance Eq ASN1Length
+ Data.ASN1.Raw: instance Exception ASN1Err
+ Data.ASN1.Raw: instance Ord ASN1Class
+ Data.ASN1.Raw: instance Show ASN1Class
+ Data.ASN1.Raw: instance Show ASN1Event
+ Data.ASN1.Raw: instance Show ASN1Header
+ Data.ASN1.Raw: instance Show ASN1Length
+ Data.ASN1.Raw: instance Typeable ASN1Err
+ Data.ASN1.Raw: iterateByteString :: Monad m => ByteString -> Iteratee ASN1Event m a -> m (Either SomeException a)
+ Data.ASN1.Raw: iterateFile :: FilePath -> Iteratee ASN1Event IO a -> IO (Either SomeException a)
+ Data.ASN1.Raw: putHeader :: ASN1Header -> ByteString
+ Data.ASN1.Raw: type ASN1Tag = Int
+ Data.ASN1.Stream: BMPString :: Text -> ASN1
+ Data.ASN1.Stream: BitString :: Int -> ByteString -> ASN1
+ Data.ASN1.Stream: Boolean :: Bool -> ASN1
+ Data.ASN1.Stream: CharacterString :: ByteString -> ASN1
+ Data.ASN1.Stream: Container :: ASN1Class -> ASN1Tag -> ASN1ConstructionType
+ Data.ASN1.Stream: End :: ASN1ConstructionType -> ASN1
+ Data.ASN1.Stream: Enumerated :: ASN1
+ Data.ASN1.Stream: GeneralString :: ByteString -> ASN1
+ Data.ASN1.Stream: GeneralizedTime :: (Int, Int, Int, Int, Int, Int, Bool) -> ASN1
+ Data.ASN1.Stream: GraphicString :: ByteString -> ASN1
+ Data.ASN1.Stream: IA5String :: Text -> ASN1
+ Data.ASN1.Stream: IntVal :: Integer -> ASN1
+ Data.ASN1.Stream: Null :: ASN1
+ Data.ASN1.Stream: NumericString :: ByteString -> ASN1
+ Data.ASN1.Stream: OID :: [Integer] -> ASN1
+ Data.ASN1.Stream: OctetString :: ByteString -> ASN1
+ Data.ASN1.Stream: Other :: ASN1Class -> ASN1Tag -> ByteString -> ASN1
+ Data.ASN1.Stream: PrintableString :: Text -> ASN1
+ Data.ASN1.Stream: Real :: Double -> ASN1
+ Data.ASN1.Stream: Sequence :: ASN1ConstructionType
+ Data.ASN1.Stream: Set :: ASN1ConstructionType
+ Data.ASN1.Stream: Start :: ASN1ConstructionType -> ASN1
+ Data.ASN1.Stream: T61String :: ByteString -> ASN1
+ Data.ASN1.Stream: UTCTime :: (Int, Int, Int, Int, Int, Int, Bool) -> ASN1
+ Data.ASN1.Stream: UTF8String :: Text -> ASN1
+ Data.ASN1.Stream: UniversalString :: Text -> ASN1
+ Data.ASN1.Stream: VideoTexString :: ByteString -> ASN1
+ Data.ASN1.Stream: VisibleString :: ByteString -> ASN1
+ Data.ASN1.Stream: data ASN1
+ Data.ASN1.Stream: data ASN1ConstructionType
+ Data.ASN1.Stream: getConstructedEnd :: Int -> [ASN1] -> ([ASN1], [ASN1])
+ Data.ASN1.Stream: instance Eq ASN1
+ Data.ASN1.Stream: instance Eq ASN1ConstructionType
+ Data.ASN1.Stream: instance Show ASN1
+ Data.ASN1.Stream: instance Show ASN1ConstructionType
+ Data.ASN1.Types: BMPString :: Text -> ASN1t
+ Data.ASN1.Types: BitString :: Int -> ByteString -> ASN1t
+ Data.ASN1.Types: Boolean :: Bool -> ASN1t
+ Data.ASN1.Types: CharacterString :: ByteString -> ASN1t
+ Data.ASN1.Types: Container :: ASN1Class -> ASN1Tag -> [ASN1t] -> ASN1t
+ Data.ASN1.Types: Enumerated :: ASN1t
+ Data.ASN1.Types: GeneralString :: ByteString -> ASN1t
+ Data.ASN1.Types: GeneralizedTime :: (Int, Int, Int, Int, Int, Int, Bool) -> ASN1t
+ Data.ASN1.Types: GraphicString :: ByteString -> ASN1t
+ Data.ASN1.Types: IA5String :: Text -> ASN1t
+ Data.ASN1.Types: IntVal :: Integer -> ASN1t
+ Data.ASN1.Types: Null :: ASN1t
+ Data.ASN1.Types: NumericString :: ByteString -> ASN1t
+ Data.ASN1.Types: OID :: [Integer] -> ASN1t
+ Data.ASN1.Types: OctetString :: ByteString -> ASN1t
+ Data.ASN1.Types: Other :: ASN1Class -> ASN1Tag -> ByteString -> ASN1t
+ Data.ASN1.Types: PrintableString :: Text -> ASN1t
+ Data.ASN1.Types: Real :: Double -> ASN1t
+ Data.ASN1.Types: Sequence :: [ASN1t] -> ASN1t
+ Data.ASN1.Types: Set :: [ASN1t] -> ASN1t
+ Data.ASN1.Types: T61String :: ByteString -> ASN1t
+ Data.ASN1.Types: UTCTime :: (Int, Int, Int, Int, Int, Int, Bool) -> ASN1t
+ Data.ASN1.Types: UTF8String :: Text -> ASN1t
+ Data.ASN1.Types: UniversalString :: Text -> ASN1t
+ Data.ASN1.Types: VideoTexString :: ByteString -> ASN1t
+ Data.ASN1.Types: VisibleString :: ByteString -> ASN1t
+ Data.ASN1.Types: data ASN1t
+ Data.ASN1.Types: instance Eq ASN1t
+ Data.ASN1.Types: instance Show ASN1t
+ Data.ASN1.Types: ofStream :: [ASN1] -> [ASN1t]
+ Data.ASN1.Types: toStream :: [ASN1t] -> [ASN1]
- Data.ASN1.BER: Application :: TagClass
+ Data.ASN1.BER: Application :: ASN1Class
- Data.ASN1.BER: Context :: TagClass
+ Data.ASN1.BER: Context :: ASN1Class
- Data.ASN1.BER: Other :: TagClass -> TagNumber -> (Either ByteString [ASN1]) -> ASN1
+ Data.ASN1.BER: Other :: ASN1Class -> ASN1Tag -> ByteString -> ASN1
- Data.ASN1.BER: Private :: TagClass
+ Data.ASN1.BER: Private :: ASN1Class
- Data.ASN1.BER: Sequence :: [ASN1] -> ASN1
+ Data.ASN1.BER: Sequence :: ASN1ConstructionType
- Data.ASN1.BER: Set :: [ASN1] -> ASN1
+ Data.ASN1.BER: Set :: ASN1ConstructionType
- Data.ASN1.BER: Universal :: TagClass
+ Data.ASN1.BER: Universal :: ASN1Class
- Data.ASN1.BER: decodeASN1 :: ByteString -> Either ASN1Err ASN1
+ Data.ASN1.BER: decodeASN1 :: ByteString -> Either ASN1Err ASN1t
- Data.ASN1.BER: decodeASN1s :: ByteString -> Either ASN1Err [ASN1]
+ Data.ASN1.BER: decodeASN1s :: ByteString -> Either ASN1Err [ASN1t]
- Data.ASN1.BER: encodeASN1 :: ASN1 -> ByteString
+ Data.ASN1.BER: encodeASN1 :: ASN1t -> ByteString
- Data.ASN1.BER: encodeASN1s :: [ASN1] -> ByteString
+ Data.ASN1.BER: encodeASN1s :: [ASN1t] -> ByteString
- Data.ASN1.CER: Application :: TagClass
+ Data.ASN1.CER: Application :: ASN1Class
- Data.ASN1.CER: Context :: TagClass
+ Data.ASN1.CER: Context :: ASN1Class
- Data.ASN1.CER: Other :: TagClass -> TagNumber -> (Either ByteString [ASN1]) -> ASN1
+ Data.ASN1.CER: Other :: ASN1Class -> ASN1Tag -> ByteString -> ASN1
- Data.ASN1.CER: Private :: TagClass
+ Data.ASN1.CER: Private :: ASN1Class
- Data.ASN1.CER: Universal :: TagClass
+ Data.ASN1.CER: Universal :: ASN1Class
- Data.ASN1.CER: decodeASN1 :: ByteString -> Either ASN1Err ASN1
+ Data.ASN1.CER: decodeASN1 :: ByteString -> Either ASN1Err ASN1t
- Data.ASN1.CER: encodeASN1 :: ASN1 -> ByteString
+ Data.ASN1.CER: encodeASN1 :: ASN1t -> ByteString
- Data.ASN1.DER: Application :: TagClass
+ Data.ASN1.DER: Application :: ASN1Class
- Data.ASN1.DER: Context :: TagClass
+ Data.ASN1.DER: Context :: ASN1Class
- Data.ASN1.DER: Other :: TagClass -> TagNumber -> (Either ByteString [ASN1]) -> ASN1
+ Data.ASN1.DER: Other :: ASN1Class -> ASN1Tag -> ByteString -> ASN1
- Data.ASN1.DER: Private :: TagClass
+ Data.ASN1.DER: Private :: ASN1Class
- Data.ASN1.DER: Sequence :: [ASN1] -> ASN1
+ Data.ASN1.DER: Sequence :: ASN1ConstructionType
- Data.ASN1.DER: Set :: [ASN1] -> ASN1
+ Data.ASN1.DER: Set :: ASN1ConstructionType
- Data.ASN1.DER: Universal :: TagClass
+ Data.ASN1.DER: Universal :: ASN1Class
- Data.ASN1.DER: decodeASN1 :: ByteString -> Either ASN1Err ASN1
+ Data.ASN1.DER: decodeASN1 :: ByteString -> Either ASN1Err ASN1t
- Data.ASN1.DER: decodeASN1s :: ByteString -> Either ASN1Err [ASN1]
+ Data.ASN1.DER: decodeASN1s :: ByteString -> Either ASN1Err [ASN1t]
- Data.ASN1.DER: encodeASN1 :: ASN1 -> ByteString
+ Data.ASN1.DER: encodeASN1 :: ASN1t -> ByteString
- Data.ASN1.DER: encodeASN1s :: [ASN1] -> ByteString
+ Data.ASN1.DER: encodeASN1s :: [ASN1t] -> ByteString
- Data.ASN1.Raw: Application :: TagClass
+ Data.ASN1.Raw: Application :: ASN1Class
- Data.ASN1.Raw: Context :: TagClass
+ Data.ASN1.Raw: Context :: ASN1Class
- Data.ASN1.Raw: LenIndefinite :: ValLength
+ Data.ASN1.Raw: LenIndefinite :: ASN1Length
- Data.ASN1.Raw: LenLong :: Int -> Int -> ValLength
+ Data.ASN1.Raw: LenLong :: Int -> Int -> ASN1Length
- Data.ASN1.Raw: LenShort :: Int -> ValLength
+ Data.ASN1.Raw: LenShort :: Int -> ASN1Length
- Data.ASN1.Raw: Primitive :: ByteString -> ValStruct
+ Data.ASN1.Raw: Primitive :: !ByteString -> ASN1Event
- Data.ASN1.Raw: Private :: TagClass
+ Data.ASN1.Raw: Private :: ASN1Class
- Data.ASN1.Raw: Universal :: TagClass
+ Data.ASN1.Raw: Universal :: ASN1Class

Files

Data/ASN1/BER.hs view
@@ -8,126 +8,171 @@ -- A module containing ASN1 BER specification serialization/derialization tools -- module Data.ASN1.BER-	( TagClass(..)+	( ASN1Class(..) 	, ASN1(..)+	, ASN1ConstructionType(..) -	-- * BER interface when using directly Raw objects-	, ofRaw-	, toRaw+	-- * enumeratee to transform between ASN1 and raw+	, enumReadRaw+	, enumWriteRaw -	-- * BER serial functions-	, decodeASN1Get-	, decodeASN1State+	-- * enumeratee to transform between ASN1 and bytes+	, enumReadBytes+	, enumWriteBytes++	-- * iterate over common representation to an ASN1 stream+	, iterateFile+	, iterateByteString++	-- * BER serialize functions+	, decodeASN1Stream+	, encodeASN1Stream++	-- * BER serialize functions, deprecated 	, decodeASN1 	, decodeASN1s-	, encodeASN1Put-	, encodeASN1sPut 	, encodeASN1 	, encodeASN1s 	) where -import Data.Int-import Data.ASN1.Raw+import Data.ASN1.Raw (ASN1Header(..), ASN1Class(..), ASN1Err(..))+import qualified Data.ASN1.Raw as Raw++import Data.ASN1.Stream+import Data.ASN1.Types (ofStream, toStream, ASN1t) import Data.ASN1.Prim-import Data.Either-import Data.Binary.Get-import Data.Binary.Put-import Control.Monad (liftM)-import Control.Monad.Error (throwError)++import Control.Monad.Identity+import Control.Exception+ import qualified Data.ByteString.Lazy as L-import qualified Data.ByteString as B-import Data.Text.Lazy.Encoding (encodeUtf8, encodeUtf32BE)+import Data.ByteString (ByteString) -ofRaws :: [Value] -> Either ASN1Err [ASN1]-ofRaws x = if l == [] then Right r else Left $ ASN1Multiple l+import Data.Enumerator.IO+import Data.Enumerator (Iteratee(..), Enumeratee, ($$), (>>==))+import qualified Data.Enumerator as E++decodeConstruction :: ASN1Header -> ASN1ConstructionType+decodeConstruction (ASN1Header Universal 0x10 _ _) = Sequence+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 [] 	where-		(l, r) = partitionEithers $ map ofRaw x+		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") -ofRaw :: Value -> Either ASN1Err ASN1-ofRaw (Value Universal 0x0 (Primitive b))    = getEOC b-ofRaw (Value Universal 0x1 (Primitive b))    = getBoolean False b-ofRaw (Value Universal 0x2 (Primitive b))    = getInteger b-ofRaw (Value Universal 0x3 v)                = getBitString v-ofRaw (Value Universal 0x4 v)                = getOctetString v-ofRaw (Value Universal 0x5 (Primitive b))    = getNull b-ofRaw (Value Universal 0x6 (Primitive b))    = getOID b-ofRaw (Value Universal 0x7 (Primitive _))    = Left $ ASN1NotImplemented "Object Descriptor"-ofRaw (Value Universal 0x8 (Constructed _))  = Left $ ASN1NotImplemented "External"-ofRaw (Value Universal 0x9 (Primitive _))    = Left $ ASN1NotImplemented "real"-ofRaw (Value Universal 0xa (Primitive _))    = Left $ ASN1NotImplemented "enumerated"-ofRaw (Value Universal 0xb (Constructed _))  = Left $ ASN1NotImplemented "EMBEDDED PDV"-ofRaw (Value Universal 0xc v)                = getUTF8String v-ofRaw (Value Universal 0xd (Primitive _))    = Left $ ASN1NotImplemented "RELATIVE-OID"-ofRaw (Value Universal 0x10 (Constructed l)) = either Left (Right . Sequence) $ ofRaws l-ofRaw (Value Universal 0x11 (Constructed l)) = either Left (Right . Set) $ ofRaws l-ofRaw (Value Universal 0x12 v)               = getNumericString v-ofRaw (Value Universal 0x13 v)               = getPrintableString v-ofRaw (Value Universal 0x14 v)               = getT61String v-ofRaw (Value Universal 0x15 v)               = getVideoTexString v-ofRaw (Value Universal 0x16 v)               = getIA5String v-ofRaw (Value Universal 0x17 x)               = getUTCTime x-ofRaw (Value Universal 0x18 x)               = getGeneralizedTime x-ofRaw (Value Universal 0x19 x)               = getGraphicString x-ofRaw (Value Universal 0x1a x)               = getVisibleString x-ofRaw (Value Universal 0x1b x)               = getGeneralString x-ofRaw (Value Universal 0x1c x)               = getUniversalString x-ofRaw (Value Universal 0x1d x)               = getCharacterString x-ofRaw (Value Universal 0x1e x)               = getBMPString x-ofRaw (Value tc tn (Primitive b))            = Right $ Other tc tn (Left b)-ofRaw (Value tc tn (Constructed l))          = either Left (Right . Other tc tn . Right) $ ofRaws l+{- | 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)) -toRaw :: ASN1 -> Value-toRaw EOC                    = Value Universal 0x0 (Primitive B.empty)-toRaw (Boolean v)            = Value Universal 0x1 (Primitive $ B.singleton (if v then 0xff else 0))-toRaw (IntVal i)             = Value Universal 0x2 (putInteger i)-toRaw (BitString i bits)     = Value Universal 0x3 (putBitString i bits)-toRaw (OctetString b)        = Value Universal 0x4 (putString b)-toRaw Null                   = Value Universal 0x5 (Primitive B.empty)-toRaw (OID oid)              = Value Universal 0x6 (putOID oid)-toRaw (Real _)               = Value Universal 0x9 (Constructed []) -- not implemented-toRaw Enumerated             = Value Universal 0xa (Constructed []) -- not implemented-toRaw (UTF8String b)         = Value Universal 0xc (putString $ encodeUtf8 b)-toRaw (Sequence children)    = Value Universal 0x10 (Constructed $ map toRaw children)-toRaw (Set children)         = Value Universal 0x11 (Constructed $ map toRaw children)-toRaw (NumericString b)      = Value Universal 0x12 (putString b)-toRaw (PrintableString b)    = Value Universal 0x13 (putString $ encodeUtf8 b)-toRaw (T61String b)          = Value Universal 0x14 (putString b)-toRaw (VideoTexString b)     = Value Universal 0x15 (putString b)-toRaw (IA5String b)          = Value Universal 0x16 (putString $ encodeUtf8 b)-toRaw (UTCTime time)         = Value Universal 0x17 (putUTCTime time)-toRaw (GeneralizedTime time) = Value Universal 0x18 (putGeneralizedTime time)-toRaw (GraphicString b)      = Value Universal 0x19 (putString b)-toRaw (VisibleString b)      = Value Universal 0x1a (putString b)-toRaw (GeneralString b)      = Value Universal 0x1b (putString b)-toRaw (UniversalString b)    = Value Universal 0x1c (putString $ encodeUtf32BE b)-toRaw (CharacterString b)    = Value Universal 0x1d (putString b)-toRaw (BMPString b)          = Value Universal 0x1e (putString $ encodeUCS2BE b)-toRaw (Other tc tn c)        = Value tc tn (either Primitive (Constructed . map toRaw) c)+enumWriteTree :: Monad m => Enumeratee ASN1 (ASN1, [ASN1]) m a+enumWriteTree = do+	E.checkDone $ \k -> k (E.Chunks []) >>== loop+	where+		loop = E.checkDone $ go+		go k = E.head >>= \x -> case x of+			Nothing          -> k (E.Chunks []) >>== return+			Just n@(Start _) -> consumeTillEnd >>= \y -> k (E.Chunks [(n, y)] ) >>== loop+			Just p           -> k (E.Chunks [(p, [])] ) >>== loop -decodeASN1Get :: Get (Either ASN1Err ASN1)-decodeASN1Get = either Left ofRaw `fmap` runGetErrInGet getValue+		consumeTillEnd :: Monad m => Iteratee ASN1 m [ASN1]+		consumeTillEnd = E.liftI $ step (1 :: Int) id where+			step l acc chunk = case chunk of+				E.Chunks [] -> E.Continue $ E.returnI . step l acc+				E.Chunks xs -> do+					let (ys, zs) = spanEnd l xs+					let nbend = length $ filter isEnd ys+					let nbstart = length $ filter isStart ys+					let nl = l - nbend + nbstart+					if nl == 0+						then E.Yield (acc ys) (E.Chunks zs)+						else E.Continue $ E.returnI . (step nl $ acc . (ys ++))+				E.EOF       -> E.Yield (acc []) E.EOF -decodeASN1State :: L.ByteString -> Either ASN1Err (ASN1, L.ByteString, Int64)-decodeASN1State b =-	runGetErrState (getValue >>= either throwError return . ofRaw) b 0+			spanEnd :: Int -> [ASN1] -> ([ASN1], [ASN1])+			spanEnd _ []               = ([], [])+			spanEnd 0 (x@(End _):xs)   = ([x], xs)+			spanEnd 0 (x@(Start _):xs) = let (ys, zs) = spanEnd 1 xs in (x:ys, zs)+			spanEnd 0 (x:xs)           = let (ys, zs) = spanEnd 0 xs in (x:ys, zs)+			spanEnd l (x:xs)           = case x of+				Start _ -> let (ys, zs) = spanEnd (l+1) xs in (x:ys, zs)+				End _   -> let (ys, zs) = spanEnd (l-1) xs in (x:ys, zs)+				_       -> let (ys, zs) = spanEnd l xs in (x:ys, zs) -decodeASN1 :: L.ByteString -> Either ASN1Err ASN1-decodeASN1 = either Left ofRaw . runGetErr getValue+			isStart (Start _) = True+			isStart _         = False+			isEnd (End _)     = True+			isEnd _           = False -decodeASN1s :: L.ByteString -> Either ASN1Err [ASN1]-decodeASN1s = loop where-	loop z = case decodeASN1State z of-		Left err -> throwError err-		Right (v, rest, _) -> if L.length rest > 0 then liftM (v :) (loop rest) else return [v] -encodeASN1Put :: ASN1 -> Put-encodeASN1Put = putValue . toRaw+enumWriteTreeRaw :: Monad m => Enumeratee (ASN1, [ASN1]) Raw.ASN1Event m a+enumWriteTreeRaw = E.concatMap writeTree+	where writeTree (p,children) = snd $ case p of+		Start _ -> encodeConstructed p children+		_       -> encodePrimitive p -encodeASN1sPut :: [ASN1] -> Put-encodeASN1sPut = mapM_ encodeASN1Put+{-| 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 $$ (enumReadRaw f)) -encodeASN1 :: ASN1 -> L.ByteString-encodeASN1 = runPut . encodeASN1Put+{-| 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+enumWriteBytes = \f -> E.joinI (enumWriteRaw $$ (Raw.enumWriteBytes f)) -encodeASN1s :: [ASN1] -> L.ByteString-encodeASN1s = runPut . encodeASN1sPut+{-| iterate over a file using a file enumerator. -}+iterateFile :: FilePath -> Iteratee ASN1 IO a -> IO (Either SomeException a)+iterateFile path p = E.run (enumFile path $$ E.joinI $ enumReadBytes $$ p)++{-| iterate over a bytestring using a list enumerator over each chunks -}+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)++{-| decode a lazy bytestring as an ASN1 stream -}+decodeASN1Stream :: L.ByteString -> Either ASN1Err [ASN1]+decodeASN1Stream l = do+	case runIdentity (iterateByteString l E.consume) of+		Left err -> Left (maybe (ASN1ParsingFail "unknown") id $ fromException err)+		Right x  -> Right x++encodeASN1Stream :: Monad m => [ASN1] -> Iteratee ByteString m a -> m (Either SomeException a)+encodeASN1Stream l p = E.run (E.enumList 1 l $$ E.joinI $ enumWriteBytes $$ p)++{-# DEPRECATED decodeASN1s "use stream types with decodeASN1Stream" #-}+decodeASN1s :: L.ByteString -> Either ASN1Err [ASN1t]+decodeASN1s l = either (Left) (Right . ofStream) $ decodeASN1Stream l++{-# DEPRECATED decodeASN1 "use stream types with decodeASN1Stream" #-}+decodeASN1 :: L.ByteString -> Either ASN1Err ASN1t+decodeASN1 = either (Left) (Right . head) . decodeASN1s++{-# DEPRECATED encodeASN1s "use stream types with encodeASN1Stream" #-}+encodeASN1s :: [ASN1t] -> L.ByteString+encodeASN1s l = case runIdentity (encodeASN1Stream (toStream l) E.consume) of+	Left _  -> error "encoding failed"+	Right x -> L.fromChunks x++{-# DEPRECATED encodeASN1 "use stream types with encodeASN1Stream" #-}+encodeASN1 :: ASN1t -> L.ByteString+encodeASN1 = encodeASN1s . (:[])
Data/ASN1/CER.hs view
@@ -8,34 +8,22 @@ -- A module containing ASN1 CER specification serialization/derialization tools -- module Data.ASN1.CER-	( TagClass(..)+	( ASN1Class(..) 	, ASN1(..)  	-- * CER serial functions-	, decodeASN1Get+	, decodeASN1s+	, encodeASN1s 	, decodeASN1-	, encodeASN1Put 	, encodeASN1 	) where  import Data.ASN1.Raw import Data.ASN1.Prim-import Data.Binary.Get-import Data.Binary.Put+import Data.ASN1.Types (ASN1t) import qualified Data.ASN1.BER as BER-import qualified Data.ByteString as B import qualified Data.ByteString.Lazy as L-import Data.Text.Lazy.Encoding (encodeUtf8, encodeUtf32BE) -{- | check if the value is bounded by CER policies -}-check :: (TagClass, Bool, TagNumber) -> ValLength -> Maybe ASN1Err-check (_, _, _) _ = Nothing--{- | ofRaw same as BER.ofRAW but check some additional CER constraint. -}-ofRaw :: Value -> Either ASN1Err ASN1-ofRaw v = BER.ofRaw v-- {- - 9.2        String encoding forms string values shall be encoded with a primitive encoding if they would@@ -43,6 +31,7 @@ The string fragments contained in the constructed encoding shall be encoded with a primitive encoding. The encoding of each fragment, except possibly the last, shall have 1000 contents octets. -}+{- putStringCER :: Int -> L.ByteString -> ValStruct putStringCER tn l = 	if L.length l > 1000@@ -56,38 +45,20 @@ 					x1 : repack1000 x2 				else 					[ x ]--{- | toRaw create a CER encoded value ready -}-toRaw :: ASN1 -> Value-toRaw (BitString i bits)     = Value Universal 0x3 (putBitString i bits)-toRaw (OctetString b)        = Value Universal 0x4 (putStringCER 0x4 b)-toRaw (UTF8String b)         = Value Universal 0xc (putStringCER 0xc (encodeUtf8 b))-toRaw (NumericString b)      = Value Universal 0x12 (putStringCER 0x12 b)-toRaw (PrintableString b)    = Value Universal 0x13 (putStringCER 0x13 (encodeUtf8 b))-toRaw (T61String b)          = Value Universal 0x14 (putStringCER 0x14 b)-toRaw (VideoTexString b)     = Value Universal 0x15 (putStringCER 0x15 b)-toRaw (IA5String b)          = Value Universal 0x16 (putStringCER 0x16 (encodeUtf8 b))-toRaw (GraphicString b)      = Value Universal 0x19 (putStringCER 0x19 b)-toRaw (VisibleString b)      = Value Universal 0x1a (putStringCER 0x1a b)-toRaw (GeneralString b)      = Value Universal 0x1b (putStringCER 0x1b b)-toRaw (UniversalString b)    = Value Universal 0x1c (putStringCER 0x1c (encodeUtf32BE b))-toRaw (BMPString b)          = Value Universal 0x1e (putStringCER 0x1e (encodeUCS2BE b))-toRaw v                      = BER.toRaw v--decodeASN1Get :: Get (Either ASN1Err ASN1)-decodeASN1Get = runGetErrInGet (getValueCheck check) >>= return . either Left ofRaw+-} -decodeASN1 :: L.ByteString -> Either ASN1Err ASN1-decodeASN1 b = either Left ofRaw $ runGetErr (getValueCheck check) b+{-# DEPRECATED decodeASN1s "use stream types with decodeASN1Stream" #-}+decodeASN1s :: L.ByteString -> Either ASN1Err [ASN1t]+decodeASN1s = BER.decodeASN1s -encodePolicyCER :: Value -> Int -> ValLength-encodePolicyCER (Value _ _ (Primitive _)) len-	| len < 0x80   = LenShort len-	| otherwise    = LenLong 0 len-encodePolicyCER (Value _ _ (Constructed _)) _ = LenIndefinite+{-# DEPRECATED decodeASN1 "use stream types with decodeASN1Stream" #-}+decodeASN1 :: L.ByteString -> Either ASN1Err ASN1t+decodeASN1 = BER.decodeASN1 -encodeASN1Put :: ASN1 -> Put-encodeASN1Put d = putValuePolicy encodePolicyCER $ toRaw d+{-# DEPRECATED encodeASN1s "use stream types with encodeASN1Stream" #-}+encodeASN1s :: [ASN1t] -> L.ByteString+encodeASN1s = BER.encodeASN1s -encodeASN1 :: ASN1 -> L.ByteString-encodeASN1 = runPut . encodeASN1Put+{-# DEPRECATED encodeASN1 "use stream types with encodeASN1Stream" #-}+encodeASN1 :: ASN1t -> L.ByteString+encodeASN1 = BER.encodeASN1
Data/ASN1/DER.hs view
@@ -8,80 +8,124 @@ -- A module containing ASN1 DER specification serialization/derialization tools -- module Data.ASN1.DER-	( TagClass(..)+	( ASN1Class(..) 	, ASN1(..)+	, ASN1ConstructionType(..) +	-- * enumeratee to transform between ASN1 and raw+	, enumReadRaw+	, enumWriteRaw++	-- * enumeratee to transform between ASN1 and bytes+	, enumReadBytes+	, enumWriteBytes++	-- * iterate over common representation to an ASN1 stream+	, iterateFile+	, iterateByteString+ 	-- * DER serialize functions-	, decodeASN1Get-	, decodeASN1State+	, decodeASN1Stream+	, encodeASN1Stream++	-- * DER serialize functions, deprecated 	, decodeASN1 	, decodeASN1s-	, encodeASN1Put-	, encodeASN1sPut 	, encodeASN1 	, encodeASN1s 	) where -import Data.Int-import Data.ASN1.Raw+import Data.ASN1.Raw (ASN1Class(..), ASN1Length(..), ASN1Header(..), ASN1Event(..), ASN1Err(..))+import qualified Data.ASN1.Raw as Raw+ import Data.ASN1.Prim-import Data.Binary.Get-import Data.Binary.Put-import Control.Monad (mplus, liftM)-import Control.Monad.Error (throwError)+import Data.ASN1.Types (ofStream, toStream, ASN1t)+ import qualified Data.ASN1.BER as BER++import Data.ByteString (ByteString) import qualified Data.ByteString.Lazy as L +import Control.Monad.Identity+import Control.Exception++import Data.Enumerator (Iteratee, Enumeratee, ($$), (>>==))+import Data.Enumerator.IO+import qualified Data.Enumerator as E+ {- | Check if the length is the minimum possible and it's not indefinite -}-checkLength :: ValLength -> Maybe ASN1Err+checkLength :: ASN1Length -> Maybe ASN1Err checkLength LenIndefinite = Just $ ASN1PolicyFailed "DER" "indefinite length not allowed" checkLength (LenShort _)  = Nothing checkLength (LenLong n i) 	| n == 1 && i < 0x80  = Just $ ASN1PolicyFailed "DER" "long length should be a short length" 	| n == 1 && i >= 0x80 = Nothing-	| otherwise           = if i >= 2^((n-1)*8) && i < 2^(n*8) then Nothing else Just $ ASN1PolicyFailed "DER" "long length is not shortest"+	| otherwise           = if i >= 2^((n-1)*8) && i < 2^(n*8)+		then Nothing+		else Just $ ASN1PolicyFailed "DER" "long length is not shortest" -{- | check if the value type is correct -}-checkType :: TagClass -> TagNumber -> Maybe ASN1Err-checkType _ _ = Nothing+checkRawDER :: Monad m => Enumeratee Raw.ASN1Event Raw.ASN1Event m a+checkRawDER = E.checkDone $ \k -> k (E.Chunks []) >>== loop+	where+		loop = E.checkDone go+		go k = E.head >>= \x -> case x of+			Nothing -> k (E.Chunks []) >>== return+			Just l  -> case tyCheck l of+				Nothing  -> k (E.Chunks [l]) >>== loop+				Just err -> E.throwError err+		tyCheck (Header (ASN1Header _ _ _ len)) = checkLength len+		tyCheck _                               = Nothing -{- | check if the value is bounded by DER policies -}-check :: (TagClass, Bool, TagNumber) -> ValLength -> Maybe ASN1Err-check (tc,_,tn) vallen = checkLength vallen `mplus` checkType tc tn+{- | enumReadRaw is an enumeratee from raw events to asn1 -}+enumReadRaw :: Monad m => Enumeratee Raw.ASN1Event ASN1 m a+enumReadRaw = \f -> E.joinI (checkRawDER $$ BER.enumReadRaw f) -{- | ofRaw same as BER.ofRAW but check some additional DER constraint. -}-ofRaw :: Value -> Either ASN1Err ASN1-ofRaw (Value Universal 0x1 (Primitive b)) = getBoolean True b-ofRaw v                                   = BER.ofRaw v+{- | enumWriteRaw is an enumeratee from asn1 to raw events -}+enumWriteRaw :: Monad m => Enumeratee ASN1 Raw.ASN1Event m a+enumWriteRaw = BER.enumWriteRaw -{- | toRaw create a DER encoded value ready -}-toRaw :: ASN1 -> Value-toRaw = BER.toRaw+{-| 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)) -decodeASN1Get :: Get (Either ASN1Err ASN1)-decodeASN1Get = runGetErrInGet (getValueCheck check) >>= return . either Left ofRaw+{-| 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+enumWriteBytes = \f -> E.joinI (enumWriteRaw $$ (Raw.enumWriteBytes f)) -decodeASN1State :: L.ByteString -> Either ASN1Err (ASN1, L.ByteString, Int64)-decodeASN1State b =-	runGetErrState (getValueCheck check >>= either throwError return . BER.ofRaw) b 0+{-| iterate over a file using a file enumerator. -}+iterateFile :: FilePath -> Iteratee ASN1 IO a -> IO (Either SomeException a)+iterateFile path p = E.run (enumFile path $$ E.joinI $ enumReadBytes $$ p) -decodeASN1 :: L.ByteString -> Either ASN1Err ASN1-decodeASN1 b = either Left BER.ofRaw $ runGetErr (getValueCheck check) b+{-| iterate over a bytestring using a list enumerator over each chunks -}+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) -decodeASN1s :: L.ByteString -> Either ASN1Err [ASN1]-decodeASN1s = loop where-	loop z = case decodeASN1State z of-		Left err -> throwError err-		Right (v, rest, _) -> if L.length rest > 0 then liftM (v :) (loop rest) else return [v]+{-| decode a lazy bytestring as an ASN1 stream -}+decodeASN1Stream :: L.ByteString -> Either ASN1Err [ASN1]+decodeASN1Stream l = do+	case runIdentity (iterateByteString l E.consume) of+		Left err -> Left (maybe (ASN1ParsingFail "unknown") id $ fromException err)+		Right x  -> Right x -encodeASN1Put :: ASN1 -> Put-encodeASN1Put d = putValue $ toRaw d+encodeASN1Stream :: Monad m => [ASN1] -> Iteratee ByteString m a -> m (Either SomeException a)+encodeASN1Stream l p = E.run (E.enumList 1 l $$ E.joinI $ enumWriteBytes $$ p) -encodeASN1sPut :: [ASN1] -> Put-encodeASN1sPut = mapM_ encodeASN1Put+{-# DEPRECATED decodeASN1s "use stream types with decodeASN1Stream" #-}+decodeASN1s :: L.ByteString -> Either ASN1Err [ASN1t]+decodeASN1s l = either (Left) (Right . ofStream) $ decodeASN1Stream l -encodeASN1 :: ASN1 -> L.ByteString-encodeASN1 = runPut . encodeASN1Put+{-# DEPRECATED decodeASN1 "use stream types with decodeASN1Stream" #-}+decodeASN1 :: L.ByteString -> Either ASN1Err ASN1t+decodeASN1 = either (Left) (Right . head) . decodeASN1s -encodeASN1s :: [ASN1] -> L.ByteString-encodeASN1s = runPut . encodeASN1sPut+{-# DEPRECATED encodeASN1s "use stream types with encodeASN1Stream" #-}+encodeASN1s :: [ASN1t] -> L.ByteString+encodeASN1s l = case runIdentity (encodeASN1Stream (toStream l) E.consume) of+	Left _  -> error "encoding failed"+	Right x -> L.fromChunks x++{-# DEPRECATED encodeASN1 "use stream types with encodeASN1Stream" #-}+encodeASN1 :: ASN1t -> L.ByteString+encodeASN1 = encodeASN1s . (:[])
Data/ASN1/Internal.hs view
@@ -1,8 +1,8 @@-module Data.ASN1.Internal (-	uintOfBytes,-	intOfBytes,-	bytesOfUInt,-	bytesOfInt+module Data.ASN1.Internal+	( uintOfBytes+	, intOfBytes+	, bytesOfUInt+	, bytesOfInt 	) where  import Data.Word
Data/ASN1/Prim.hs view
@@ -12,9 +12,18 @@ 	( 	-- * ASN1 high level algebraic type 	  ASN1(..)+	, ASN1ConstructionType(..) +	, encodeHeader+	, encodePrimitiveHeader+	, encodePrimitive+	, decodePrimitive+	, encodeConstructed+	, encodeList+	, encodeOne+	, mkSmallestLength+ 	-- * marshall an ASN1 type from a val struct or a bytestring-	, getEOC 	, getBoolean 	, getInteger 	, getBitString@@ -43,14 +52,13 @@ 	, putBitString 	, putString 	, putOID-	, encodeUCS2BE 	) where  import Data.ASN1.Internal import Data.ASN1.Raw+import Data.ASN1.Stream import Data.Bits import Data.Word-import Data.Maybe (catMaybes) import Data.List (unfoldr) import Data.ByteString (ByteString) import Data.Char (ord)@@ -58,36 +66,7 @@ import qualified Data.ByteString.Lazy as L import Data.Text.Lazy (Text) import qualified Data.Text.Lazy as T-import Data.Text.Lazy.Encoding (decodeASCII, decodeUtf8, decodeUtf32BE)--data ASN1 =-	  EOC-	| Boolean Bool-	| IntVal Integer-	| BitString Int L.ByteString-	| OctetString L.ByteString-	| Null-	| OID [Integer]-	| Real Double-	| Enumerated-	| UTF8String Text-	| Sequence [ASN1]-	| Set [ASN1]-	| NumericString L.ByteString-	| PrintableString Text-	| T61String L.ByteString-	| VideoTexString L.ByteString-	| IA5String Text-	| UTCTime (Int, Int, Int, Int, Int, Int, Bool)-	| GeneralizedTime (Int, Int, Int, Int, Int, Int, Bool)-	| GraphicString L.ByteString-	| VisibleString L.ByteString-	| GeneralString L.ByteString-	| UniversalString Text-	| CharacterString L.ByteString-	| BMPString Text-	| Other TagClass TagNumber (Either ByteString [ASN1])-	deriving (Show, Eq)+import Data.Text.Lazy.Encoding (decodeASCII, decodeUtf8, decodeUtf32BE, encodeUtf8, encodeUtf32BE)  encodeUCS2BE :: Text -> L.ByteString encodeUCS2BE t =@@ -105,12 +84,145 @@ 					_     -> loop r 	 -getEOC :: ByteString -> Either ASN1Err ASN1-getEOC s =-	if B.length s == 0-		then Right $ EOC-		else Left $ ASN1Misc "EOC: data length not within bound"+encodeHeader :: Bool -> ASN1Length -> ASN1 -> ASN1Header+encodeHeader pc len (Boolean _)                = ASN1Header Universal 0x1 pc len+encodeHeader pc len (IntVal _)                 = ASN1Header Universal 0x2 pc len+encodeHeader pc len (BitString _ _)            = ASN1Header Universal 0x3 pc len+encodeHeader pc len (OctetString _)            = ASN1Header Universal 0x4 pc len+encodeHeader pc len Null                       = ASN1Header Universal 0x5 pc len+encodeHeader pc len (OID _)                    = ASN1Header Universal 0x6 pc len+encodeHeader pc len (Real _)                   = ASN1Header Universal 0x9 pc len+encodeHeader pc len Enumerated                 = ASN1Header Universal 0xa pc len+encodeHeader pc len (UTF8String _)             = ASN1Header Universal 0xc pc len+encodeHeader pc len (NumericString _)          = ASN1Header Universal 0x12 pc len+encodeHeader pc len (PrintableString _)        = ASN1Header Universal 0x13 pc len+encodeHeader pc len (T61String _)              = ASN1Header Universal 0x14 pc len+encodeHeader pc len (VideoTexString _)         = ASN1Header Universal 0x15 pc len+encodeHeader pc len (IA5String _)              = ASN1Header Universal 0x16 pc len+encodeHeader pc len (UTCTime _)                = ASN1Header Universal 0x17 pc len+encodeHeader pc len (GeneralizedTime _)        = ASN1Header Universal 0x18 pc len+encodeHeader pc len (GraphicString _)          = ASN1Header Universal 0x19 pc len+encodeHeader pc len (VisibleString _)          = ASN1Header Universal 0x1a pc len+encodeHeader pc len (GeneralString _)          = ASN1Header Universal 0x1b pc len+encodeHeader pc len (UniversalString _)        = ASN1Header Universal 0x1c pc len+encodeHeader pc len (CharacterString _)        = ASN1Header Universal 0x1d pc len+encodeHeader pc len (BMPString _)              = ASN1Header Universal 0x1e pc len+encodeHeader pc len (Start Sequence)           = ASN1Header Universal 0x10 pc len+encodeHeader pc len (Start Set)                = ASN1Header Universal 0x11 pc len+encodeHeader pc len (Start (Container tc tag)) = ASN1Header tc tag pc len+encodeHeader pc len (Other tc tag _)           = ASN1Header tc tag pc len+encodeHeader _ _ (End _)                       = error "this should not happen" +encodePrimitiveHeader :: ASN1Length -> ASN1 -> ASN1Header+encodePrimitiveHeader = encodeHeader False++encodePrimitiveData :: ASN1 -> ByteString+encodePrimitiveData (Boolean b)         = B.singleton (if b then 0xff else 0)+encodePrimitiveData (IntVal i)          = putInteger i+encodePrimitiveData (BitString i bits)  = putBitString i bits+encodePrimitiveData (OctetString b)     = putString b+encodePrimitiveData Null                = B.empty+encodePrimitiveData (OID oid)           = putOID oid+encodePrimitiveData (Real _)            = B.empty -- not implemented+encodePrimitiveData Enumerated          = B.empty -- not implemented+encodePrimitiveData (UTF8String b)      = putString $ encodeUtf8 b+encodePrimitiveData (NumericString b)   = putString b+encodePrimitiveData (PrintableString b) = putString $ encodeUtf8 b+encodePrimitiveData (T61String b)       = putString b+encodePrimitiveData (VideoTexString b)  = putString b+encodePrimitiveData (IA5String b)       = putString $ encodeUtf8 b+encodePrimitiveData (UTCTime t)         = putUTCTime t+encodePrimitiveData (GeneralizedTime t) = putGeneralizedTime t+encodePrimitiveData (GraphicString b)   = putString b+encodePrimitiveData (VisibleString b)   = putString b+encodePrimitiveData (GeneralString b)   = putString b+encodePrimitiveData (UniversalString b) = putString $ encodeUtf32BE b+encodePrimitiveData (CharacterString b) = putString b+encodePrimitiveData (BMPString b)       = putString $ encodeUCS2BE b+encodePrimitiveData (Other _ _ b)       = b+encodePrimitiveData o                   = error ("not a primitive " ++ show o)++encodePrimitive :: ASN1 -> (Int, [ASN1Event])+encodePrimitive a =+	let b = encodePrimitiveData a in+	let blen = B.length b in+	let len = makeLength blen in+	let hdr = encodePrimitiveHeader len a in+	(B.length (putHeader hdr) + blen, [Header hdr, Primitive b])+	where+		makeLength len+			| len < 0x80 = LenShort len+			| otherwise  = LenLong (nbBytes len) len+		nbBytes nb = if nb > 255 then 1 + nbBytes (nb `div` 256) else 1++encodeOne :: ASN1 -> (Int, [ASN1Event])+encodeOne (Start _) = error "encode one cannot do start"+encodeOne t         = encodePrimitive t++encodeList :: [ASN1] -> (Int, [ASN1Event])+encodeList []               = (0, [])+encodeList (End _:xs)       = encodeList xs+encodeList (t@(Start _):xs) =+	let (ys, zs)    = getConstructedEnd 0 xs in+	let (llen, lev) = encodeList zs in+	let (len, ev)   = encodeConstructed t ys in+	(llen + len, ev ++ lev)++encodeList (x:xs)           =+	let (llen, lev) = encodeList xs in+	let (len, ev)   = encodeOne x in+	(llen + len, ev ++ lev)++encodeConstructed :: ASN1 -> [ASN1] -> (Int, [ASN1Event])+encodeConstructed c@(Start _) children =+	let (clen, events) = encodeList children in+	let len = mkSmallestLength clen in+	let h = encodeHeader True len c in+	let tlen = B.length (putHeader h) + clen in+	(tlen, Header h : ConstructionBegin : events ++ [ConstructionEnd])++encodeConstructed _ _ = error "not a start node"++mkSmallestLength :: Int -> ASN1Length+mkSmallestLength i+	| i < 0x80  = LenShort i+	| otherwise = LenLong (nbBytes i) i+		where nbBytes nb = if nb > 255 then 1 + nbBytes (nb `div` 256) else 1++type ASN1Ret = Either ASN1Err ASN1++decodePrimitive :: ASN1Header -> B.ByteString -> ASN1Ret+decodePrimitive (ASN1Header Universal 0x1 _ _) p   = getBoolean False p+decodePrimitive (ASN1Header Universal 0x2 _ _) p   = getInteger p+decodePrimitive (ASN1Header Universal 0x3 _ _) p   = getBitString p+decodePrimitive (ASN1Header Universal 0x4 _ _) p   = getOctetString p+decodePrimitive (ASN1Header Universal 0x5 _ _) p   = getNull p+decodePrimitive (ASN1Header Universal 0x6 _ _) p   = getOID p+decodePrimitive (ASN1Header Universal 0x7 _ _) _   = Left $ ASN1NotImplemented "Object Descriptor"+decodePrimitive (ASN1Header Universal 0x8 _ _) _   = Left $ ASN1NotImplemented "External"+decodePrimitive (ASN1Header Universal 0x9 _ _) _   = Left $ ASN1NotImplemented "real"+decodePrimitive (ASN1Header Universal 0xa _ _) _   = Left $ ASN1NotImplemented "enumerated"+decodePrimitive (ASN1Header Universal 0xb _ _) _   = Left $ ASN1NotImplemented "EMBEDDED PDV"+decodePrimitive (ASN1Header Universal 0xc _ _) p   = getUTF8String p+decodePrimitive (ASN1Header Universal 0xd _ _) _   = Left $ ASN1NotImplemented "RELATIVE-OID"+decodePrimitive (ASN1Header Universal 0x10 _ _) _  = error "sequence not a primitive"+decodePrimitive (ASN1Header Universal 0x11 _ _) _  = error "set not a primitive"+decodePrimitive (ASN1Header Universal 0x12 _ _) p  = getNumericString p+decodePrimitive (ASN1Header Universal 0x13 _ _) p  = getPrintableString p+decodePrimitive (ASN1Header Universal 0x14 _ _) p  = getT61String p+decodePrimitive (ASN1Header Universal 0x15 _ _) p  = getVideoTexString p+decodePrimitive (ASN1Header Universal 0x16 _ _) p  = getIA5String p+decodePrimitive (ASN1Header Universal 0x17 _ _) p  = getUTCTime p+decodePrimitive (ASN1Header Universal 0x18 _ _) p  = getGeneralizedTime p+decodePrimitive (ASN1Header Universal 0x19 _ _) p  = getGraphicString p+decodePrimitive (ASN1Header Universal 0x1a _ _) p  = getVisibleString p+decodePrimitive (ASN1Header Universal 0x1b _ _) p  = getGeneralString p+decodePrimitive (ASN1Header Universal 0x1c _ _) p  = getUniversalString p+decodePrimitive (ASN1Header Universal 0x1d _ _) p  = getCharacterString p+decodePrimitive (ASN1Header Universal 0x1e _ _) p  = getBMPString p+decodePrimitive (ASN1Header tc        tag  _ _) p  = Right $ Other tc tag p++ getBoolean :: Bool -> ByteString -> Either ASN1Err ASN1 getBoolean isDer s = 	if B.length s == 1@@ -135,8 +247,8 @@ 			v2 = s `B.index` 1  -getBitString :: ValStruct -> Either ASN1Err ASN1-getBitString (Primitive s) =+getBitString :: ByteString -> Either ASN1Err ASN1+getBitString s = 	let toSkip = B.head s in 	let toSkip' = if toSkip >= 48 && toSkip <= 48 + 7 then toSkip - (fromIntegral $ ord '0') else toSkip in 	let xs = B.tail s in@@ -144,59 +256,49 @@ 		then Right $ BitString (fromIntegral toSkip') (L.fromChunks [xs]) 		else Left $ ASN1Misc ("bitstring: skip number not within bound " ++ show toSkip' ++ " " ++  show s) -getBitString (Constructed _) = Left $ ASN1NotImplemented "bitstring"--getString :: (Either ByteString Value -> Maybe ASN1Err) -> ValStruct -> Either ASN1Err L.ByteString-getString check (Primitive s) =-	case check (Left s) of+getString :: (ByteString -> Maybe ASN1Err) -> ByteString -> Either ASN1Err L.ByteString+getString check s =+	case check s of 		Nothing  -> Right $ L.fromChunks [s] 		Just err -> Left err -getString check (Constructed l) =-	case catMaybes $ map (check . Right) l of-		[]   -> Right $ L.fromChunks $ map catPrimitiveString l-		errs -> Left $ ASN1Multiple errs-	where-		catPrimitiveString (Value _ _ (Primitive b)) = b-		catPrimitiveString (Value _ _ (Constructed _)) = B.empty {- FIXME -}--getOctetString :: ValStruct -> Either ASN1Err ASN1+getOctetString :: ByteString -> Either ASN1Err ASN1 getOctetString = either Left (Right . OctetString) . getString (\_ -> Nothing) -getNumericString :: ValStruct -> Either ASN1Err ASN1+getNumericString :: ByteString -> Either ASN1Err ASN1 getNumericString = either Left (Right . NumericString) . getString (\_ -> Nothing) -getPrintableString :: ValStruct -> Either ASN1Err ASN1+getPrintableString :: ByteString -> Either ASN1Err ASN1 getPrintableString = either Left (Right . PrintableString . decodeASCII) . getString (\_ -> Nothing) -getUTF8String :: ValStruct -> Either ASN1Err ASN1+getUTF8String :: ByteString -> Either ASN1Err ASN1 getUTF8String = either Left (Right . UTF8String . decodeUtf8) . getString (\_ -> Nothing) -getT61String :: ValStruct -> Either ASN1Err ASN1+getT61String :: ByteString -> Either ASN1Err ASN1 getT61String = either Left (Right . T61String) . getString (\_ -> Nothing) -getVideoTexString :: ValStruct -> Either ASN1Err ASN1+getVideoTexString :: ByteString -> Either ASN1Err ASN1 getVideoTexString = either Left (Right . VideoTexString) . getString (\_ -> Nothing) -getIA5String :: ValStruct -> Either ASN1Err ASN1+getIA5String :: ByteString -> Either ASN1Err ASN1 getIA5String = either Left (Right . IA5String . decodeASCII) . getString (\_ -> Nothing) -getGraphicString :: ValStruct -> Either ASN1Err ASN1+getGraphicString :: ByteString -> Either ASN1Err ASN1 getGraphicString = either Left (Right . GraphicString) . getString (\_ -> Nothing) -getVisibleString :: ValStruct -> Either ASN1Err ASN1+getVisibleString :: ByteString -> Either ASN1Err ASN1 getVisibleString = either Left (Right . VisibleString) . getString (\_ -> Nothing) -getGeneralString :: ValStruct -> Either ASN1Err ASN1+getGeneralString :: ByteString -> Either ASN1Err ASN1 getGeneralString = either Left (Right . GeneralString) . getString (\_ -> Nothing) -getUniversalString :: ValStruct -> Either ASN1Err ASN1+getUniversalString :: ByteString -> Either ASN1Err ASN1 getUniversalString = either Left (Right . UniversalString . decodeUtf32BE) . getString (\_ -> Nothing) -getCharacterString :: ValStruct -> Either ASN1Err ASN1+getCharacterString :: ByteString -> Either ASN1Err ASN1 getCharacterString = either Left (Right . CharacterString) . getString (\_ -> Nothing) -getBMPString :: ValStruct -> Either ASN1Err ASN1+getBMPString :: ByteString -> Either ASN1Err ASN1 getBMPString = either Left (Right . BMPString . decodeUCS2BE) . getString (\_ -> Nothing)  getNull :: ByteString -> Either ASN1Err ASN1@@ -221,8 +323,8 @@ 		spanSubOIDbound (a:as) = if testBit a 7 then (clearBit a 7 : ys, zs) else ([a], as) 			where (ys, zs) = spanSubOIDbound as -getUTCTime :: ValStruct -> Either ASN1Err ASN1-getUTCTime (Primitive s) =+getUTCTime :: ByteString -> Either ASN1Err ASN1+getUTCTime s = 	case B.unpack s of 		[y1, y2, m1, m2, d1, d2, h1, h2, mi1, mi2, s1, s2, z] -> 			let y = integerise y1 y2 in@@ -237,10 +339,8 @@ 	where 		integerise a b = ((fromIntegral a) - (ord '0')) * 10 + ((fromIntegral b) - (ord '0')) -getUTCTime (Constructed _) = Left $ ASN1NotImplemented "utctime constructed"--getGeneralizedTime :: ValStruct -> Either ASN1Err ASN1-getGeneralizedTime (Primitive s) =+getGeneralizedTime :: ByteString -> Either ASN1Err ASN1+getGeneralizedTime s = 	case B.unpack s of 		[y1, y2, y3, y4, m1, m2, d1, d2, h1, h2, mi1, mi2, s1, s2, z] -> 			let year = (integerise y1 y2) * 100 + (integerise y3 y4) in@@ -253,11 +353,9 @@ 		_                                                     -> Left $ ASN1Misc "utctime unexpected format" 	where 		integerise a b = ((fromIntegral a) - (ord '0')) * 10 + ((fromIntegral b) - (ord '0'))-getGeneralizedTime (Constructed _) = Left $ ASN1NotImplemented "generalizedtime constructed" -putTime :: Bool -> (Int, Int, Int, Int, Int, Int, Bool) -> ValStruct-putTime generalized (y,m,d,h,mi,s,z) =-	Primitive $ B.pack etime+putTime :: Bool -> (Int, Int, Int, Int, Int, Int, Bool) -> ByteString+putTime generalized (y,m,d,h,mi,s,z) = B.pack etime 	where 		etime = 			if generalized@@ -271,24 +369,24 @@ 		(mi1, mi2)        = split2 mi 		(s1, s2)          = split2 s -putUTCTime :: (Int, Int, Int, Int, Int, Int, Bool) -> ValStruct+putUTCTime :: (Int, Int, Int, Int, Int, Int, Bool) -> ByteString putUTCTime time = putTime False time -putGeneralizedTime :: (Int, Int, Int, Int, Int, Int, Bool) -> ValStruct+putGeneralizedTime :: (Int, Int, Int, Int, Int, Int, Bool) -> ByteString putGeneralizedTime time = putTime True time -putInteger :: Integer -> ValStruct-putInteger i = Primitive $ B.pack $ bytesOfInt i+putInteger :: Integer -> ByteString+putInteger i = B.pack $ bytesOfInt i -putBitString :: Int -> L.ByteString -> ValStruct-putBitString i bits = Primitive $ B.concat $ B.singleton (fromIntegral i) : L.toChunks bits+putBitString :: Int -> L.ByteString -> ByteString+putBitString i bits = B.concat $ B.singleton (fromIntegral i) : L.toChunks bits -putString :: L.ByteString -> ValStruct-putString l = Primitive $ B.concat $ L.toChunks l+putString :: L.ByteString -> ByteString+putString l = B.concat $ L.toChunks l  {- no enforce check that oid1 is between [0..2] and oid2 is between [0..39] -}-putOID :: [Integer] -> ValStruct-putOID oids = Primitive $ B.pack $ eoid+putOID :: [Integer] -> ByteString+putOID oids = B.pack $ eoid 	where 		(oid1:oid2:suboids) = oids 		eoidclass           = fromIntegral (oid1 * 40 + oid2)
Data/ASN1/Raw.hs view
@@ -1,4 +1,4 @@-{-#  LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE BangPatterns, DeriveDataTypeable #-} -- | -- Module      : Data.ASN1.Raw -- License     : BSD-style@@ -8,118 +8,229 @@ -- -- A module containing raw ASN1 serialization/derialization tools --+ module Data.ASN1.Raw-	( GetErr-	-- * get structure-	, runGetErr-	, runGetErrState-	, runGetErrInGet+	( 	-- * ASN1 definitions+	  ASN1Class(..)+	, ASN1Tag+	, ASN1Length(..)+	, ASN1Header(..) 	, ASN1Err(..)-	, CheckFn-	, TagClass(..)-	, TagNumber-	, ValLength(..)-	, ValStruct(..)-	, Value(..)-	-- * get value from a Get structure-	, getValueCheck-	, getValue-	-- * put value in a Put structure-	, putValuePolicy-	, putValue+	-- * Enumerator events+	, ASN1Event(..)+	, iterateFile+	, iterateByteString+	, enumReadBytes+	, enumWriteBytes+	-- * serialize asn1 headers+	, getHeader+	, putHeader 	) where -import Data.Bits-import Data.Int-import Data.ASN1.Internal-import Data.Binary.Get-import Data.Binary.Put+import Data.Enumerator hiding (head, length, map)+import qualified Data.Enumerator as E+import Data.Enumerator.IO+import Data.Attoparsec.Enumerator+import Data.Attoparsec+import qualified Data.Attoparsec as A import Data.ByteString (ByteString)-import Data.Word-import Control.Monad.Error import qualified Data.ByteString as B import qualified Data.ByteString.Lazy as L+import Data.ASN1.Internal+import Control.Exception+import Data.Typeable+import Data.Word+import Data.Bits+import Control.Monad+import Control.Applicative ((<|>), (<$>)) -data TagClass =+data ASN1Class = 	  Universal 	| Application 	| Context 	| Private-	deriving (Show, Eq)+	deriving (Show,Eq,Ord,Enum) -data ValLength =+type ASN1Tag = Int++data ASN1Length = 	  LenShort Int      -- ^ Short form with only one byte. length has to be < 127. 	| LenLong Int Int   -- ^ Long form of N bytes 	| LenIndefinite     -- ^ Length is indefinite expect an EOC in the stream to finish the type-	deriving (Show, Eq)--type TagNumber = Int-type TagConstructed = Bool-type Identifier = (TagClass, TagConstructed, TagNumber)+	deriving (Show,Eq) -data ValStruct =-	  Primitive ByteString -- ^ Primitive of a strict value-	| Constructed [Value]  -- ^ Constructed of a list of values-	deriving (Show, Eq)+data ASN1Header = ASN1Header !ASN1Class !ASN1Tag !Bool !ASN1Length+	deriving (Show,Eq) -data Value = Value TagClass TagNumber ValStruct-	deriving (Show, Eq)+data ASN1Event =+	  Header ASN1Header     -- ^ ASN1 Header+	| Primitive !ByteString -- ^ Primitive+	| ConstructionBegin     -- ^ Constructed value start+	| ConstructionEnd       -- ^ Constructed value end+	deriving (Show,Eq)  data ASN1Err = 	  ASN1LengthDecodingLongContainsZero+	| ASN1WritingUnexpectedConstructionEnd+	| ASN1WritingUnexpectedInputEOF 	| ASN1PolicyFailed String String 	| ASN1NotImplemented String 	| ASN1Multiple [ASN1Err] 	| ASN1Misc String-	deriving (Show, Eq)+	| ASN1ParsingPartial+	| ASN1ParsingFail String+	deriving (Typeable, Show, Eq) -type CheckFn = (TagClass, Bool, TagNumber) -> ValLength -> Maybe ASN1Err+instance Exception ASN1Err -instance Error ASN1Err where-	noMsg = ASN1Misc ""-	strMsg = ASN1Misc+{-| iterate over a file using a file enumerator. -}+iterateFile :: FilePath -> Iteratee ASN1Event IO a -> IO (Either SomeException a)+iterateFile path p = run (enumFile path $$ joinI (enumReadBytes $$ p)) -newtype GetErr a = GE { runGE :: ErrorT ASN1Err Get a }-	deriving (Monad, MonadError ASN1Err)+{-| iterate over a lazy bytestring using a list enumerator over the bytestring chunks. -}+iterateByteString :: Monad m => L.ByteString -> Iteratee ASN1Event m a -> m (Either SomeException a)+iterateByteString bs p = run (enumList 1 (L.toChunks bs) $$ joinI (enumReadBytes $$ p)) -instance Functor GetErr where-	fmap f = GE . fmap f . runGE+{- parse state machine -}+data ParseState =+	  PSPrimitive Int+	| PSConstructing Int+	| PSConstructingEOC -runGetErr :: GetErr a -> L.ByteString -> Either ASN1Err a-runGetErr = runGet . runErrorT . runGE+{-| enumReadBytes parse bytestring and generate asn1event. -}+enumReadBytes :: Monad m => Enumeratee ByteString ASN1Event m a+enumReadBytes = checkDone $ \k -> k (Chunks []) >>== loop [0] []+	where+		loop !cs !ps = checkDone (go cs ps)+		go (n:[]) [] k = iterDesc >>= eofCheck k+				(\(c,e,nps) -> case nps of+					PSPrimitive _ -> k (Chunks [e]) >>== loop [c+n] [nps]+					_             -> k (Chunks [e, ConstructionBegin]) >>== loop [0, c+n] [nps]+				) -runGetErrState :: GetErr a -> L.ByteString -> Int64 -> Either ASN1Err (a, L.ByteString, Int64)-runGetErrState g l o =-	case runGetState (runErrorT $ runGE g) l o of-		(Left err, _, _)           -> Left err-		(Right v, datarem, parsed) -> Right (v, datarem, parsed)+		go (n:cs) (PSPrimitive i:pss) k =+			iterPrim i >>= (\e -> k (Chunks [e]) >>== loop (n+i:cs) pss) -runGetErrInGet :: GetErr a -> Get (Either ASN1Err a)-runGetErrInGet = runErrorT . runGE+		go (n:m:cs) fps@(PSConstructing i:pss) k+			| n == i    = k (Chunks [ConstructionEnd]) >>== loop (n+m:cs) pss+			| otherwise = iterDesc >>= eofCheck k+				(\(c, e, nps) -> case nps of+					PSPrimitive _ -> k (Chunks [e]) >>== loop (n+c:m:cs) (nps:fps)+					_             -> k (Chunks [e, ConstructionBegin]) >>== loop (0:n+c:m:cs) (nps:fps)+				) -liftGet :: Get a -> GetErr a-liftGet = GE . lift+		go (n:m:cs) fps@(PSConstructingEOC:pss) k =+			iterDesc >>= eofCheck k+				(\(c, e, nps) -> case e of -- check if EOC or continue+					(Header (ASN1Header _ 0 _ _)) -> k (Chunks [ConstructionEnd]) >>== loop (c+n+m:cs) pss+					_                             -> k (Chunks [e]) >>== loop (n+c:m:cs) (nps:fps)+				)+		-- error case+		go _ _ k = k (Chunks []) >>== return -geteWord8 :: GetErr Word8-geteWord8 = liftGet getWord8+		eofCheck k _ Nothing  = k (Chunks []) >>== return+		eofCheck _ f (Just x) = f $! x -geteBytes :: Int -> GetErr ByteString-geteBytes = liftGet . getBytes+		iterDesc :: Monad m => Iteratee ByteString m (Maybe (Int, ASN1Event, ParseState))+		iterDesc = iterParser ((endOfInput >> return Nothing) <|> fmap Just parseHeaderEvent) -{- marshall helper for getIdentifier to unserialize long tag number -}-getTagNumberLong :: GetErr TagNumber-getTagNumberLong = getNext 0 True-	where getNext n nz = do-		t <- fromIntegral `fmap` geteWord8-		when (nz && t == 0x80) $ throwError ASN1LengthDecodingLongContainsZero+		iterPrim i = iterParser (fmap (Primitive) (A.take i))++{- parseHeaderEvent returns the asn1event header, the length parsed and the next parse state. -}+parseHeaderEvent :: Parser (Int, ASN1Event, ParseState)+parseHeaderEvent = do+	(lbytes, asn1header@(ASN1Header _ _ pc len)) <- parseHeader+	let ps = if pc+		-- constructed value(s)+		then case len of+			LenIndefinite -> PSConstructingEOC+			LenLong _ i   -> PSConstructing i+			LenShort i    -> PSConstructing i+		-- primitive value+		else case len of+			LenIndefinite -> error "cannot do indefinite primitive"+			LenLong _ i   -> PSPrimitive i+			LenShort i    -> PSPrimitive i+	return (lbytes, Header asn1header, ps)++{- parseHeader parse a asn1 header in an attoparsec context.+ - it returns the number of bytes parsed, the asn1event for this event -}+parseHeader :: Parser (Int, ASN1Header)+parseHeader = do+	(cl,pc,t1)      <- parseFirstWord <$> anyWord8+	(tagbytes, tag) <- if t1 == 0x1f then getTagLong else return (0, t1)+	(lenbytes, len) <- getLength+	return (1+tagbytes+lenbytes, ASN1Header cl tag pc len)++{- parse an header from a single bytestring. -}+getHeader :: ByteString -> Either ASN1Err ASN1Header+getHeader l = case parse parseHeader l of+	(Fail _ _ _) -> Left (ASN1ParsingFail "header")+	(Partial _)  -> Left (ASN1ParsingPartial)+	Done b r     -> if B.null b then Right (snd r) else Left ASN1ParsingPartial++{- parse the first word of an header -}+parseFirstWord :: Word8 -> (ASN1Class, Bool, ASN1Tag)+parseFirstWord w = (cl,pc,t1)+	where+		cl = toEnum $ fromIntegral $ (w `shiftR` 6)+		pc = testBit w 5+		t1 = fromIntegral (w .&. 0x1f)++{- when the first tag is 0x1f, the tag is in long form, where+ - we get bytes while the 7th bit is set. -}+getTagLong :: Parser (Int, ASN1Tag)+getTagLong = do+	t <- fromIntegral <$> anyWord8+	when (t == 0x80) $ error "not canonical encoding of tag"+	if testBit t 7+		then getNext 1 (clearBit t 7)+		else return (1, t)++	where getNext !blen !n = do+		t <- fromIntegral <$> anyWord8 		if testBit t 7-			then getNext (n `shiftL` 7 + clearBit t 7) False-			else return (n `shiftL` 7 + t)+			then getNext (blen + 1) (n `shiftL` 7 + clearBit t 7)+			else return (blen + 1, n `shiftL` 7 + t) +{- get the asn1 length which is either short form if 7th bit is not set,+ - indefinite form is the 7 bit is set and every other bits clear,+ - or long form otherwise, where the next bytes will represent the length+ -}+getLength :: Parser (Int, ASN1Length)+getLength = do+	l1 <- fromIntegral <$> anyWord8+	if testBit l1 7+		then case clearBit l1 7 of+			0   -> return (1, LenIndefinite)+			len -> do+				lw <- A.take len+				return (1+len, LenLong len $ uintbs lw)+		else+			return (1, LenShort l1)+	where+		{- uintbs return the unsigned int represented by the bytes -}+		uintbs = B.foldl (\acc n -> (acc `shiftL` 8) + fromIntegral n) 0++{- | putIdentifier encode an ASN1 Identifier into a marshalled value -}+putHeader :: ASN1Header -> ByteString+putHeader (ASN1Header cl tag pc len) = B.pack+	( putFirstWord (cl, pc, if tag < 0x1f then tag else 0x1f)+	: (if tag >= 0x1f then putTagLong tag else [])+	++ putLength len+	)++{- put first word of a header -}+putFirstWord :: (ASN1Class, Bool, ASN1Tag) -> Word8+putFirstWord (cl,pc,t1) = (cli `shiftL` 6) .|. (pcval `shiftL` 5) .|. (fromIntegral t1 .&. 0x1f)+	where+		cli   = fromIntegral $ fromEnum cl+		pcval = if pc then 0x1 else 0x0+ {- marshall helper for putIdentifier to serialize long tag number -}-putTagNumberLong :: TagNumber -> Put-putTagNumberLong n = mapM_ putWord8 $ revSethighbits $ split7bits n+putTagLong :: ASN1Tag -> [Word8]+putTagLong n = revSethighbits $ split7bits n 	where 		revSethighbits :: [Word8] -> [Word8] 		revSethighbits []     = []@@ -128,145 +239,36 @@ 			| i == 0    = [] 			| i <= 0x7f = [ fromIntegral i ] 			| otherwise = fromIntegral (i .&. 0x7f) : split7bits (i `shiftR` 7)-		 -{- | getIdentifier get an ASN1 encoded Identifier.- - if the first 5 bytes value is less than 1f then it's encoded on 1 byte, otherwise- - read bytes until the 8th bit is not set -}-getIdentifier :: GetErr Identifier-getIdentifier = do-	w <- geteWord8-	let cl =-		case (w `shiftR` 6) .&. 3 of-			0 -> Universal-			1 -> Application -			2 -> Context-			3 -> Private-			_ -> Universal -- this cannot happens because of the .&. 3-	let pc = (w .&. 0x20) > 0-	let val = fromIntegral (w .&. 0x1f)-	vencoded <- if val < 0x1f then return val else getTagNumberLong-	return (cl, pc, vencoded)--{- | putIdentifier encode an ASN1 Identifier into a marshalled value -}-putIdentifier :: Identifier -> Put-putIdentifier (cl, pc, val) = do-	let cli = case cl of-		Universal   -> 0-		Application -> 1-		Context     -> 2-		Private     -> 3-	let pcval = if pc then 0x20 else 0x00-	if val < 0x1f-		then-			putWord8 $ fromIntegral $ (cli `shiftL` 6) .|. pcval .|. val-		else do-			putWord8 $ fromIntegral $ (cli `shiftL` 6) .|. pcval .|. 0x1f-			putTagNumberLong val--{- | getLength get the ASN1 encoded length of an item.- - if less than 0x80 then it's encoded on 1 byte, otherwise- - the first byte is the number of bytes to read as the length.- - if the number of bytes is 0, then the length is indefinite,- - and the content length is bounded by an EOC -}-getLength :: GetErr ValLength-getLength = do-	l1 <- geteWord8-	if testBit l1 7-		then case fromIntegral (clearBit l1 7) of-			0   -> return LenIndefinite-			len -> do-				lw <- geteBytes len-				return $ LenLong len (fromIntegral $ snd $ uintOfBytes lw)-		else-			return $ LenShort $ fromIntegral l1- {- | putLength encode a length into a ASN1 length.  - see getLength for the encoding rules -}-putLength :: ValLength -> Put+putLength :: ASN1Length -> [Word8] putLength (LenShort i) 	| i < 0 || i > 0x7f = error "putLength: short length is not between 0x0 and 0x80"-	| otherwise         = putWord8 $ fromIntegral i-+	| otherwise         = [fromIntegral i] putLength (LenLong _ i) 	| i < 0     = error "putLength: long length is negative"-	| otherwise = putWord8 lenbytes >> mapM_ putWord8 lw+	| otherwise = lenbytes : lw 		where 			lw       = bytesOfUInt $ fromIntegral i 			lenbytes = fromIntegral (length lw .|. 0x80)-	-putLength (LenIndefinite) = putWord8 0x80--{- helper to getValue to build a constructed list of values when length is known -}-getValueConstructed :: CheckFn -> GetErr [Value]-getValueConstructed check = do-	remain <- liftGet remaining-	if remain > 0-		then liftM2 (:) (getValueCheck check) (getValueConstructed check)-		else return []--{- helper to getValue to build a constructed list of values when length is unknown -}-getValueConstructedUntilEOC :: CheckFn -> GetErr [Value]-getValueConstructedUntilEOC check = do-	o <- getValueCheck check-	case o of-		-- technically EOC should also match (Primitive B.empty) (LenShort 0)-		Value Universal 0 _ -> return []-		_                   -> liftM (o :) (getValueConstructedUntilEOC check)--getValueOfLength :: CheckFn -> Int -> Bool -> GetErr ValStruct-getValueOfLength check len pc = do-	b <- geteBytes len-	if pc-		then case runGetErr (getValueConstructed check) (L.fromChunks [b]) of-			Right x  -> return $ Constructed x-			Left err -> throwError err-		else-			return $ Primitive b--{- | getValueCheck decode an ASN1 value and check the values received through the check fn -}-getValueCheck :: CheckFn -> GetErr Value-getValueCheck check = do-	(tc, pc, tn) <- getIdentifier-	vallen <- getLength--	{- policy checker, if it returns an error, raise it -}-	case check (tc, pc, tn) vallen of-		Just err -> throwError err-		Nothing  -> return ()--	struct <- case vallen of-		LenIndefinite -> do-			unless pc $ throwError $ ASN1Misc "lenght indefinite not allowed with primitive"-			vs <- getValueConstructedUntilEOC check-			return $ Constructed vs-		(LenShort len)  -> getValueOfLength check len pc-		(LenLong _ len) -> getValueOfLength check len pc-	return $ Value tc tn struct--getValue :: GetErr Value-getValue = getValueCheck (\_ _ -> Nothing)--putValStruct :: ValStruct -> Put-putValStruct (Primitive x)   = putByteString x-putValStruct (Constructed l) = mapM_ putValue l--putValuePolicy :: (Value -> Int -> ValLength) -> Value -> Put-putValuePolicy policy v@(Value tc tn struct) = do-	let pc =-		case struct of-			Primitive _   -> False-			Constructed _ -> True-	putIdentifier (tc, pc, tn)-	let content = runPut (putValStruct struct)-	let len = fromIntegral $ L.length content -	let lenEncoded = policy v len-	putLength lenEncoded-	putLazyByteString content-	case lenEncoded of-		LenIndefinite -> putValue $ Value Universal 0x0 (Primitive B.empty)-		_             -> return ()+putLength (LenIndefinite) = [0x80] -{- | putValue encode an ASN1 value using the shortest definite length -}-putValue :: Value -> Put-putValue = putValuePolicy (\_ len -> if len < 0x80 then LenShort len else LenLong 0 len)+{-| write Bytes of events enumeratee -}+enumWriteBytes :: Monad m => Enumeratee ASN1Event ByteString m a+enumWriteBytes = checkDone $ \k -> k (Chunks []) >>== loop []+	where+		putEoc    = putHeader $ ASN1Header Universal 0 False (LenShort 0)+		loop eocs = checkDone $ go eocs+		go eocs k = E.head >>= \x -> case x of+			Nothing                ->+				if eocs == [] then k (Chunks []) >>== return else E.throwError ASN1WritingUnexpectedInputEOF+			Just (Header hdr@(ASN1Header _ _ True len)) ->+				k (Chunks [putHeader hdr]) >>== loop ((len == LenIndefinite) : eocs)+			Just (Header hdr)      -> k (Chunks [putHeader hdr]) >>== loop eocs+			Just (Primitive p)     -> k (Chunks [p]) >>== loop eocs+			Just ConstructionBegin -> k (Chunks []) >>== loop eocs+			Just ConstructionEnd   -> case eocs of+				[]         -> E.throwError ASN1WritingUnexpectedConstructionEnd+				True : tl  -> k (Chunks [putEoc]) >>== loop tl+				False : tl -> k (Chunks []) >>== loop tl
+ Data/ASN1/Stream.hs view
@@ -0,0 +1,52 @@+module Data.ASN1.Stream+	( ASN1(..)+	, ASN1ConstructionType(..)+	, getConstructedEnd+	) where++import Data.ASN1.Raw+import Data.Text.Lazy (Text)+import Data.ByteString (ByteString)+import qualified Data.ByteString.Lazy as L++data ASN1ConstructionType =+	  Sequence+	| Set+	| Container ASN1Class ASN1Tag+	deriving (Show,Eq)++data ASN1 =+	  Boolean Bool+	| IntVal Integer+	| BitString Int L.ByteString+	| OctetString L.ByteString+	| Null+	| OID [Integer]+	| Real Double+	| Enumerated+	| UTF8String Text+	| NumericString L.ByteString+	| PrintableString Text+	| T61String L.ByteString+	| VideoTexString L.ByteString+	| IA5String Text+	| UTCTime (Int, Int, Int, Int, Int, Int, Bool)+	| GeneralizedTime (Int, Int, Int, Int, Int, Int, Bool)+	| GraphicString L.ByteString+	| VisibleString L.ByteString+	| GeneralString L.ByteString+	| UniversalString Text+	| CharacterString L.ByteString+	| BMPString Text+	| Other ASN1Class ASN1Tag ByteString+	| Start ASN1ConstructionType+	| End ASN1ConstructionType+	deriving (Show, Eq)++getConstructedEnd :: Int -> [ASN1] -> ([ASN1],[ASN1])+getConstructedEnd _ xs@[]                = (xs, xs)+getConstructedEnd i ((x@(Start _)):xs)   = let (yz, zs) = getConstructedEnd (i+1) xs in (x:yz,zs)+getConstructedEnd i ((x@(End _)):xs)+	| i == 0                         = ([], xs)+	| otherwise                      = let (ys, zs) = getConstructedEnd (i-1) xs in (x:ys,zs)+getConstructedEnd i (x:xs)               = let (ys, zs) = getConstructedEnd i xs in (x:ys,zs)
+ Data/ASN1/Types.hs view
@@ -0,0 +1,106 @@+module Data.ASN1.Types+	( ASN1t(..)+	, ofStream+	, toStream+	) where++import qualified Data.ASN1.Stream as S+import qualified Data.ByteString.Lazy as L+import Data.ByteString (ByteString)+import Data.Text.Lazy (Text)+import Data.ASN1.Raw (ASN1Class, ASN1Tag)++data ASN1t =+	  Boolean Bool+	| IntVal Integer+	| BitString Int L.ByteString+	| OctetString L.ByteString+	| Null+	| OID [Integer]+	| Real Double+	| Enumerated+	| UTF8String Text+	| NumericString L.ByteString+	| PrintableString Text+	| T61String L.ByteString+	| VideoTexString L.ByteString+	| IA5String Text+	| UTCTime (Int, Int, Int, Int, Int, Int, Bool)+	| GeneralizedTime (Int, Int, Int, Int, Int, Int, Bool)+	| GraphicString L.ByteString+	| VisibleString L.ByteString+	| GeneralString L.ByteString+	| UniversalString Text+	| CharacterString L.ByteString+	| BMPString Text+	| Other ASN1Class ASN1Tag ByteString+	| Sequence [ASN1t]+	| Set [ASN1t]+	| Container ASN1Class ASN1Tag [ASN1t]+	deriving (Show, Eq)++ofStream :: [S.ASN1] -> [ASN1t]+ofStream []                        = []+ofStream (S.End _ : l)             = ofStream l++ofStream (S.Start ty : l)          =+	let (c, rest) = S.getConstructedEnd 0 l in+	(case ty of+		S.Sequence         -> Sequence (ofStream c)+		S.Set              -> Set (ofStream c)+		S.Container tc tag -> Container tc tag (ofStream c)+	) : ofStream rest++ofStream (S.Boolean b : l)         = Boolean b : ofStream l+ofStream (S.IntVal i : l)          = IntVal i : ofStream l+ofStream (S.BitString i bits : l)  = BitString i bits : ofStream l+ofStream (S.OctetString b : l)     = OctetString b : ofStream l+ofStream (S.Null : l)              = Null : ofStream l+ofStream (S.OID oid : l)           = OID oid : ofStream l+ofStream (S.Real d : l)            = Real d : ofStream l+ofStream (S.Enumerated : l)        = Enumerated : ofStream l +ofStream (S.UTF8String b : l)      = UTF8String b : ofStream l +ofStream (S.NumericString b : l)   = NumericString b : ofStream l +ofStream (S.PrintableString b : l) = PrintableString b : ofStream l +ofStream (S.T61String b : l)       = T61String b : ofStream l +ofStream (S.VideoTexString b : l)  = VideoTexString b : ofStream l +ofStream (S.IA5String b : l)       = IA5String b : ofStream l +ofStream (S.UTCTime t : l)         = UTCTime t : ofStream l +ofStream (S.GeneralizedTime t : l) = GeneralizedTime t : ofStream l +ofStream (S.GraphicString b : l)   = GraphicString b : ofStream l +ofStream (S.VisibleString b : l)   = VisibleString b : ofStream l +ofStream (S.GeneralString b : l)   = GeneralString b : ofStream l +ofStream (S.UniversalString b : l) = UniversalString b : ofStream l +ofStream (S.CharacterString b : l) = CharacterString b : ofStream l +ofStream (S.BMPString b : l)       = BMPString b : ofStream l +ofStream (S.Other c t b : l)       = Other c t b : ofStream l ++toStream :: [ASN1t] -> [S.ASN1]+toStream l = concatMap toStreamOne l+	where+		toStreamOne (Sequence s)          = ([S.Start S.Sequence] ++ toStream s ++ [S.End S.Sequence])+		toStreamOne (Set s)               = ([S.Start S.Set] ++ toStream s ++ [S.End S.Set])+		toStreamOne (Container tc tag s)  = ([S.Start (S.Container tc tag)] ++ toStream s ++ [S.End (S.Container tc tag)])+		toStreamOne (Boolean b)         = [S.Boolean b]+		toStreamOne (IntVal b)          = [S.IntVal b]+		toStreamOne (BitString i b)     = [S.BitString i b]+		toStreamOne (OctetString b)     = [S.OctetString b]+		toStreamOne (Null)              = [S.Null]+		toStreamOne (OID b)             = [S.OID b]+		toStreamOne (Real b)            = [S.Real b]+		toStreamOne (Enumerated)        = [S.Enumerated]+		toStreamOne (UTF8String b)      = [S.UTF8String b]+		toStreamOne (NumericString b)   = [S.NumericString b]+		toStreamOne (PrintableString b) = [S.PrintableString b]+		toStreamOne (T61String b)       = [S.T61String b]+		toStreamOne (VideoTexString b)  = [S.VideoTexString b]+		toStreamOne (IA5String b)       = [S.IA5String b]+		toStreamOne (UTCTime b)         = [S.UTCTime b]+		toStreamOne (GeneralizedTime b) = [S.GeneralizedTime b]+		toStreamOne (GraphicString b)   = [S.GraphicString b]+		toStreamOne (VisibleString b)   = [S.VisibleString b]+		toStreamOne (GeneralString b)   = [S.GeneralString b]+		toStreamOne (UniversalString b) = [S.UniversalString b]+		toStreamOne (CharacterString b) = [S.CharacterString b]+		toStreamOne (BMPString b)       = [S.BMPString b]+		toStreamOne (Other c t b)       = [S.Other c t b]
TODO view
@@ -1,1 +1,4 @@-remove FIXMEs+- remove FIXMEs+- repair CER+- remove deprecated interface and deprecated asn1t types.+- improve testing
Tests.hs view
@@ -1,21 +1,70 @@+--{-# LANGUAGE FlexibleInstances, OverlappingInstances #-}+ import Test.QuickCheck import Text.Printf  import Data.ASN1.Raw-import Data.ASN1.DER (ASN1(..))+import Data.ASN1.Stream (ASN1(..), ASN1ConstructionType(..))+import Data.ASN1.Prim+import qualified Data.ASN1.Types as T (ASN1t(..)) import qualified Data.ASN1.DER as DER+import qualified Data.ASN1.BER as BER -import Data.Binary.Get-import Data.Binary.Put import Data.Word  import qualified Data.ByteString as B import qualified Data.ByteString.Lazy as L import qualified Data.Text.Lazy as T+import qualified Data.Enumerator as E+import Data.Enumerator (($$))  import Control.Monad+import Control.Monad.Identity import System.IO +instance Arbitrary ASN1Class where+	arbitrary = elements [ Universal, Application, Context, Private ]+++instance Arbitrary ASN1Length where+	arbitrary = do+		c <- choose (0,2) :: Gen Int+		case c of+			0 -> liftM LenShort (choose (0,0x79))+			1 -> do+				nb <- choose (0x80,0x1000)+				return $ mkSmallestLength nb+			_ -> return LenIndefinite+		where+			nbBytes nb = if nb > 255 then 1 + nbBytes (nb `div` 256) else 1++arbitraryDefiniteLength :: Gen ASN1Length+arbitraryDefiniteLength = arbitrary `suchThat` (\l -> l /= LenIndefinite)++arbitraryTag :: Gen ASN1Tag+arbitraryTag = choose(0,10000)++instance Arbitrary ASN1Header where+	arbitrary = liftM4 ASN1Header arbitrary arbitraryTag arbitrary arbitrary++arbitraryEvents :: Gen ASN1Events+arbitraryEvents = do+	hdr@(ASN1Header _ _ _ len) <- liftM4 ASN1Header arbitrary arbitraryTag (return False) arbitraryDefiniteLength+	let blen = case len of+		LenLong _ x -> x+		LenShort x  -> x+		_           -> 0+	pr <- liftM Primitive (arbitraryBSsized blen)+	return (ASN1Events [Header hdr, pr])++newtype ASN1Events = ASN1Events [ASN1Event]++instance Show ASN1Events where+	show (ASN1Events x) = show x++instance Arbitrary ASN1Events where+	arbitrary = arbitraryEvents+ arbitraryOID :: Gen [Integer] arbitraryOID = do 	i1  <- choose (0,2) :: Gen Integer@@ -24,11 +73,16 @@ 	l   <- replicateM ran (suchThat arbitrary (\i -> i > 0)) 	return (i1:i2:l) ++arbitraryBSsized :: Int -> Gen B.ByteString+arbitraryBSsized len = do+	ws <- replicateM len (choose (0, 255) :: Gen Int)+	return $ B.pack $ map fromIntegral ws+ instance Arbitrary B.ByteString where 	arbitrary = do 		len <- choose (0, 529) :: Gen Int-		ws <- replicateM len (choose (0, 255) :: Gen Int)-		return $ B.pack $ map fromIntegral ws+		arbitraryBSsized len  instance Arbitrary L.ByteString where 	arbitrary = do@@ -42,22 +96,6 @@ 		ws <- replicateM len arbitrary 		return $ T.pack ws -instance Arbitrary TagClass where-	arbitrary = elements [ Universal, Application, Context, Private ]--arbitraryValueList = choose (0,20) >>= \len -> replicateM len (suchThat arbitrary (not . isConstructed))-	where-		isConstructed (Value _ _ (Constructed _)) = True-		isConstructed _                           = False--instance Arbitrary ValStruct where-	arbitrary = oneof-		[ liftM Primitive arbitrary-		, liftM Constructed arbitraryValueList ]--instance Arbitrary Value where-	arbitrary = liftM3 Value arbitrary (suchThat arbitrary (\i -> i > 0)) arbitrary- arbitraryTime = do 	y <- choose (1951, 2050) 	m <- choose (0, 11)@@ -70,9 +108,9 @@  arbitraryListASN1 = choose (0, 20) >>= \len -> replicateM len (suchThat arbitrary (not . aList)) 	where-		aList (Set _)      = True-		aList (Sequence _) = True-		aList _            = False+		aList (T.Set _)      = True+		aList (T.Sequence _) = True+		aList _              = False  arbitraryPrintString = do 	let printableString = (['a'..'z'] ++ ['A'..'Z'] ++ ['0'..'9'] ++ " ()+,-./:=?")@@ -85,8 +123,7 @@  instance Arbitrary ASN1 where 	arbitrary = oneof-		[ return EOC-		, liftM Boolean arbitrary+		[ liftM Boolean arbitrary 		, liftM IntVal arbitrary 		, liftM2 BitString (choose (0,7)) arbitrary 		, liftM OctetString arbitrary@@ -95,8 +132,6 @@ 		--, Real Double 		-- , return Enumerated 		, liftM UTF8String arbitrary-		, liftM Sequence arbitraryListASN1-		, liftM Set arbitraryListASN1 		, liftM NumericString arbitrary 		, liftM PrintableString arbitraryPrintString 		, liftM T61String arbitrary@@ -110,15 +145,59 @@ 		, liftM UniversalString arbitrary 		] -prop_value_marshalling_id :: Value -> Bool-prop_value_marshalling_id v = (getVal . putVal) v == Right v+instance Arbitrary T.ASN1t where+	arbitrary = oneof+		[ liftM T.Boolean arbitrary+		, liftM T.IntVal arbitrary+		, liftM2 T.BitString (choose (0,7)) arbitrary+		, liftM T.OctetString arbitrary+		, return T.Null+		, liftM T.OID arbitraryOID+		--, Real Double+		-- , return Enumerated+		, liftM T.UTF8String arbitrary+		, liftM T.Sequence arbitraryListASN1+		, liftM T.Set arbitraryListASN1+		, liftM T.NumericString arbitrary+		, liftM T.PrintableString arbitraryPrintString+		, liftM T.T61String arbitrary+		, liftM T.VideoTexString arbitrary+		, liftM T.IA5String arbitraryIA5String+		, liftM T.UTCTime arbitraryTime+		, liftM T.GeneralizedTime arbitraryTime+		, liftM T.GraphicString arbitrary+		, liftM T.VisibleString arbitrary+		, liftM T.GeneralString arbitrary+		, liftM T.UniversalString arbitrary+		]++prop_header_marshalling_id :: ASN1Header -> Bool+prop_header_marshalling_id v = (getHeader . putHeader) v == Right v++prop_event_marshalling_id :: ASN1Events -> Bool+prop_event_marshalling_id (ASN1Events e) =+	let r = runIdentity $ E.run (E.enumList 1 e $$ E.joinI $ enumWriteReadBytes $$ E.consume) in+	case r of+		Left _  -> False+		Right z -> e == z 	where-		getVal = runGetErr getValue-		putVal = runPut . putValue+		enumWriteReadBytes = \f -> E.joinI (enumWriteBytes $$ (enumReadBytes f)) -prop_asn1_marshalling_id :: ASN1 -> Bool-prop_asn1_marshalling_id v = (DER.decodeASN1 . DER.encodeASN1) v == Right v+prop_asn1_event_marshalling_id :: ASN1 -> Bool+prop_asn1_event_marshalling_id x =+	let r = runIdentity $ E.run (E.enumList 1 [x] $$ E.joinI $ enumWriteReadRaw $$ E.consume) in+	case r of+		Left _  -> False+		Right z -> [x] == z+	where+		enumWriteReadRaw = \f -> E.joinI (BER.enumWriteRaw $$ (BER.enumReadRaw f)) +prop_asn1_ber_marshalling_id :: T.ASN1t -> Bool+prop_asn1_ber_marshalling_id v = (BER.decodeASN1 . BER.encodeASN1) v == Right v++prop_asn1_der_marshalling_id :: T.ASN1t -> Bool+prop_asn1_der_marshalling_id v = (DER.decodeASN1 . DER.encodeASN1) v == Right v+ args = stdArgs 	{ replay     = Nothing 	, maxSuccess = 500@@ -129,5 +208,8 @@ run_test n t = putStr ("  " ++ n ++ " ... ") >> hFlush stdout >> quickCheckWith args t  main = do-	run_test "marshalling value = id" prop_value_marshalling_id-	run_test "marshalling asn1 = id" prop_asn1_marshalling_id+	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 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,7 +1,9 @@ Name:                asn1-data-Version:             0.3.0+Version:             0.4.0 Description:-    ASN1 data reader and writer in raw form with supports for high level forms of ASN1 (BER, CER and DER)+    ASN1 data reader and writer in raw form with supports for high level forms of ASN1 (BER, CER and DER).+    .+    All interfaces use the enumerator interface. License:             BSD3 License-file:        LICENSE Copyright:           Vincent Hanquez <vincent@snarc.org>@@ -22,14 +24,18 @@  Library   Build-Depends:     base >= 3 && < 7,-                     binary >= 0.5,                      bytestring,                      text >= 0.11,+                     enumerator >= 0.4 && < 0.5,+                     attoparsec >= 0.8 && < 0.9,+                     attoparsec-enumerator >= 0.2 && < 0.3,                      mtl   Exposed-modules:   Data.ASN1.BER                      Data.ASN1.CER                      Data.ASN1.DER                      Data.ASN1.Raw+                     Data.ASN1.Types+                     Data.ASN1.Stream   other-modules:     Data.ASN1.Prim                      Data.ASN1.Internal   ghc-options:       -Wall