From 3ab331ed29279cdf53ade59aa1b57372caece359 Mon Sep 17 00:00:00 2001 From: Adam Langley Date: Wed, 18 Nov 2009 16:32:44 -0800 Subject: [PATCH] asn1: add support for RawContent R=rsc CC=golang-dev https://golang.org/cl/157056 --- src/pkg/asn1/asn1.go | 21 ++++++++++++++++++++- src/pkg/asn1/asn1_test.go | 26 ++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/src/pkg/asn1/asn1.go b/src/pkg/asn1/asn1.go index 5e264dc5ca..a345a3b551 100644 --- a/src/pkg/asn1/asn1.go +++ b/src/pkg/asn1/asn1.go @@ -349,6 +349,11 @@ type RawValue struct { Bytes []byte; } +// 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 @@ -460,6 +465,7 @@ var ( objectIdentifierType = reflect.Typeof(ObjectIdentifier{}); timeType = reflect.Typeof(&time.Time{}); rawValueType = reflect.Typeof(RawValue{}); + rawContentsType = reflect.Typeof(RawContent(nil)); ) // invalidLength returns true iff offset + length > sliceLength, or if the @@ -594,7 +600,7 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam if ok { offset = initOffset } else { - err = StructuralError{fmt.Sprintf("tags don't match (%d vs %+v) %+v %s %#v", expectedTag, t, params, fieldType.Name(), bytes[offset:len(bytes)])} + err = StructuralError{fmt.Sprintf("tags don't match (%d vs %+v) %+v %s @%d", expectedTag, t, params, fieldType.Name(), offset)} } return; } @@ -662,9 +668,19 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam return; case *reflect.StructValue: structType := fieldType.(*reflect.StructType); + + if structType.NumField() > 0 && + structType.Field(0).Type == rawContentsType { + bytes := bytes[initOffset : offset+t.length]; + val.Field(0).SetValue(reflect.NewValue(RawContent(bytes))); + } + innerOffset := 0; for i := 0; i < structType.NumField(); i++ { field := structType.Field(i); + if i == 0 && field.Type == rawContentsType { + continue + } innerOffset, err = parseField(val.Field(i), innerBytes, innerOffset, parseFieldParameters(field.Tag)); if err != nil { return @@ -763,6 +779,9 @@ func setDefaultValue(v reflect.Value, params fieldParameters) (ok bool) { // [explicit] tag:x specifies the ASN.1 tag number; implies ASN.1 CONTEXT SPECIFIC // default:x sets the default value for optional integer fields // +// 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. +// // Other ASN.1 types are not supported; if it encounters them, // Unmarshal returns a parse error. func Unmarshal(val interface{}, b []byte) (rest []byte, err os.Error) { diff --git a/src/pkg/asn1/asn1_test.go b/src/pkg/asn1/asn1_test.go index 0e818dc300..6f677ffb69 100644 --- a/src/pkg/asn1/asn1_test.go +++ b/src/pkg/asn1/asn1_test.go @@ -354,6 +354,32 @@ func TestCertificateWithNUL(t *testing.T) { } } +type rawStructTest struct { + Raw RawContent; + A int; +} + +func TestRawStructs(t *testing.T) { + var s rawStructTest; + input := []byte{0x30, 0x03, 0x02, 0x01, 0x50}; + + rest, err := Unmarshal(&s, input); + if len(rest) != 0 { + t.Errorf("incomplete parse: %x", rest); + return; + } + if err != nil { + t.Error(err); + return; + } + if s.A != 0x50 { + t.Errorf("bad value for A: got %d want %d", s.A, 0x50) + } + if bytes.Compare([]byte(s.Raw), input) != 0 { + t.Errorf("bad value for Raw: got %x want %x", s.Raw, input) + } +} + var derEncodedSelfSignedCert = Certificate{ TBSCertificate: TBSCertificate{ Version: 0, -- 2.50.0