...

Source file src/pkg/encoding/asn1/common.go

     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	}
   183	

View as plain text