mirror of
https://github.com/golang/go
synced 2024-11-18 16:04:44 -07:00
encoding/asn1: add NullBytes and NullRawValue for working with ASN.1 NULL
There were a number of places in crypto/x509 that used hardcoded representations of the ASN.1 NULL type, in both byte slice and RawValue struct forms. This change adds two new exported vars to the asn1 package for working with ASN.1 NULL in both its forms, and converts all usages from the x509 package. In addition, tests were added to exercise Marshal and Unmarshal on both vars. See #19446 for discussion. Change-Id: I63dbd0835841ccbc810bd6ec794360a84e933f1e Reviewed-on: https://go-review.googlesource.com/38660 Run-TryBot: Adam Langley <agl@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Adam Langley <agl@golang.org>
This commit is contained in:
parent
8fcd69d330
commit
d9b1f9e85e
@ -69,9 +69,7 @@ func marshalPublicKey(pub interface{}) (publicKeyBytes []byte, publicKeyAlgorith
|
|||||||
publicKeyAlgorithm.Algorithm = oidPublicKeyRSA
|
publicKeyAlgorithm.Algorithm = oidPublicKeyRSA
|
||||||
// This is a NULL parameters value which is required by
|
// This is a NULL parameters value which is required by
|
||||||
// https://tools.ietf.org/html/rfc3279#section-2.3.1.
|
// https://tools.ietf.org/html/rfc3279#section-2.3.1.
|
||||||
publicKeyAlgorithm.Parameters = asn1.RawValue{
|
publicKeyAlgorithm.Parameters = asn1.NullRawValue
|
||||||
Tag: 5,
|
|
||||||
}
|
|
||||||
case *ecdsa.PublicKey:
|
case *ecdsa.PublicKey:
|
||||||
publicKeyBytes = elliptic.Marshal(pub.Curve, pub.X, pub.Y)
|
publicKeyBytes = elliptic.Marshal(pub.Curve, pub.X, pub.Y)
|
||||||
oid, ok := oidFromNamedCurve(pub.Curve)
|
oid, ok := oidFromNamedCurve(pub.Curve)
|
||||||
@ -355,10 +353,8 @@ func rsaPSSParameters(hashFunc crypto.Hash) asn1.RawValue {
|
|||||||
|
|
||||||
params := pssParameters{
|
params := pssParameters{
|
||||||
Hash: pkix.AlgorithmIdentifier{
|
Hash: pkix.AlgorithmIdentifier{
|
||||||
Algorithm: hashOID,
|
Algorithm: hashOID,
|
||||||
Parameters: asn1.RawValue{
|
Parameters: asn1.NullRawValue,
|
||||||
Tag: 5, /* ASN.1 NULL */
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
MGF: pkix.AlgorithmIdentifier{
|
MGF: pkix.AlgorithmIdentifier{
|
||||||
Algorithm: oidMGF1,
|
Algorithm: oidMGF1,
|
||||||
@ -368,10 +364,8 @@ func rsaPSSParameters(hashFunc crypto.Hash) asn1.RawValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mgf1Params := pkix.AlgorithmIdentifier{
|
mgf1Params := pkix.AlgorithmIdentifier{
|
||||||
Algorithm: hashOID,
|
Algorithm: hashOID,
|
||||||
Parameters: asn1.RawValue{
|
Parameters: asn1.NullRawValue,
|
||||||
Tag: 5, /* ASN.1 NULL */
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
@ -418,11 +412,10 @@ func getSignatureAlgorithmFromAI(ai pkix.AlgorithmIdentifier) SignatureAlgorithm
|
|||||||
// https://tools.ietf.org/html/rfc3447#section-8.1), that the
|
// https://tools.ietf.org/html/rfc3447#section-8.1), that the
|
||||||
// salt length matches the hash length, and that the trailer
|
// salt length matches the hash length, and that the trailer
|
||||||
// field has the default value.
|
// field has the default value.
|
||||||
asn1NULL := []byte{0x05, 0x00}
|
if !bytes.Equal(params.Hash.Parameters.FullBytes, asn1.NullBytes) ||
|
||||||
if !bytes.Equal(params.Hash.Parameters.FullBytes, asn1NULL) ||
|
|
||||||
!params.MGF.Algorithm.Equal(oidMGF1) ||
|
!params.MGF.Algorithm.Equal(oidMGF1) ||
|
||||||
!mgf1HashFunc.Algorithm.Equal(params.Hash.Algorithm) ||
|
!mgf1HashFunc.Algorithm.Equal(params.Hash.Algorithm) ||
|
||||||
!bytes.Equal(mgf1HashFunc.Parameters.FullBytes, asn1NULL) ||
|
!bytes.Equal(mgf1HashFunc.Parameters.FullBytes, asn1.NullBytes) ||
|
||||||
params.TrailerField != 1 {
|
params.TrailerField != 1 {
|
||||||
return UnknownSignatureAlgorithm
|
return UnknownSignatureAlgorithm
|
||||||
}
|
}
|
||||||
@ -928,16 +921,13 @@ type distributionPointName struct {
|
|||||||
RelativeName pkix.RDNSequence `asn1:"optional,tag:1"`
|
RelativeName pkix.RDNSequence `asn1:"optional,tag:1"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// asn1Null is the ASN.1 encoding of a NULL value.
|
|
||||||
var asn1Null = []byte{5, 0}
|
|
||||||
|
|
||||||
func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{}, error) {
|
func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{}, error) {
|
||||||
asn1Data := keyData.PublicKey.RightAlign()
|
asn1Data := keyData.PublicKey.RightAlign()
|
||||||
switch algo {
|
switch algo {
|
||||||
case RSA:
|
case RSA:
|
||||||
// RSA public keys must have a NULL in the parameters
|
// RSA public keys must have a NULL in the parameters
|
||||||
// (https://tools.ietf.org/html/rfc3279#section-2.3.1).
|
// (https://tools.ietf.org/html/rfc3279#section-2.3.1).
|
||||||
if !bytes.Equal(keyData.Algorithm.Parameters.FullBytes, asn1Null) {
|
if !bytes.Equal(keyData.Algorithm.Parameters.FullBytes, asn1.NullBytes) {
|
||||||
return nil, errors.New("x509: RSA key missing NULL parameters")
|
return nil, errors.New("x509: RSA key missing NULL parameters")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1650,9 +1640,7 @@ func signingParamsForPublicKey(pub interface{}, requestedSigAlgo SignatureAlgori
|
|||||||
pubType = RSA
|
pubType = RSA
|
||||||
hashFunc = crypto.SHA256
|
hashFunc = crypto.SHA256
|
||||||
sigAlgo.Algorithm = oidSignatureSHA256WithRSA
|
sigAlgo.Algorithm = oidSignatureSHA256WithRSA
|
||||||
sigAlgo.Parameters = asn1.RawValue{
|
sigAlgo.Parameters = asn1.NullRawValue
|
||||||
Tag: 5,
|
|
||||||
}
|
|
||||||
|
|
||||||
case *ecdsa.PublicKey:
|
case *ecdsa.PublicKey:
|
||||||
pubType = ECDSA
|
pubType = ECDSA
|
||||||
|
@ -207,6 +207,14 @@ func parseBitString(bytes []byte) (ret BitString, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NULL
|
||||||
|
|
||||||
|
// NullRawValue is a RawValue with its Tag set to the ASN.1 NULL type tag (5).
|
||||||
|
var NullRawValue = RawValue{Tag: TagNull}
|
||||||
|
|
||||||
|
// NullBytes contains bytes representing the DER-encoded ASN.1 NULL type.
|
||||||
|
var NullBytes = []byte{TagNull, 0}
|
||||||
|
|
||||||
// OBJECT IDENTIFIER
|
// OBJECT IDENTIFIER
|
||||||
|
|
||||||
// An ObjectIdentifier represents an ASN.1 OBJECT IDENTIFIER.
|
// An ObjectIdentifier represents an ASN.1 OBJECT IDENTIFIER.
|
||||||
|
@ -479,6 +479,7 @@ var unmarshalTestData = []struct {
|
|||||||
out interface{}
|
out interface{}
|
||||||
}{
|
}{
|
||||||
{[]byte{0x02, 0x01, 0x42}, newInt(0x42)},
|
{[]byte{0x02, 0x01, 0x42}, newInt(0x42)},
|
||||||
|
{[]byte{0x05, 0x00}, &RawValue{0, 5, false, []byte{}, []byte{0x05, 0x00}}},
|
||||||
{[]byte{0x30, 0x08, 0x06, 0x06, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d}, &TestObjectIdentifierStruct{[]int{1, 2, 840, 113549}}},
|
{[]byte{0x30, 0x08, 0x06, 0x06, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d}, &TestObjectIdentifierStruct{[]int{1, 2, 840, 113549}}},
|
||||||
{[]byte{0x03, 0x04, 0x06, 0x6e, 0x5d, 0xc0}, &BitString{[]byte{110, 93, 192}, 18}},
|
{[]byte{0x03, 0x04, 0x06, 0x6e, 0x5d, 0xc0}, &BitString{[]byte{110, 93, 192}, 18}},
|
||||||
{[]byte{0x30, 0x09, 0x02, 0x01, 0x01, 0x02, 0x01, 0x02, 0x02, 0x01, 0x03}, &[]int{1, 2, 3}},
|
{[]byte{0x30, 0x09, 0x02, 0x01, 0x01, 0x02, 0x01, 0x02, 0x02, 0x01, 0x03}, &[]int{1, 2, 3}},
|
||||||
@ -1007,3 +1008,28 @@ func TestUnexportedStructField(t *testing.T) {
|
|||||||
t.Errorf("got %v, want %v", err, want)
|
t.Errorf("got %v, want %v", err, want)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNull(t *testing.T) {
|
||||||
|
marshaled, err := Marshal(NullRawValue)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if !bytes.Equal(NullBytes, marshaled) {
|
||||||
|
t.Errorf("Expected Marshal of NullRawValue to yeild %x, got %x", NullBytes, marshaled)
|
||||||
|
}
|
||||||
|
|
||||||
|
unmarshaled := RawValue{}
|
||||||
|
if _, err := Unmarshal(NullBytes, &unmarshaled); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
unmarshaled.FullBytes = NullRawValue.FullBytes
|
||||||
|
if len(unmarshaled.Bytes) == 0 {
|
||||||
|
// DeepEqual considers a nil slice and an empty slice to be different.
|
||||||
|
unmarshaled.Bytes = NullRawValue.Bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(NullRawValue, unmarshaled) {
|
||||||
|
t.Errorf("Expected Unmarshal of NullBytes to yield %v, got %v", NullRawValue, unmarshaled)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -24,6 +24,7 @@ const (
|
|||||||
TagInteger = 2
|
TagInteger = 2
|
||||||
TagBitString = 3
|
TagBitString = 3
|
||||||
TagOctetString = 4
|
TagOctetString = 4
|
||||||
|
TagNull = 5
|
||||||
TagOID = 6
|
TagOID = 6
|
||||||
TagEnum = 10
|
TagEnum = 10
|
||||||
TagUTF8String = 12
|
TagUTF8String = 12
|
||||||
|
Loading…
Reference in New Issue
Block a user