Skip to content

Commit abb10c1

Browse files
jhoylabwesterb
authored andcommitted
Fix DC implementation #131
Addresses issues #127, #128, #129, and #130. Add tool for generating delegated credentials.
1 parent ca3fe71 commit abb10c1

File tree

6 files changed

+220
-118
lines changed

6 files changed

+220
-118
lines changed

src/crypto/tls/auth.go

Lines changed: 7 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -259,72 +259,26 @@ func signatureSchemesForCertificate(version uint16, cert *Certificate) []Signatu
259259
return sigAlgs
260260
}
261261

262-
// signatureSchemeForDelegatedCredential returns the list of supported
263-
// SignatureSchemes for a given delegated credential, based on the public
264-
// key, and optionally filtered by its explicit
265-
// SupportedSignatureAlgorithmsDC.
266-
//
267-
// This function must be kept in sync with supportedSignatureAlgorithmsDC.
268-
func signatureSchemeForDelegatedCredential(version uint16, dc *DelegatedCredential) []SignatureScheme {
269-
pub := dc.cred.publicKey
270-
271-
var sigAlgs []SignatureScheme
272-
switch pub.(type) {
273-
case *ecdsa.PublicKey:
274-
pk, ok := pub.(*ecdsa.PublicKey)
275-
if !ok {
276-
return nil
277-
}
278-
switch pk.Curve {
279-
case elliptic.P256():
280-
sigAlgs = []SignatureScheme{ECDSAWithP256AndSHA256}
281-
case elliptic.P384():
282-
sigAlgs = []SignatureScheme{ECDSAWithP384AndSHA384}
283-
case elliptic.P521():
284-
sigAlgs = []SignatureScheme{ECDSAWithP521AndSHA512}
285-
default:
286-
return nil
287-
}
288-
case ed25519.PublicKey:
289-
sigAlgs = []SignatureScheme{Ed25519}
290-
case circlSign.PublicKey:
291-
pk, ok := pub.(circlSign.PublicKey)
292-
if !ok {
293-
return nil
294-
}
295-
scheme := pk.Scheme()
296-
tlsScheme, ok := scheme.(circlPki.TLSScheme)
297-
if !ok {
298-
return nil
299-
}
300-
sigAlgs = []SignatureScheme{SignatureScheme(tlsScheme.TLSIdentifier())}
301-
default:
302-
return nil
303-
}
304-
305-
return sigAlgs
306-
}
307-
308262
// selectSignatureSchemeDC picks a SignatureScheme from the peer's preference list
309263
// that works with the selected delegated credential. It's only called for protocol
310264
// versions that support delegated credential, so TLS 1.3.
311-
func selectSignatureSchemeDC(vers uint16, dc *DelegatedCredential, peerAlgs []SignatureScheme) (SignatureScheme, error) {
265+
func selectSignatureSchemeDC(vers uint16, dc *DelegatedCredential, peerAlgs []SignatureScheme, peerAlgsDC []SignatureScheme) (SignatureScheme, error) {
312266
if vers != VersionTLS13 {
313267
return 0, errors.New("unsupported TLS version for dc")
314268
}
315269

316-
supportedAlgs := signatureSchemeForDelegatedCredential(vers, dc)
317-
if len(supportedAlgs) == 0 {
318-
return 0, errors.New("unsupported scheme for dc")
270+
if !isSupportedSignatureAlgorithm(dc.algorithm, peerAlgs) {
271+
return undefinedSignatureScheme, errors.New("tls: peer doesn't support the delegated credential's signature")
319272
}
273+
320274
// Pick signature scheme in the peer's preference order, as our
321275
// preference order is not configurable.
322-
for _, preferredAlg := range peerAlgs {
323-
if isSupportedSignatureAlgorithm(preferredAlg, supportedAlgs) {
276+
for _, preferredAlg := range peerAlgsDC {
277+
if preferredAlg == dc.cred.expCertVerfAlgo {
324278
return preferredAlg, nil
325279
}
326280
}
327-
return 0, errors.New("tls: peer doesn't support any of the delegated credential's signature algorithms")
281+
return 0, errors.New("tls: peer doesn't support the delegated credential's signature algorithm")
328282
}
329283

330284
// selectSignatureScheme picks a SignatureScheme from the peer's preference list

src/crypto/tls/delegated_credentials.go

Lines changed: 50 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"crypto/ed25519"
2222
"crypto/elliptic"
2323
"crypto/rand"
24+
"crypto/rsa"
2425
"crypto/x509"
2526
"encoding/binary"
2627
"errors"
@@ -40,6 +41,10 @@ const (
4041
dcMaxSignatureLen = (1 << 16) - 1 // Bytes
4142
)
4243

44+
const (
45+
undefinedSignatureScheme SignatureScheme = 0x0000
46+
)
47+
4348
var extensionDelegatedCredential = []int{1, 3, 6, 1, 4, 1, 44363, 44}
4449

4550
// isValidForDelegation returns true if a certificate can be used for Delegated
@@ -61,7 +66,6 @@ func isValidForDelegation(cert *x509.Certificate) bool {
6166
return true
6267
}
6368
}
64-
6569
return false
6670
}
6771

@@ -133,6 +137,7 @@ func (cred *credential) marshalPublicKeyInfo() ([]byte, error) {
133137
}
134138

135139
return rawPub, nil
140+
136141
default:
137142
return nil, fmt.Errorf("tls: unsupported signature scheme: 0x%04x", cred.expCertVerfAlgo)
138143
}
@@ -228,6 +233,12 @@ func getHash(scheme SignatureScheme) crypto.Hash {
228233
return crypto.SHA512
229234
case Ed25519:
230235
return directSigning
236+
case PKCS1WithSHA256, PSSWithSHA256:
237+
return crypto.SHA256
238+
case PSSWithSHA384:
239+
return crypto.SHA384
240+
case PSSWithSHA512:
241+
return crypto.SHA512
231242
default:
232243
return 0 //Unknown hash function
233244
}
@@ -291,28 +302,29 @@ func prepareDelegationSignatureInput(hash crypto.Hash, cred *credential, dCert [
291302
// Extract the algorithm used to sign the Delegated Credential from the
292303
// end-entity (leaf) certificate.
293304
func getSignatureAlgorithm(cert *Certificate) (SignatureScheme, error) {
294-
var sigAlgo SignatureScheme
295305
switch sk := cert.PrivateKey.(type) {
296306
case *ecdsa.PrivateKey:
297307
pk := sk.Public().(*ecdsa.PublicKey)
298308
curveName := pk.Curve.Params().Name
299-
certAlg := cert.Leaf.SignatureAlgorithm
300-
if certAlg == x509.ECDSAWithSHA256 && curveName == "P-256" {
301-
sigAlgo = ECDSAWithP256AndSHA256
302-
} else if certAlg == x509.ECDSAWithSHA384 && curveName == "P-384" {
303-
sigAlgo = ECDSAWithP384AndSHA384
304-
} else if certAlg == x509.ECDSAWithSHA512 && curveName == "P-521" {
305-
sigAlgo = ECDSAWithP521AndSHA512
309+
certAlg := cert.Leaf.PublicKeyAlgorithm
310+
if certAlg == x509.ECDSA && curveName == "P-256" {
311+
return ECDSAWithP256AndSHA256, nil
312+
} else if certAlg == x509.ECDSA && curveName == "P-384" {
313+
return ECDSAWithP384AndSHA384, nil
314+
} else if certAlg == x509.ECDSA && curveName == "P-521" {
315+
return ECDSAWithP521AndSHA512, nil
306316
} else {
307-
return SignatureScheme(0x00), fmt.Errorf("using curve %s for %s is not supported", curveName, cert.Leaf.SignatureAlgorithm)
317+
return undefinedSignatureScheme, fmt.Errorf("using curve %s for %s is not supported", curveName, cert.Leaf.SignatureAlgorithm)
308318
}
309319
case ed25519.PrivateKey:
310-
sigAlgo = Ed25519
320+
return Ed25519, nil
321+
case *rsa.PrivateKey:
322+
// If the certificate has the RSAEncryption OID there are a number of valid signature schemes that may sign the DC.
323+
// In the absence of better information, we make a reasonable choice.
324+
return PSSWithSHA256, nil
311325
default:
312-
return SignatureScheme(0x00), fmt.Errorf("tls: unsupported algorithm for Delegated Credential")
326+
return undefinedSignatureScheme, fmt.Errorf("tls: unsupported algorithm for signing Delegated Credential")
313327
}
314-
315-
return sigAlgo, nil
316328
}
317329

318330
// NewDelegatedCredential creates a new Delegated Credential using 'cert' for
@@ -365,7 +377,7 @@ func NewDelegatedCredential(cert *Certificate, pubAlgo SignatureScheme, validTim
365377
return nil, nil, err
366378
}
367379
default:
368-
return nil, nil, fmt.Errorf("tls: unsupported algorithm for Delegated Credential: %T", pubAlgo)
380+
return nil, nil, fmt.Errorf("tls: unsupported algorithm for Delegated Credential: %s", pubAlgo)
369381
}
370382

371383
// Prepare the credential for signing
@@ -390,6 +402,13 @@ func NewDelegatedCredential(cert *Certificate, pubAlgo SignatureScheme, validTim
390402
if err != nil {
391403
return nil, nil, err
392404
}
405+
case *rsa.PrivateKey:
406+
opts := &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash,
407+
Hash: hash}
408+
sig, err = rsa.SignPSS(rand.Reader, sk, hash, values, opts)
409+
if err != nil {
410+
return nil, nil, err
411+
}
393412
default:
394413
return nil, nil, fmt.Errorf("tls: unsupported key type for Delegated Credential")
395414
}
@@ -448,17 +467,29 @@ func (dc *DelegatedCredential) Validate(cert *x509.Certificate, isClient bool, n
448467
}
449468

450469
return ed25519.Verify(pk, in, dc.signature)
470+
case PSSWithSHA256,
471+
PSSWithSHA384,
472+
PSSWithSHA512:
473+
pk, ok := cert.PublicKey.(*rsa.PublicKey)
474+
if !ok {
475+
return false
476+
}
477+
hash := getHash(dc.algorithm)
478+
return rsa.VerifyPSS(pk, hash, in, dc.signature, nil) == nil
451479
default:
452480
return false
453481
}
454482
}
455483

