1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
13 // ASN.1 objects have metadata preceeding them:
14 // the tag: the type of the object
15 // a flag denoting if this object is compound or not
16 // the class type: the namespace of the tag
17 // the length of the object, in bytes
19 // Here are some standard tags and classes
30 tagPrintableString = 19
34 tagGeneralizedTime = 24
40 classContextSpecific = 2
44 type tagAndLength struct {
45 class, tag, length int
49 // ASN.1 has IMPLICIT and EXPLICIT tags, which can be translated as "instead
50 // of" and "in addition to". When not specified, every primitive type has a
51 // default tag in the UNIVERSAL class.
53 // For example: a BIT STRING is tagged [UNIVERSAL 3] by default (although ASN.1
54 // doesn't actually have a UNIVERSAL keyword). However, by saying [IMPLICIT
55 // CONTEXT-SPECIFIC 42], that means that the tag is replaced by another.
57 // On the other hand, if it said [EXPLICIT CONTEXT-SPECIFIC 10], then an
58 // /additional/ tag would wrap the default tag. This explicit tag will have the
61 // (This is used in order to remove ambiguity with optional elements.)
63 // You can layer EXPLICIT and IMPLICIT tags to an arbitrary depth, however we
64 // don't support that here. We support a single layer of EXPLICIT or IMPLICIT
65 // tagging with tag strings on the fields of a structure.
67 // fieldParameters is the parsed representation of tag string from a structure field.
68 type fieldParameters struct {
69 optional bool // true iff the field is OPTIONAL
70 explicit bool // true iff and EXPLICIT tag is in use.
71 defaultValue *int64 // a default value for INTEGER typed fields (maybe nil).
72 tag *int // the EXPLICIT or IMPLICIT tag (maybe nil).
73 stringType int // the string tag to use when marshaling.
74 set bool // true iff this should be encoded as a SET
77 // if explicit is set, tag is non-nil.
80 // Given a tag string with the format specified in the package comment,
81 // parseFieldParameters will parse it into a fieldParameters structure,
82 // ignoring unknown parts of the string.
83 func parseFieldParameters(str string) (ret fieldParameters) {
84 for _, part := range strings.Split(str, ",", -1) {
86 case part == "optional":
88 case part == "explicit":
95 ret.stringType = tagIA5String
96 case part == "printable":
97 ret.stringType = tagPrintableString
98 case strings.HasPrefix(part, "default:"):
99 i, err := strconv.Atoi64(part[8:])
101 ret.defaultValue = new(int64)
102 *ret.defaultValue = i
104 case strings.HasPrefix(part, "tag:"):
105 i, err := strconv.Atoi(part[4:])
117 // Given a reflected Go type, getUniversalType returns the default tag number
118 // and expected compound flag.
119 func getUniversalType(t reflect.Type) (tagNumber int, isCompound, ok bool) {
121 case objectIdentifierType:
122 return tagOID, false, true
124 return tagBitString, false, true
126 return tagUTCTime, false, true
128 return tagEnum, false, true
130 switch t := t.(type) {
131 case *reflect.BoolType:
132 return tagBoolean, false, true
133 case *reflect.IntType:
134 return tagInteger, false, true
135 case *reflect.StructType:
136 return tagSequence, true, true
137 case *reflect.SliceType:
138 if t.Elem().Kind() == reflect.Uint8 {
139 return tagOctetString, false, true
141 if strings.HasSuffix(t.Name(), "SET") {
142 return tagSet, true, true
144 return tagSequence, true, true
145 case *reflect.StringType:
146 return tagPrintableString, false, true
148 return 0, false, false