module Main(main) where import Data.Char import Data.Maybe import Control.Monad.Error import Control.Monad.State import Language.ASN1.BER import Language.ASN1 import Test.HUnit {- Some of the ASN.1 definitions are taken from various standards and these are annotated with references. The other ASN.1 definitions have been created specifically to check decoding. These have been checked using the on-line tool, Asnp, available at http://asn1.elibel.tm.fr/en/tools/asnp/index.htm Notes: Definitions using ANY DEFINED BY have to be checked with -1990 option. Asnp was developed in Objective Caml. -} expectSuccess testName asnType berValue expectedAbsValue = TestCase $ do (w,x) <- typeCheck asnType berValue let (_ ::= c) = w d = decode c (Just x) (Just y) = d assertEqual testName expectedAbsValue y expectFailure testName asnType berValue expectedError = TestCase $ do x <- (do y <- typeCheck asnType berValue return "Unexpected successful typechecking") `catchError` (\e -> return $ show e) assertEqual testName x expectedError {- Some tagged value tests. See 8.14.3 of X.690 (ISO 8825-1). Type1 ::= VisibleString Type2 ::= [APPLICATION 3] IMPLICIT Type1 Type3 ::= [2] Type2 Type4 ::= [APPLICATION 7] IMPLICIT Type3 Type5 ::= [2] IMPLICIT Type2 -} type1' = modName "Type1" absVisibleString type Type1 = VisibleString jones1 = Primitive Universal 26 5 [0x4a,0x6f,0x6e,0x65,0x73] decodedJones1 = VisibleString "Jones" tagTest1 = expectSuccess "Type1" type1' jones1 decodedJones1 type2 = "Type2" ::= AbsRef Application 3 Implicit type1' data Type2 = Type2 VisibleString deriving (Eq,Show) instance Encode Type2 where decode a b = do x <- decode a b return $ Type2 x jones2 = Primitive Application 3 5 [0x4a,0x6f,0x6e,0x65,0x73] decodedJones2 = Type2 decodedJones1 tagTest2 = expectSuccess "Type2" type2 jones2 decodedJones2 type3 = "Type3" ::= AbsRef Context 2 Explicit type2 data Type3 = Type3 Type2 deriving (Eq,Show) instance Encode Type3 where decode a b = do y <- b let a' = absRefedType a b' = (encodedDefComps y)!!0 x <- decode a' b' return $ Type3 x jones3 = Constructed Context 2 7 [jones2] decodedJones3 = Type3 decodedJones2 tagTest3 = expectSuccess "Type3" type3 jones3 decodedJones3 type4 = "Type4" ::= AbsRef Application 7 Implicit type3 jones4 = Constructed Application 7 7 [jones2] data Type4 = Type4 Type3 deriving (Eq,Show) instance Encode Type4 where decode a b = do x <- decode a b return $ Type4 x decodedJones4 = Type4 decodedJones3 tagTest4 = expectSuccess "Type4" type4 jones4 decodedJones4 {- Some tests for OPTIONAL components. -} {- Journey ::= SEQUENCE { origin IA5String, stop1 [0] IA5String OPTIONAL, stop2 [1] IA5String OPTIONAL, destination IA5String } -} journey = "Journey" ::= AbsSeq Universal 16 Implicit [ Regular (Just "origin" :>: (Nothing :@: absIA5String)), Optional (Just "stop1" :>: (Just 0 :@: absIA5String)), Optional (Just "stop2" :>: (Just 1 :@: absIA5String)), Regular (Just "destination" :>: (Nothing :@: absIA5String)) ] j1 = Constructed Universal 16 24 [ Primitive Universal 22 3 [97,97,98], Primitive Context 0 3 [99,100,101], Primitive Context 1 3 [102,103,104], Primitive Universal 22 3 [97,97,98] ] j2 = Constructed Universal 16 24 [ Primitive Universal 22 3 [97,97,98], Primitive Context 1 3 [102,103,104], Primitive Universal 22 3 [97,97,98] ] data Journey = Journey { origin :: IA5String, stop1 :: Maybe IA5String, stop2 :: Maybe IA5String, destination :: IA5String } deriving (Eq,Show) instance Encode Journey where decode a b = do x <- b let as = absSeqComponents a bs = encodedDefComps x return $ Journey { origin = fromJust (decode (as!!0) (bs!!0)), stop1 = do decode (as!!1) (bs!!1), stop2 = do decode (as!!2) (bs!!2), destination = fromJust (decode (as!!3) (bs!!3)) } decodedJ1 = Journey { origin = IA5String "aab", stop1 = Just $ IA5String "cde", stop2 = Just $ IA5String "fgh", destination = IA5String "aab" } decodedJ2 = Journey { origin = IA5String "aab", stop1 = Nothing, stop2 = Just $ IA5String "fgh", destination = IA5String "aab" } journeyTest1 = expectSuccess "Journey1" journey j1 decodedJ1 journeyTest2 = expectSuccess "Journey2" journey j2 decodedJ2 {- Odyssey ::= SEQUENCE { start Journey, trip1 [0] Journey OPTIONAL, trip2 [1] Journey OPTIONAL, trip3 [2] Journey OPTIONAL, end Journey } -} odyssey = "Odyssey" ::= AbsSeq Universal 16 Implicit [ Regular (Just "start" :>: (Nothing :@: journey)), Optional (Just "trip1" :>: (Just 0 :@: journey)), Optional (Just "trip2" :>: (Just 1 :@: journey)), Optional (Just "trip3" :>: (Just 2 :@: journey)), Regular (Just "end" :>: (Nothing :@: journey)) ] prej1 = [ Primitive Universal 22 3 [97,97,98], Primitive Context 0 3 [99,100,101], Primitive Context 1 3 [102,103,104], Primitive Universal 22 3 [97,97,98] ] o1 = Constructed Universal 16 130 [ j1, Constructed Context 0 26 prej1, Constructed Context 1 26 prej1, Constructed Context 2 26 prej1, j1 ] o2 = Constructed Universal 16 52 [ j1, j1 ] data Odyssey = Odyssey { start :: Journey, trip1 :: Maybe Journey, trip2 :: Maybe Journey, trip3 :: Maybe Journey, end :: Journey } deriving (Eq,Show) instance Encode Odyssey where decode a b = do x <- b let as = absSeqComponents a bs = encodedDefComps x return $ Odyssey { start = fromJust (decode (as!!0) (bs!!0)), trip1 = do decode (as!!1) (bs!!1), trip2 = do decode (as!!2) (bs!!2), trip3 = do decode (as!!3) (bs!!3), end = fromJust (decode (as!!4) (bs!!4)) } decodedO1 = Odyssey { start = decodedJ1, trip1 = Just decodedJ1, trip2 = Just decodedJ1, trip3 = Just decodedJ1, end = decodedJ1 } decodedO2 = Odyssey { start = decodedJ1, trip1 = Nothing, trip2 = Nothing, trip3 = Nothing, end = decodedJ1 } odysseyTest1 = expectSuccess "Odyssey1" odyssey o1 decodedO1 odysseyTest2 = expectSuccess "Odyssey2" odyssey o2 decodedO2 {- FunnyOptional ::= SEQUENCE { perhaps [0] IA5String OPTIONAL } -} funnyOptional = "FunnyOptional" ::= AbsSeq Universal 16 Implicit [ Optional (Just "perhaps" :>: (Just 0 :@: absIA5String)) ] fo1 = Constructed Universal 16 7 [ Primitive Context 0 3 [97,97,98] ] fo2 = Constructed Universal 16 0 [] data FunnyOptional = FunnyOptional { perhaps :: Maybe IA5String } deriving (Eq,Show) instance Encode FunnyOptional where decode a b = do x <- b let as = absSeqComponents a bs = encodedDefComps x return $ FunnyOptional { perhaps = do decode (as!!0) (bs!!0) } decodedFO1 = FunnyOptional { perhaps = Just $ IA5String "aab" } funnyOptionalTest1 = expectSuccess "FunnyOptional1" funnyOptional fo1 decodedFO1 decodedFO2 = FunnyOptional { perhaps = Nothing } funnyOptionalTest2 = expectSuccess "FunnyOptional2" funnyOptional fo2 decodedFO2 {- Some ANY DEFINED BY tests. See the former versions of the ASN.1 standards, X.208 and X.209, sometimes referred to as ASN.1:1988 or ASN.1:1990. This was used in some definitions of X.509 certificates, for example: AlgorithmIdentifier ::= SEQUENCE { algorithm OBJECT IDENTIFIER, parameters ANY DEFINED BY algorithm OPTIONAL } -- contains a value of the type -- registered for use with the -- algorithm object identifier value -} {- TextBook = SEQUENCE { author PrintableString, citationType OID, reference ANY DEFINED BY CitationType } -} textBook = "TextBook" ::= AbsSeq Universal 16 Implicit [Regular (Just "author" :>: (Nothing :@: absPrintableString)), Regular (Just "citationType" :>: (Nothing :@: absOID)), AnyDefBy 1] data TextBook = TextBook { author :: PrintableString, citationType :: OID, reference :: PrintableString } deriving (Eq,Show) instance Encode TextBook where decode a b = do x <- b let as = absSeqComponents a bs = encodedDefComps x return $ TextBook { author = fromJust $ decode (as!!0) (bs!!0), citationType = fromJust $ decode (as!!1) (bs!!1), reference = fromJust $ decode (as!!2) (bs!!2) } encodedPrintableString1 = Primitive Universal 19 5 [104,101,108,108,111] encodedPrintableString2 = Primitive Universal 19 5 [105,101,108,108,111] encodedPrintableString3 = Primitive Universal 19 5 [106,101,108,108,111] encodedPrintableString4 = Primitive Universal 19 5 [107,101,108,108,111] encodedOID1 = Primitive Universal 6 3 [85,4,7] encodedTextBook1 = Constructed Universal 16 13 [ encodedPrintableString1, encodedOID1 ] decodedTextBook1 = "user error (Checking AnyDefBy 1: insufficient components)" encodedTextBook2 = Constructed Universal 16 13 [ encodedPrintableString1, encodedOID1, encodedPrintableString2 ] decodedTextBook2 = TextBook { author = PrintableString "hello", citationType = OID [2,5,4,7], reference = PrintableString "iello" } encodedTextBook3 = Constructed Universal 16 13 [ encodedPrintableString3, encodedOID1, encodedPrintableString4 ] decodedTextBook3 = TextBook { author = PrintableString "jello", citationType = OID [2,5,4,7], reference = PrintableString "kello" } textBookTest1 = expectFailure "TextBook1" textBook encodedTextBook1 decodedTextBook1 textBookTest2 = expectSuccess "TextBook2" textBook encodedTextBook2 decodedTextBook2 textBookTest3 = expectSuccess "TextBook3" textBook encodedTextBook3 decodedTextBook3 library = "Library" ::= AbsSeq Universal 16 Implicit [Regular (Just "first" :>: (Nothing :@: textBook)), Regular (Just "second" :>: (Nothing :@: textBook))] data Library = Library { first :: TextBook, second :: TextBook } deriving (Eq,Show) instance Encode Library where decode a b = do x <- b let as = absSeqComponents a bs = encodedDefComps x return $ Library { first = fromJust $ decode (as!!0) (bs!!0), second = fromJust $ decode (as!!1) (bs!!1) } encodedLibrary = Constructed Universal 16 28 [encodedTextBook2,encodedTextBook3] decodedLibrary = Library { first = decodedTextBook2, second = decodedTextBook3 } libraryTest = expectSuccess "Library1" library encodedLibrary decodedLibrary v1 = Primitive Universal 26 5 [104,101,108,108,111] -- Valid v2 = Primitive Universal 26 5 [103,101,108,108,111] -- Valid v3 = Primitive Universal 26 5 [31,101,108,108,111] -- Not valid VisibleString expectedv1 = VisibleString "hello" expectedv2 = VisibleString "gello" expectedv3 = "user error (Checking \"VisibleString\": type not compatible " ++ "with values [31,101,108,108,111])" visibleStringTest1 = expectSuccess "VisibleString1" absVisibleString v1 expectedv1 visibleStringTest2 = expectSuccess "VisibleString2" absVisibleString v2 expectedv2 visibleStringTest3 = expectFailure "VisibleString3" absVisibleString v3 expectedv3 {- A modified version of the example in Annex A of X.690 (ISO 8825-1). -} {- Name ::= [APPLICATION 1] IMPLICIT SEQUENCE {givenName VisibleString, initial VisibleString, familyName VisibleString} -} name = "Name" ::= AbsSeq Application 1 Implicit [ Regular (Just "givenName" :>: (Nothing :@: absVisibleString)), Regular (Just "initial" :>: (Nothing :@: absVisibleString)), Regular (Just "familyName" :>: (Nothing :@: absVisibleString)) ] data Name = Name {givenName :: VisibleString, initial :: VisibleString, familyName :: VisibleString} deriving (Eq,Show) instance Encode Name where decode a b = do x <- b let as = absSeqComponents a bs = encodedDefComps x return $ Name { givenName = fromJust $ decode (as!!0) (bs!!0), initial = fromJust $ decode (as!!1) (bs!!1), familyName = fromJust $ decode (as!!2) (bs!!2) } n1 = Constructed Application 1 14 [v1,v2] -- Invalid number -- of components n2 = Constructed Application 1 14 [v1] -- Invalid number -- of components n3 = Constructed Application 1 14 [] -- Invalid number -- of components n4 = Constructed Application 1 14 [v1,v2,v1] -- Valid n5 = Constructed Application 1 14 [v1,v2,v3] -- Invalid component expectedn1 = "user error (Checking Regular (Just \"familyName\" :>: " ++ "(Nothing :@: (\"VisibleString\" ::= " ++ "AbsBasePrim Universal 26 AbsVisibleString))): " ++ "insufficient components)" nameTest1 = expectFailure "Name1" name n1 expectedn1 expectedn2 = "user error (Checking Regular (Just \"initial\" :>: " ++ "(Nothing :@: (\"VisibleString\" ::= " ++ "AbsBasePrim Universal 26 AbsVisibleString))): " ++ "insufficient components)" nameTest2 = expectFailure "Name2" name n2 expectedn2 expectedn3 = "user error (Checking Regular (Just \"givenName\" :>: " ++ "(Nothing :@: (\"VisibleString\" ::= " ++ "AbsBasePrim Universal 26 AbsVisibleString))): " ++ "insufficient components)" nameTest3 = expectFailure "Name3" name n3 expectedn3 expectedn4 = Name { givenName = VisibleString "hello", initial = VisibleString "gello", familyName = VisibleString "hello" } nameTest4 = expectSuccess "Name4" name n4 expectedn4 expectedn5 = "user error (Checking \"VisibleString\": " ++ "type not compatible with values [31,101,108,108,111])" nameTest5 = expectFailure "Name5" name n5 expectedn5 {- EmployeeNumber ::= [APPLICATION 2] IMPLICIT INTEGER -} employeeNumber = "EmployeeNumber" ::= AbsRef Application 2 Implicit absInteger data EmployeeNumber = EmployeeNumber Integer deriving (Eq,Show) instance Encode EmployeeNumber where decode a b = do x <- decode a b return $ EmployeeNumber x en1 = Primitive Application 2 1 [0x33] decodedEN1 = EmployeeNumber 51 enTest1 = expectSuccess "EmployeeNumber1" employeeNumber en1 decodedEN1 {- Date ::= [APPLICATION 3] IMPLICIT VisibleString -- YYYYMMDD -} date = "Date" ::= AbsRef Application 3 Implicit absVisibleString data Date = Date VisibleString deriving (Eq,Show) instance Encode Date where decode a b = do x <- decode a b return $ Date x b = "30/03/2003 19:37:34 GMT" a = "30/03/2004 19:37:34 GMT" nb = map (fromIntegral . ord) b na = map (fromIntegral . ord) a d1 = Constructed Application 3 7 [Primitive Universal 23 23 na] -- Invalid d2 = Primitive Application 3 6 nb -- Valid expectedD1 = "user error (Checking \"Date\": " ++ "expected PRIMITIVE Tag found CONSTRUCTED Tag\n" ++ "\"Date\" ::= AbsBasePrim Application 3 AbsVisibleString\n" ++ show d1 ++ ")" decodedD2 = Date $ VisibleString b dateTest1 = expectFailure "Date1" date d1 expectedD1 dateTest2 = expectSuccess "Date2" date d2 decodedD2 {- ChildInformation ::= SEQUENCE { name Name, dateOfBirth [0] Date} -} childInformation = "ChildInformation" ::= AbsSeq Universal 16 Implicit [ Regular (Just "name" :>: (Nothing :@: name)), Regular (Just "dateOfBirth" :>: (Just 0 :@: date)) ] data ChildInformation = ChildInformation { name1 :: Name, dateOfBirth :: Date } deriving (Eq,Show) instance Encode ChildInformation where decode a b = do x <- b let as = absSeqComponents a bs = encodedDefComps x return $ ChildInformation { name1 = fromJust $ decode (as!!0) (bs!!0), dateOfBirth = fromJust $ decode (as!!1) (bs!!1) } ci1 = Constructed Universal 16 28 [n4,Primitive Context 0 6 nb] expectedCI1 = ChildInformation { name1 = expectedn4, dateOfBirth = decodedD2 } ciTest1 = expectSuccess "ChildInformation1" childInformation ci1 expectedCI1 {- PersonnelRecord ::= [APPLICATION 0] IMPLICIT SEQUENCE { name Name, title [0] VisibleString, number EmployeeNumber, dateOfHire [1] Date, nameOfSpouse [2] Name, children [3] IMPLICIT SEQUENCE OF ChildInformation DEFAULT {} } -} personnelRecord = "PersonnelRecord" ::= AbsSeq Application 0 Implicit [ Regular (Just "name" :>: (Nothing :@: name)), Regular (Just "title" :>: (Just 0 :@: absVisibleString)), Regular (Just "number" :>: (Nothing :@: employeeNumber)), Regular (Just "dateOfHire" :>: (Just 1 :@: date)), Regular (Just "nameOfSpouse" :>: (Just 2 :@: name)), Regular ( Just "children" :>: ( Just 3 :@: ( "SEQUENCE OF ChildInformation" ::= AbsSeqOf Universal 16 Implicit childInformation ) ) ) ] data PersonnelRecord = PersonnelRecord {name2 :: Name, title :: VisibleString, number :: EmployeeNumber, dateOfHire :: Date, nameOfSpouse :: Name, children :: [ChildInformation]} deriving (Eq,Show) instance Encode PersonnelRecord where decode a b = do x <- b let as = absSeqComponents a bs = encodedDefComps x return $ PersonnelRecord { name2 = fromJust $ decode (as!!0) (bs!!0), title = fromJust $ decode (as!!1) (bs!!1), number = fromJust $ decode (as!!2) (bs!!2), dateOfHire = fromJust $ decode (as!!3) (bs!!3), nameOfSpouse = fromJust $ decode (as!!4) (bs!!4), children = fromJust $ decode (as!!5) (bs!!5)} pr1 = Constructed Application 0 23 [ n4, Primitive Context 0 5 [104,101,108,108,111], en1, Primitive Context 1 6 nb, Constructed Context 2 14 [v1,v2,v1], Constructed Context 3 30 [ci1] -- Constructed Context 3 18 [Constructed Universal 16 16 [ci1]] ] decodedpr1 = PersonnelRecord { name2 = expectedn4, title = expectedv1, number = decodedEN1, dateOfHire = decodedD2, nameOfSpouse = expectedn4, children = [expectedCI1] } prTest1 = expectSuccess "PersonnelRecord1" personnelRecord pr1 decodedpr1 taggedRecord = "PersonnelRecord" ::= AbsSeq Application 0 Implicit [ Regular (Just "name" :>: (Nothing :@: name)), Regular (Just "nameOfSpouse" :>: (Just 2 :@: name)) ] tr1 = Constructed Application 0 23 [ n4, Constructed Context 2 14 [v1,v2,v1] ] taggedRecord1 = "PersonnelRecord" ::= AbsSeq Application 0 Implicit [ Regular (Just "name" :>: (Nothing :@: name)), Regular (Just "title" :>: (Just 0 :@: absVisibleString)), Regular (Just "number" :>: (Nothing :@: employeeNumber)), Regular (Just "dateOfHire" :>: (Just 1 :@: date)), Regular (Just "nameOfSpouse" :>: (Just 2 :@: name)), Regular (Just "another" :>: (Just 3 :@: name)) ] tr2 = Constructed Application 0 23 [ n4, Primitive Context 0 5 [104,101,108,108,111], en1, Primitive Context 1 6 nb, Constructed Context 2 14 [v1,v2,v1], Constructed Context 3 14 [v1,v2,v1] ] taggedRecord2 = "PersonnelRecord" ::= AbsSeq Application 0 Implicit [ Regular (Just "name" :>: (Nothing :@: name)), Regular ( Just "children" :>: ( Just 3 :@: ( "SEQUENCE OF ChildInformation" ::= AbsSeqOf Universal 16 Implicit childInformation ) ) ) ] tr3 = Constructed Application 0 23 [ n4, Constructed Context 3 18 [Constructed Universal 16 16 [ci1]] ] taggedRecord3 = "TaggedRecord3" ::= AbsSeq Application 0 Implicit [ Regular ( Just "children" :>: ( Just 3 :@: ( "SEQUENCE OF ChildInformation" ::= AbsSeqOf Universal 16 Implicit childInformation ) ) ) ] tr4 = Constructed Application 0 23 [ Constructed Context 3 18 [Constructed Universal 16 16 [ci1]] ] sequenceOfChildInformation = "SEQUENCE OF ChildInformation" ::= AbsSeqOf Universal 16 Implicit childInformation soci1 = Constructed Universal 16 30 [ci1] tr5 = Constructed Application 0 32 [ Constructed Context 3 30 [ci1] ] taggedRecord4 = "TaggedRecord3" ::= AbsSeq Application 0 Implicit [ Regular (Just "children" :>: (Just 3 :@: sequenceOfChildInformation)) ] {- Choice1 ::= CHOICE { z1 [0] EmployeeNumber, z2 [1] EmployeeNumber, z3 [2] EmployeeNumber } A ::= CHOICE { b B, c C } B ::= CHOICE { d [0] NULL, e [1] NULL } C ::= CHOICE { f [2] NULL, g [3] NULL } -} choice1 = "Choice1" ::= AbsChoice [ (Implicit, Just "z1" :>: (Just 0 :@: employeeNumber)), (Implicit, Just "z2" :>: (Just 1 :@: employeeNumber)), (Implicit, Just "z3" :>: (Just 2 :@: employeeNumber)) ] c1 = Primitive Context 0 1 [0x33] c2 = Primitive Context 1 1 [0x33] c3 = Primitive Context 2 1 [0x33] c4 = Primitive Context 3 1 [0x33] decodedC1 = Z1 (EmployeeNumber' 51) decodedC2 = Z2 (EmployeeNumber' 51) decodedC3 = Z3 (EmployeeNumber' 51) data Choice1 = Z1 EmployeeNumber' | Z2 EmployeeNumber' | Z3 EmployeeNumber' deriving (Eq,Show) instance Encode Choice1 where decode a b = do x <- b let t = defaultedTagValue x case t of 0 -> do foo <- decode a b return $ Z1 foo 1 -> do foo <- decode a b return $ Z2 foo 2 -> do foo <- decode a b return $ Z3 foo {- EmployeeNumber ::= [APPLICATION 2] IMPLICIT INTEGER -} employeeNumber' = "EmployeeNumber" ::= AbsRef Application 2 Implicit absInteger data EmployeeNumber' = EmployeeNumber' Integer deriving (Eq,Show) instance Encode EmployeeNumber' where decode a b = do x <- decode a b return $ EmployeeNumber' x tChoice11 = expectSuccess "Choice1" choice1 c1 decodedC1 choice2 = "A" ::= AbsChoice [ (Implicit, Just "b" :>: (Nothing :@: choice3)), (Implicit, Just "c" :>: (Nothing :@: choice4)) ] data Choice2 = B Choice3 | C Choice4 deriving (Eq,Show) instance Encode Choice2 where decode a b = do x <- b let t = defaultedTagValue x f t | t `elem` [0,1] = do foo <- decode a b return $ B foo | t `elem` [2,3] = do foo <- decode a b return $ C foo f t decodedCBD = B decodedCD decodedCBE = B decodedCE tChoice21 = expectSuccess "Choice2BD" choice2 c1 decodedCBD tChoice22 = expectSuccess "Choice2BE" choice2 c2 decodedCBE choice3 = "B" ::= AbsChoice [ (Implicit, Just "d" :>: (Just 0 :@: employeeNumber)), (Implicit, Just "e" :>: (Just 1 :@: employeeNumber)) ] decodedCD = D (EmployeeNumber' 51) decodedCE = E (EmployeeNumber' 51) data Choice3 = D EmployeeNumber' | E EmployeeNumber' deriving (Eq,Show) instance Encode Choice3 where decode a b = do x <- b let t = defaultedTagValue x case t of 0 -> do foo <- decode a b return $ D foo 1 -> do foo <- decode a b return $ E foo tChoice31 = expectSuccess "Choice3D" choice3 c1 decodedCD tChoice32 = expectSuccess "Choice3E" choice3 c2 decodedCE choice4 = "C" ::= AbsChoice [ (Implicit, Just "f" :>: (Just 2 :@: employeeNumber)), (Implicit, Just "g" :>: (Just 3 :@: employeeNumber)) ] decodedCF = F (EmployeeNumber' 51) decodedCG = G (EmployeeNumber' 51) data Choice4 = F EmployeeNumber' | G EmployeeNumber' deriving (Eq,Show) instance Encode Choice4 where decode a b = do x <- b let t = defaultedTagValue x case t of 2 -> do foo <- decode a b return $ F foo 3 -> do foo <- decode a b return $ G foo tChoice43 = expectSuccess "Choice4F" choice4 c3 decodedCF tChoice44 = expectSuccess "Choice4G" choice2 c4 decodedCG {- NoTags ::= CHOICE { myInt INTEGER, myIA5 IA5String } -} noTags = "NoTags" ::= AbsChoice [ (Implicit, Just "myInt" :>: (Nothing :@: absInteger)), (Implicit, Just "myIA5" :>: (Nothing :@: absIA5String)) ] nt1 = Primitive Universal 2 1 [0x33] nt2 = Primitive Universal 22 1 [0x33] nt3 = Primitive Universal 3 1 [0x33] nt4 = Primitive Universal 23 1 [0x33] decodedNT1 = MyInt 51 decodedNT2 = MyIA5 (IA5String "3") data NoTags = MyInt Integer | MyIA5 IA5String deriving (Eq,Show) instance Encode NoTags where decode a b = do x <- b let t = defaultedTagValue x f t | t `elem` [2] = do foo <- decode a b return $ MyInt foo | t `elem` [22] = do foo <- decode a b return $ MyIA5 foo f t tNoTags1 = expectSuccess "NoTags1" noTags nt1 decodedNT1 tNoTags2 = expectSuccess "NoTags2" noTags nt2 decodedNT2 {- ExplicitChoice ::= CHOICE { x1 [0] EXPLICIT EmployeeNumber, x2 [1] EXPLICIT EmployeeNumber, x3 [2] EXPLICIT EmployeeNumber } -} explicitChoice = "ExplicitChoice" ::= AbsChoice [ (Explicit, Just "z1" :>: (Just 0 :@: employeeNumber)), (Explicit, Just "z2" :>: (Just 1 :@: employeeNumber)), (Explicit, Just "z3" :>: (Just 2 :@: employeeNumber)) ] ec1 = Constructed Context 0 3 [en1] ec2 = Constructed Context 1 3 [en1] ec3 = Constructed Context 2 3 [en1] ec4 = Constructed Context 3 3 [en1] foo e = do (w,x) <- typeCheck explicitChoice e putStrLn (show x) putStrLn (show w) let (_ ::= c) = w d = decode c (Just x) (Just y) = d::(Maybe ExplicitChoice) putStrLn (show y) data ExplicitChoice = X1 EmployeeNumber | X2 EmployeeNumber | X3 EmployeeNumber deriving (Eq,Show) instance Encode ExplicitChoice where decode a b = do x <- b let t = defaultedTagValue x a' = absRefedType a b' = (encodedDefComps x)!!0 foo <- decode a' b' case t of 0 -> return (X1 foo) 1 -> return (X2 foo) 2 -> return (X3 foo) {- We can't put this in a test yet as w does not return something that can be decoded mechanically. It needs more investigation but is probably because EXPLICIT doesn't get handled correctly either for CHOICE or SEQUENCE. -} version = modName "Version" absInteger type Version = Integer certificateVersion = "version" ::= AbsRef Context 0 Explicit version data CertificateVersion = CertificateVersion Version deriving (Eq,Show) instance Encode CertificateVersion where decode a b = do y <- b let a' = absRefedType a b' = (encodedDefComps y)!!0 x <- decode a' b' return $ CertificateVersion x ver1 = Constructed Universal 16 17 [ Constructed Context 0 3 [ Primitive Universal 2 1 [2] ], Primitive Universal 2 10 [25,139,17,209,63,154,143,254,105,160] ] ver2 = Constructed Context 0 3 [ Primitive Universal 2 1 [2] ] decodedVer2 = CertificateVersion 2 bar = do (w,x) <- typeCheck certificateVersion ver2 putStrLn (show x) putStrLn (show w) let (_ ::= c) = w d = decode c (Just x) (Just y) = d::(Maybe CertificateVersion) putStrLn (show y) tVer1 = expectSuccess "Version1" certificateVersion ver2 decodedVer2 tests = TestList [ tagTest1, tagTest2, tagTest3, tagTest4, textBookTest1, textBookTest2, textBookTest3, libraryTest, visibleStringTest1, visibleStringTest2, visibleStringTest3, nameTest1, nameTest2, nameTest3, nameTest4, nameTest5, enTest1, dateTest1, dateTest2, ciTest1, prTest1, journeyTest1, journeyTest2, odysseyTest1, odysseyTest2, funnyOptionalTest1, funnyOptionalTest2, tChoice11, tChoice31, tChoice32, tChoice43, tChoice44, tChoice21, tChoice22, tNoTags1, tNoTags2, tVer1 ] main = runTestTT tests {- 051217083900 Three (at least) things to think about. 1. Real errors in choice. At the moment, all errors get treated as a trigger to try the next alternative. 2. Typechecking a reference returns the abstract BER representation of the referenced element. Should this be the whole element? 3. SEQUENCE elements can be IMPLICIT or EXPLICIT. Currently all are treated as IMPLICIT because of k (Regular (mn :>: (tv :@: td)):as) (bv:bvs) = do foo <- lift $ case tv of Nothing -> tc td bv Just v -> case mn of Nothing -> tc ("" ::= AbsRef Context v Implicit td) bv Just name -> tc (name ::= AbsRef Context v Implicit td) bv -}