import Text.PrettyPrint
data ZeroTuple = ZeroTuple
data Tuple e es = Tuple e es
newtype IA5String = IA5String {unIA5String :: String}
data ASNType :: * -> * where
BOOLEAN :: ASNType Bool
INTEGER :: ASNType Integer
IA5STRING :: ASNType IA5String
prettyType :: ASNType a -> Doc
prettyType BOOLEAN = text "BOOLEAN"
prettyType INTEGER = text "INTEGER"
prettyType IA5STRING = text "IA5STRING"
data UbjClass :: * where
USingleton :: UbjClassComponent -> UbjClass
UCons :: UbjClassComponent -> UbjClass -> UbjClass
type FieldName = String
data UbjClassComponent :: * where
UCFTV :: FieldName -> ASNType a -> UbjClassComponent
UCIO :: FieldName -> UbjClass -> UbjClassComponent
uF2 = UCFTV "code" INTEGER
uF = UCons (UCIO "another" uF) (USingleton uF2)
data ObjClass :: * -> * where
Singleton :: ObjClassComponent a -> ObjClass a
Cons :: ObjClassComponent a -> ObjClass l -> ObjClass (Tuple a l)
Lift :: Mu a l -> ObjClass (Mu a l)
data ObjClassComponent :: * -> * where
OCFTV :: FieldName -> ASNType a -> ObjClassComponent a
OCIO :: FieldName -> ObjClass a -> ObjClassComponent a
oF2 = OCFTV "code" INTEGER
oF = Lift (Inl (Cons (OCIO "another" oF) (Singleton oF2)))
oFV = Inlx (Tuple oFV (3::Integer))
oG = Lift (Inr (Cons oF2 (Singleton (OCIO "another" oG))))
oH = Lift (Inl (Cons (OCIO "another" oH) (Cons oF2 (Singleton oF2))))
oJ = Cons ((OCIO "bar") $ oH) (Singleton . (OCIO "foo") $ oH)
oK = Lift (Inr (Cons oF2 (Lift (Inl (Cons (OCIO "foo" oK) (Singleton oF2))))))
data Mu :: * -> * -> * where
Inl :: ObjClass (Tuple (Mu a b) b) -> Mu a b
Inr :: ObjClass (Tuple a (Mu a b)) -> Mu a b
Inlx :: Tuple (Mu a b) b -> Mu a b
Inrx :: Tuple a (Mu a b) -> Mu a b
prettyOCC :: ObjClassComponent a -> String
prettyOCC (OCFTV fn ty) = fn ++ " " ++ prettyASN ty
prettyOCC (OCIO fn oc) = fn
prettyASN :: ASNType a -> String
prettyASN BOOLEAN = "BOOLEAN"
prettyASN INTEGER = "INTEGER"
prettyOC :: ObjClass a -> String
prettyOC (Singleton occ) = prettyOCC occ
prettyOC (Cons occ oc) = prettyOCC occ ++ " " ++ prettyOC oc
prettyOC (Lift mu) = prettyMu mu
prettyMu :: Mu a b -> String
prettyMu (Inl oc) = prettyOC oc
prettyMu (Inr oc) = prettyOC oc
f :: ObjClass a -> a -> String
f (Singleton occ) x = undefined
data ObjClassComponent1 :: * -> * where
OCType :: FieldName -> ObjClassComponent1 a
OCFixedTypeValue :: FieldName -> ASNType a -> ObjClassComponent1 a
OCVariableTypeValue :: FieldName -> ObjClassComponent1 a -> ObjClassComponent1 a
OCFixedTypeValueSet :: FieldName -> ASNType a -> ObjClassComponent1 a
OCVariableTypeValueSet :: FieldName -> ObjClassComponent1 a -> ObjClassComponent1 a
OCInformationObject :: FieldName -> ObjClass1 a -> ObjClassComponent1 a
data ObjClass1 :: * -> * where
Singleton1 :: ObjClassComponent1 a -> ObjClass1 a
Cons1 :: ObjClassComponent1 a -> ObjClass1 l -> ObjClass1 (Tuple a l)
Lift1 :: Mu1 a l -> ObjClass1 (Mu1 a l)
data Mu1 :: * -> * -> * where
Inl1 :: ObjClass1 (Tuple (Mu1 a b) b) -> Mu1 a b
Inr1 :: ObjClass1 (Tuple a (Mu1 a b)) -> Mu1 a b
{-
The definition in Haskell below is very similar to the one on page 314 in
Dubuisson which is reproduced below.
OTHER-FUNCTION ::= CLASS {
&code INTEGER (0..MAX) UNIQUE,
&Alphabet BMPString
DEFAULT {Latin1 INTERSECTION Level1},
&ArgumentType ,
&SupportedArguments &ArgumentType OPTIONAL,
&ResultType DEFAULT NULL,
&result-if-error &ResultType DEFAULT NULL,
&associated-function OTHER-FUNCTION OPTIONAL,
&Errors ERROR DEFAULT
{rejected-argument | memory-fault} }
-}
x1 = OCType "ArgumentType"
x2 = OCFixedTypeValue "code" INTEGER
x3 = OCType "ResultType"
x4 = OCVariableTypeValue "result-if-error" x3
x5 = OCFixedTypeValueSet "Alphabet" IA5STRING
x6 = OCVariableTypeValueSet "Supported Arguments" x1
x7 = OCFixedTypeValueSet "Errors" BOOLEAN
x = Lift1 (Inr1 (Cons1 x7 (Lift1 (Inl1 (Cons1 (OCInformationObject "other function" x) (Cons1 x6 (Cons1 x5 (Cons1 x4 (Cons1 x3 (Cons1 x2 (Singleton1 x1)))))))))))
printObjClassComp (OCType fn) = text "Type" <+> text fn
printObjClassComp (OCFixedTypeValue fn t) = text "Fixed Type Value" <+> text fn <+> prettyType t
printObjClassComp (OCVariableTypeValue fn c) = text "Variable Type Value" <+> text fn <+> braces (printObjClassComp c)
printObjClassComp (OCFixedTypeValueSet fn t) = text "Fixed Type Value Set" <+> text fn <+> prettyType t
printObjClassComp (OCVariableTypeValueSet fn c) = text "Variable Type Value Set" <+> text fn <+> braces (printObjClassComp c)
printObjClassComp (OCInformationObject fn oc) = text "Information Object" <+> text fn
prettyOC1 :: ObjClass1 a -> Doc
prettyOC1 (Singleton1 occ) = printObjClassComp occ
prettyOC1 (Cons1 occ oc) = printObjClassComp occ $$ prettyOC1 oc
prettyOC1 (Lift1 mu) = prettyMu1 mu
prettyMu1 :: Mu1 a b -> Doc
prettyMu1 (Inl1 oc) = prettyOC1 oc
prettyMu1 (Inr1 oc) = prettyOC1 oc
{-
Email to the ASN.1 mailing list from Jeffrey Walton
AlgorithmIdentifier ::= SEQUENCE {
algorithm ALGORITHM.&id ({SupportedAlgorithms}),
parameters ALGORITHM.&Type ({SupportedAlgorithms}{ @algorithm}) OPTIONAL }
[1] X.509, The Directory: Public-key and Attribute Certificate
Frameworks, http://www.itu.int/rec/T-REC-X/recommendation.asp?lang=en&parent=T-REC-X.509,
August 2008, p 11.
Response from Conrad Sigona
If you look for the definition of ALGORITHM on p. 101, you'll find
ALGORITHM ::= TYPE-IDENTIFIER
and if you look in a textbook about ASN.1 or in the ASN.1 standard documents, you'll find
TYPE-IDENTIFIER ::= CLASS {
&id OBJECT IDENTIFIER UNIQUE,
&Type }
WITH SYNTAX { &Type IDENTIFIED BY &id }
Thus ALGORITHM is not a type, but a CLASS. On the other hand, ALGORITHM.&id is a type, namely, an OBJECT IDENTIFIER. ALGORITHM.&Type is also a type, an open type. This means it can be various types, but since it is constrained by ({SupportedAlgorithms}{ @algorithm}), it is not just any type, but one that fits the constraint. Let's look at the two elements one at a time.
ALGORITHM.&id is, as we said above, an OBJECT IDENTIFIER. Since it appears as
ALGORITHM.&id ({SupportedAlgorithms})
it is constrained to be one of the OBJECT IDENTIFIERs in the SupportedAlgorithms object set. Page 22 shows
-- Definition of the following information object set
-- is deferred, perhaps to standardized profiles or
-- to protocol implementation conformance statements.
-- The set is required to specify a table constraint
-- on the parameters component of AlgorithmIdentifier.
-- SupportedAlgorithms ALGORITHM ::= { ... }
which says that SupportedAlgorithms should be defined but isn't (yet). If it were defined, it would look something like
SupportedAlgorithms ALGORITHM ::= {
Algo1 IDENTIFIED BY { 1 2 3 4 1 } |
Algo2 IDENTIFIED BY { 1 2 3 4 2 } |
Algo3 IDENTIFIED BY { 1 2 3 4 3 },
...
}
I just made up some types (Algo1, Algo2, and Algo3) and objects identifiers. They serve only as examples and have no meaning per se.
Note the "WITH SYNTAX" in the definition of TYPE-IDENTIFIER above. It describes the way to specify each object as a type (&Type) followed by the string "IDENTIFIED BY" followed by an OBJECT IDENTIFIER (&id). Thus Algo1 is associated with { 1 2 3 4 1 }; Algo2 is associated with { 1 2 3 4 2 }; and Algo3 is associated with { 1 2 3 4 3 }.
I wrote above that ALGORITHM.&id is constrained to be one of the OBJECT IDENTIFIERS in the SupportedAlgorithms object set. Using my example above, you see that it is limited to taking the value of one of the three object identifiers.
ALGORITHM.&Type ({SupportedAlgorithms}{ @algorithm}) is an open type constrained to be one of the types specified in SupportedAlgorithms depending upon algorithm. Bear in mind the definition of algorithm, and you'll see that what
AlgorithmIdentifier ::= SEQUENCE {
algorithm ALGORITHM.&id ({SupportedAlgorithms}),
parameters ALGORITHM.&Type
({SupportedAlgorithms}{ @algorithm}) OPTIONAL
}
means is that we have a SEQUENCE consisting of
a) algorithm, which is one of the OBJECT IDENTIFIERs drawn from the set above, and
b) parameters, which is an open type also drawn from the set above, but which depends upon algorithm.
You can look at SupportedAlgorithm as a set of rules, namely,
if algorithm = { 1 2 3 4 1 }, then parameters is Algo1;
if algorithm = { 1 2 3 4 2 }, then parameters is Algo2;
if algorithm = { 1 2 3 4 3 }, then parameters is Algo3;
if algorithm is anything else (...), then parameters can be anything, that is, some type, but unspecified.
So what can you do with this information? Now you know what the syntax means, but you still need either a fully specified SupportedAlgorithms or else knowledge from some external source (e.g., a sheet of paper) that tells you which type is associated with which object identifier.
I guess you were hoping to get a simpler and more pointed answer. Unfortunately I have none. If you wish to learn more about information object classes, information object sets, and open types, permit me to suggest
http://www.oss.com/asn1/booksintro.html
where you can download two ASN.1 reference manuals. They are both
comprehensive, although with different emphasis. Each has its own fans,
but both are quite good.
-}