encoding/asn1: error instead of panic on invalid value to Unmarshal

Changes Unmarshal to return an error, instead of
panicking when its value is nil or not a pointer.

This change matches the behavior of other encoding
packages like json.

Fixes #41509.

Change-Id: I92c3af3a960144566e4c2b55d00c3a6fe477c8d5
GitHub-Last-Rev: c668b6e4ad826f84542c2675eb31ccfb010c45bb
GitHub-Pull-Request: golang/go#41485
Reviewed-on: https://go-review.googlesource.com/c/go/+/255881
Run-TryBot: Emmanuel Odeke <emm.odeke@gmail.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Emmanuel Odeke <emm.odeke@gmail.com>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Trust: Emmanuel Odeke <emm.odeke@gmail.com>
diff --git a/src/encoding/asn1/asn1.go b/src/encoding/asn1/asn1.go
index d809dde..fa3d4e3 100644
--- a/src/encoding/asn1/asn1.go
+++ b/src/encoding/asn1/asn1.go
@@ -1035,7 +1035,8 @@
 // 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.
+// 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,
@@ -1095,11 +1096,31 @@
 	return UnmarshalWithParams(b, val, "")
 }
 
+// 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 (e *invalidUnmarshalError) Error() string {
+	if e.Type == nil {
+		return "asn1: Unmarshal recipient value is nil"
+	}
+
+	if e.Type.Kind() != reflect.Ptr {
+		return "asn1: Unmarshal recipient value is non-pointer " + e.Type.String()
+	}
+	return "asn1: Unmarshal recipient value is nil " + e.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 UnmarshalWithParams(b []byte, val interface{}, params string) (rest []byte, err error) {
-	v := reflect.ValueOf(val).Elem()
-	offset, err := parseField(v, b, 0, parseFieldParameters(params))
+	v := reflect.ValueOf(val)
+	if v.Kind() != reflect.Ptr || v.IsNil() {
+		return nil, &invalidUnmarshalError{reflect.TypeOf(val)}
+	}
+	offset, err := parseField(v.Elem(), b, 0, parseFieldParameters(params))
 	if err != nil {
 		return nil, err
 	}
diff --git a/src/encoding/asn1/asn1_test.go b/src/encoding/asn1/asn1_test.go
index 8daae97..8985538 100644
--- a/src/encoding/asn1/asn1_test.go
+++ b/src/encoding/asn1/asn1_test.go
@@ -518,6 +518,29 @@
 	}
 }
 
+func TestUnmarshalWithNilOrNonPointer(t *testing.T) {
+	tests := []struct {
+		b    []byte
+		v    interface{}
+		want string
+	}{
+		{b: []byte{0x05, 0x00}, v: nil, want: "asn1: Unmarshal recipient value is nil"},
+		{b: []byte{0x05, 0x00}, v: RawValue{}, want: "asn1: Unmarshal recipient value is non-pointer asn1.RawValue"},
+		{b: []byte{0x05, 0x00}, v: (*RawValue)(nil), want: "asn1: Unmarshal recipient value is nil *asn1.RawValue"},
+	}
+
+	for _, test := range tests {
+		_, err := Unmarshal(test.b, test.v)
+		if err == nil {
+			t.Errorf("Unmarshal expecting error, got nil")
+			continue
+		}
+		if g, w := err.Error(), test.want; g != w {
+			t.Errorf("InvalidUnmarshalError mismatch\nGot:  %q\nWant: %q", g, w)
+		}
+	}
+}
+
 type Certificate struct {
 	TBSCertificate     TBSCertificate
 	SignatureAlgorithm AlgorithmIdentifier