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