From bd388cbad516d5256198841ecb7c73b47514a371 Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Sun, 1 Sep 2019 13:23:13 -0400 Subject: [PATCH] Change the signature context according to protocol role --- client-state-machine.go | 4 ++-- crypto.go | 2 ++ handshake-messages.go | 21 ++++++++++----------- handshake-messages_test.go | 29 +++++++++++++++++++---------- server-state-machine.go | 4 ++-- tls_test.go | 1 + 6 files changed, 36 insertions(+), 25 deletions(-) diff --git a/client-state-machine.go b/client-state-machine.go index d8464a1..9d0601e 100644 --- a/client-state-machine.go +++ b/client-state-machine.go @@ -819,7 +819,7 @@ func (state clientStateWaitCV) Next(hr handshakeMessageReader) (HandshakeState, logf(logTypeHandshake, "Handshake Hash to be verified: [%d] %x", len(hcv), hcv) serverPublicKey := state.serverCertificate.CertificateList[0].CertData.PublicKey - if err := certVerify.Verify(serverPublicKey, hcv); err != nil { + if err := certVerify.Verify(true, serverPublicKey, hcv); err != nil { logf(logTypeHandshake, "[ClientStateWaitCV] Server signature failed to verify") return nil, nil, AlertHandshakeFailure } @@ -1021,7 +1021,7 @@ func (state clientStateWaitFinished) Next(hr handshakeMessageReader) (HandshakeS certificateVerify := &CertificateVerifyBody{Algorithm: certScheme} logf(logTypeHandshake, "Creating CertVerify: %04x %v", certScheme, state.cryptoParams.Hash) - err = certificateVerify.Sign(cert.PrivateKey, hcv) + err = certificateVerify.Sign(false, cert.PrivateKey, hcv) if err != nil { logf(logTypeHandshake, "[ClientStateWaitFinished] Error signing CertificateVerify [%v]", err) return nil, nil, AlertInternalError diff --git a/crypto.go b/crypto.go index 4fa59a2..e1a0b98 100644 --- a/crypto.go +++ b/crypto.go @@ -523,6 +523,8 @@ func HkdfExtract(hash crypto.Hash, saltIn, input []byte) []byte { } const ( + clientCertVerifyContext = "TLS 1.3, client CertificateVerify" + serverCertVerifyContext = "TLS 1.3, server CertificateVerify" labelExternalBinder = "ext binder" labelResumptionBinder = "res binder" labelEarlyTrafficSecret = "c e traffic" diff --git a/handshake-messages.go b/handshake-messages.go index e8e3aef..5457d8d 100644 --- a/handshake-messages.go +++ b/handshake-messages.go @@ -124,7 +124,6 @@ func (ch *ClientHelloBody) Unmarshal(data []byte) (int, error) { return read, nil } -// TODO: File a spec bug to clarify this func (ch ClientHelloBody) Truncated() ([]byte, error) { if len(ch.Extensions) == 0 { return nil, fmt.Errorf("tls.clienthello.truncate: No extensions") @@ -205,8 +204,6 @@ func (sh *ServerHelloBody) Unmarshal(data []byte) (int, error) { // // For similar reasons, we don't use the `syntax` module here, because this // struct doesn't map well to standard TLS presentation language concepts. -// -// TODO: File a spec bug type FinishedBody struct { VerifyDataLen int VerifyData []byte @@ -351,10 +348,12 @@ func (cv *CertificateVerifyBody) Unmarshal(data []byte) (int, error) { return syntax.Unmarshal(data, cv) } -func (cv *CertificateVerifyBody) EncodeSignatureInput(data []byte) []byte { - // TODO: Change context for client auth - // TODO: Put this in a const - const context = "TLS 1.3, server CertificateVerify" +func (cv *CertificateVerifyBody) EncodeSignatureInput(server bool, data []byte) []byte { + context := clientCertVerifyContext + if server { + context = serverCertVerifyContext + } + sigInput := bytes.Repeat([]byte{0x20}, 64) sigInput = append(sigInput, []byte(context)...) sigInput = append(sigInput, []byte{0}...) @@ -362,15 +361,15 @@ func (cv *CertificateVerifyBody) EncodeSignatureInput(data []byte) []byte { return sigInput } -func (cv *CertificateVerifyBody) Sign(privateKey crypto.Signer, handshakeHash []byte) (err error) { - sigInput := cv.EncodeSignatureInput(handshakeHash) +func (cv *CertificateVerifyBody) Sign(server bool, privateKey crypto.Signer, handshakeHash []byte) (err error) { + sigInput := cv.EncodeSignatureInput(server, handshakeHash) cv.Signature, err = sign(cv.Algorithm, privateKey, sigInput) logf(logTypeHandshake, "Signed: alg=[%04x] sigInput=[%x], sig=[%x]", cv.Algorithm, sigInput, cv.Signature) return } -func (cv *CertificateVerifyBody) Verify(publicKey crypto.PublicKey, handshakeHash []byte) error { - sigInput := cv.EncodeSignatureInput(handshakeHash) +func (cv *CertificateVerifyBody) Verify(server bool, publicKey crypto.PublicKey, handshakeHash []byte) error { + sigInput := cv.EncodeSignatureInput(server, handshakeHash) logf(logTypeHandshake, "About to verify: alg=[%04x] sigInput=[%x], sig=[%x]", cv.Algorithm, sigInput, cv.Signature) return verify(cv.Algorithm, publicKey, sigInput, cv.Signature) } diff --git a/handshake-messages_test.go b/handshake-messages_test.go index 0f387d6..3ab36ca 100644 --- a/handshake-messages_test.go +++ b/handshake-messages_test.go @@ -539,29 +539,38 @@ func TestCertificateVerifyMarshalUnmarshal(t *testing.T) { _, err = cv.Unmarshal(certVerifyValid[:5]) assertError(t, err, "Unmarshaled a CertificateVerify with no header") - // Test successful sign / verify round-trip - certVerifyValidIn.Algorithm = RSA_PSS_SHA256 - err = certVerifyValidIn.Sign(privRSA, handshakeHash) - assertNotError(t, err, "Failed to sign CertificateVerify") - // Test sign failure on algorithm originalAlg := certVerifyValidIn.Algorithm certVerifyValidIn.Algorithm = SignatureScheme(0) - err = certVerifyValidIn.Sign(privRSA, handshakeHash) + err = certVerifyValidIn.Sign(true, privRSA, handshakeHash) assertError(t, err, "Signed CertificateVerify despite bad algorithm") certVerifyValidIn.Algorithm = originalAlg - // Test successful verify + // Test successful sign / verify round trip (client side) certVerifyValidIn = CertificateVerifyBody{Algorithm: RSA_PSS_SHA256} - err = certVerifyValidIn.Sign(privRSA, handshakeHash) + err = certVerifyValidIn.Sign(false, privRSA, handshakeHash) assertNotError(t, err, "Failed to sign CertificateVerify") - err = certVerifyValidIn.Verify(privRSA.Public(), handshakeHash) + err = certVerifyValidIn.Verify(false, privRSA.Public(), handshakeHash) assertNotError(t, err, "Failed to verify CertificateVerify") + // Test successful sign / verify round trip (server side) + certVerifyValidIn = CertificateVerifyBody{Algorithm: RSA_PSS_SHA256} + err = certVerifyValidIn.Sign(true, privRSA, handshakeHash) + assertNotError(t, err, "Failed to sign CertificateVerify") + err = certVerifyValidIn.Verify(true, privRSA.Public(), handshakeHash) + assertNotError(t, err, "Failed to verify CertificateVerify") + + // Test verify failure on client/server difference + certVerifyValidIn = CertificateVerifyBody{Algorithm: RSA_PSS_SHA256} + err = certVerifyValidIn.Sign(true, privRSA, handshakeHash) + assertNotError(t, err, "Failed to sign CertificateVerify") + err = certVerifyValidIn.Verify(false, privRSA.Public(), handshakeHash) + assertError(t, err, "Accpepted CertificateVerify in wrong context") + // Test verify failure on bad algorithm originalAlg = certVerifyValidIn.Algorithm certVerifyValidIn.Algorithm = SignatureScheme(0) - err = certVerifyValidIn.Verify(privRSA.Public(), handshakeHash) + err = certVerifyValidIn.Verify(true, privRSA.Public(), handshakeHash) assertError(t, err, "Verified CertificateVerify despite bad hash algorithm") certVerifyValidIn.Algorithm = originalAlg } diff --git a/server-state-machine.go b/server-state-machine.go index e392a5d..28e2bdb 100644 --- a/server-state-machine.go +++ b/server-state-machine.go @@ -665,7 +665,7 @@ func (state serverStateNegotiated) Next(_ handshakeMessageReader) (HandshakeStat hcv := handshakeHash.Sum(nil) logf(logTypeHandshake, "Handshake Hash to be verified: [%d] %x", len(hcv), hcv) - err = certificateVerify.Sign(state.cert.PrivateKey, hcv) + err = certificateVerify.Sign(true, state.cert.PrivateKey, hcv) if err != nil { logf(logTypeHandshake, "[ServerStateNegotiated] Error signing CertificateVerify [%v]", err) return nil, nil, AlertInternalError @@ -1061,7 +1061,7 @@ func (state serverStateWaitCV) Next(hr handshakeMessageReader) (HandshakeState, logf(logTypeHandshake, "Handshake Hash to be verified: [%d] %x", len(hcv), hcv) clientPublicKey := state.clientCertificate.CertificateList[0].CertData.PublicKey - if err := certVerify.Verify(clientPublicKey, hcv); err != nil { + if err := certVerify.Verify(false, clientPublicKey, hcv); err != nil { logf(logTypeHandshake, "[ServerStateWaitCV] Failure in client auth verification [%v]", err) return nil, nil, AlertHandshakeFailure } diff --git a/tls_test.go b/tls_test.go index ba0ac67..9e2e9d1 100644 --- a/tls_test.go +++ b/tls_test.go @@ -215,6 +215,7 @@ func TestExchangeData(t *testing.T) { srv := <-srvCh assertNotNil(t, srv, "Server should have completed handshake") + assertNotError(t, serr, "Error in server handshake") buf := make([]byte, 16) buf = buf[0:6]