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