internal/wycheproof: add crypto/ecdh tests
Alongside the existing ECDH tests, add tests that use the new crypto/ecdh package. The test vectors include a number of private that use non-standard sizes, which we reject, but aren't flagged, so we need to skip them. Change-Id: Iaaef225b0149a86833095f51748d230385d43bfe Reviewed-on: https://go-review.googlesource.com/c/crypto/+/424274 Reviewed-by: Russ Cox <rsc@golang.org> Run-TryBot: Roland Shoemaker <roland@golang.org> Reviewed-by: Filippo Valsorda <filippo@golang.org> TryBot-Result: Gopher Robot <gobot@golang.org> Auto-Submit: Roland Shoemaker <roland@golang.org>
This commit is contained in:
committed by
Gopher Robot
parent
bd7e27e617
commit
c86fa9a7ed
@@ -0,0 +1,142 @@
|
||||
// Copyright 2022 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.
|
||||
|
||||
//go:build go1.20
|
||||
|
||||
package wycheproof
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/ecdh"
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestECDHStdLib(t *testing.T) {
|
||||
type ECDHTestVector struct {
|
||||
// A brief description of the test case
|
||||
Comment string `json:"comment,omitempty"`
|
||||
// A list of flags
|
||||
Flags []string `json:"flags,omitempty"`
|
||||
// the private key
|
||||
Private string `json:"private,omitempty"`
|
||||
// Encoded public key
|
||||
Public string `json:"public,omitempty"`
|
||||
// Test result
|
||||
Result string `json:"result,omitempty"`
|
||||
// The shared secret key
|
||||
Shared string `json:"shared,omitempty"`
|
||||
// Identifier of the test case
|
||||
TcID int `json:"tcId,omitempty"`
|
||||
}
|
||||
|
||||
type ECDHTestGroup struct {
|
||||
Curve string `json:"curve,omitempty"`
|
||||
Tests []*ECDHTestVector `json:"tests,omitempty"`
|
||||
}
|
||||
|
||||
type Root struct {
|
||||
TestGroups []*ECDHTestGroup `json:"testGroups,omitempty"`
|
||||
}
|
||||
|
||||
flagsShouldPass := map[string]bool{
|
||||
// We don't support compressed points.
|
||||
"CompressedPoint": false,
|
||||
// We don't support decoding custom curves.
|
||||
"UnnamedCurve": false,
|
||||
// WrongOrder and UnusedParam are only found with UnnamedCurve.
|
||||
"WrongOrder": false,
|
||||
"UnusedParam": false,
|
||||
|
||||
// X25519 specific flags
|
||||
"Twist": true,
|
||||
"SmallPublicKey": false,
|
||||
"LowOrderPublic": false,
|
||||
"ZeroSharedSecret": false,
|
||||
"NonCanonicalPublic": true,
|
||||
}
|
||||
|
||||
// curveToCurve is a map of all elliptic curves supported
|
||||
// by crypto/elliptic, which can subsequently be parsed and tested.
|
||||
curveToCurve := map[string]ecdh.Curve{
|
||||
"secp256r1": ecdh.P256(),
|
||||
"secp384r1": ecdh.P384(),
|
||||
"secp521r1": ecdh.P521(),
|
||||
"curve25519": ecdh.X25519(),
|
||||
}
|
||||
|
||||
curveToKeySize := map[string]int{
|
||||
"secp256r1": 32,
|
||||
"secp384r1": 48,
|
||||
"secp521r1": 66,
|
||||
"curve25519": 32,
|
||||
}
|
||||
|
||||
for _, f := range []string{
|
||||
"ecdh_secp256r1_ecpoint_test.json",
|
||||
"ecdh_secp384r1_ecpoint_test.json",
|
||||
"ecdh_secp521r1_ecpoint_test.json",
|
||||
"x25519_test.json",
|
||||
} {
|
||||
var root Root
|
||||
readTestVector(t, f, &root)
|
||||
for _, tg := range root.TestGroups {
|
||||
if _, ok := curveToCurve[tg.Curve]; !ok {
|
||||
continue
|
||||
}
|
||||
for _, tt := range tg.Tests {
|
||||
tg, tt := tg, tt
|
||||
t.Run(fmt.Sprintf("%s/%d", tg.Curve, tt.TcID), func(t *testing.T) {
|
||||
t.Logf("Type: %v", tt.Result)
|
||||
t.Logf("Flags: %q", tt.Flags)
|
||||
t.Log(tt.Comment)
|
||||
|
||||
shouldPass := shouldPass(tt.Result, tt.Flags, flagsShouldPass)
|
||||
|
||||
curve := curveToCurve[tg.Curve]
|
||||
p := decodeHex(tt.Public)
|
||||
pub, err := curve.NewPublicKey(p)
|
||||
if err != nil {
|
||||
if shouldPass {
|
||||
t.Errorf("NewPublicKey: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
privBytes := decodeHex(tt.Private)
|
||||
if len(privBytes) != curveToKeySize[tg.Curve] {
|
||||
t.Skipf("non-standard key size %d", len(privBytes))
|
||||
}
|
||||
|
||||
priv, err := curve.NewPrivateKey(privBytes)
|
||||
if err != nil {
|
||||
if shouldPass {
|
||||
t.Errorf("NewPrivateKey: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
shared := decodeHex(tt.Shared)
|
||||
x, err := curve.ECDH(priv, pub)
|
||||
if err != nil {
|
||||
if tg.Curve == "curve25519" && !shouldPass {
|
||||
// ECDH is expected to only return an error when using X25519,
|
||||
// in all other cases an error is unexpected.
|
||||
return
|
||||
}
|
||||
t.Fatalf("ECDH: %v", err)
|
||||
}
|
||||
|
||||
if bytes.Equal(shared, x) != shouldPass {
|
||||
if shouldPass {
|
||||
t.Errorf("ECDH = %x, want %x", shared, x)
|
||||
} else {
|
||||
t.Errorf("ECDH = %x, want anything else", shared)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user