123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173 |
- // Copyright 2009 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- package asn1
- import (
- "reflect"
- "strconv"
- "strings"
- )
- // ASN.1 objects have metadata preceding them:
- // the tag: the type of the object
- // a flag denoting if this object is compound or not
- // the class type: the namespace of the tag
- // the length of the object, in bytes
- // Here are some standard tags and classes
- // ASN.1 tags represent the type of the following object.
- const (
- TagBoolean = 1
- TagInteger = 2
- TagBitString = 3
- TagOctetString = 4
- TagOID = 6
- TagEnum = 10
- TagUTF8String = 12
- TagSequence = 16
- TagSet = 17
- TagPrintableString = 19
- TagT61String = 20
- TagIA5String = 22
- TagUTCTime = 23
- TagGeneralizedTime = 24
- TagGeneralString = 27
- )
- // ASN.1 class types represent the namespace of the tag.
- const (
- ClassUniversal = 0
- ClassApplication = 1
- ClassContextSpecific = 2
- ClassPrivate = 3
- )
- type tagAndLength struct {
- class, tag, length int
- isCompound bool
- }
- // ASN.1 has IMPLICIT and EXPLICIT tags, which can be translated as "instead
- // of" and "in addition to". When not specified, every primitive type has a
- // default tag in the UNIVERSAL class.
- //
- // For example: a BIT STRING is tagged [UNIVERSAL 3] by default (although ASN.1
- // doesn't actually have a UNIVERSAL keyword). However, by saying [IMPLICIT
- // CONTEXT-SPECIFIC 42], that means that the tag is replaced by another.
- //
- // On the other hand, if it said [EXPLICIT CONTEXT-SPECIFIC 10], then an
- // /additional/ tag would wrap the default tag. This explicit tag will have the
- // compound flag set.
- //
- // (This is used in order to remove ambiguity with optional elements.)
- //
- // You can layer EXPLICIT and IMPLICIT tags to an arbitrary depth, however we
- // don't support that here. We support a single layer of EXPLICIT or IMPLICIT
- // tagging with tag strings on the fields of a structure.
- // fieldParameters is the parsed representation of tag string from a structure field.
- type fieldParameters struct {
- optional bool // true iff the field is OPTIONAL
- explicit bool // true iff an EXPLICIT tag is in use.
- application bool // true iff an APPLICATION tag is in use.
- defaultValue *int64 // a default value for INTEGER typed fields (maybe nil).
- tag *int // the EXPLICIT or IMPLICIT tag (maybe nil).
- stringType int // the string tag to use when marshaling.
- timeType int // the time tag to use when marshaling.
- set bool // true iff this should be encoded as a SET
- omitEmpty bool // true iff this should be omitted if empty when marshaling.
- // Invariants:
- // if explicit is set, tag is non-nil.
- }
- // Given a tag string with the format specified in the package comment,
- // parseFieldParameters will parse it into a fieldParameters structure,
- // ignoring unknown parts of the string.
- func parseFieldParameters(str string) (ret fieldParameters) {
- for _, part := range strings.Split(str, ",") {
- switch {
- case part == "optional":
- ret.optional = true
- case part == "explicit":
- ret.explicit = true
- if ret.tag == nil {
- ret.tag = new(int)
- }
- case part == "generalized":
- ret.timeType = TagGeneralizedTime
- case part == "utc":
- ret.timeType = TagUTCTime
- case part == "ia5":
- ret.stringType = TagIA5String
- // jtasn1 case below added
- case part == "generalstring":
- ret.stringType = TagGeneralString
- case part == "printable":
- ret.stringType = TagPrintableString
- case part == "utf8":
- ret.stringType = TagUTF8String
- case strings.HasPrefix(part, "default:"):
- i, err := strconv.ParseInt(part[8:], 10, 64)
- if err == nil {
- ret.defaultValue = new(int64)
- *ret.defaultValue = i
- }
- case strings.HasPrefix(part, "tag:"):
- i, err := strconv.Atoi(part[4:])
- if err == nil {
- ret.tag = new(int)
- *ret.tag = i
- }
- case part == "set":
- ret.set = true
- case part == "application":
- ret.application = true
- if ret.tag == nil {
- ret.tag = new(int)
- }
- case part == "omitempty":
- ret.omitEmpty = true
- }
- }
- return
- }
- // Given a reflected Go type, getUniversalType returns the default tag number
- // and expected compound flag.
- func getUniversalType(t reflect.Type) (tagNumber int, isCompound, ok bool) {
- switch t {
- case objectIdentifierType:
- return TagOID, false, true
- case bitStringType:
- return TagBitString, false, true
- case timeType:
- return TagUTCTime, false, true
- case enumeratedType:
- return TagEnum, false, true
- case bigIntType:
- return TagInteger, false, true
- }
- switch t.Kind() {
- case reflect.Bool:
- return TagBoolean, false, true
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- return TagInteger, false, true
- case reflect.Struct:
- return TagSequence, true, true
- case reflect.Slice:
- if t.Elem().Kind() == reflect.Uint8 {
- return TagOctetString, false, true
- }
- if strings.HasSuffix(t.Name(), "SET") {
- return TagSet, true, true
- }
- return TagSequence, true, true
- case reflect.String:
- return TagPrintableString, false, true
- }
- return 0, false, false
- }
|