Skip to content

Commit

Permalink
Tolerate leading zeros in RSA-SSA-PKCS1 public key modulus
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 689347032
Change-Id: Ie1ed29a7c6a21203e403d6aace629b22c03cae32
  • Loading branch information
morambro authored and copybara-github committed Oct 24, 2024
1 parent d87fb11 commit 4dd6945
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 6 deletions.
14 changes: 8 additions & 6 deletions signature/rsassapkcs1/protoserialization.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,15 +166,16 @@ func (s *publicKeyParser) ParseKey(keySerialization *protoserialization.KeySeria
if err != nil {
return nil, err
}
modulus := protoKey.GetN()
// Tolerate leading zeros in modulus encoding.
modulus := new(big.Int).SetBytes(protoKey.GetN())
exponent := new(big.Int).SetBytes(protoKey.GetE())
params, err := NewParameters(new(big.Int).SetBytes(modulus).BitLen(), hashType, int(exponent.Int64()), variant)
params, err := NewParameters(modulus.BitLen(), hashType, int(exponent.Int64()), variant)
if err != nil {
return nil, err
}
// keySerialization.IDRequirement() returns zero if the key doesn't have a key requirement.
keyID, _ := keySerialization.IDRequirement()
return NewPublicKey(modulus, keyID, params)
return NewPublicKey(modulus.Bytes(), keyID, params)
}

type privateKeyParser struct{}
Expand Down Expand Up @@ -208,9 +209,10 @@ func (s *privateKeyParser) ParseKey(keySerialization *protoserialization.KeySeri
if err != nil {
return nil, err
}
modulus := protoPublicKey.GetN()
// Tolerate leading zeros in modulus encoding.
modulus := new(big.Int).SetBytes(protoPublicKey.GetN())
exponent := new(big.Int).SetBytes(protoPublicKey.GetE())
params, err := NewParameters(new(big.Int).SetBytes(modulus).BitLen(), hashType, int(exponent.Int64()), variant)
params, err := NewParameters(modulus.BitLen(), hashType, int(exponent.Int64()), variant)
if err != nil {
return nil, err
}
Expand All @@ -219,7 +221,7 @@ func (s *privateKeyParser) ParseKey(keySerialization *protoserialization.KeySeri
}
// keySerialization.IDRequirement() returns zero if the key doesn't have a key requirement.
keyID, _ := keySerialization.IDRequirement()
publicKey, err := NewPublicKey(modulus, keyID, params)
publicKey, err := NewPublicKey(modulus.Bytes(), keyID, params)
if err != nil {
return nil, err
}
Expand Down
85 changes: 85 additions & 0 deletions signature/rsassapkcs1/protoserialization_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,40 @@ func newPublicKey(t *testing.T, modulus []byte, idRequirement uint32, parameters
return key
}

func TestParsePublicKeyWithZeroPaddingModulus(t *testing.T) {
n := base64Decode(t, n2048Base64)
publicKey := &rsassapkcs1pb.RsaSsaPkcs1PublicKey{
Params: &rsassapkcs1pb.RsaSsaPkcs1Params{
HashType: commonpb.HashType_SHA256,
},
N: append([]byte{0, 0, 0, 0}, n...),
E: new(big.Int).SetUint64(uint64(f4)).Bytes(),
Version: publicKeyProtoVersion,
}
serializedPublicKey, err := proto.Marshal(publicKey)
if err != nil {
t.Fatalf("proto.Marshal(%v) err = %v, want nil", publicKey, err)
}

keySerialization := newKeySerialization(t, &tinkpb.KeyData{
TypeUrl: "type.googleapis.com/google.crypto.tink.RsaSsaPkcs1PublicKey",
Value: serializedPublicKey,
KeyMaterialType: tinkpb.KeyData_ASYMMETRIC_PUBLIC,
}, tinkpb.OutputPrefixType_TINK, 123)

wantPublicKey :=
newPublicKey(t, n, 123, newParameters(t, 2048, SHA256, f4, VariantTink))

parser := &publicKeyParser{}
parsedPublicKey, err := parser.ParseKey(keySerialization)
if err != nil {
t.Fatalf("parser.ParseKey(%v) err = %v, want non-nil", keySerialization, err)
}
if got, want := parsedPublicKey, wantPublicKey; !got.Equals(want) {
t.Errorf("got.Equals(want) = false, want true")
}
}

func TestParseAndSerializePublicKey(t *testing.T) {
publicKey2048 := rsassapkcs1pb.RsaSsaPkcs1PublicKey{
Params: &rsassapkcs1pb.RsaSsaPkcs1Params{
Expand Down Expand Up @@ -602,6 +636,57 @@ func newPrivateKey(t *testing.T, publicKey *PublicKey, privateKeyValues PrivateK
return privateKey
}

func TestParsePrivateKeyWithZeroPaddingModulus(t *testing.T) {
n := base64Decode(t, n2048Base64)
p := base64Decode(t, p2048Base64)
q := base64Decode(t, q2048Base64)
d := base64Decode(t, d2048Base64)
dp := base64Decode(t, dp2048Base64)
dq := base64Decode(t, dq2048Base64)
qInv := base64Decode(t, qInv2048Base64)
privateKey := &rsassapkcs1pb.RsaSsaPkcs1PrivateKey{
D: d,
P: p,
Q: q,
Dp: dp,
Dq: dq,
Crt: qInv,
PublicKey: &rsassapkcs1pb.RsaSsaPkcs1PublicKey{
Params: &rsassapkcs1pb.RsaSsaPkcs1Params{
HashType: commonpb.HashType_SHA256,
},
// Pad with zeros.
N: append([]byte{0, 0, 0, 0}, base64Decode(t, n2048Base64)...),
E: new(big.Int).SetUint64(uint64(f4)).Bytes(),
Version: publicKeyProtoVersion,
},
Version: privateKeyProtoVersion,
}
serializedPrivateKey, err := proto.Marshal(privateKey)
if err != nil {
t.Fatalf("proto.Marshal(%v) err = %v, want nil", privateKey, err)
}
token := insecuresecretdataaccess.Token{}
keySerialization := newKeySerialization(t, &tinkpb.KeyData{
TypeUrl: "type.googleapis.com/google.crypto.tink.RsaSsaPkcs1PrivateKey",
Value: serializedPrivateKey,
KeyMaterialType: tinkpb.KeyData_ASYMMETRIC_PRIVATE,
}, tinkpb.OutputPrefixType_TINK, 12345)
wantPrivateKey := newPrivateKey(t, newPublicKey(t, n, 12345, newParameters(t, 2048, SHA256, f4, VariantTink)), PrivateKeyValues{
P: secretdata.NewBytesFromData(p, token),
Q: secretdata.NewBytesFromData(q, token),
D: secretdata.NewBytesFromData(d, token),
})
parser := &privateKeyParser{}
parsedPrivateKey, err := parser.ParseKey(keySerialization)
if err != nil {
t.Fatalf("parser.ParseKey(%v) err = %v, want non-nil", keySerialization, err)
}
if got, want := parsedPrivateKey, wantPrivateKey; !got.Equals(want) {
t.Errorf("got.Equals(want) = false, want true")
}
}

func TestParseAndSerializePrivateKey(t *testing.T) {
privateKey2048 := &rsassapkcs1pb.RsaSsaPkcs1PrivateKey{
D: base64Decode(t, d2048Base64),
Expand Down

0 comments on commit 4dd6945

Please sign in to comment.