]> Cypherpunks.ru repositories - gostls13.git/blobdiff - src/crypto/ecdsa/ecdsa.go
[dev.boringcrypto] all: merge master into dev.boringcrypto
[gostls13.git] / src / crypto / ecdsa / ecdsa.go
index e4e580fada7930a4ca4642f655c0f2507954de63..d10e354c762b437c0fbd6358de5ec3588c0bb047 100644 (file)
@@ -33,10 +33,12 @@ import (
        "crypto/elliptic"
        "crypto/internal/randutil"
        "crypto/sha512"
-       "encoding/asn1"
        "errors"
        "io"
        "math/big"
+
+       "golang.org/x/crypto/cryptobyte"
+       "golang.org/x/crypto/cryptobyte/asn1"
 )
 
 import (
@@ -67,6 +69,24 @@ type PublicKey struct {
        boring unsafe.Pointer
 }
 
+// Equal reports whether pub and x have the same value.
+//
+// Two keys are only considered to have the same value if they have the same Curve value.
+// Note that for example elliptic.P256() and elliptic.P256().Params() are different
+// values, as the latter is a generic not constant time implementation.
+func (pub *PublicKey) Equal(x crypto.PublicKey) bool {
+       xx, ok := x.(*PublicKey)
+       if !ok {
+               return false
+       }
+       return pub.X.Cmp(xx.X) == 0 && pub.Y.Cmp(xx.Y) == 0 &&
+               // Standard library Curve implementations are singletons, so this check
+               // will work for those. Other Curves might be equivalent even if not
+               // singletons, but there is no definitive way to check for that, and
+               // better to err on the side of safety.
+               pub.Curve == xx.Curve
+}
+
 // PrivateKey represents an ECDSA private key.
 type PrivateKey struct {
        PublicKey
@@ -75,10 +95,6 @@ type PrivateKey struct {
        boring unsafe.Pointer
 }
 
-type ecdsaSignature struct {
-       R, S *big.Int
-}
-
 // Public returns the public key corresponding to priv.
 func (priv *PrivateKey) Public() crypto.PublicKey {
        return &priv.PublicKey
@@ -106,7 +122,12 @@ func (priv *PrivateKey) Sign(rand io.Reader, digest []byte, opts crypto.SignerOp
                return nil, err
        }
 
-       return asn1.Marshal(ecdsaSignature{r, s})
+       var b cryptobyte.Builder
+       b.AddASN1(asn1.SEQUENCE, func(b *cryptobyte.Builder) {
+               b.AddASN1BigInt(r)
+               b.AddASN1BigInt(s)
+       })
+       return b.Bytes()
 }
 
 var one = new(big.Int).SetInt64(1)
@@ -186,7 +207,7 @@ var errZeroParam = errors.New("zero parameter")
 
 // Sign signs a hash (which should be the result of hashing a larger message)
 // using the private key, priv. If the hash is longer than the bit-length of the
-// private key's curve order, the hash will be truncated to that length.  It
+// private key's curve order, the hash will be truncated to that length. It
 // returns the signature as a pair of integers. The security of the private key
 // depends on the entropy of rand.
 func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error) {
@@ -274,6 +295,15 @@ func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err err
        return
 }
 
+// SignASN1 signs a hash (which should be the result of hashing a larger message)
+// using the private key, priv. If the hash is longer than the bit-length of the
+// private key's curve order, the hash will be truncated to that length. It
+// returns the ASN.1 encoded signature. The security of the private key
+// depends on the entropy of rand.
+func SignASN1(rand io.Reader, priv *PrivateKey, hash []byte) ([]byte, error) {
+       return priv.Sign(rand, hash, nil)
+}
+
 // Verify verifies the signature in r, s of hash using the public key, pub. Its
 // return value records whether the signature is valid.
 func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool {
@@ -327,6 +357,24 @@ func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool {
        return x.Cmp(r) == 0
 }
 
+// VerifyASN1 verifies the ASN.1 encoded signature, sig, of hash using the
+// public key, pub. Its return value records whether the signature is valid.
+func VerifyASN1(pub *PublicKey, hash, sig []byte) bool {
+       var (
+               r, s  = &big.Int{}, &big.Int{}
+               inner cryptobyte.String
+       )
+       input := cryptobyte.String(sig)
+       if !input.ReadASN1(&inner, asn1.SEQUENCE) ||
+               !input.Empty() ||
+               !inner.ReadASN1Integer(r) ||
+               !inner.ReadASN1Integer(s) ||
+               !inner.Empty() {
+               return false
+       }
+       return Verify(pub, hash, r, s)
+}
+
 type zr struct {
        io.Reader
 }