-
Notifications
You must be signed in to change notification settings - Fork 17.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
crypto/rsa,crypto/ecdsa,crypto/ed25519: implement PublicKey.Equal
This makes all modern public keys in the standard library implement a common interface (below) that can be used by applications for better type safety and allows for checking that public (and private keys via Public()) are equivalent. interface { Equal(crypto.PublicKey) bool } Equality for ECDSA keys is complicated, we take a strict interpretation that works for all secure applications (the ones not using the unfortunate non-constant time CurveParams implementation) and fails closed otherwise. Tests in separate files to make them x_tests and avoid an import loop with crypto/x509. Fixes #21704 Change-Id: Id5379c96384a11c5afde0614955360e7470bb1c4 Reviewed-on: https://go-review.googlesource.com/c/go/+/223754 Reviewed-by: Katie Hockman <[email protected]>
- Loading branch information
1 parent
24925c7
commit 5c9bd49
Showing
6 changed files
with
171 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
// Copyright 2020 The Go Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
package ecdsa_test | ||
|
||
import ( | ||
"crypto" | ||
"crypto/ecdsa" | ||
"crypto/elliptic" | ||
"crypto/rand" | ||
"crypto/x509" | ||
"testing" | ||
) | ||
|
||
func testEqual(t *testing.T, c elliptic.Curve) { | ||
private, _ := ecdsa.GenerateKey(c, rand.Reader) | ||
public := &private.PublicKey | ||
|
||
if !public.Equal(public) { | ||
t.Errorf("public key is not equal to itself: %v", public) | ||
} | ||
if !public.Equal(crypto.Signer(private).Public().(*ecdsa.PublicKey)) { | ||
t.Errorf("private.Public() is not Equal to public: %q", public) | ||
} | ||
|
||
enc, err := x509.MarshalPKIXPublicKey(public) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
decoded, err := x509.ParsePKIXPublicKey(enc) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
if !public.Equal(decoded) { | ||
t.Errorf("public key is not equal to itself after decoding: %v", public) | ||
} | ||
|
||
other, _ := ecdsa.GenerateKey(c, rand.Reader) | ||
if public.Equal(other) { | ||
t.Errorf("different public keys are Equal") | ||
} | ||
|
||
// Ensure that keys with the same coordinates but on different curves | ||
// aren't considered Equal. | ||
differentCurve := &ecdsa.PublicKey{} | ||
*differentCurve = *public // make a copy of the public key | ||
if differentCurve.Curve == elliptic.P256() { | ||
differentCurve.Curve = elliptic.P224() | ||
} else { | ||
differentCurve.Curve = elliptic.P256() | ||
} | ||
if public.Equal(differentCurve) { | ||
t.Errorf("public keys with different curves are Equal") | ||
} | ||
|
||
// This is not necessarily desirable, but if the Curve implementations are | ||
// different, the PublicKeys are not considered Equal. | ||
differentImpl := &ecdsa.PublicKey{} | ||
*differentImpl = *public | ||
// CurveParams also implements the Curve interface, although with a generic | ||
// non-constant time implementation. See golang.org/issue/34648. | ||
differentImpl.Curve = differentImpl.Curve.Params() | ||
if public.Equal(differentImpl) { | ||
t.Errorf("public keys with different curve implementations are Equal") | ||
} | ||
} | ||
|
||
func TestEqual(t *testing.T) { | ||
t.Run("P224", func(t *testing.T) { testEqual(t, elliptic.P224()) }) | ||
if testing.Short() { | ||
return | ||
} | ||
t.Run("P256", func(t *testing.T) { testEqual(t, elliptic.P256()) }) | ||
t.Run("P384", func(t *testing.T) { testEqual(t, elliptic.P384()) }) | ||
t.Run("P521", func(t *testing.T) { testEqual(t, elliptic.P521()) }) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
// Copyright 2020 The Go Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
package rsa_test | ||
|
||
import ( | ||
"crypto" | ||
"crypto/rand" | ||
"crypto/rsa" | ||
"crypto/x509" | ||
"testing" | ||
) | ||
|
||
func TestEqual(t *testing.T) { | ||
private, _ := rsa.GenerateKey(rand.Reader, 512) | ||
public := &private.PublicKey | ||
|
||
if !public.Equal(public) { | ||
t.Errorf("public key is not equal to itself: %v", public) | ||
} | ||
if !public.Equal(crypto.Signer(private).Public().(*rsa.PublicKey)) { | ||
t.Errorf("private.Public() is not Equal to public: %q", public) | ||
} | ||
|
||
enc, err := x509.MarshalPKIXPublicKey(public) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
decoded, err := x509.ParsePKIXPublicKey(enc) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
if !public.Equal(decoded) { | ||
t.Errorf("public key is not equal to itself after decoding: %v", public) | ||
} | ||
|
||
other, _ := rsa.GenerateKey(rand.Reader, 512) | ||
if public.Equal(other) { | ||
t.Errorf("different public keys are Equal") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters