-- |-- Module : Data.ASN1.BER-- License : BSD-style-- Maintainer : Vincent Hanquez <vincent@snarc.org>-- Stability : experimental-- Portability : unknown---- A module containing ASN1 BER specification serialization/derialization tools--moduleData.ASN1.BER(ASN1Class(..),ASN1(..),ASN1ConstructionType(..)-- * enumeratee to transform between ASN1 and raw,enumReadRawRepr,enumReadRaw,enumWriteRaw-- * enumeratee to transform between ASN1 and bytes,enumReadBytes,enumWriteBytes-- * 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,decodeASN1,decodeASN1s,encodeASN1,encodeASN1s)whereimportData.ASN1.Raw(ASN1Header(..),ASN1Class(..),ASN1Err(..))importqualifiedData.ASN1.RawasRawimportData.ASN1.StreamimportData.ASN1.Types(ofStream,toStream,ASN1t)importData.ASN1.PrimimportControl.Monad.IdentityimportControl.ExceptionimportqualifiedData.ByteString.LazyasLimportData.ByteString(ByteString)importData.Enumerator.Binary(enumFile)importData.Enumerator(Iteratee(..),Enumeratee,($$),(>>==))importqualifiedData.EnumeratorasEimportqualifiedData.Enumerator.ListasELdecodeConstruction::ASN1Header->ASN1ConstructionTypedecodeConstruction(ASN1HeaderUniversal0x10__)=SequencedecodeConstruction(ASN1HeaderUniversal0x11__)=SetdecodeConstruction(ASN1Headerct__)=Containerct{- | enumerate from 'Raw.ASN1Event' to an 'ASN1Repr' (ASN1 augmented by a list of raw asn1 events)
-}enumReadRawRepr::Monadm=>EnumerateeRaw.ASN1EventASN1ReprmaenumReadRawRepr=E.checkDone$\k->k(E.Chunks[])>>==loop[]whereloopl=E.checkDone$golgolk=EL.head>>=\x->casexofNothing->ifl==[]thenk(E.Chunks[])>>==returnelseE.throwError(Raw.ASN1ParsingPartial)Justel->plkel{- on construction end, we pop the list context -}plkRaw.ConstructionEnd=k(E.Chunks[headl])>>==loop(taill){- 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 -}plkel@(Raw.Headerhdr@(ASN1Header__True_))=EL.head>>=\z->casezofJustel2@Raw.ConstructionBegin->letctype=decodeConstructionhdrink(E.Chunks[(Startctype,[el,el2])])>>==loop((Endctype,[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 -}plkel@(Raw.Headerhdr@(ASN1Header__False_))=EL.head>>=\z->casezofJustel2@(Raw.Primitiveprim)->let(Rightpr)=decodePrimitivehdrprimink(E.Chunks[(pr,[el,el2])])>>==looplJust_->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::Monadm=>EnumerateeRaw.ASN1EventASN1maenumReadRaw=\f->E.joinI(enumReadRawRepr$$(E.mapfstf)){- | enumWriteRaw is an enumeratee from asn1 to raw events -}enumWriteRaw::Monadm=>EnumerateeASN1Raw.ASN1EventmaenumWriteRaw=\f->E.joinI(enumWriteTree$$(enumWriteTreeRawf))enumWriteTree::Monadm=>EnumerateeASN1(ASN1,[ASN1])maenumWriteTree=doE.checkDone$\k->k(E.Chunks[])>>==loopwhereloop=E.checkDone$gogok=EL.head>>=\x->casexofNothing->k(E.Chunks[])>>==returnJustn@(Start_)->consumeTillEnd>>=\y->k(E.Chunks[(n,y)])>>==loopJustp->k(E.Chunks[(p,[])])>>==loopconsumeTillEnd::Monadm=>IterateeASN1m[ASN1]consumeTillEnd=E.liftI$step(1::Int)idwheresteplaccchunk=casechunkofE.Chunks[]->E.Continue$E.returnI.steplaccE.Chunksxs->dolet(ys,zs)=spanEndlxsletnbend=length$filterisEndysletnbstart=length$filterisStartysletnl=l-nbend+nbstartifnl==0thenE.Yield(accys)(E.Chunkszs)elseE.Continue$E.returnI.(stepnl$acc.(ys++))E.EOF->E.Yield(acc[])E.EOFspanEnd::Int->[ASN1]->([ASN1],[ASN1])spanEnd_[]=([],[])spanEnd0(x@(End_):xs)=([x],xs)spanEnd0(x@(Start_):xs)=let(ys,zs)=spanEnd1xsin(x:ys,zs)spanEnd0(x:xs)=let(ys,zs)=spanEnd0xsin(x:ys,zs)spanEndl(x:xs)=casexofStart_->let(ys,zs)=spanEnd(l+1)xsin(x:ys,zs)End_->let(ys,zs)=spanEnd(l-1)xsin(x:ys,zs)_->let(ys,zs)=spanEndlxsin(x:ys,zs)isStart(Start_)=TrueisStart_=FalseisEnd(End_)=TrueisEnd_=FalseenumWriteTreeRaw::Monadm=>Enumeratee(ASN1,[ASN1])Raw.ASN1EventmaenumWriteTreeRaw=E.concatMapwriteTreewherewriteTree(p,children)=snd$casepofStart_->encodeConstructedpchildren_->encodePrimitivep{-| enumReadBytes is an enumeratee converting from bytestring to ASN1
it transforms chunks of bytestring into chunks of ASN1 objects -}enumReadBytes::Monadm=>EnumerateeByteStringASN1maenumReadBytes=\f->E.joinI(Raw.enumReadBytes$$(enumReadRawf)){-| enumReadBytes is an enumeratee converting from bytestring to ASN1
it transforms chunks of bytestring into chunks of ASN1 objects -}enumReadBytesRepr::Monadm=>EnumerateeByteStringASN1ReprmaenumReadBytesRepr=\f->E.joinI(Raw.enumReadBytes$$(enumReadRawReprf)){-| enumWriteBytes is an enumeratee converting from ASN1 to bytestring.
it transforms chunks of ASN1 objects into chunks of bytestring -}enumWriteBytes::Monadm=>EnumerateeASN1ByteStringmaenumWriteBytes=\f->E.joinI(enumWriteRaw$$(Raw.enumWriteBytesf)){-| iterate over a file using a file enumerator. -}iterateFile::FilePath->IterateeASN1IOa->IO(EitherSomeExceptiona)iterateFilepathp=E.run(enumFilepath$$E.joinI$enumReadBytes$$p){-| iterate over a bytestring using a list enumerator over each chunks -}iterateByteString::Monadm=>L.ByteString->IterateeASN1ma->m(EitherSomeExceptiona)iterateByteStringbsp=E.run(E.enumList1(L.toChunksbs)$$E.joinI$enumReadBytes$$p){-| iterate over a bytestring using a list enumerator over each chunks -}iterateByteStringRepr::Monadm=>L.ByteString->IterateeASN1Reprma->m(EitherSomeExceptiona)iterateByteStringReprbsp=E.run(E.enumList1(L.toChunksbs)$$E.joinI$enumReadBytesRepr$$p){-| iterate over asn1 events using a list enumerator over each chunks -}iterateEvents::Monadm=>[Raw.ASN1Event]->IterateeASN1ma->m(EitherSomeExceptiona)iterateEventsevsp=E.run(E.enumList8evs$$E.joinI$enumReadRaw$$p){-| iterate over asn1 events using a list enumerator over each chunks -}iterateEventsRepr::Monadm=>[Raw.ASN1Event]->IterateeASN1Reprma->m(EitherSomeExceptiona)iterateEventsReprevsp=E.run(E.enumList8evs$$E.joinI$enumReadRawRepr$$p){- helper to transform a Someexception from the enumerator to an ASN1Err if possible -}wrapASN1Err::EitherSomeExceptiona->EitherASN1ErrawrapASN1Err(Lefterr)=Left(maybe(ASN1ParsingFail"unknown")id$fromExceptionerr)wrapASN1Err(Rightx)=Rightx{-| decode a list of raw ASN1Events into a stream of ASN1 types -}decodeASN1Events::[Raw.ASN1Event]->EitherASN1Err[ASN1]decodeASN1Eventsevs=wrapASN1Err$runIdentity(iterateEventsevsEL.consume){-| decode a list of raw ASN1Events into a stream of ASN1Repr types -}decodeASN1EventsRepr::[Raw.ASN1Event]->EitherASN1Err[ASN1Repr]decodeASN1EventsReprevs=wrapASN1Err$runIdentity(iterateEventsReprevsEL.consume){-| decode a lazy bytestring as an ASN1 stream -}decodeASN1Stream::L.ByteString->EitherASN1Err[ASN1]decodeASN1Streaml=wrapASN1Err$runIdentity(iterateByteStringlEL.consume){-| decode a lazy bytestring as an ASN1repr stream -}decodeASN1StreamRepr::L.ByteString->EitherASN1Err[ASN1Repr]decodeASN1StreamReprl=wrapASN1Err$runIdentity(iterateByteStringReprlEL.consume){-| encode an ASN1 Stream as raw ASN1 Events -}encodeASN1Events::[ASN1]->EitherASN1Err[Raw.ASN1Event]encodeASN1Eventso=wrapASN1Err$runIdentityrunwhererun=E.run(E.enumList8o$$E.joinI$enumWriteRaw$$EL.consume){-| encode an ASN1 Stream as lazy bytestring -}encodeASN1Stream::[ASN1]->EitherASN1ErrL.ByteStringencodeASN1Streaml=eitherLeft(Right.L.fromChunks)$wrapASN1Err$runIdentityrunwhererun=E.run(E.enumList1l$$E.joinI$enumWriteBytes$$EL.consume){-# DEPRECATED decodeASN1s "use stream types with decodeASN1Stream" #-}decodeASN1s::L.ByteString->EitherASN1Err[ASN1t]decodeASN1s=either(Left)(Right.ofStream).decodeASN1Stream{-# DEPRECATED decodeASN1 "use stream types with decodeASN1Stream" #-}decodeASN1::L.ByteString->EitherASN1ErrASN1tdecodeASN1=either(Left)(Right.head.ofStream).decodeASN1Stream{-# DEPRECATED encodeASN1s "use stream types with encodeASN1Stream" #-}encodeASN1s::[ASN1t]->L.ByteStringencodeASN1ss=caseencodeASN1Stream$toStreamsofLefterr->error$showerrRightx->x{-# DEPRECATED encodeASN1 "use stream types with encodeASN1Stream" #-}encodeASN1::ASN1t->L.ByteStringencodeASN1s=caseencodeASN1Stream$toStream[s]ofLefterr->error$showerrRightx->x