]> Cypherpunks repositories - gostls13.git/commitdiff
asn1: add support for RawContent
authorAdam Langley <agl@golang.org>
Thu, 19 Nov 2009 00:32:44 +0000 (16:32 -0800)
committerAdam Langley <agl@golang.org>
Thu, 19 Nov 2009 00:32:44 +0000 (16:32 -0800)
R=rsc
CC=golang-dev
https://golang.org/cl/157056

src/pkg/asn1/asn1.go
src/pkg/asn1/asn1_test.go

index 5e264dc5cae6b1e52bfd661a3bdd6311f4005414..a345a3b5510d661dc477d994b531e6a2884d3967 100644 (file)
@@ -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) {
index 0e818dc300a629f31c94b7a6a31ccc9a4ba92030..6f677ffb69e52753c07348ab7884ec2d98ae251e 100644 (file)
@@ -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,