Commit 3ab331ed authored by Adam Langley's avatar Adam Langley

asn1: add support for RawContent

R=rsc
CC=golang-dev
https://golang.org/cl/157056
parent cc56fc38
...@@ -349,6 +349,11 @@ type RawValue struct { ...@@ -349,6 +349,11 @@ type RawValue struct {
Bytes []byte; 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 // Tagging
// parseTagAndLength parses an ASN.1 tag and length pair from the given offset // parseTagAndLength parses an ASN.1 tag and length pair from the given offset
...@@ -460,6 +465,7 @@ var ( ...@@ -460,6 +465,7 @@ var (
objectIdentifierType = reflect.Typeof(ObjectIdentifier{}); objectIdentifierType = reflect.Typeof(ObjectIdentifier{});
timeType = reflect.Typeof(&time.Time{}); timeType = reflect.Typeof(&time.Time{});
rawValueType = reflect.Typeof(RawValue{}); rawValueType = reflect.Typeof(RawValue{});
rawContentsType = reflect.Typeof(RawContent(nil));
) )
// invalidLength returns true iff offset + length > sliceLength, or if the // 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 ...@@ -594,7 +600,7 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
if ok { if ok {
offset = initOffset offset = initOffset
} else { } 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; return;
} }
...@@ -662,9 +668,19 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam ...@@ -662,9 +668,19 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
return; return;
case *reflect.StructValue: case *reflect.StructValue:
structType := fieldType.(*reflect.StructType); 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; innerOffset := 0;
for i := 0; i < structType.NumField(); i++ { for i := 0; i < structType.NumField(); i++ {
field := structType.Field(i); field := structType.Field(i);
if i == 0 && field.Type == rawContentsType {
continue
}
innerOffset, err = parseField(val.Field(i), innerBytes, innerOffset, parseFieldParameters(field.Tag)); innerOffset, err = parseField(val.Field(i), innerBytes, innerOffset, parseFieldParameters(field.Tag));
if err != nil { if err != nil {
return return
...@@ -763,6 +779,9 @@ func setDefaultValue(v reflect.Value, params fieldParameters) (ok bool) { ...@@ -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 // [explicit] tag:x specifies the ASN.1 tag number; implies ASN.1 CONTEXT SPECIFIC
// default:x sets the default value for optional integer fields // 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, // Other ASN.1 types are not supported; if it encounters them,
// Unmarshal returns a parse error. // Unmarshal returns a parse error.
func Unmarshal(val interface{}, b []byte) (rest []byte, err os.Error) { func Unmarshal(val interface{}, b []byte) (rest []byte, err os.Error) {
......
...@@ -354,6 +354,32 @@ func TestCertificateWithNUL(t *testing.T) { ...@@ -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{ var derEncodedSelfSignedCert = Certificate{
TBSCertificate: TBSCertificate{ TBSCertificate: TBSCertificate{
Version: 0, Version: 0,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment