1
0
mirror of https://github.com/golang/go synced 2024-11-22 05:54:40 -07:00

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:
Adam Langley 2012-07-10 18:23:30 -04:00
parent 685a61df7e
commit eeffa738a9
4 changed files with 43 additions and 7 deletions

View File

@ -251,7 +251,7 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
SerialNumber: big.NewInt(1),
Subject: pkix.Name{
CommonName: commonName,
Organization: []string{"Acme Co"},
Organization: []string{"Σ Acme Co"},
},
NotBefore: time.Unix(1000, 0),
NotAfter: time.Unix(100000, 0),

View File

@ -98,6 +98,8 @@ func parseFieldParameters(str string) (ret fieldParameters) {
ret.stringType = tagIA5String
case part == "printable":
ret.stringType = tagPrintableString
case part == "utf8":
ret.stringType = tagUTF8String
case strings.HasPrefix(part, "default:"):
i, err := strconv.ParseInt(part[8:], 10, 64)
if err == nil {

View File

@ -6,11 +6,13 @@ package asn1
import (
"bytes"
"errors"
"fmt"
"io"
"math/big"
"reflect"
"time"
"unicode/utf8"
)
// A forkableWriter is an in-memory buffer that can be
@ -280,6 +282,11 @@ func marshalIA5String(out *forkableWriter, s string) (err error) {
return
}
func marshalUTF8String(out *forkableWriter, s string) (err error) {
_, err = out.Write([]byte(s))
return
}
func marshalTwoDigits(out *forkableWriter, v int) (err error) {
err = out.WriteByte(byte('0' + (v/10)%10))
if err != nil {
@ -446,10 +453,13 @@ func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameter
}
return
case reflect.String:
if params.stringType == tagIA5String {
switch params.stringType {
case tagIA5String:
return marshalIA5String(out, v.String())
} else {
case tagPrintableString:
return marshalPrintableString(out, v.String())
default:
return marshalUTF8String(out, v.String())
}
return
}
@ -492,11 +502,27 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters)
}
class := classUniversal
if params.stringType != 0 {
if tag != tagPrintableString {
return StructuralError{"Explicit string type given to non-string member"}
if params.stringType != 0 && tag != tagPrintableString {
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 {

View File

@ -122,6 +122,7 @@ var marshalTests = []marshalTest{
{testSET([]int{10}), "310302010a"},
{omitEmptyTest{[]string{}}, "3000"},
{omitEmptyTest{[]string{"1"}}, "30053003130131"},
{"Σ", "0c02cea3"},
}
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")
}
}