common.mx raw

   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  	"strconv"
   9  	"bytes"
  10  )
  11  
  12  // ASN.1 objects have metadata preceding them:
  13  //   the tag: the type of the object
  14  //   a flag denoting if this object is compound or not
  15  //   the class type: the namespace of the tag
  16  //   the length of the object, in bytes
  17  
  18  // Here are some standard tags and classes
  19  
  20  // ASN.1 tags represent the type of the following object.
  21  const (
  22  	TagBoolean         = 1
  23  	TagInteger         = 2
  24  	TagBitString       = 3
  25  	TagOctetString     = 4
  26  	TagNull            = 5
  27  	TagOID             = 6
  28  	TagEnum            = 10
  29  	TagUTF8String      = 12
  30  	TagSequence        = 16
  31  	TagSet             = 17
  32  	TagNumericString   = 18
  33  	TagPrintableString = 19
  34  	TagT61String       = 20
  35  	TagIA5String       = 22
  36  	TagUTCTime         = 23
  37  	TagGeneralizedTime = 24
  38  	TagGeneralString   = 27
  39  	TagBMPString       = 30
  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 []byte) (ret fieldParameters) {
  94  	var part []byte
  95  	for len(str) > 0 {
  96  		part, str, _ = bytes.Cut(str, ",")
  97  		switch {
  98  		case part == "optional":
  99  			ret.optional = true
 100  		case part == "explicit":
 101  			ret.explicit = true
 102  			if ret.tag == nil {
 103  				var zero int
 104  				ret.tag = &zero
 105  			}
 106  		case part == "generalized":
 107  			ret.timeType = TagGeneralizedTime
 108  		case part == "utc":
 109  			ret.timeType = TagUTCTime
 110  		case part == "ia5":
 111  			ret.stringType = TagIA5String
 112  		case part == "printable":
 113  			ret.stringType = TagPrintableString
 114  		case part == "numeric":
 115  			ret.stringType = TagNumericString
 116  		case part == "utf8":
 117  			ret.stringType = TagUTF8String
 118  		case bytes.HasPrefix(part, "default:"):
 119  			i, err := strconv.ParseInt(part[8:], 10, 64)
 120  			if err == nil {
 121  				dv := i
 122  				ret.defaultValue = &dv
 123  			}
 124  		case bytes.HasPrefix(part, "tag:"):
 125  			i, err := strconv.Atoi(part[4:])
 126  			if err == nil {
 127  				tag := i
 128  				ret.tag = &tag
 129  			}
 130  		case part == "set":
 131  			ret.set = true
 132  		case part == "application":
 133  			ret.application = true
 134  			if ret.tag == nil {
 135  				var zero int
 136  				ret.tag = &zero
 137  			}
 138  		case part == "private":
 139  			ret.private = true
 140  			if ret.tag == nil {
 141  				var zero int
 142  				ret.tag = &zero
 143  			}
 144  		case part == "omitempty":
 145  			ret.omitEmpty = true
 146  		}
 147  	}
 148  	return
 149  }
 150  
 151  // getUniversalType returns the default ASN.1 tag number and expected compound
 152  // flag for a type identified by its raw type code pointer.
 153  func getUniversalType(t *_rawType) (matchAny bool, tagNumber int, isCompound, ok bool) {
 154  	switch t {
 155  	case _rawValueTC:
 156  		return true, -1, false, true
 157  	case _objectIdentifierTC:
 158  		return false, TagOID, false, true
 159  	case _bitStringTC:
 160  		return false, TagBitString, false, true
 161  	case _timeTC:
 162  		return false, TagUTCTime, false, true
 163  	case _enumeratedTC:
 164  		return false, TagEnum, false, true
 165  	case _bigIntPtrTC:
 166  		return false, TagInteger, false, true
 167  	}
 168  	switch t.kind() {
 169  	case akBool:
 170  		return false, TagBoolean, false, true
 171  	case akInt, akInt8, akInt16, akInt32, akInt64:
 172  		return false, TagInteger, false, true
 173  	case akStruct:
 174  		return false, TagSequence, true, true
 175  	case akSlice:
 176  		if t.elem().kind() == akUint8 {
 177  			return false, TagOctetString, false, true
 178  		}
 179  		if bytes.HasSuffix(t.typeName(), "SET") {
 180  			return false, TagSet, true, true
 181  		}
 182  		return false, TagSequence, true, true
 183  	case akBytes:
 184  		return false, TagPrintableString, false, true
 185  	}
 186  	return false, 0, false, false
 187  }
 188