src/pkg/encoding/asn1/common.go - The Go Programming Language

Golang

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