mirror of https://github.com/golang/go.git
encoding/asn1: promote untyped strings to UTF8 as needed.
Previously, strings that didn't have an explicit ASN.1 string type were taken to be ASN.1 PrintableStrings. This resulted in an error if a unrepresentable charactor was included. For compatibility reasons, I'm too afraid to switch the default string type to UTF8String, but this patch causes untyped strings to become UTF8Strings if they contain a charactor that's not valid in a PrintableString. Fixes #3791. R=golang-dev, bradfitz, r, r CC=golang-dev https://golang.org/cl/6348074
This commit is contained in:
parent
685a61df7e
commit
eeffa738a9
|
|
@ -251,7 +251,7 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
|
||||||
SerialNumber: big.NewInt(1),
|
SerialNumber: big.NewInt(1),
|
||||||
Subject: pkix.Name{
|
Subject: pkix.Name{
|
||||||
CommonName: commonName,
|
CommonName: commonName,
|
||||||
Organization: []string{"Acme Co"},
|
Organization: []string{"Σ Acme Co"},
|
||||||
},
|
},
|
||||||
NotBefore: time.Unix(1000, 0),
|
NotBefore: time.Unix(1000, 0),
|
||||||
NotAfter: time.Unix(100000, 0),
|
NotAfter: time.Unix(100000, 0),
|
||||||
|
|
|
||||||
|
|
@ -98,6 +98,8 @@ func parseFieldParameters(str string) (ret fieldParameters) {
|
||||||
ret.stringType = tagIA5String
|
ret.stringType = tagIA5String
|
||||||
case part == "printable":
|
case part == "printable":
|
||||||
ret.stringType = tagPrintableString
|
ret.stringType = tagPrintableString
|
||||||
|
case part == "utf8":
|
||||||
|
ret.stringType = tagUTF8String
|
||||||
case strings.HasPrefix(part, "default:"):
|
case strings.HasPrefix(part, "default:"):
|
||||||
i, err := strconv.ParseInt(part[8:], 10, 64)
|
i, err := strconv.ParseInt(part[8:], 10, 64)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
|
|
||||||
|
|
@ -6,11 +6,13 @@ package asn1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"math/big"
|
"math/big"
|
||||||
"reflect"
|
"reflect"
|
||||||
"time"
|
"time"
|
||||||
|
"unicode/utf8"
|
||||||
)
|
)
|
||||||
|
|
||||||
// A forkableWriter is an in-memory buffer that can be
|
// A forkableWriter is an in-memory buffer that can be
|
||||||
|
|
@ -280,6 +282,11 @@ func marshalIA5String(out *forkableWriter, s string) (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func marshalUTF8String(out *forkableWriter, s string) (err error) {
|
||||||
|
_, err = out.Write([]byte(s))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func marshalTwoDigits(out *forkableWriter, v int) (err error) {
|
func marshalTwoDigits(out *forkableWriter, v int) (err error) {
|
||||||
err = out.WriteByte(byte('0' + (v/10)%10))
|
err = out.WriteByte(byte('0' + (v/10)%10))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -446,10 +453,13 @@ func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameter
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
if params.stringType == tagIA5String {
|
switch params.stringType {
|
||||||
|
case tagIA5String:
|
||||||
return marshalIA5String(out, v.String())
|
return marshalIA5String(out, v.String())
|
||||||
} else {
|
case tagPrintableString:
|
||||||
return marshalPrintableString(out, v.String())
|
return marshalPrintableString(out, v.String())
|
||||||
|
default:
|
||||||
|
return marshalUTF8String(out, v.String())
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -492,11 +502,27 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters)
|
||||||
}
|
}
|
||||||
class := classUniversal
|
class := classUniversal
|
||||||
|
|
||||||
if params.stringType != 0 {
|
if params.stringType != 0 && tag != tagPrintableString {
|
||||||
if tag != tagPrintableString {
|
return StructuralError{"Explicit string type given to non-string member"}
|
||||||
return StructuralError{"Explicit string type given to non-string member"}
|
}
|
||||||
|
|
||||||
|
if tag == tagPrintableString {
|
||||||
|
if params.stringType == 0 {
|
||||||
|
// This is a string without an explicit string type. We'll use
|
||||||
|
// a PrintableString if the character set in the string is
|
||||||
|
// sufficiently limited, otherwise we'll use a UTF8String.
|
||||||
|
for _, r := range v.String() {
|
||||||
|
if r >= utf8.RuneSelf || !isPrintable(byte(r)) {
|
||||||
|
if !utf8.ValidString(v.String()) {
|
||||||
|
return errors.New("asn1: string not valid UTF-8")
|
||||||
|
}
|
||||||
|
tag = tagUTF8String
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tag = params.stringType
|
||||||
}
|
}
|
||||||
tag = params.stringType
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if params.set {
|
if params.set {
|
||||||
|
|
|
||||||
|
|
@ -122,6 +122,7 @@ var marshalTests = []marshalTest{
|
||||||
{testSET([]int{10}), "310302010a"},
|
{testSET([]int{10}), "310302010a"},
|
||||||
{omitEmptyTest{[]string{}}, "3000"},
|
{omitEmptyTest{[]string{}}, "3000"},
|
||||||
{omitEmptyTest{[]string{"1"}}, "30053003130131"},
|
{omitEmptyTest{[]string{"1"}}, "30053003130131"},
|
||||||
|
{"Σ", "0c02cea3"},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMarshal(t *testing.T) {
|
func TestMarshal(t *testing.T) {
|
||||||
|
|
@ -137,3 +138,10 @@ func TestMarshal(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestInvalidUTF8(t *testing.T) {
|
||||||
|
_, err := Marshal(string([]byte{0xff, 0xff}))
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("invalid UTF8 string was accepted")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue