mirror of
https://github.com/refraction-networking/utls.git
synced 2025-04-01 19:17:36 +03:00
* crypto/tls: Add hybrid post-quantum key agreement (#13) * import: client-side KEM from cloudflare/go * import: server-side KEM from cloudflare/go * fix: modify test to get rid of CFEvents. Note: uTLS does not promise any server-side functionality, and this change is made to be able to conduct unit tests which requires both side to be able to handle KEM Curves. Co-authored-by: Christopher Wood <caw@heapingbits.net> Co-Authored-By: Bas Westerbaan <bas@westerbaan.name> ---- Based on: * crypto/tls: Add hybrid post-quantum key agreement Adds X25519Kyber512Draft00, X25519Kyber768Draft00, and P256Kyber768Draft00 hybrid post-quantum key agreements with temporary group identifiers. The hybrid post-quantum key exchanges uses plain X{25519,448} instead of HPKE, which we assume will be more likely to be adopted. The order is chosen to match CECPQ2. Not enabled by default. Adds CFEvents to detect `HelloRetryRequest`s and to signal which key agreement was used. Co-authored-by: Christopher Wood <caw@heapingbits.net> [bas, 1.20.1: also adds P256Kyber768Draft00] [pwu, 1.20.4: updated circl to v1.3.3, moved code to cfevent.go] * crypto: add support for CIRCL signature schemes * only partially port the commit from cloudflare/go. We would stick to the official x509 at the cost of incompatibility. Co-Authored-By: Bas Westerbaan <bas@westerbaan.name> Co-Authored-By: Christopher Patton <3453007+cjpatton@users.noreply.github.com> Co-Authored-By: Peter Wu <peter@lekensteyn.nl> * crypto/tls: add new X25519Kyber768Draft00 code point Ported from cloudflare/go to support the upcoming new post-quantum keyshare. ---- * Point tls.X25519Kyber768Draft00 to the new 0x6399 identifier while the old 0xfe31 identifier is available as tls.X25519Kyber768Draft00Old. * Make sure that the kem.PrivateKey can always be mapped to the CurveID that was linked to it. This is needed since we now have two ID aliasing to the same scheme, and clients need to be able to detect whether the key share presented by the server actually matches the key share that the client originally sent. * Update tests, add the new identifier and remove unnecessary code. Link: https://mailarchive.ietf.org/arch/msg/tls/HAWpNpgptl--UZNSYuvsjB-Pc2k/ Link: https://datatracker.ietf.org/doc/draft-tls-westerbaan-xyber768d00/02/ Co-Authored-By: Peter Wu <peter@lekensteyn.nl> Co-Authored-By: Bas Westerbaan <bas@westerbaan.name> --------- Co-authored-by: Bas Westerbaan <bas@westerbaan.name> Co-authored-by: Christopher Patton <3453007+cjpatton@users.noreply.github.com> Co-authored-by: Peter Wu <peter@lekensteyn.nl>
170 lines
7 KiB
Go
170 lines
7 KiB
Go
// Copyright 2017 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 tls
|
|
|
|
import (
|
|
"crypto"
|
|
"testing"
|
|
|
|
circlPki "github.com/cloudflare/circl/pki"
|
|
)
|
|
|
|
func TestSignatureSelection(t *testing.T) {
|
|
rsaCert := &Certificate{
|
|
Certificate: [][]byte{testRSACertificate},
|
|
PrivateKey: testRSAPrivateKey,
|
|
}
|
|
pkcs1Cert := &Certificate{
|
|
Certificate: [][]byte{testRSACertificate},
|
|
PrivateKey: testRSAPrivateKey,
|
|
SupportedSignatureAlgorithms: []SignatureScheme{PKCS1WithSHA1, PKCS1WithSHA256},
|
|
}
|
|
ecdsaCert := &Certificate{
|
|
Certificate: [][]byte{testP256Certificate},
|
|
PrivateKey: testP256PrivateKey,
|
|
}
|
|
ed25519Cert := &Certificate{
|
|
Certificate: [][]byte{testEd25519Certificate},
|
|
PrivateKey: testEd25519PrivateKey,
|
|
}
|
|
|
|
tests := []struct {
|
|
cert *Certificate
|
|
peerSigAlgs []SignatureScheme
|
|
tlsVersion uint16
|
|
|
|
expectedSigAlg SignatureScheme
|
|
expectedSigType uint8
|
|
expectedHash crypto.Hash
|
|
}{
|
|
{rsaCert, []SignatureScheme{PKCS1WithSHA1, PKCS1WithSHA256}, VersionTLS12, PKCS1WithSHA1, signaturePKCS1v15, crypto.SHA1},
|
|
{rsaCert, []SignatureScheme{PKCS1WithSHA512, PKCS1WithSHA1}, VersionTLS12, PKCS1WithSHA512, signaturePKCS1v15, crypto.SHA512},
|
|
{rsaCert, []SignatureScheme{PSSWithSHA256, PKCS1WithSHA256}, VersionTLS12, PSSWithSHA256, signatureRSAPSS, crypto.SHA256},
|
|
{pkcs1Cert, []SignatureScheme{PSSWithSHA256, PKCS1WithSHA256}, VersionTLS12, PKCS1WithSHA256, signaturePKCS1v15, crypto.SHA256},
|
|
{rsaCert, []SignatureScheme{PSSWithSHA384, PKCS1WithSHA1}, VersionTLS13, PSSWithSHA384, signatureRSAPSS, crypto.SHA384},
|
|
{ecdsaCert, []SignatureScheme{ECDSAWithSHA1}, VersionTLS12, ECDSAWithSHA1, signatureECDSA, crypto.SHA1},
|
|
{ecdsaCert, []SignatureScheme{ECDSAWithP256AndSHA256}, VersionTLS12, ECDSAWithP256AndSHA256, signatureECDSA, crypto.SHA256},
|
|
{ecdsaCert, []SignatureScheme{ECDSAWithP256AndSHA256}, VersionTLS13, ECDSAWithP256AndSHA256, signatureECDSA, crypto.SHA256},
|
|
{ed25519Cert, []SignatureScheme{Ed25519}, VersionTLS12, Ed25519, signatureEd25519, directSigning},
|
|
{ed25519Cert, []SignatureScheme{Ed25519}, VersionTLS13, Ed25519, signatureEd25519, directSigning},
|
|
|
|
// TLS 1.2 without signature_algorithms extension
|
|
{rsaCert, nil, VersionTLS12, PKCS1WithSHA1, signaturePKCS1v15, crypto.SHA1},
|
|
{ecdsaCert, nil, VersionTLS12, ECDSAWithSHA1, signatureECDSA, crypto.SHA1},
|
|
|
|
// TLS 1.2 does not restrict the ECDSA curve (our ecdsaCert is P-256)
|
|
{ecdsaCert, []SignatureScheme{ECDSAWithP384AndSHA384}, VersionTLS12, ECDSAWithP384AndSHA384, signatureECDSA, crypto.SHA384},
|
|
}
|
|
|
|
for testNo, test := range tests {
|
|
sigAlg, err := selectSignatureScheme(test.tlsVersion, test.cert, test.peerSigAlgs)
|
|
if err != nil {
|
|
t.Errorf("test[%d]: unexpected selectSignatureScheme error: %v", testNo, err)
|
|
}
|
|
if test.expectedSigAlg != sigAlg {
|
|
t.Errorf("test[%d]: expected signature scheme %v, got %v", testNo, test.expectedSigAlg, sigAlg)
|
|
}
|
|
sigType, hashFunc, err := typeAndHashFromSignatureScheme(sigAlg)
|
|
if err != nil {
|
|
t.Errorf("test[%d]: unexpected typeAndHashFromSignatureScheme error: %v", testNo, err)
|
|
}
|
|
if test.expectedSigType != sigType {
|
|
t.Errorf("test[%d]: expected signature algorithm %#x, got %#x", testNo, test.expectedSigType, sigType)
|
|
}
|
|
if test.expectedHash != hashFunc {
|
|
t.Errorf("test[%d]: expected hash function %#x, got %#x", testNo, test.expectedHash, hashFunc)
|
|
}
|
|
}
|
|
|
|
brokenCert := &Certificate{
|
|
Certificate: [][]byte{testRSACertificate},
|
|
PrivateKey: testRSAPrivateKey,
|
|
SupportedSignatureAlgorithms: []SignatureScheme{Ed25519},
|
|
}
|
|
|
|
badTests := []struct {
|
|
cert *Certificate
|
|
peerSigAlgs []SignatureScheme
|
|
tlsVersion uint16
|
|
}{
|
|
{rsaCert, []SignatureScheme{ECDSAWithP256AndSHA256, ECDSAWithSHA1}, VersionTLS12},
|
|
{ecdsaCert, []SignatureScheme{PKCS1WithSHA256, PKCS1WithSHA1}, VersionTLS12},
|
|
{rsaCert, []SignatureScheme{0}, VersionTLS12},
|
|
{ed25519Cert, []SignatureScheme{ECDSAWithP256AndSHA256, ECDSAWithSHA1}, VersionTLS12},
|
|
{ecdsaCert, []SignatureScheme{Ed25519}, VersionTLS12},
|
|
{brokenCert, []SignatureScheme{Ed25519}, VersionTLS12},
|
|
{brokenCert, []SignatureScheme{PKCS1WithSHA256}, VersionTLS12},
|
|
// RFC 5246, Section 7.4.1.4.1, says to only consider {sha1,ecdsa} as
|
|
// default when the extension is missing, and RFC 8422 does not update
|
|
// it. Anyway, if a stack supports Ed25519 it better support sigalgs.
|
|
{ed25519Cert, nil, VersionTLS12},
|
|
// TLS 1.3 has no default signature_algorithms.
|
|
{rsaCert, nil, VersionTLS13},
|
|
{ecdsaCert, nil, VersionTLS13},
|
|
{ed25519Cert, nil, VersionTLS13},
|
|
// Wrong curve, which TLS 1.3 checks
|
|
{ecdsaCert, []SignatureScheme{ECDSAWithP384AndSHA384}, VersionTLS13},
|
|
// TLS 1.3 does not support PKCS1v1.5 or SHA-1.
|
|
{rsaCert, []SignatureScheme{PKCS1WithSHA256}, VersionTLS13},
|
|
{pkcs1Cert, []SignatureScheme{PSSWithSHA256, PKCS1WithSHA256}, VersionTLS13},
|
|
{ecdsaCert, []SignatureScheme{ECDSAWithSHA1}, VersionTLS13},
|
|
// The key can be too small for the hash.
|
|
{rsaCert, []SignatureScheme{PSSWithSHA512}, VersionTLS12},
|
|
}
|
|
|
|
for testNo, test := range badTests {
|
|
sigAlg, err := selectSignatureScheme(test.tlsVersion, test.cert, test.peerSigAlgs)
|
|
if err == nil {
|
|
t.Errorf("test[%d]: unexpected success, got %v", testNo, sigAlg)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestLegacyTypeAndHash(t *testing.T) {
|
|
sigType, hashFunc, err := legacyTypeAndHashFromPublicKey(testRSAPrivateKey.Public())
|
|
if err != nil {
|
|
t.Errorf("RSA: unexpected error: %v", err)
|
|
}
|
|
if expectedSigType := signaturePKCS1v15; expectedSigType != sigType {
|
|
t.Errorf("RSA: expected signature type %#x, got %#x", expectedSigType, sigType)
|
|
}
|
|
if expectedHashFunc := crypto.MD5SHA1; expectedHashFunc != hashFunc {
|
|
t.Errorf("RSA: expected hash %#x, got %#x", expectedHashFunc, hashFunc)
|
|
}
|
|
|
|
sigType, hashFunc, err = legacyTypeAndHashFromPublicKey(testECDSAPrivateKey.Public())
|
|
if err != nil {
|
|
t.Errorf("ECDSA: unexpected error: %v", err)
|
|
}
|
|
if expectedSigType := signatureECDSA; expectedSigType != sigType {
|
|
t.Errorf("ECDSA: expected signature type %#x, got %#x", expectedSigType, sigType)
|
|
}
|
|
if expectedHashFunc := crypto.SHA1; expectedHashFunc != hashFunc {
|
|
t.Errorf("ECDSA: expected hash %#x, got %#x", expectedHashFunc, hashFunc)
|
|
}
|
|
|
|
// Ed25519 is not supported by TLS 1.0 and 1.1.
|
|
_, _, err = legacyTypeAndHashFromPublicKey(testEd25519PrivateKey.Public())
|
|
if err == nil {
|
|
t.Errorf("Ed25519: unexpected success")
|
|
}
|
|
}
|
|
|
|
// TestSupportedSignatureAlgorithms checks that all supportedSignatureAlgorithms
|
|
// have valid type and hash information.
|
|
func TestSupportedSignatureAlgorithms(t *testing.T) {
|
|
for _, sigAlg := range supportedSignatureAlgorithms() {
|
|
sigType, hash, err := typeAndHashFromSignatureScheme(sigAlg)
|
|
if err != nil {
|
|
t.Errorf("%v: unexpected error: %v", sigAlg, err)
|
|
}
|
|
if sigType == 0 {
|
|
t.Errorf("%v: missing signature type", sigAlg)
|
|
}
|
|
if hash == 0 && sigAlg != Ed25519 && circlPki.SchemeByTLSID(uint(sigAlg)) == nil { // [UTLS] ported from cloudflare/go
|
|
t.Errorf("%v: missing hash", sigAlg)
|
|
}
|
|
}
|
|
}
|