456-
// marshal encodes a DelegatedCredential structure. It also sets dc.Raw to that
484+
// Marshal encodes a DelegatedCredential structure. It also sets dc.Raw to that
457485
// encoding.
458-
func (dc *DelegatedCredential) marshal() ([]byte, error) {
486+
func (dc *DelegatedCredential) Marshal() ([]byte, error) {
459487
if len(dc.signature) > dcMaxSignatureLen {
460488
return nil, errors.New("tls: delegated credential is not valid")
461489
}
490+
if len(dc.signature) == 0 {
491+
return nil, errors.New("tls: delegated credential has no signature")
492+
}
462493

463494
raw, err := dc.cred.marshal()
464495
if err != nil {
@@ -475,8 +506,8 @@ func (dc *DelegatedCredential) marshal() ([]byte, error) {
475506
return dc.raw, nil
476507
}
477508

478-
// unmarshalDelegatedCredential decodes a DelegatedCredential structure.
479-
func unmarshalDelegatedCredential(raw []byte) (*DelegatedCredential, error) {
509+
// UnmarshalDelegatedCredential decodes a DelegatedCredential structure.
510+
func UnmarshalDelegatedCredential(raw []byte) (*DelegatedCredential, error) {
480511
rawCredentialLen, err := getCredentialLen(raw)
481512
if err != nil {
482513
return nil, err

src/crypto/tls/delegated_credentials_test.go

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -385,12 +385,12 @@ func TestDelegatedCredentialMarshal(t *testing.T) {
385385
t.Fatal(err)
386386
}
387387

388-
ser, err := delegatedCred.marshal()
388+
ser, err := delegatedCred.Marshal()
389389
if err != nil {
390390
t.Error(err)
391391
}
392392

393-
delegatedCred2, err := unmarshalDelegatedCredential(ser)
393+
delegatedCred2, err := UnmarshalDelegatedCredential(ser)
394394
if err != nil {
395395
t.Error(err)
396396
}
@@ -466,6 +466,12 @@ func testServerGetCertificate(ch *ClientHelloInfo) (*Certificate, error) {
466466

467467
}
468468

469+
// Used when the server doesn't support DCs.
470+
// This function always returns a non-DC cert.
471+
func testServerGetCertificateNoDC(ch *ClientHelloInfo) (*Certificate, error) {
472+
return dcTestCerts["no dc"], nil
473+
}
474+
469475
// Checks that the client suppports a version >= 1.3 and accepts Delegated
470476
// Credentials. If so, it returns the delegation certificate; otherwise it
471477
// returns a non-Delegated certificate.
@@ -507,8 +513,8 @@ func testConnWithDC(t *testing.T, clientMsg, serverMsg string, clientConfig, ser
507513
}
508514
serverCh <- server
509515
}()
510-
511516
client, err := Dial("tcp", ln.Addr().String(), clientConfig)
517+
512518
if err != nil {
513519
return false, err
514520
}
@@ -552,20 +558,22 @@ func testConnWithDC(t *testing.T, clientMsg, serverMsg string, clientConfig, ser
552558
func TestDCHandshakeServerAuth(t *testing.T) {
553559
serverMsg := "hello, client"
554560
clientMsg := "hello, server"
555-
561+
initDCTest()
556562
clientConfig := dcTestConfig.Clone()
557563
serverConfig := dcTestConfig.Clone()
558-
clientConfig.InsecureSkipVerify = true
559564

560565
for i, test := range dcServerTests {
561566
clientConfig.SupportDelegatedCredential = test.clientDCSupport
562-
563-
initDCTest()
564567
for dcCount = 0; dcCount < len(dcTestDCSignatureScheme); dcCount++ {
565-
serverConfig.GetCertificate = testServerGetCertificate
568+
if test.serverMaxVers < VersionTLS13 {
569+
t.Logf("Server doesn't support DCs, not offering. test %d", i)
570+
serverConfig.GetCertificate = testServerGetCertificateNoDC
571+
} else {
572+
serverConfig.GetCertificate = testServerGetCertificate
573+
}
574+
566575
clientConfig.MaxVersion = test.clientMaxVers
567576
serverConfig.MaxVersion = test.serverMaxVers
568-
569577
usedDC, err := testConnWithDC(t, clientMsg, serverMsg, clientConfig, serverConfig, "client")
570578

571579
if err != nil && test.expectSuccess {
@@ -586,6 +594,7 @@ func TestDCHandshakeClientAuth(t *testing.T) {
586594
clientMsg := "hello, server"
587595
serverMsg := "hello, client"
588596

597+
initDCTest()
589598
serverConfig := dcTestConfig.Clone()
590599
serverConfig.ClientAuth = RequestClientCert
591600
serverConfig.GetCertificate = testServerGetCertificate
@@ -595,7 +604,6 @@ func TestDCHandshakeClientAuth(t *testing.T) {
595604
for j, test := range dcClientTests {
596605
serverConfig.SupportDelegatedCredential = test.serverDCSupport
597606

598-
initDCTest()
599607
for dcCount = 0; dcCount < len(dcTestDCSignatureScheme); dcCount++ {
600608
serverConfig.MaxVersion = test.serverMaxVers
601609
clientConfig.MaxVersion = test.clientMaxVers
@@ -620,6 +628,7 @@ func TestDCHandshakeClientAndServerAuth(t *testing.T) {
620628
clientMsg := "hello, server"
621629
serverMsg := "hello, client"
622630

631+
initDCTest()
623632
serverConfig := dcTestConfig.Clone()
624633
serverConfig.ClientAuth = RequestClientCert
625634
serverConfig.GetCertificate = testServerGetCertificate
@@ -632,8 +641,6 @@ func TestDCHandshakeClientAndServerAuth(t *testing.T) {
632641
serverConfig.MaxVersion = VersionTLS13
633642
clientConfig.MaxVersion = VersionTLS13
634643

635-
initDCTest()
636-
637644
usedDC, err := testConnWithDC(t, clientMsg, serverMsg, clientConfig, serverConfig, "both")
638645

639646
if err != nil {

0 commit comments

Comments
 (0)