// 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.typeStructuralErrorstruct { Msg string}func ( StructuralError) () string { return"asn1: structure error: " + .Msg }// A SyntaxError suggests that the ASN.1 data is invalid.typeSyntaxErrorstruct { Msg string}func ( SyntaxError) () string { return"asn1: syntax error: " + .Msg }// We start by dealing with each of the primitive types in turn.// BOOLEANfunc parseBool( []byte) ( bool, error) {iflen() != 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] {case0: = falsecase0xff: = truedefault: = SyntaxError{"invalid boolean"} }return}// INTEGER// checkInteger returns nil if the given bytes are a valid DER-encoded// INTEGER and an error otherwise.func checkInteger( []byte) error {iflen() == 0 {returnStructuralError{"empty integer"} }iflen() == 1 {returnnil }if ([0] == 0 && [1]&0x80 == 0) || ([0] == 0xff && [1]&0x80 == 0x80) {returnStructuralError{"integer not minimally-encoded"} }returnnil}// parseInt64 treats the given bytes as a big-endian, signed integer and// returns the result.func parseInt64( []byte) ( int64, error) { = checkInteger()if != nil {return }iflen() > 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())*8return}// parseInt32 treats the given bytes as a big-endian, signed integer and returns// the result.func parseInt32( []byte) (int32, error) {if := checkInteger(); != nil {return0, } , := parseInt64()if != nil {return0, }if != int64(int32()) {return0, StructuralError{"integer too large"} }returnint32(), nil}var bigOne = big.NewInt(1)// parseBigInt treats the given bytes as a big-endian, signed integer and returns// the result.func parseBigInt( []byte) (*big.Int, error) {if := checkInteger(); != nil {returnnil, } := new(big.Int)iflen() > 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.typeBitStringstruct { 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 {return0 } := / 8 := 7 - uint(%8)returnint(.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 parseBitString( []byte) ( BitString, error) {iflen() == 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).varNullRawValue = RawValue{Tag: TagNull}// NullBytes contains bytes representing the DER-encoded ASN.1 NULL type.varNullBytes = []byte{TagNull, 0}// OBJECT IDENTIFIER// An ObjectIdentifier represents an ASN.1 OBJECT IDENTIFIER.typeObjectIdentifier []int// Equal reports whether oi and other represent the same identifier.func ( ObjectIdentifier) ( ObjectIdentifier) bool {iflen() != len() {returnfalse }for := 0; < len(); ++ {if [] != [] {returnfalse } }returntrue}func ( ObjectIdentifier) () string {varstrings.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 parseObjectIdentifier( []byte) ( ObjectIdentifier, error) {iflen() == 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 } := 2for ; < len(); ++ { , , = parseBase128Int(, )if != nil {return } [] = } = [0:]return}// ENUMERATED// An Enumerated is represented as a plain int.typeEnumeratedint// FLAG// A Flag accepts any data and is set to true if present.typeFlagbool// 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 parseBase128Int( []byte, int) (, int, error) { = varint64for := 0; < len(); ++ {// 5 * 7 bits per byte == 35 bits of data // Thus the representation is either non-minimal or too large for an int32if == 5 { = StructuralError{"base 128 integer too large"}return } <<= 7 := []// integers should be minimally encoded, so the leading octet should // never be 0x80if == 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 platformsif > math.MaxInt32 { = StructuralError{"base 128 integer too large"} }return } } = SyntaxError{"truncated base 128 integer"}return}// UTCTimefunc parseUTCTime( []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 parseGeneralizedTime( []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 parseNumericString( []byte) ( string, error) {for , := range {if !isNumeric() {return"", SyntaxError{"NumericString contains invalid character"} } }returnstring(), nil}// isNumeric reports whether the given b is in the ASN.1 NumericString set.func isNumeric( byte) bool {return'0' <= && <= '9' || == ' '}// PrintableString// parsePrintableString parses an ASN.1 PrintableString from the given byte// array and returns it.func parsePrintableString( []byte) ( string, error) {for , := range {if !isPrintable(, allowAsterisk, allowAmpersand) { = SyntaxError{"PrintableString contains invalid character"}return } } = string()return}type asteriskFlag booltype ampersandFlag boolconst ( 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 isPrintable( 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 parseIA5String( []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 parseT61String( []byte) ( string, error) {returnstring(), nil}// UTF8String// parseUTF8String parses an ASN.1 UTF8String (raw UTF-8) from the given byte// array and returns it.func parseUTF8String( []byte) ( string, error) {if !utf8.Valid() {return"", errors.New("asn1: invalid UTF-8 string") }returnstring(), 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 parseBMPString( []byte) (string, error) {iflen()%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)forlen() > 0 { = append(, uint16([0])<<8+uint16([1])) = [2:] }returnstring(utf16.Decode()), nil}// A RawValue represents an undecoded ASN.1 object.typeRawValuestruct { 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.typeRawContent []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 parseTagAndLength( []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 afterwardsif .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 = 0for := 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 parseSequenceOf( []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. := 0for := 0; < len(); {vartagAndLength , , = parseTagAndLength(, )if != nil {return }switch .tag {caseTagIA5String, 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 = TagPrintableStringcaseTagGeneralizedTime, TagUTCTime:// Likewise, both time types are treated the same. .tag = TagUTCTime }if ! && (.class != ClassUniversal || .isCompound != || .tag != ) { = StructuralError{"sequence tag mismatch"}return }ifinvalidLength(, .length, len()) { = SyntaxError{"truncated sequence"}return } += .length ++ } = reflect.MakeSlice(, , ) := fieldParameters{} := 0for := 0; < ; ++ { , = parseField(.Index(), , , )if != nil {return } }return}var ( bitStringType = reflect.TypeFor[BitString]() objectIdentifierType = reflect.TypeFor[ObjectIdentifier]() enumeratedType = reflect.TypeFor[Enumerated]() flagType = reflect.TypeFor[Flag]() timeType = reflect.TypeFor[time.Time]() rawValueType = reflect.TypeFor[RawValue]() rawContentsType = reflect.TypeFor[RawContent]() bigIntType = reflect.TypeFor[*big.Int]())// invalidLength reports whether offset + length > sliceLength, or if the// addition would overflow.func invalidLength(, , 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 parseField( 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 {vartagAndLength , , = parseTagAndLength(, )if != nil {return }ifinvalidLength(, .length, len()) { = SyntaxError{"data truncated"}return }varanyif !.isCompound && .class == ClassUniversal { := [ : +.length]switch .tag {caseTagPrintableString: , = parsePrintableString()caseTagNumericString: , = parseNumericString()caseTagIA5String: , = parseIA5String()caseTagT61String: , = parseT61String()caseTagUTF8String: , = parseUTF8String()caseTagInteger: , = parseInt64()caseTagBitString: , = parseBitString()caseTagOID: , = parseObjectIdentifier()caseTagUTCTime: , = parseUTCTime()caseTagGeneralizedTime: , = parseGeneralizedTime()caseTagOctetString: = caseTagBMPString: , = parseBMPString()default:// If we don't know how to handle the type, we just leave Value as nil. } } += .lengthif != nil {return }if != nil { .Set(reflect.ValueOf()) }return } , , := parseTagAndLength(, )if != nil {return }if .explicit { := ClassContextSpecificif .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. } elseif .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 {caseTagIA5String, TagGeneralString, TagT61String, TagUTF8String, TagNumericString, TagBMPString: = .tag } } elseif .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 }ifinvalidLength(, .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, , [:]}returncase *ObjectIdentifier: *, = parseObjectIdentifier()returncase *BitString: *, = parseBitString()returncase *time.Time:if == TagUTCTime { *, = parseUTCTime()return } *, = parseGeneralizedTime()returncase *Enumerated: , := parseInt32()if == nil { * = Enumerated() } = returncase *Flag: * = truereturncase **big.Int: , := parseBigInt()if == nil { * = } = return }switch := ; .Kind() {casereflect.Bool: , := parseBool()if == nil { .SetBool() } = returncasereflect.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 typescasereflect.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())) } := 0for := 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.returncasereflect.Slice: := if .Elem().Kind() == reflect.Uint8 { .Set(reflect.MakeSlice(, len(), len()))reflect.Copy(, reflect.ValueOf())return } , := parseSequenceOf(, , .Elem())if == nil { .Set() } = returncasereflect.String:varstringswitch {caseTagPrintableString: , = parsePrintableString()caseTagNumericString: , = parseNumericString()caseTagIA5String: , = parseIA5String()caseTagT61String: , = parseT61String()caseTagUTF8String: , = parseUTF8String()caseTagGeneralString:// 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()caseTagBMPString: , = 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 canHaveDefaultValue( reflect.Kind) bool {switch {casereflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:returntrue }returnfalse}// 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 setDefaultValue( reflect.Value, fieldParameters) ( bool) {if !.optional {return } = trueif .defaultValue == nil {return }ifcanHaveDefaultValue(.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].// 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) {returnUnmarshalWithParams(, , "")}// 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() {returnnil, &invalidUnmarshalError{reflect.TypeOf()} } , := parseField(.Elem(), , 0, parseFieldParameters())if != nil {returnnil, }return [:], nil}
The pages are generated with Goldsv0.7.0-preview. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.