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 preceding 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
31 tagPrintableString = 19
35 tagGeneralizedTime = 24
42 classContextSpecific = 2
46 type tagAndLength struct {
47 class, tag, length int
51 // ASN.1 has IMPLICIT and EXPLICIT tags, which can be translated as "instead
52 // of" and "in addition to". When not specified, every primitive type has a
53 // default tag in the UNIVERSAL class.
55 // For example: a BIT STRING is tagged [UNIVERSAL 3] by default (although ASN.1
56 // doesn't actually have a UNIVERSAL keyword). However, by saying [IMPLICIT
57 // CONTEXT-SPECIFIC 42], that means that the tag is replaced by another.
59 // On the other hand, if it said [EXPLICIT CONTEXT-SPECIFIC 10], then an
60 // /additional/ tag would wrap the default tag. This explicit tag will have the
63 // (This is used in order to remove ambiguity with optional elements.)
65 // You can layer EXPLICIT and IMPLICIT tags to an arbitrary depth, however we
66 // don't support that here. We support a single layer of EXPLICIT or IMPLICIT
67 // tagging with tag strings on the fields of a structure.
69 // fieldParameters is the parsed representation of tag string from a structure field.
70 type fieldParameters struct {
71 optional bool // true iff the field is OPTIONAL
72 explicit bool // true iff an EXPLICIT tag is in use.
73 application bool // true iff an APPLICATION tag is in use.
74 defaultValue *int64 // a default value for INTEGER typed fields (maybe nil).
75 tag *int // the EXPLICIT or IMPLICIT tag (maybe nil).
76 stringType int // the string tag to use when marshaling.
77 set bool // true iff this should be encoded as a SET
78 omitEmpty bool // true iff this should be omitted if empty when marshaling.
81 // if explicit is set, tag is non-nil.
84 // Given a tag string with the format specified in the package comment,
85 // parseFieldParameters will parse it into a fieldParameters structure,
86 // ignoring unknown parts of the string.
87 func parseFieldParameters(str string) (ret fieldParameters) {
88 for _, part := range strings.Split(str, ",") {
90 case part == "optional":
92 case part == "explicit":
98 ret.stringType = tagIA5String
99 case part == "printable":
100 ret.stringType = tagPrintableString
102 ret.stringType = tagUTF8String
103 case strings.HasPrefix(part, "default:"):
104 i, err := strconv.ParseInt(part[8:], 10, 64)
106 ret.defaultValue = new(int64)
107 *ret.defaultValue = i
109 case strings.HasPrefix(part, "tag:"):
110 i, err := strconv.Atoi(part[4:])
117 case part == "application":
118 ret.application = true
122 case part == "omitempty":
129 // Given a reflected Go type, getUniversalType returns the default tag number
130 // and expected compound flag.
131 func getUniversalType(t reflect.Type) (tagNumber int, isCompound, ok bool) {
133 case objectIdentifierType:
134 return tagOID, false, true
136 return tagBitString, false, true
138 return tagUTCTime, false, true
140 return tagEnum, false, true
142 return tagInteger, false, true
146 return tagBoolean, false, true
147 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
148 return tagInteger, false, true
150 return tagSequence, true, true
152 if t.Elem().Kind() == reflect.Uint8 {
153 return tagOctetString, false, true
155 if strings.HasSuffix(t.Name(), "SET") {
156 return tagSet, true, true
158 return tagSequence, true, true
160 return tagPrintableString, false, true
162 return 0, false, false