// 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 ber// 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 ()// We start by dealing with each of the primitive types in turn.// BOOLEANfunc parseBool( []byte) ( bool, error) {iflen() != 1 { = asn1.SyntaxError{Msg: "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: = asn1.SyntaxError{Msg: "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 {returnasn1.StructuralError{Msg: "empty integer"} }iflen() == 1 {returnnil }if ([0] == 0 && [1]&0x80 == 0) || ([0] == 0xff && [1]&0x80 == 0x80) {returnasn1.StructuralError{Msg: "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. = asn1.StructuralError{Msg: "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}// parseInt 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, asn1.StructuralError{Msg: "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// parseBitString parses an ASN.1 bit string from the given byte slice and returns it.func parseBitString( []byte) ( asn1.BitString, error) {iflen() == 0 { = asn1.SyntaxError{Msg: "zero length BIT STRING"}return } := int([0])if > 7 ||len() == 1 && > 0 || [len()-1]&((1<<[0])-1) != 0 { = asn1.SyntaxError{Msg: "invalid padding bits in BIT STRING"}return } .BitLength = (len()-1)*8 - .Bytes = [1:]return}// OBJECT IDENTIFIER// 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) ( asn1.ObjectIdentifier, error) {iflen() == 0 { = asn1.SyntaxError{Msg: "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}// 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 { = asn1.StructuralError{Msg: "base 128 integer too large"}return } <<= 7 := [] |= int64( & 0x7f) ++if &0x80 == 0 { = int()// Ensure that the returned value fits in an int on all platformsif > math.MaxInt32 { = asn1.StructuralError{Msg: "base 128 integer too large"} }return } } = asn1.SyntaxError{Msg: "truncated base 128 integer"}return}func _parseBase128Int( []byte, int) (, int, error) { = for := 0; < len(); ++ { <<= 7 := [] |= int( & 0x7f) ++if &0x80 == 0 {return } } = asn1.SyntaxError{Msg: "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 = "20060102150405Z0700" := 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"", asn1.SyntaxError{Msg: "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) { = asn1.SyntaxError{Msg: "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 { = asn1.SyntaxError{Msg: "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}// 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 { = asn1.SyntaxError{Msg: "non-minimal tag"}return } }if >= len() { = asn1.SyntaxError{Msg: "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 {// TODO: Fix this for BER as it should be allowed. Not seen this in // the wild with SNMP devices though. = asn1.SyntaxError{Msg: "indefinite length found (not DER)"}return } .length = 0for := 0; < ; ++ {if >= len() { = asn1.SyntaxError{Msg: "truncated tag or length"}return } = [] ++if .length >= 1<<23 {// We can't shift ret.length up without // overflowing. = asn1.StructuralError{Msg: "length too large"}return } .length <<= 8 .length |= int() } }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 ! { = asn1.StructuralError{Msg: "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 != ) { = asn1.StructuralError{Msg: "sequence tag mismatch"}return }ifinvalidLength(, .length, len()) { = asn1.SyntaxError{Msg: "truncated sequence"}return } += .length ++ } = reflect.MakeSlice(, , ) := fieldParameters{} := 0for := 0; < ; ++ { , = parseField(.Index(), , , )if != nil {return } }return}var ( bitStringType = reflect.TypeOf(asn1.BitString{}) objectIdentifierType = reflect.TypeOf(asn1.ObjectIdentifier{}) enumeratedType = reflect.TypeOf(asn1.Enumerated(0)) flagType = reflect.TypeOf(asn1.Flag(false)) timeType = reflect.TypeOf(time.Time{}) rawValueType = reflect.TypeOf(asn1.RawValue{}) rawContentsType = reflect.TypeOf(asn1.RawContent(nil)) bigIntType = reflect.TypeOf(new(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(, ) { = asn1.SyntaxError{Msg: "sequence truncated"} }return }// Deal with the ANY type.if := ; .Kind() == reflect.Interface && .NumMethod() == 0 {vartagAndLength , , = parseTagAndLength(, )if != nil {return }ifinvalidLength(, .length, len()) { = asn1.SyntaxError{Msg: "data truncated"}return }varinterface{}if !.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() { = asn1.StructuralError{Msg: "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 { = asn1.StructuralError{Msg: "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 { = asn1.StructuralError{Msg: "explicitly tagged member didn't match"} }return } } , , , := getUniversalType()if ! { = asn1.StructuralError{Msg: 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 { = asn1.StructuralError{Msg: fmt.Sprintf("tags don't match (%d vs %+v) %+v %s @%d", , , , .Name(), )} }return }ifinvalidLength(, .length, len()) { = asn1.SyntaxError{Msg: "data truncated"}return } := [ : +.length] += .length// We deal with the structures defined in this package first.switch {caserawValueType: := asn1.RawValue{.class, .tag, .isCompound, , [:]} .Set(reflect.ValueOf())returncaseobjectIdentifierType: , := parseObjectIdentifier() .Set(reflect.MakeSlice(.Type(), len(), len()))if == nil {reflect.Copy(, reflect.ValueOf()) } = returncasebitStringType: , := parseBitString()if == nil { .Set(reflect.ValueOf()) } = returncasetimeType:vartime.Timevarerrorif == tagUTCTime { , = parseUTCTime() } else { , = parseGeneralizedTime() }if == nil { .Set(reflect.ValueOf()) } = returncaseenumeratedType: , := parseInt32()if == nil { .SetInt(int64()) } = returncaseflagType: .SetBool(true)returncasebigIntType: , := parseBigInt()if == nil { .Set(reflect.ValueOf()) } = 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().PkgPath != "" { = asn1.StructuralError{Msg: "struct contains unexported fields"}return } }if .NumField() > 0 && .Field(0).Type == rawContentsType { := [:] .Field(0).Set(reflect.ValueOf(asn1.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: = asn1.SyntaxError{Msg: fmt.Sprintf("internal error: unknown string type %d", )} }if == nil { .SetString() }return } = asn1.StructuralError{Msg: "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 BER-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.//// 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//// 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 type name of a slice element ends with "SET" then it's treated as if// the "set" tag was set on it. 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, interface{}) ( []byte, error) {returnUnmarshalWithParams(, , "")}// 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, interface{}, string) ( []byte, error) { := reflect.ValueOf().Elem() , := parseField(, , 0, parseFieldParameters())if != nil {returnnil, }return [:], nil}
The pages are generated with Goldsv0.6.7. (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 @Go100and1 (reachable from the left QR code) to get the latest news of Golds.