// 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 implements parsing of DER-encoded ASN.1 data structures, // as defined in ITU-T Rec X.690. // // See also “A Layman's Guide to a Subset of ASN.1, BER, and DER,” // http://luca.ntop.org/Teaching/Appunti/asn1.html.
package asn1 // ASN.1 is a syntax for specifying abstract objects and BER, DER, PER, XER etc // are different encoding formats for those objects. Here, we'll be dealing // with DER, the Distinguished Encoding Rules. DER is used in X.509 because // it's fast to parse and, unlike BER, has a unique encoding for every object. // When calculating hashes over objects, it's important that the resulting // bytes be the same at both ends and DER removes this margin of error. // // ASN.1 is very complex and this package doesn't attempt to implement // everything by any means. import ( ) // A StructuralError suggests that the ASN.1 data is valid, but the Go type // which is receiving it doesn't match. type StructuralError struct { Msg string } func ( StructuralError) () string { return "asn1: structure error: " + .Msg } // A SyntaxError suggests that the ASN.1 data is invalid. type SyntaxError struct { Msg string } func ( SyntaxError) () string { return "asn1: syntax error: " + .Msg } // We start by dealing with each of the primitive types in turn. // BOOLEAN func ( []byte) ( bool, error) { if len() != 1 { = SyntaxError{"invalid boolean"} return } // DER demands that "If the encoding represents the boolean value TRUE, // its single contents octet shall have all eight bits set to one." // Thus only 0 and 255 are valid encoded values. switch [0] { case 0: = false case 0xff: = true default: = SyntaxError{"invalid boolean"} } return } // INTEGER // checkInteger returns nil if the given bytes are a valid DER-encoded // INTEGER and an error otherwise. func ( []byte) error { if len() == 0 { return StructuralError{"empty integer"} } if len() == 1 { return nil } if ([0] == 0 && [1]&0x80 == 0) || ([0] == 0xff && [1]&0x80 == 0x80) { return StructuralError{"integer not minimally-encoded"} } return nil } // parseInt64 treats the given bytes as a big-endian, signed integer and // returns the result. func ( []byte) ( int64, error) { = checkInteger() if != nil { return } if len() > 8 { // We'll overflow an int64 in this case. = StructuralError{"integer too large"} return } for := 0; < len(); ++ { <<= 8 |= int64([]) } // Shift up and down in order to sign extend the result. <<= 64 - uint8(len())*8 >>= 64 - uint8(len())*8 return } // parseInt32 treats the given bytes as a big-endian, signed integer and returns // the result. func ( []byte) (int32, error) { if := checkInteger(); != nil { return 0, } , := parseInt64() if != nil { return 0, } if != int64(int32()) { return 0, StructuralError{"integer too large"} } return int32(), nil } var bigOne = big.NewInt(1) // parseBigInt treats the given bytes as a big-endian, signed integer and returns // the result. func ( []byte) (*big.Int, error) { if := checkInteger(); != nil { return nil, } := new(big.Int) if len() > 0 && [0]&0x80 == 0x80 { // This is a negative number. := make([]byte, len()) for := range { [] = ^[] } .SetBytes() .Add(, bigOne) .Neg() return , nil } .SetBytes() return , nil } // BIT STRING // BitString is the structure to use when you want an ASN.1 BIT STRING type. A // bit string is padded up to the nearest byte in memory and the number of // valid bits is recorded. Padding bits will be zero. type BitString struct { Bytes []byte // bits packed into bytes. BitLength int // length in bits. } // At returns the bit at the given index. If the index is out of range it // returns 0. func ( BitString) ( int) int { if < 0 || >= .BitLength { return 0 } := / 8 := 7 - uint(%8) return int(.Bytes[]>>) & 1 } // RightAlign returns a slice where the padding bits are at the beginning. The // slice may share memory with the BitString. func ( BitString) () []byte { := uint(8 - (.BitLength % 8)) if == 8 || len(.Bytes) == 0 { return .Bytes } := make([]byte, len(.Bytes)) [0] = .Bytes[0] >> for := 1; < len(.Bytes); ++ { [] = .Bytes[-1] << (8 - ) [] |= .Bytes[] >> } return } // parseBitString parses an ASN.1 bit string from the given byte slice and returns it. func ( []byte) ( BitString, error) { if len() == 0 { = SyntaxError{"zero length BIT STRING"} return } := int([0]) if > 7 || len() == 1 && > 0 || [len()-1]&((1<<[0])-1) != 0 { = SyntaxError{"invalid padding bits in BIT STRING"} return } .BitLength = (len()-1)*8 - .Bytes = [1:] return } // NULL // NullRawValue is a RawValue with its Tag set to the ASN.1 NULL type tag (5). var NullRawValue = RawValue{Tag: TagNull} // NullBytes contains bytes representing the DER-encoded ASN.1 NULL type. var NullBytes = []byte{TagNull, 0} // OBJECT IDENTIFIER // An ObjectIdentifier represents an ASN.1 OBJECT IDENTIFIER. type ObjectIdentifier []int // Equal reports whether oi and other represent the same identifier. func ( ObjectIdentifier) ( ObjectIdentifier) bool { if len() != len() { return false } for := 0; < len(); ++ { if [] != [] { return false } } return true } func ( ObjectIdentifier) () string { var strings.Builder .Grow(32) := make([]byte, 0, 19) for , := range { if > 0 { .WriteByte('.') } .Write(strconv.AppendInt(, int64(), 10)) } return .String() } // parseObjectIdentifier parses an OBJECT IDENTIFIER from the given bytes and // returns it. An object identifier is a sequence of variable length integers // that are assigned in a hierarchy. func ( []byte) ( ObjectIdentifier, error) { if len() == 0 { = SyntaxError{"zero length OBJECT IDENTIFIER"} return } // In the worst case, we get two elements from the first byte (which is // encoded differently) and then every varint is a single byte long. = make([]int, len()+1) // The first varint is 40*value1 + value2: // According to this packing, value1 can take the values 0, 1 and 2 only. // When value1 = 0 or value1 = 1, then value2 is <= 39. When value1 = 2, // then there are no restrictions on value2. , , := parseBase128Int(, 0) if != nil { return } if < 80 { [0] = / 40 [1] = % 40 } else { [0] = 2 [1] = - 80 } := 2 for ; < len(); ++ { , , = parseBase128Int(, ) if != nil { return } [] = } = [0:] return } // ENUMERATED // An Enumerated is represented as a plain int. type Enumerated int // FLAG // A Flag accepts any data and is set to true if present. type Flag bool // parseBase128Int parses a base-128 encoded int from the given offset in the // given byte slice. It returns the value and the new offset. func ( []byte, int) (, int, error) { = var int64 for := 0; < len(); ++ { // 5 * 7 bits per byte == 35 bits of data // Thus the representation is either non-minimal or too large for an int32 if == 5 { = StructuralError{"base 128 integer too large"} return } <<= 7 := [] // integers should be minimally encoded, so the leading octet should // never be 0x80 if == 0 && == 0x80 { = SyntaxError{"integer is not minimally encoded"} return } |= int64( & 0x7f) ++ if &0x80 == 0 { = int() // Ensure that the returned value fits in an int on all platforms if > math.MaxInt32 { = StructuralError{"base 128 integer too large"} } return } } = SyntaxError{"truncated base 128 integer"} return } // UTCTime func ( []byte) ( time.Time, error) { := string() := "0601021504Z0700" , = time.Parse(, ) if != nil { = "060102150405Z0700" , = time.Parse(, ) } if != nil { return } if := .Format(); != { = fmt.Errorf("asn1: time did not serialize back to the original value and may be invalid: given %q, but serialized as %q", , ) return } if .Year() >= 2050 { // UTCTime only encodes times prior to 2050. See https://tools.ietf.org/html/rfc5280#section-4.1.2.5.1 = .AddDate(-100, 0, 0) } return } // parseGeneralizedTime parses the GeneralizedTime from the given byte slice // and returns the resulting time. func ( []byte) ( time.Time, error) { const = "20060102150405.999999999Z0700" := string() if , = time.Parse(, ); != nil { return } if := .Format(); != { = fmt.Errorf("asn1: time did not serialize back to the original value and may be invalid: given %q, but serialized as %q", , ) } return } // NumericString // parseNumericString parses an ASN.1 NumericString from the given byte array // and returns it. func ( []byte) ( string, error) { for , := range { if !isNumeric() { return "", SyntaxError{"NumericString contains invalid character"} } } return string(), nil } // isNumeric reports whether the given b is in the ASN.1 NumericString set. func ( byte) bool { return '0' <= && <= '9' || == ' ' } // PrintableString // parsePrintableString parses an ASN.1 PrintableString from the given byte // array and returns it. func ( []byte) ( string, error) { for , := range { if !isPrintable(, allowAsterisk, allowAmpersand) { = SyntaxError{"PrintableString contains invalid character"} return } } = string() return } type asteriskFlag bool type ampersandFlag bool const ( allowAsterisk asteriskFlag = true rejectAsterisk asteriskFlag = false allowAmpersand ampersandFlag = true rejectAmpersand ampersandFlag = false ) // isPrintable reports whether the given b is in the ASN.1 PrintableString set. // If asterisk is allowAsterisk then '*' is also allowed, reflecting existing // practice. If ampersand is allowAmpersand then '&' is allowed as well. func ( byte, asteriskFlag, ampersandFlag) bool { return 'a' <= && <= 'z' || 'A' <= && <= 'Z' || '0' <= && <= '9' || '\'' <= && <= ')' || '+' <= && <= '/' || == ' ' || == ':' || == '=' || == '?' || // This is technically not allowed in a PrintableString. // However, x509 certificates with wildcard strings don't // always use the correct string type so we permit it. (bool() && == '*') || // This is not technically allowed either. However, not // only is it relatively common, but there are also a // handful of CA certificates that contain it. At least // one of which will not expire until 2027. (bool() && == '&') } // IA5String // parseIA5String parses an ASN.1 IA5String (ASCII string) from the given // byte slice and returns it. func ( []byte) ( string, error) { for , := range { if >= utf8.RuneSelf { = SyntaxError{"IA5String contains invalid character"} return } } = string() return } // T61String // parseT61String parses an ASN.1 T61String (8-bit clean string) from the given // byte slice and returns it. func ( []byte) ( string, error) { return string(), nil } // UTF8String // parseUTF8String parses an ASN.1 UTF8String (raw UTF-8) from the given byte // array and returns it. func ( []byte) ( string, error) { if !utf8.Valid() { return "", errors.New("asn1: invalid UTF-8 string") } return string(), nil } // BMPString // parseBMPString parses an ASN.1 BMPString (Basic Multilingual Plane of // ISO/IEC/ITU 10646-1) from the given byte slice and returns it. func ( []byte) (string, error) { if len()%2 != 0 { return "", errors.New("pkcs12: odd-length BMP string") } // Strip terminator if present. if := len(); >= 2 && [-1] == 0 && [-2] == 0 { = [:-2] } := make([]uint16, 0, len()/2) for len() > 0 { = append(, uint16([0])<<8+uint16([1])) = [2:] } return string(utf16.Decode()), nil } // A RawValue represents an undecoded ASN.1 object. type RawValue struct { Class, Tag int IsCompound bool Bytes []byte FullBytes []byte // includes the tag and length } // RawContent is used to signal that the undecoded, DER data needs to be // preserved for a struct. To use it, the first field of the struct must have // this type. It's an error for any of the other fields to have this type. type RawContent []byte // Tagging // parseTagAndLength parses an ASN.1 tag and length pair from the given offset // into a byte slice. It returns the parsed data and the new offset. SET and // SET OF (tag 17) are mapped to SEQUENCE and SEQUENCE OF (tag 16) since we // don't distinguish between ordered and unordered objects in this code. func ( []byte, int) ( tagAndLength, int, error) { = // parseTagAndLength should not be called without at least a single // byte to read. Thus this check is for robustness: if >= len() { = errors.New("asn1: internal error in parseTagAndLength") return } := [] ++ .class = int( >> 6) .isCompound = &0x20 == 0x20 .tag = int( & 0x1f) // If the bottom five bits are set, then the tag number is actually base 128 // encoded afterwards if .tag == 0x1f { .tag, , = parseBase128Int(, ) if != nil { return } // Tags should be encoded in minimal form. if .tag < 0x1f { = SyntaxError{"non-minimal tag"} return } } if >= len() { = SyntaxError{"truncated tag or length"} return } = [] ++ if &0x80 == 0 { // The length is encoded in the bottom 7 bits. .length = int( & 0x7f) } else { // Bottom 7 bits give the number of length bytes to follow. := int( & 0x7f) if == 0 { = SyntaxError{"indefinite length found (not DER)"} return } .length = 0 for := 0; < ; ++ { if >= len() { = SyntaxError{"truncated tag or length"} return } = [] ++ if .length >= 1<<23 { // We can't shift ret.length up without // overflowing. = StructuralError{"length too large"} return } .length <<= 8 .length |= int() if .length == 0 { // DER requires that lengths be minimal. = StructuralError{"superfluous leading zeros in length"} return } } // Short lengths must be encoded in short form. if .length < 0x80 { = StructuralError{"non-minimal length"} return } } return } // parseSequenceOf is used for SEQUENCE OF and SET OF values. It tries to parse // a number of ASN.1 values from the given byte slice and returns them as a // slice of Go values of the given type. func ( []byte, reflect.Type, reflect.Type) ( reflect.Value, error) { , , , := getUniversalType() if ! { = StructuralError{"unknown Go type for slice"} return } // First we iterate over the input and count the number of elements, // checking that the types are correct in each case. := 0 for := 0; < len(); { var tagAndLength , , = parseTagAndLength(, ) if != nil { return } switch .tag { case TagIA5String, TagGeneralString, TagT61String, TagUTF8String, TagNumericString, TagBMPString: // We pretend that various other string types are // PRINTABLE STRINGs so that a sequence of them can be // parsed into a []string. .tag = TagPrintableString case TagGeneralizedTime, TagUTCTime: // Likewise, both time types are treated the same. .tag = TagUTCTime } if ! && (.class != ClassUniversal || .isCompound != || .tag != ) { = StructuralError{"sequence tag mismatch"} return } if invalidLength(, .length, len()) { = SyntaxError{"truncated sequence"} return } += .length ++ } = reflect.MakeSlice(, , ) := fieldParameters{} := 0 for := 0; < ; ++ { , = parseField(.Index(), , , ) if != nil { return } } return } var ( bitStringType = reflect.TypeOf(BitString{}) objectIdentifierType = reflect.TypeOf(ObjectIdentifier{}) enumeratedType = reflect.TypeOf(Enumerated(0)) flagType = reflect.TypeOf(Flag(false)) timeType = reflect.TypeOf(time.Time{}) rawValueType = reflect.TypeOf(RawValue{}) rawContentsType = reflect.TypeOf(RawContent(nil)) bigIntType = reflect.TypeOf((*big.Int)(nil)) ) // invalidLength reports whether offset + length > sliceLength, or if the // addition would overflow. func (, , int) bool { return + < || + > } // parseField is the main parsing function. Given a byte slice and an offset // into the array, it will try to parse a suitable ASN.1 value out and store it // in the given Value. func ( reflect.Value, []byte, int, fieldParameters) ( int, error) { = := .Type() // If we have run out of data, it may be that there are optional elements at the end. if == len() { if !setDefaultValue(, ) { = SyntaxError{"sequence truncated"} } return } // Deal with the ANY type. if := ; .Kind() == reflect.Interface && .NumMethod() == 0 { var tagAndLength , , = parseTagAndLength(, ) if != nil { return } if invalidLength(, .length, len()) { = SyntaxError{"data truncated"} return } var any if !.isCompound && .class == ClassUniversal { := [ : +.length] switch .tag { case TagPrintableString: , = parsePrintableString() case TagNumericString: , = parseNumericString() case TagIA5String: , = parseIA5String() case TagT61String: , = parseT61String() case TagUTF8String: , = parseUTF8String() case TagInteger: , = parseInt64() case TagBitString: , = parseBitString() case TagOID: , = parseObjectIdentifier() case TagUTCTime: , = parseUTCTime() case TagGeneralizedTime: , = parseGeneralizedTime() case TagOctetString: = case TagBMPString: , = parseBMPString() default: // If we don't know how to handle the type, we just leave Value as nil. } } += .length if != nil { return } if != nil { .Set(reflect.ValueOf()) } return } , , := parseTagAndLength(, ) if != nil { return } if .explicit { := ClassContextSpecific if .application { = ClassApplication } if == len() { = StructuralError{"explicit tag has no child"} return } if .class == && .tag == *.tag && (.length == 0 || .isCompound) { if == rawValueType { // The inner element should not be parsed for RawValues. } else if .length > 0 { , , = parseTagAndLength(, ) if != nil { return } } else { if != flagType { = StructuralError{"zero length explicit tag was not an asn1.Flag"} return } .SetBool(true) return } } else { // The tags didn't match, it might be an optional element. := setDefaultValue(, ) if { = } else { = StructuralError{"explicitly tagged member didn't match"} } return } } , , , := getUniversalType() if ! { = StructuralError{fmt.Sprintf("unknown Go type: %v", )} return } // Special case for strings: all the ASN.1 string types map to the Go // type string. getUniversalType returns the tag for PrintableString // when it sees a string, so if we see a different string type on the // wire, we change the universal type to match. if == TagPrintableString { if .class == ClassUniversal { switch .tag { case TagIA5String, TagGeneralString, TagT61String, TagUTF8String, TagNumericString, TagBMPString: = .tag } } else if .stringType != 0 { = .stringType } } // Special case for time: UTCTime and GeneralizedTime both map to the // Go type time.Time. if == TagUTCTime && .tag == TagGeneralizedTime && .class == ClassUniversal { = TagGeneralizedTime } if .set { = TagSet } := := ClassUniversal := if !.explicit && .tag != nil { = ClassContextSpecific = *.tag = false } if !.explicit && .application && .tag != nil { = ClassApplication = *.tag = false } if !.explicit && .private && .tag != nil { = ClassPrivate = *.tag = false } // We have unwrapped any explicit tagging at this point. if ! && (.class != || .tag != ) || (! && .isCompound != ) { // Tags don't match. Again, it could be an optional element. := setDefaultValue(, ) if { = } else { = StructuralError{fmt.Sprintf("tags don't match (%d vs %+v) %+v %s @%d", , , , .Name(), )} } return } if invalidLength(, .length, len()) { = SyntaxError{"data truncated"} return } := [ : +.length] += .length // We deal with the structures defined in this package first. switch v := .Addr().Interface().(type) { case *RawValue: * = RawValue{.class, .tag, .isCompound, , [:]} return case *ObjectIdentifier: *, = parseObjectIdentifier() return case *BitString: *, = parseBitString() return case *time.Time: if == TagUTCTime { *, = parseUTCTime() return } *, = parseGeneralizedTime() return case *Enumerated: , := parseInt32() if == nil { * = Enumerated() } = return case *Flag: * = true return case **big.Int: , := parseBigInt() if == nil { * = } = return } switch := ; .Kind() { case reflect.Bool: , := parseBool() if == nil { .SetBool() } = return case reflect.Int, reflect.Int32, reflect.Int64: if .Type().Size() == 4 { , := parseInt32() if == nil { .SetInt(int64()) } = } else { , := parseInt64() if == nil { .SetInt() } = } return // TODO(dfc) Add support for the remaining integer types case reflect.Struct: := for := 0; < .NumField(); ++ { if !.Field().IsExported() { = StructuralError{"struct contains unexported fields"} return } } if .NumField() > 0 && .Field(0).Type == rawContentsType { := [:] .Field(0).Set(reflect.ValueOf(RawContent())) } := 0 for := 0; < .NumField(); ++ { := .Field() if == 0 && .Type == rawContentsType { continue } , = (.Field(), , , parseFieldParameters(.Tag.Get("asn1"))) if != nil { return } } // We allow extra bytes at the end of the SEQUENCE because // adding elements to the end has been used in X.509 as the // version numbers have increased. return case reflect.Slice: := if .Elem().Kind() == reflect.Uint8 { .Set(reflect.MakeSlice(, len(), len())) reflect.Copy(, reflect.ValueOf()) return } , := parseSequenceOf(, , .Elem()) if == nil { .Set() } = return case reflect.String: var string switch { case TagPrintableString: , = parsePrintableString() case TagNumericString: , = parseNumericString() case TagIA5String: , = parseIA5String() case TagT61String: , = parseT61String() case TagUTF8String: , = parseUTF8String() case TagGeneralString: // GeneralString is specified in ISO-2022/ECMA-35, // A brief review suggests that it includes structures // that allow the encoding to change midstring and // such. We give up and pass it as an 8-bit string. , = parseT61String() case TagBMPString: , = parseBMPString() default: = SyntaxError{fmt.Sprintf("internal error: unknown string type %d", )} } if == nil { .SetString() } return } = StructuralError{"unsupported: " + .Type().String()} return } // canHaveDefaultValue reports whether k is a Kind that we will set a default // value for. (A signed integer, essentially.) func ( reflect.Kind) bool { switch { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return true } return false } // setDefaultValue is used to install a default value, from a tag string, into // a Value. It is successful if the field was optional, even if a default value // wasn't provided or it failed to install it into the Value. func ( reflect.Value, fieldParameters) ( bool) { if !.optional { return } = true if .defaultValue == nil { return } if canHaveDefaultValue(.Kind()) { .SetInt(*.defaultValue) } return } // Unmarshal parses the DER-encoded ASN.1 data structure b // and uses the reflect package to fill in an arbitrary value pointed at by val. // Because Unmarshal uses the reflect package, the structs // being written to must use upper case field names. If val // is nil or not a pointer, Unmarshal returns an error. // // After parsing b, any bytes that were leftover and not used to fill // val will be returned in rest. When parsing a SEQUENCE into a struct, // any trailing elements of the SEQUENCE that do not have matching // fields in val will not be included in rest, as these are considered // valid elements of the SEQUENCE and not trailing data. // // An ASN.1 INTEGER can be written to an int, int32, int64, // or *big.Int (from the math/big package). // If the encoded value does not fit in the Go type, // Unmarshal returns a parse error. // // An ASN.1 BIT STRING can be written to a BitString. // // An ASN.1 OCTET STRING can be written to a []byte. // // An ASN.1 OBJECT IDENTIFIER can be written to an // ObjectIdentifier. // // An ASN.1 ENUMERATED can be written to an Enumerated. // // An ASN.1 UTCTIME or GENERALIZEDTIME can be written to a time.Time. // // An ASN.1 PrintableString, IA5String, or NumericString can be written to a string. // // Any of the above ASN.1 values can be written to an interface{}. // The value stored in the interface has the corresponding Go type. // For integers, that type is int64. // // An ASN.1 SEQUENCE OF x or SET OF x can be written // to a slice if an x can be written to the slice's element type. // // An ASN.1 SEQUENCE or SET can be written to a struct // if each of the elements in the sequence can be // written to the corresponding element in the struct. // // The following tags on struct fields have special meaning to Unmarshal: // // application specifies that an APPLICATION tag is used // private specifies that a PRIVATE tag is used // default:x sets the default value for optional integer fields (only used if optional is also present) // explicit specifies that an additional, explicit tag wraps the implicit one // optional marks the field as ASN.1 OPTIONAL // set causes a SET, rather than a SEQUENCE type to be expected // tag:x specifies the ASN.1 tag number; implies ASN.1 CONTEXT SPECIFIC // // When decoding an ASN.1 value with an IMPLICIT tag into a string field, // Unmarshal will default to a PrintableString, which doesn't support // characters such as '@' and '&'. To force other encodings, use the following // tags: // // ia5 causes strings to be unmarshaled as ASN.1 IA5String values // numeric causes strings to be unmarshaled as ASN.1 NumericString values // utf8 causes strings to be unmarshaled as ASN.1 UTF8String values // // If the type of the first field of a structure is RawContent then the raw // ASN1 contents of the struct will be stored in it. // // If the name of a slice type ends with "SET" then it's treated as if // the "set" tag was set on it. This results in interpreting the type as a // SET OF x rather than a SEQUENCE OF x. This can be used with nested slices // where a struct tag cannot be given. // // Other ASN.1 types are not supported; if it encounters them, // Unmarshal returns a parse error. func ( []byte, any) ( []byte, error) { return UnmarshalWithParams(, , "") } // An invalidUnmarshalError describes an invalid argument passed to Unmarshal. // (The argument to Unmarshal must be a non-nil pointer.) type invalidUnmarshalError struct { Type reflect.Type } func ( *invalidUnmarshalError) () string { if .Type == nil { return "asn1: Unmarshal recipient value is nil" } if .Type.Kind() != reflect.Pointer { return "asn1: Unmarshal recipient value is non-pointer " + .Type.String() } return "asn1: Unmarshal recipient value is nil " + .Type.String() } // UnmarshalWithParams allows field parameters to be specified for the // top-level element. The form of the params is the same as the field tags. func ( []byte, any, string) ( []byte, error) { := reflect.ValueOf() if .Kind() != reflect.Pointer || .IsNil() { return nil, &invalidUnmarshalError{reflect.TypeOf()} } , := parseField(.Elem(), , 0, parseFieldParameters()) if != nil { return nil, } return [:], nil }