mirror of
https://github.com/golang/go
synced 2024-11-18 19:44:46 -07:00
encoding/asn1: handle ASN1's string type BMPString
This code enables handling of ASN1's string type BMPString, used in some digital signatures.
Parsing code taken from golang.org/x/crypto/pkcs12.
Change-Id: Ibeae9cf4d8ae7c18f8b5420ad9244a16e117ff6b
GitHub-Last-Rev: 6945253514
GitHub-Pull-Request: golang/go#26690
Reviewed-on: https://go-review.googlesource.com/c/go/+/126624
Run-TryBot: Andrew Bonventre <andybons@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Andrew Bonventre <andybons@golang.org>
This commit is contained in:
parent
5e907e38b8
commit
a3a1bdff79
@ -27,6 +27,7 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
"unicode/utf16"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -475,6 +476,29 @@ func parseUTF8String(bytes []byte) (ret string, err error) {
|
|||||||
return string(bytes), nil
|
return string(bytes), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BMPString
|
||||||
|
|
||||||
|
// parseBMPString parses an ASN.1 BMPString (Basic Multilingual Plane of
|
||||||
|
// ISO/IEC/ITU 10646-1) from the given byte slice and returns it.
|
||||||
|
func parseBMPString(bmpString []byte) (string, error) {
|
||||||
|
if len(bmpString)%2 != 0 {
|
||||||
|
return "", errors.New("pkcs12: odd-length BMP string")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strip terminator if present.
|
||||||
|
if l := len(bmpString); l >= 2 && bmpString[l-1] == 0 && bmpString[l-2] == 0 {
|
||||||
|
bmpString = bmpString[:l-2]
|
||||||
|
}
|
||||||
|
|
||||||
|
s := make([]uint16, 0, len(bmpString)/2)
|
||||||
|
for len(bmpString) > 0 {
|
||||||
|
s = append(s, uint16(bmpString[0])<<8+uint16(bmpString[1]))
|
||||||
|
bmpString = bmpString[2:]
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(utf16.Decode(s)), nil
|
||||||
|
}
|
||||||
|
|
||||||
// A RawValue represents an undecoded ASN.1 object.
|
// A RawValue represents an undecoded ASN.1 object.
|
||||||
type RawValue struct {
|
type RawValue struct {
|
||||||
Class, Tag int
|
Class, Tag int
|
||||||
@ -589,7 +613,7 @@ func parseSequenceOf(bytes []byte, sliceType reflect.Type, elemType reflect.Type
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
switch t.tag {
|
switch t.tag {
|
||||||
case TagIA5String, TagGeneralString, TagT61String, TagUTF8String, TagNumericString:
|
case TagIA5String, TagGeneralString, TagT61String, TagUTF8String, TagNumericString, TagBMPString:
|
||||||
// We pretend that various other string types are
|
// We pretend that various other string types are
|
||||||
// PRINTABLE STRINGs so that a sequence of them can be
|
// PRINTABLE STRINGs so that a sequence of them can be
|
||||||
// parsed into a []string.
|
// parsed into a []string.
|
||||||
@ -691,6 +715,8 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
|
|||||||
result, err = parseGeneralizedTime(innerBytes)
|
result, err = parseGeneralizedTime(innerBytes)
|
||||||
case TagOctetString:
|
case TagOctetString:
|
||||||
result = innerBytes
|
result = innerBytes
|
||||||
|
case TagBMPString:
|
||||||
|
result, err = parseBMPString(innerBytes)
|
||||||
default:
|
default:
|
||||||
// If we don't know how to handle the type, we just leave Value as nil.
|
// If we don't know how to handle the type, we just leave Value as nil.
|
||||||
}
|
}
|
||||||
@ -759,7 +785,7 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
|
|||||||
if universalTag == TagPrintableString {
|
if universalTag == TagPrintableString {
|
||||||
if t.class == ClassUniversal {
|
if t.class == ClassUniversal {
|
||||||
switch t.tag {
|
switch t.tag {
|
||||||
case TagIA5String, TagGeneralString, TagT61String, TagUTF8String, TagNumericString:
|
case TagIA5String, TagGeneralString, TagT61String, TagUTF8String, TagNumericString, TagBMPString:
|
||||||
universalTag = t.tag
|
universalTag = t.tag
|
||||||
}
|
}
|
||||||
} else if params.stringType != 0 {
|
} else if params.stringType != 0 {
|
||||||
@ -957,6 +983,9 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
|
|||||||
// that allow the encoding to change midstring and
|
// that allow the encoding to change midstring and
|
||||||
// such. We give up and pass it as an 8-bit string.
|
// such. We give up and pass it as an 8-bit string.
|
||||||
v, err = parseT61String(innerBytes)
|
v, err = parseT61String(innerBytes)
|
||||||
|
case TagBMPString:
|
||||||
|
v, err = parseBMPString(innerBytes)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
err = SyntaxError{fmt.Sprintf("internal error: unknown string type %d", universalTag)}
|
err = SyntaxError{fmt.Sprintf("internal error: unknown string type %d", universalTag)}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ package asn1
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"math/big"
|
"math/big"
|
||||||
@ -1096,3 +1097,35 @@ func TestTaggedRawValue(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var bmpStringTests = []struct {
|
||||||
|
decoded string
|
||||||
|
encodedHex string
|
||||||
|
}{
|
||||||
|
{"", "0000"},
|
||||||
|
// Example from https://tools.ietf.org/html/rfc7292#appendix-B.
|
||||||
|
{"Beavis", "0042006500610076006900730000"},
|
||||||
|
// Some characters from the "Letterlike Symbols Unicode block".
|
||||||
|
{"\u2115 - Double-struck N", "21150020002d00200044006f00750062006c0065002d00730074007200750063006b0020004e0000"},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBMPString(t *testing.T) {
|
||||||
|
for i, test := range bmpStringTests {
|
||||||
|
encoded, err := hex.DecodeString(test.encodedHex)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("#%d: failed to decode from hex string", i)
|
||||||
|
}
|
||||||
|
|
||||||
|
decoded, err := parseBMPString(encoded)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("#%d: decoding output gave an error: %s", i, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if decoded != test.decoded {
|
||||||
|
t.Errorf("#%d: decoding output resulted in %q, but it should have been %q", i, decoded, test.decoded)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -37,6 +37,7 @@ const (
|
|||||||
TagUTCTime = 23
|
TagUTCTime = 23
|
||||||
TagGeneralizedTime = 24
|
TagGeneralizedTime = 24
|
||||||
TagGeneralString = 27
|
TagGeneralString = 27
|
||||||
|
TagBMPString = 30
|
||||||
)
|
)
|
||||||
|
|
||||||
// ASN.1 class types represent the namespace of the tag.
|
// ASN.1 class types represent the namespace of the tag.
|
||||||
|
Loading…
Reference in New Issue
Block a user