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. 4 5 package asn1 6 7 import ( 8 "reflect" 9 "strconv" 10 "strings" 11 ) 12 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 18 19 // Here are some standard tags and classes 20 21 // ASN.1 tags represent the type of the following object. 22 const ( 23 TagBoolean = 1 24 TagInteger = 2 25 TagBitString = 3 26 TagOctetString = 4 27 TagOID = 6 28 TagEnum = 10 29 TagUTF8String = 12 30 TagSequence = 16 31 TagSet = 17 32 TagPrintableString = 19 33 TagT61String = 20 34 TagIA5String = 22 35 TagUTCTime = 23 36 TagGeneralizedTime = 24 37 TagGeneralString = 27 38 ) 39 40 // ASN.1 class types represent the namespace of the tag. 41 const ( 42 ClassUniversal = 0 43 ClassApplication = 1 44 ClassContextSpecific = 2 45 ClassPrivate = 3 46 ) 47 48 type tagAndLength struct { 49 class, tag, length int 50 isCompound bool 51 } 52 53 // ASN.1 has IMPLICIT and EXPLICIT tags, which can be translated as "instead 54 // of" and "in addition to". When not specified, every primitive type has a 55 // default tag in the UNIVERSAL class. 56 // 57 // For example: a BIT STRING is tagged [UNIVERSAL 3] by default (although ASN.1 58 // doesn't actually have a UNIVERSAL keyword). However, by saying [IMPLICIT 59 // CONTEXT-SPECIFIC 42], that means that the tag is replaced by another. 60 // 61 // On the other hand, if it said [EXPLICIT CONTEXT-SPECIFIC 10], then an 62 // /additional/ tag would wrap the default tag. This explicit tag will have the 63 // compound flag set. 64 // 65 // (This is used in order to remove ambiguity with optional elements.) 66 // 67 // You can layer EXPLICIT and IMPLICIT tags to an arbitrary depth, however we 68 // don't support that here. We support a single layer of EXPLICIT or IMPLICIT 69 // tagging with tag strings on the fields of a structure. 70 71 // fieldParameters is the parsed representation of tag string from a structure field. 72 type fieldParameters struct { 73 optional bool // true iff the field is OPTIONAL 74 explicit bool // true iff an EXPLICIT tag is in use. 75 application bool // true iff an APPLICATION tag is in use. 76 defaultValue *int64 // a default value for INTEGER typed fields (maybe nil). 77 tag *int // the EXPLICIT or IMPLICIT tag (maybe nil). 78 stringType int // the string tag to use when marshaling. 79 timeType int // the time tag to use when marshaling. 80 set bool // true iff this should be encoded as a SET 81 omitEmpty bool // true iff this should be omitted if empty when marshaling. 82 83 // Invariants: 84 // if explicit is set, tag is non-nil. 85 } 86 87 // Given a tag string with the format specified in the package comment, 88 // parseFieldParameters will parse it into a fieldParameters structure, 89 // ignoring unknown parts of the string. 90 func parseFieldParameters(str string) (ret fieldParameters) { 91 for _, part := range strings.Split(str, ",") { 92 switch { 93 case part == "optional": 94 ret.optional = true 95 case part == "explicit": 96 ret.explicit = true 97 if ret.tag == nil { 98 ret.tag = new(int) 99 } 100 case part == "generalized": 101 ret.timeType = TagGeneralizedTime 102 case part == "utc": 103 ret.timeType = TagUTCTime 104 case part == "ia5": 105 ret.stringType = TagIA5String 106 case part == "printable": 107 ret.stringType = TagPrintableString 108 case part == "utf8": 109 ret.stringType = TagUTF8String 110 case strings.HasPrefix(part, "default:"): 111 i, err := strconv.ParseInt(part[8:], 10, 64) 112 if err == nil { 113 ret.defaultValue = new(int64) 114 *ret.defaultValue = i 115 } 116 case strings.HasPrefix(part, "tag:"): 117 i, err := strconv.Atoi(part[4:]) 118 if err == nil { 119 ret.tag = new(int) 120 *ret.tag = i 121 } 122 case part == "set": 123 ret.set = true 124 case part == "application": 125 ret.application = true 126 if ret.tag == nil { 127 ret.tag = new(int) 128 } 129 case part == "omitempty": 130 ret.omitEmpty = true 131 } 132 } 133 return 134 } 135 136 // Given a reflected Go type, getUniversalType returns the default tag number 137 // and expected compound flag. 138 func getUniversalType(t reflect.Type) (tagNumber int, isCompound, ok bool) { 139 switch t { 140 case objectIdentifierType: 141 return TagOID, false, true 142 case bitStringType: 143 return TagBitString, false, true 144 case timeType: 145 return TagUTCTime, false, true 146 case enumeratedType: 147 return TagEnum, false, true 148 case bigIntType: 149 return TagInteger, false, true 150 } 151 switch t.Kind() { 152 case reflect.Bool: 153 return TagBoolean, false, true 154 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 155 return TagInteger, false, true 156 case reflect.Struct: 157 return TagSequence, true, true 158 case reflect.Slice: 159 if t.Elem().Kind() == reflect.Uint8 { 160 return TagOctetString, false, true 161 } 162 if strings.HasSuffix(t.Name(), "SET") { 163 return TagSet, true, true 164 } 165 return TagSequence, true, true 166 case reflect.String: 167 return TagPrintableString, false, true 168 } 169 return 0, false, false 170 } 171