コミットを比較

...

25 コミット

作成者 SHA1 メッセージ 日付
  Henry Case a21fd9c1bc
refactors record encryption code (#122) 6年前
  Henry D. Case e81269b57e Revert "Small refactoring of record encryption code" 6年前
  Henry D. Case 1782162852 Small refactoring of record encryption code 6年前
  Henry D. Case ad86d61c42 Let's use constant instead of hardcoding values (same is done in bssl) 6年前
  Henry D. Case 91a6fcebab Cleanup 6年前
  Christopher Patton a2fe2d9a71 DC draft-02, last minute change (#121) 6年前
  Henry Case e77e39e7aa
server must NOT send version prior to TLS1.3 in supported_versions (#119) 6年前
  Henry Case d3e18f99e2
Minimal number of changes needed to udpate to draft-28 (#115) 6年前
  Christopher Patton 0d6e4561a6 Add DC test data for tls13draft28 and tls13rfc (#117) 6年前
  Christopher Patton 174a68a0fb Update implementation of draft-ietf-tls-subcerts to draft 02 (#108) 6年前
  Henry D. Case 77d1fbf262 Don't use VersionTLS13DraftXX anywhere 6年前
  Christopher Patton c5280001a4 Remove delegated credential minting from the API 6年前
  Christopher Patton 1ea9624098 Use static test data for testing delegated credentials 6年前
  Brendan Mc 22d6deb0e7
Merge pull request #95 from cjpatton/subcerts 6年前
  Christopher Patton 84fe9084cd Implement the delegated_credential extension for TLS 6年前
  Christopher Patton 963d5877be Refactor the keyAgreement interface 6年前
  Henry D. Case 3ff71dcdc5 tests: enable client authentication in bogo 6年前
  Henry D. Case 6e4abe2d07 TLSv1.3 draft-23: align tests 6年前
  Henry D. Case 03138ec18e TLSv1.3 -draft23: Implementation of signature_algorithms_cert 6年前
  Henry D. Case 5bdf1af124 TLS1.3 -draft23: Renumber key_share 6年前
  Evan Klitzke 67bc308e04 Update client SCT list during TLS 1.3 handshake, fixes #76 6年前
  Henry D. Case b1d6c0aeaa Change function name verifyPeerCertificate->verifyPeerHandshakeSignature 6年前
  Henry D. Case 91d6db578b CI: Fail build if code is wrongly formatted 6年前
  Henry D. Case b6af4dd343 Code formatting for handshake_server_test.go 6年前
  Henry D. Case 3f720fc50c Code formatting for TRIS test client and server 6年前
26個のファイルの変更1408行の追加247行の削除
分割表示
  1. +3
    -0
      .travis.yml
  2. +55
    -7
      13.go
  3. +3
    -2
      README.md
  4. +4
    -2
      _dev/Makefile
  5. +14
    -5
      _dev/bogo/Dockerfile
  6. +13
    -4
      _dev/boring/Dockerfile
  7. +2
    -2
      _dev/boring/run.sh
  8. +3
    -3
      _dev/boring/server.sh
  9. +14
    -12
      _dev/interop_test_runner
  10. +41
    -39
      _dev/tris-localserver/server.go
  11. +4
    -4
      _dev/tris-testclient/client.go
  12. +7
    -1
      _dev/tstclnt/Dockerfile
  13. +20
    -0
      _dev/utils/fmtcheck.sh
  14. +27
    -0
      _dev/utils/pre-commit
  15. +9
    -6
      cipher_suites.go
  16. +63
    -18
      common.go
  17. +33
    -15
      conn.go
  18. +4
    -4
      example_test.go
  19. +52
    -2
      handshake_client.go
  20. +156
    -85
      handshake_messages.go
  21. +46
    -15
      handshake_server.go
  22. +4
    -6
      handshake_server_test.go
  23. +13
    -14
      key_agreement.go
  24. +392
    -0
      subcerts.go
  25. +423
    -0
      subcerts_test.go
  26. +3
    -1
      tls_test.go

+ 3
- 0
.travis.yml ファイルの表示

@@ -15,6 +15,9 @@ env:
matrix:
fast_finish: true

before_install:
- make -f _dev/Makefile fmtcheck

install:
- sudo pip install docker



+ 55
- 7
13.go ファイルの表示

@@ -225,6 +225,7 @@ CurvePreferenceLoop:
certReq := new(certificateRequestMsg13)
// extension 'signature_algorithms' MUST be specified
certReq.supportedSignatureAlgorithms = supportedSignatureAlgorithms13
certReq.supportedSignatureAlgorithmsCert = supportedSigAlgorithmsCert(supportedSignatureAlgorithms13)
hs.keySchedule.write(certReq.marshal())
if _, err := hs.c.writeRecord(recordTypeHandshake, certReq.marshal()); err != nil {
return err
@@ -328,7 +329,7 @@ func (hs *serverHandshakeState) readClientFinished13(hasConfirmLock bool) error
return unexpectedMessageError(certVerify, msg)
}

err, alertCode := verifyPeerCertificate(
err, alertCode := verifyPeerHandshakeSignature(
certVerify,
pubKey,
supportedSignatureAlgorithms13,
@@ -402,6 +403,16 @@ func (hs *serverHandshakeState) sendCertificate13() error {
if len(certEntries) > 0 && hs.clientHello.scts {
certEntries[0].sctList = hs.cert.SignedCertificateTimestamps
}

// If hs.delegatedCredential is set (see hs.readClientHello()) then the
// server is using the delegated credential extension. The DC is added as an
// extension to the end-entity certificate, i.e., the last CertificateEntry
// of Certificate.certficate_list. (For details, see
// https://tools.ietf.org/html/draft-ietf-tls-subcerts-02.)
if len(certEntries) > 0 && hs.clientHello.delegatedCredential && hs.delegatedCredential != nil {
certEntries[0].delegatedCredential = hs.delegatedCredential
}

certMsg := &certificateMsg13{certificates: certEntries}

hs.keySchedule.write(certMsg.marshal())
@@ -422,7 +433,7 @@ func (hs *serverHandshakeState) sendCertificate13() error {
}

toSign := prepareDigitallySigned(sigHash, "TLS 1.3, server CertificateVerify", hs.keySchedule.transcriptHash.Sum(nil))
signature, err := hs.cert.PrivateKey.(crypto.Signer).Sign(c.config.rand(), toSign[:], opts)
signature, err := hs.privateKey.(crypto.Signer).Sign(c.config.rand(), toSign[:], opts)
if err != nil {
c.sendAlert(alertInternalError)
return err
@@ -467,9 +478,9 @@ func (c *Conn) handleEndOfEarlyData() error {
// See https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.4.1.2
func (hs *serverHandshakeState) selectTLS13SignatureScheme() (sigScheme SignatureScheme, err error) {
var supportedSchemes []SignatureScheme
signer, ok := hs.cert.PrivateKey.(crypto.Signer)
signer, ok := hs.privateKey.(crypto.Signer)
if !ok {
return 0, errors.New("tls: certificate private key does not implement crypto.Signer")
return 0, errors.New("tls: private key does not implement crypto.Signer")
}
pk := signer.Public()
if _, ok := pk.(*rsa.PublicKey); ok {
@@ -841,7 +852,7 @@ func (hs *clientHandshakeState) processEncryptedExtensions(ee *encryptedExtensio
return nil
}

func verifyPeerCertificate(
func verifyPeerHandshakeSignature(
certVerify *certificateVerifyMsg,
pubKey crypto.PublicKey,
signAlgosKnown []SignatureScheme,
@@ -953,6 +964,7 @@ func (hs *clientHandshakeState) doTLS13Handshake() error {
hash := hashForSuite(hs.suite)
hashSize := hash.Size()
serverHello := hs.serverHello
c.scts = serverHello.scts

// middlebox compatibility mode, send CCS before second flight.
if _, err := c.writeRecord(recordTypeChangeCipherSpec, []byte{1}); err != nil {
@@ -1032,6 +1044,7 @@ func (hs *clientHandshakeState) doTLS13Handshake() error {
return unexpectedMessageError(certMsg, msg)
}
hs.keySchedule.write(certMsg.marshal())

// Validate certificates.
certs := getCertsFromEntries(certMsg.certificates)
if err := hs.processCertsFromServer(certs); err != nil {
@@ -1048,9 +1061,32 @@ func (hs *clientHandshakeState) doTLS13Handshake() error {
c.sendAlert(alertUnexpectedMessage)
return unexpectedMessageError(certVerifyMsg, msg)
}
err, alertCode := verifyPeerCertificate(

// Validate the DC if present. The DC is only processed if the extension was
// indicated by the ClientHello; otherwise this call will result in an
// "illegal_parameter" alert.
if len(certMsg.certificates) > 0 {
if err := hs.processDelegatedCredentialFromServer(
certMsg.certificates[0].delegatedCredential,
certVerifyMsg.signatureAlgorithm); err != nil {
return err
}
}

// Set the public key used to verify the handshake.
pk := hs.c.peerCertificates[0].PublicKey

// If the delegated credential extension has successfully been negotiated,
// then the CertificateVerify signature will have been produced with the
// DelegatedCredential's private key.
if hs.c.verifiedDc != nil {
pk = hs.c.verifiedDc.cred.publicKey
}

// Verify the handshake signature.
err, alertCode := verifyPeerHandshakeSignature(
certVerifyMsg,
hs.c.peerCertificates[0].PublicKey,
pk,
hs.hello.supportedSignatureAlgorithms,
hs.keySchedule.transcriptHash.Sum(nil),
"TLS 1.3, server CertificateVerify")
@@ -1113,3 +1149,15 @@ func (hs *clientHandshakeState) doTLS13Handshake() error {
c.in.setCipher(c.vers, appServerCipher)
return nil
}

// supportedSigAlgorithmsCert iterates over schemes and filters out those algorithms
// which are not supported for certificate verification.
func supportedSigAlgorithmsCert(schemes []SignatureScheme) (ret []SignatureScheme) {
for _, sig := range schemes {
// X509 doesn't support PSS signatures
if !signatureSchemeIsPSS(sig) {
ret = append(ret, sig)
}
}
return
}

+ 3
- 2
README.md ファイルの表示

@@ -61,7 +61,8 @@ There are number of things that need to be setup before running tests. Most impo

```
git clone https://github.com/cloudflare/tls-tris.git
cd tls-tris; make -f _dev/Makefile build-all
cd tls-tris; cp _dev/utils/pre-commit .git/hooks/
make -f _dev/Makefile build-all
```

### Testing
@@ -70,7 +71,7 @@ We run 3 kinds of test:.

* Unit testing: <br/>``make -f _dev/Makefile test-unit``
* Testing against BoringSSL test suite: <br/>``make -f _dev/Makefile test-bogo``
* Compatibility testing (see below):<br/>``make -f _dev/Makefile test-compat``
* Compatibility testing (see below):<br/>``make -f _dev/Makefile test-interop``

To run all the tests in one go use:
```


+ 4
- 2
_dev/Makefile ファイルの表示

@@ -23,7 +23,7 @@ INSTALL_RACE:= $(words $(filter $(ARCH)_$(shell go env CGO_ENABLED), amd64_1))
TARGET_TEST_COMPAT=boring picotls tstclnt

# Some target-specific constants
BORINGSSL_REVISION=1530ef3e
BORINGSSL_REVISION=03de6813d8992a649092b4874ef0ebc022e2f58a
BOGO_DOCKER_TRIS_LOCATION=/go/src/github.com/cloudflare/tls-tris

###############
@@ -112,5 +112,7 @@ clean:
clean-all: clean
rm -rf $(BUILD_DIR)

fmtcheck:
$(DEV_DIR)/utils/fmtcheck.sh

.PHONY: $(BUILD_DIR) clean build build-test test test-unit test-bogo test-compat
.PHONY: $(BUILD_DIR) clean build build-test test test-unit test-bogo test-interop

+ 14
- 5
_dev/bogo/Dockerfile ファイルの表示

@@ -10,8 +10,8 @@ RUN apk add --update \

ENV CGO_ENABLED=0

RUN git clone https://github.com/FiloSottile/crypto-tls-bogo-shim \
/go/src/github.com/FiloSottile/crypto-tls-bogo-shim
RUN git clone https://github.com/henrydcase/crypto-tls-bogo-shim \
/go/src/github.com/henrydcase/crypto-tls-bogo-shim

# Draft 18 with client-tests branch
#ARG REVISION=3f5e87d6a1931b6f6930e4eadb7b2d0b2aa7c588
@@ -20,10 +20,19 @@ RUN git clone https://github.com/FiloSottile/crypto-tls-bogo-shim \
#ARG REVISION=81cc32b846c9fe2ea32613287e57a6a0db7bbb9a

# Draft 22 with draft22-client branch (client-tests + draft22)
ARG REVISION=f9729b5e4eafb1f1d313949388c3c2b167e84734
# ARG REVISION=f9729b5e4eafb1f1d313949388c3c2b167e84734

RUN cd /go/src/github.com/FiloSottile/crypto-tls-bogo-shim && \
# Draft 23
#ARG REVISION=d07b9e80a87c871c2569ce4aabd06695336c5dc5

# Draft 23 (+ client authentication)
# ARG REVISION=cd33ad248ae9490854f0077ca046b47cac3735bf

# Draft 28
ARG REVISION=33204d1eaa497819c6325998d7ba6b66316790f3

RUN cd /go/src/github.com/henrydcase/crypto-tls-bogo-shim && \
git checkout $REVISION

WORKDIR /go/src/github.com/FiloSottile/crypto-tls-bogo-shim
WORKDIR /go/src/github.com/henrydcase/crypto-tls-bogo-shim
CMD ["make", "run"]

+ 13
- 4
_dev/boring/Dockerfile ファイルの表示

@@ -34,15 +34,24 @@ RUN mkdir boringssl/build
# ARG REVISION=89917a5

# Draft 18
#ARG REVISION=9b885c5
# ARG REVISION=9b885c5
# Draft 18, but with "bssl server -loop -www" support and build fix
ARG REVISION=40b24c8154
# ARG REVISION=40b24c8154

# Draft 21
#ARG REVISION=cd8470f
# ARG REVISION=cd8470f

# Draft 22
ARG REVISION=1530ef3e
# ARG REVISION=1530ef3e

# Draft 23
# ARG REVISION=cb15cfda29c0c60d8d74145b17c93b43a7667837

# Draft 28
# ARG REVISION=861f384d7bc59241a9df1634ae938d8e75be2d30

# Latest
ARG REVISION=03de6813d8992a649092b4874ef0ebc022e2f58a

RUN cd boringssl && git fetch
RUN cd boringssl && git checkout $REVISION


+ 2
- 2
_dev/boring/run.sh ファイルの表示

@@ -2,7 +2,7 @@
set -e

/boringssl/build/tool/bssl client -grease -min-version tls1.3 -max-version tls1.3 \
-tls13-variant draft22 -session-out /session -connect "$@" < /httpreq.txt
-tls13-variant draft28 -session-out /session -connect "$@" < /httpreq.txt
exec /boringssl/build/tool/bssl client -grease -min-version tls1.3 -max-version tls1.3 \
-tls13-variant draft22 -session-in /session -connect "$@" < /httpreq.txt
-tls13-variant draft28 -session-in /session -connect "$@" < /httpreq.txt


+ 3
- 3
_dev/boring/server.sh ファイルの表示

@@ -6,21 +6,21 @@ set -x
bssl server \
-key rsa.pem \
-min-version tls1.2 -max-version tls1.3 \
-tls13-draft22-variant \
-tls13-variant draft28 \
-accept 1443 -loop -www 2>&1 &

# ECDSA
bssl server \
-key ecdsa.pem \
-min-version tls1.2 -max-version tls1.3 \
-tls13-draft22-variant \
-tls13-variant draft28 \
-accept 2443 -loop -www 2>&1 &

# Require client authentication (with ECDSA)
bssl server \
-key ecdsa.pem \
-min-version tls1.2 -max-version tls1.3 \
-tls13-draft22-variant \
-tls13-variant draft28 \
-accept 6443 -loop -www \
-require-any-client-cert -debug 2>&1 &



+ 14
- 12
_dev/interop_test_runner ファイルの表示

@@ -46,13 +46,13 @@ class RegexSelfTest(unittest.TestCase):
''' Ensures that those regexe's actually work '''

LINE_HELLO_TLS ="\nsomestuff\nHello TLS 1.3 _o/\nsomestuff"
LINE_HELLO_DRAFT_TLS="\nsomestuff\nHello TLS 1.3 (draft 22) _o/\nsomestuff"
LINE_HELLO_DRAFT_TLS="\nsomestuff\nHello TLS 1.3 (draft 23) _o/\nsomestuff"

LINE_HELLO_RESUMED ="\nsomestuff\nHello TLS 1.3 (draft 22) [resumed] _o/\nsomestuff"
LINE_HELLO_MIXED ="\nsomestuff\nHello TLS 1.3 (draft 22) _o/\nHello TLS 1.3 (draft 22) [resumed] _o/\nsomestuff"
LINE_HELLO_TLS_12 ="\nsomestuff\nHello TLS 1.2 (draft 22) [resumed] _o/\nsomestuff"
LINE_HELLO_TLS_13_0RTT="\nsomestuff\nHello TLS 1.3 (draft 22) [resumed] [0-RTT] _o/\nsomestuff"
LINE_HELLO_TLS_13_0RTT_CONFIRMED="\nsomestuff\nHello TLS 1.3 (draft 22) [resumed] [0-RTT confirmed] _o/\nsomestuff"
LINE_HELLO_RESUMED ="\nsomestuff\nHello TLS 1.3 (draft 23) [resumed] _o/\nsomestuff"
LINE_HELLO_MIXED ="\nsomestuff\nHello TLS 1.3 (draft 23) _o/\nHello TLS 1.3 (draft 23) [resumed] _o/\nsomestuff"
LINE_HELLO_TLS_12 ="\nsomestuff\nHello TLS 1.2 (draft 23) [resumed] _o/\nsomestuff"
LINE_HELLO_TLS_13_0RTT="\nsomestuff\nHello TLS 1.3 (draft 23) [resumed] [0-RTT] _o/\nsomestuff"
LINE_HELLO_TLS_13_0RTT_CONFIRMED="\nsomestuff\nHello TLS 1.3 (draft 23) [resumed] [0-RTT confirmed] _o/\nsomestuff"

def test_regexes(self):
self.assertIsNotNone(
@@ -212,12 +212,14 @@ class InteropServer_BoringSSL(
unittest.TestCase
): CLIENT_NAME = "tls-tris:boring"

class InteropServer_PicoTLS(
InteropServer,
ServerNominalMixin,
ServerZeroRttMixin,
unittest.TestCase
): CLIENT_NAME = "tls-tris:picotls"
# PicoTLS doesn't seem to implement draft-23 correctly. It will
# be enabled when draft-28 is implemented.
# class InteropServer_PicoTLS(
# InteropServer,
# ServerNominalMixin,
# ServerZeroRttMixin,
# unittest.TestCase
# ): CLIENT_NAME = "tls-tris:picotls"

class InteropServer_NSS(
InteropServer,


+ 41
- 39
_dev/tris-localserver/server.go ファイルの表示

@@ -2,6 +2,7 @@ package main

import (
"crypto/tls"
"crypto/x509"
"encoding/hex"
"flag"
"fmt"
@@ -10,7 +11,6 @@ import (
"net/http"
"os"
"time"
"crypto/x509"
)

type ZeroRTT_t int
@@ -18,21 +18,21 @@ type PubKeyAlgo_t int

// Bitset
const (
ZeroRTT_None ZeroRTT_t = 0
ZeroRTT_Offer = 1 << 0
ZeroRTT_Accept = 1 << 1
ZeroRTT_None ZeroRTT_t = 0
ZeroRTT_Offer = 1 << 0
ZeroRTT_Accept = 1 << 1
)

const (
PubKeyRSA PubKeyAlgo_t = iota
PubKeyRSA PubKeyAlgo_t = iota
PubKeyECDSA
)

type server struct {
Address string
ZeroRTT ZeroRTT_t
PubKey PubKeyAlgo_t
ClientAuthMethod tls.ClientAuthType
Address string
ZeroRTT ZeroRTT_t
PubKey PubKeyAlgo_t
ClientAuthMethod tls.ClientAuthType
}

var tlsVersionToName = map[uint16]string{
@@ -43,14 +43,16 @@ var tlsVersionToName = map[uint16]string{
tls.VersionTLS13Draft18: "1.3 (draft 18)",
tls.VersionTLS13Draft21: "1.3 (draft 21)",
tls.VersionTLS13Draft22: "1.3 (draft 22)",
tls.VersionTLS13Draft23: "1.3 (draft 23)",
tls.VersionTLS13Draft28: "1.3 (draft 28)",
}

func NewServer() *server {
s := new(server)
s.ClientAuthMethod = tls.NoClientCert
s.ZeroRTT = ZeroRTT_None
s.Address = "0.0.0.1:443"
return s
s := new(server)
s.ClientAuthMethod = tls.NoClientCert
s.ZeroRTT = ZeroRTT_None
s.Address = "0.0.0.1:443"
return s
}

func (s *server) start() {
@@ -62,7 +64,7 @@ func (s *server) start() {
log.Fatal(err)
}
var Max0RTTDataSize uint32
if ((s.ZeroRTT&ZeroRTT_Offer) == ZeroRTT_Offer) {
if (s.ZeroRTT & ZeroRTT_Offer) == ZeroRTT_Offer {
Max0RTTDataSize = 100 * 1024
}
var keyLogWriter io.Writer
@@ -82,7 +84,7 @@ func (s *server) start() {
TLSConfig: &tls.Config{
Certificates: []tls.Certificate{cert},
Max0RTTDataSize: Max0RTTDataSize,
Accept0RTTData: (s.ZeroRTT&ZeroRTT_Accept) == ZeroRTT_Accept,
Accept0RTTData: (s.ZeroRTT & ZeroRTT_Accept) == ZeroRTT_Accept,
KeyLogWriter: keyLogWriter,
GetConfigForClient: func(*tls.ClientHelloInfo) (*tls.Config, error) {
// If we send the first flight too fast, NSS sends empty early data.
@@ -91,7 +93,7 @@ func (s *server) start() {
},
MaxVersion: tls.VersionTLS13,
ClientAuth: s.ClientAuthMethod,
ClientCAs: clientCAs,
ClientCAs: clientCAs,
},
}
log.Fatal(httpServer.ListenAndServeTLS("", ""))
@@ -99,32 +101,32 @@ func (s *server) start() {

func main() {

s := NewServer()
s := NewServer()

arg_addr := flag.String("b" , "0.0.0.0:443", "Address:port used for binding")
arg_palg := flag.String("palg", "rsa", "Public algorithm to use: rsa or ecdsa")
arg_zerortt := flag.String("rtt0", "n", `0-RTT, accepts following values [n: None, a: Accept, o: Offer, oa: Offer and Accept]`)
arg_confirm := flag.Bool("rtt0ack", false, "0-RTT confirm")
arg_clientauth := flag.Bool("cliauth", false, "Performs client authentication (RequireAndVerifyClientCert used)")
flag.Parse()
arg_addr := flag.String("b", "0.0.0.0:443", "Address:port used for binding")
arg_palg := flag.String("palg", "rsa", "Public algorithm to use: rsa or ecdsa")
arg_zerortt := flag.String("rtt0", "n", `0-RTT, accepts following values [n: None, a: Accept, o: Offer, oa: Offer and Accept]`)
arg_confirm := flag.Bool("rtt0ack", false, "0-RTT confirm")
arg_clientauth := flag.Bool("cliauth", false, "Performs client authentication (RequireAndVerifyClientCert used)")
flag.Parse()

s.Address=*arg_addr
s.Address = *arg_addr

if *arg_palg == "ecdsa" {
s.PubKey = PubKeyECDSA
}
if *arg_palg == "ecdsa" {
s.PubKey = PubKeyECDSA
}

if *arg_zerortt == "a" {
s.ZeroRTT = ZeroRTT_Accept
} else if *arg_zerortt == "o" {
s.ZeroRTT = ZeroRTT_Offer
} else if *arg_zerortt == "oa" {
s.ZeroRTT = ZeroRTT_Offer | ZeroRTT_Accept
}
if *arg_zerortt == "a" {
s.ZeroRTT = ZeroRTT_Accept
} else if *arg_zerortt == "o" {
s.ZeroRTT = ZeroRTT_Offer
} else if *arg_zerortt == "oa" {
s.ZeroRTT = ZeroRTT_Offer | ZeroRTT_Accept
}

if *arg_clientauth {
s.ClientAuthMethod = tls.RequireAndVerifyClientCert
}
if *arg_clientauth {
s.ClientAuthMethod = tls.RequireAndVerifyClientCert
}

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
tlsConn := r.Context().Value(http.TLSConnContextKey).(*tls.Conn)
@@ -212,7 +214,7 @@ ClMLEiNJQ0OMxAIaRtb2RehD4q3OWlpWf6joJ36PRBqL8T5+f2x6Tg3c64UR+QPX
98UcCQHHdEhm7y2z5Z2Wt0B48tZ+UAxDEoEwMghNyw7wUD79IRlXGYypBnXaMuLX
46aGxbsSQ7Rfg62Co3JG7vo+eJd0AoZHrtFUnfM8V70IFzMBZnSwRslHRJe56Q==
-----END CERTIFICATE-----`
rsaCa_client = `-----BEGIN CERTIFICATE-----
rsaCa_client = `-----BEGIN CERTIFICATE-----
MIIFYDCCA0igAwIBAgIJAPpBgIvtQb1EMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
aWRnaXRzIFB0eSBMdGQwHhcNMTgwMjEzMjAxNjA3WhcNMTkwMjEzMjAxNjA3WjBF


+ 4
- 4
_dev/tris-testclient/client.go ファイルの表示

@@ -17,6 +17,8 @@ var tlsVersionToName = map[uint16]string{
tls.VersionTLS12: "1.2",
tls.VersionTLS13: "1.3",
tls.VersionTLS13Draft18: "1.3 (draft 18)",
tls.VersionTLS13Draft23: "1.3 (draft 23)",
tls.VersionTLS13Draft28: "1.3 (draft 28)",
}

var cipherSuiteIdToName = map[uint16]string{
@@ -28,8 +30,8 @@ var cipherSuiteIdToName = map[uint16]string{
}

type Client struct {
KeyLogWriter io.Writer
failed uint
KeyLogWriter io.Writer
failed uint
client_cert tls.Certificate
client_certpool *x509.CertPool
}
@@ -127,7 +129,6 @@ func main() {
client.run(addr, tls.VersionTLS12, tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256)
}


client.run(addr, tls.VersionTLS13, tls.TLS_CHACHA20_POLY1305_SHA256)
client.run(addr, tls.VersionTLS13, tls.TLS_AES_128_GCM_SHA256)
client.run(addr, tls.VersionTLS13, tls.TLS_AES_256_GCM_SHA384)
@@ -226,4 +227,3 @@ LAoibwDU1NC8/3MfOBYMe6Qklu3kjexOJrfdo0Z7Khgd9F8A4tKwslUndSSlAfKF
2rjfqabVMZMLZ2XEbA4W5JTfaZS4YYGcrjY7+i7OsnSxoYG2sb+xlQ==
-----END RSA PRIVATE KEY-----`
)


+ 7
- 1
_dev/tstclnt/Dockerfile ファイルの表示

@@ -21,7 +21,13 @@ ENV USE_64=1 NSS_ENABLE_TLS_1_3=1
# ARG REVISION=e61c0f657100

# Draft 22
ARG REVISION=88c3f3fa581b
#ARG REVISION=88c3f3fa581b

# Draft 23
# ARG REVISION=16c622c9e1cc

# Latest
ARG REVISION=09ab3310e710

RUN cd nss && hg pull
RUN cd nss && hg checkout -C $REVISION


+ 20
- 0
_dev/utils/fmtcheck.sh ファイルの表示

@@ -0,0 +1,20 @@
#!/bin/sh
# Copyright 2012 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.

gofiles=$(find . -iname "*.go" ! -path "*/_dev/*")
#[ -z "$gofiles" ] && exit 0

unformatted=$(gofmt -l $gofiles)
[ -z "$unformatted" ] && exit 0

# Some files are not gofmt'd. Print message and fail.

echo >&2 "Go files must be formatted with gofmt. Please run:"
for fn in $unformatted; do
echo >&2 " gofmt -w $PWD/$fn"
done

exit 1


+ 27
- 0
_dev/utils/pre-commit ファイルの表示

@@ -0,0 +1,27 @@
#!/bin/sh
# Copyright 2012 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.

# git gofmt pre-commit hook
#
# To use, store as .git/hooks/pre-commit inside your repository and make sure
# it has execute permissions.
#
# This script does not handle file names that contain spaces.

gofiles=$(git diff --cached --name-only --diff-filter=ACM | grep '\.go$')
[ -z "$gofiles" ] && exit 0

unformatted=$(gofmt -l $gofiles)
[ -z "$unformatted" ] && exit 0

# Some files are not gofmt'd. Print message and fail.

echo >&2 "Go files must be formatted with gofmt. Please run:"
for fn in $unformatted; do
echo >&2 " gofmt -w $PWD/$fn"
done

exit 1


+ 9
- 6
cipher_suites.go ファイルの表示

@@ -5,6 +5,7 @@
package tls

import (
"crypto"
"crypto/aes"
"crypto/cipher"
"crypto/des"
@@ -12,7 +13,6 @@ import (
"crypto/rc4"
"crypto/sha1"
"crypto/sha256"
"crypto/x509"
"hash"

"golang_org/x/crypto/chacha20poly1305"
@@ -26,15 +26,15 @@ type keyAgreement interface {
// In the case that the key agreement protocol doesn't use a
// ServerKeyExchange message, generateServerKeyExchange can return nil,
// nil.
generateServerKeyExchange(*Config, *Certificate, *clientHelloMsg, *serverHelloMsg) (*serverKeyExchangeMsg, error)
processClientKeyExchange(*Config, *Certificate, *clientKeyExchangeMsg, uint16) ([]byte, error)
generateServerKeyExchange(*Config, crypto.PrivateKey, *clientHelloMsg, *serverHelloMsg) (*serverKeyExchangeMsg, error)
processClientKeyExchange(*Config, crypto.PrivateKey, *clientKeyExchangeMsg, uint16) ([]byte, error)

// On the client side, the next two methods are called in order.

// This method may not be called if the server doesn't send a
// ServerKeyExchange message.
processServerKeyExchange(*Config, *clientHelloMsg, *serverHelloMsg, *x509.Certificate, *serverKeyExchangeMsg) error
generateClientKeyExchange(*Config, *clientHelloMsg, *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error)
processServerKeyExchange(*Config, *clientHelloMsg, *serverHelloMsg, crypto.PublicKey, *serverKeyExchangeMsg) error
generateClientKeyExchange(*Config, *clientHelloMsg, crypto.PublicKey) ([]byte, *clientKeyExchangeMsg, error)
}

const (
@@ -174,7 +174,10 @@ type fixedNonceAEAD struct {
aead cipher.AEAD
}

func (f *fixedNonceAEAD) NonceSize() int { return 8 }
func (f *fixedNonceAEAD) NonceSize() int { return 8 }

// Overhead returns the maximum difference between the lengths of a
// plaintext and its ciphertext.
func (f *fixedNonceAEAD) Overhead() int { return f.aead.Overhead() }
func (f *fixedNonceAEAD) explicitNonceLen() int { return 8 }



+ 63
- 18
common.go ファイルの表示

@@ -30,6 +30,8 @@ const (
VersionTLS13Draft18 = 0x7f00 | 18
VersionTLS13Draft21 = 0x7f00 | 21
VersionTLS13Draft22 = 0x7f00 | 22
VersionTLS13Draft23 = 0x7f00 | 23
VersionTLS13Draft28 = 0x7f00 | 28
)

const (
@@ -40,7 +42,7 @@ const (
maxWarnAlertCount = 5 // maximum number of consecutive warning alerts

minVersion = VersionTLS12
maxVersion = VersionTLS13Draft22
maxVersion = VersionTLS13Draft28
)

// TLS record types.
@@ -79,22 +81,24 @@ const (

// TLS extension numbers
const (
extensionServerName uint16 = 0
extensionStatusRequest uint16 = 5
extensionSupportedCurves uint16 = 10 // Supported Groups in 1.3 nomenclature
extensionSupportedPoints uint16 = 11
extensionSignatureAlgorithms uint16 = 13
extensionALPN uint16 = 16
extensionSCT uint16 = 18 // https://tools.ietf.org/html/rfc6962#section-6
extensionSessionTicket uint16 = 35
extensionKeyShare uint16 = 40
extensionPreSharedKey uint16 = 41
extensionEarlyData uint16 = 42
extensionSupportedVersions uint16 = 43
extensionPSKKeyExchangeModes uint16 = 45
extensionCAs uint16 = 47
extensionNextProtoNeg uint16 = 13172 // not IANA assigned
extensionRenegotiationInfo uint16 = 0xff01
extensionServerName uint16 = 0
extensionStatusRequest uint16 = 5
extensionSupportedCurves uint16 = 10 // Supported Groups in 1.3 nomenclature
extensionSupportedPoints uint16 = 11
extensionSignatureAlgorithms uint16 = 13
extensionALPN uint16 = 16
extensionSCT uint16 = 18 // https://tools.ietf.org/html/rfc6962#section-6
extensionSessionTicket uint16 = 35
extensionPreSharedKey uint16 = 41
extensionEarlyData uint16 = 42
extensionSupportedVersions uint16 = 43
extensionPSKKeyExchangeModes uint16 = 45
extensionCAs uint16 = 47
extensionSignatureAlgorithmsCert uint16 = 50
extensionKeyShare uint16 = 51
extensionNextProtoNeg uint16 = 13172 // not IANA assigned
extensionRenegotiationInfo uint16 = 0xff01
extensionDelegatedCredential uint16 = 0xff02 // TODO(any) Get IANA assignment
)

// TLS signaling cipher suite values
@@ -216,6 +220,7 @@ type ConnectionState struct {
VerifiedChains [][]*x509.Certificate // verified chains built from PeerCertificates
SignedCertificateTimestamps [][]byte // SCTs from the server, if any
OCSPResponse []byte // stapled OCSP response from server, if any
DelegatedCredential []byte // Delegated credential sent by the server, if any

// TLSUnique contains the "tls-unique" channel binding value (see RFC
// 5929, section 3). For resumed sessions this value will be nil
@@ -354,6 +359,10 @@ type ClientHelloInfo struct {
// immediately available for Read.
Offered0RTTData bool

// AcceptsDelegatedCredential is true if the client indicated willingness
// to negotiate the delegated credential extension.
AcceptsDelegatedCredential bool

// The Fingerprint is an sequence of bytes unique to this Client Hello.
// It can be used to prevent or mitigate 0-RTT data replays as it's
// guaranteed that a replayed connection will have the same Fingerprint.
@@ -607,6 +616,26 @@ type Config struct {
// session tickets, instead of SessionTicketKey.
SessionTicketSealer SessionTicketSealer

// AcceptDelegatedCredential is true if the client is willing to negotiate
// the delegated credential extension.
//
// This value has no meaning for the server.
//
// See https://tools.ietf.org/html/draft-ietf-tls-subcerts-02.
AcceptDelegatedCredential bool

// GetDelegatedCredential returns a DC and its private key for use in the
// delegated credential extension. The inputs to the callback are some
// information parsed from the ClientHello, as well as the protocol version
// selected by the server. This is necessary because the DC is bound to the
// protocol version in which it's used. The return value is the raw DC
// encoded in the wire format specified in
// https://tools.ietf.org/html/draft-ietf-tls-subcerts-02. If the return
// value is nil, then the server will not offer negotiate the extension.
//
// This value has no meaning for the client.
GetDelegatedCredential func(*ClientHelloInfo, uint16) ([]byte, crypto.PrivateKey, error)

serverInitOnce sync.Once // guards calling (*Config).serverInit

// mutex protects sessionTicketKeys.
@@ -683,6 +712,8 @@ func (c *Config) Clone() *Config {
Accept0RTTData: c.Accept0RTTData,
Max0RTTDataSize: c.Max0RTTDataSize,
SessionTicketSealer: c.SessionTicketSealer,
AcceptDelegatedCredential: c.AcceptDelegatedCredential,
GetDelegatedCredential: c.GetDelegatedCredential,
sessionTicketKeys: sessionTicketKeys,
}
}
@@ -858,7 +889,7 @@ var configSuppVersArray = [...]uint16{VersionTLS13, VersionTLS12, VersionTLS11,
// with TLS 1.3 draft versions included.
//
// TODO: remove once TLS 1.3 is finalised.
var tls13DraftSuppVersArray = [...]uint16{VersionTLS13Draft22, VersionTLS12, VersionTLS11, VersionTLS10, VersionSSL30}
var tls13DraftSuppVersArray = [...]uint16{VersionTLS13Draft28, VersionTLS12, VersionTLS11, VersionTLS10, VersionSSL30}

// getSupportedVersions returns the protocol versions that are supported by the
// current configuration.
@@ -1185,3 +1216,17 @@ func signatureFromSignatureScheme(signatureAlgorithm SignatureScheme) uint8 {
return 0
}
}

// TODO(kk): Use variable length encoding?
func getUint24(b []byte) int {
n := int(b[2])
n += int(b[1] << 8)
n += int(b[0] << 16)
return n
}

func putUint24(b []byte, n int) {
b[0] = byte(n >> 16)
b[1] = byte(n >> 8)
b[2] = byte(n & 0xff)
}

+ 33
- 15
conn.go ファイルの表示

@@ -11,6 +11,7 @@ import (
"crypto/cipher"
"crypto/subtle"
"crypto/x509"
"encoding/binary"
"errors"
"fmt"
"io"
@@ -51,11 +52,14 @@ type Conn struct {
didResume bool // whether this connection was a session resumption
cipherSuite uint16
ocspResponse []byte // stapled OCSP response
scts [][]byte // signed certificate timestamps from server
scts [][]byte // Signed certificate timestamps from server
peerCertificates []*x509.Certificate
// verifiedChains contains the certificate chains that we built, as
// opposed to the ones presented by the server.
verifiedChains [][]*x509.Certificate
// verifiedDc is set by a client who negotiates the use of a valid delegated
// credential.
verifiedDc *delegatedCredential
// serverName contains the server name indicated by the client, if any.
serverName string
// secureRenegotiation is true if the server echoed the secure
@@ -355,6 +359,15 @@ func (hc *halfConn) decrypt(b *block) (ok bool, prefixLen int, alertValue alert)
hc.additionalData[11] = byte(n >> 8)
hc.additionalData[12] = byte(n)
additionalData = hc.additionalData[:]
} else {
if len(payload) > int((1<<14)+256) {
return false, 0, alertRecordOverflow
}
// Check AD header, see 5.2 of RFC8446
additionalData = make([]byte, 5)
additionalData[0] = byte(recordTypeApplicationData)
binary.BigEndian.PutUint16(additionalData[1:], VersionTLS12)
binary.BigEndian.PutUint16(additionalData[3:], uint16(len(payload)))
}
var err error
payload, err = c.Open(payload[:0], nonce, payload, additionalData)
@@ -457,13 +470,8 @@ func (hc *halfConn) encrypt(b *block, explicitIVLen int) (bool, alert) {
case cipher.Stream:
c.XORKeyStream(payload, payload)
case aead:
// explicitIVLen is always 0 for TLS1.3
payloadLen := len(b.data) - recordHeaderLen - explicitIVLen
overhead := c.Overhead()
if hc.version >= VersionTLS13 {
overhead++
}
b.resize(len(b.data) + overhead)

nonce := b.data[recordHeaderLen : recordHeaderLen+explicitIVLen]
if len(nonce) == 0 {
nonce = hc.seq[:]
@@ -475,18 +483,25 @@ func (hc *halfConn) encrypt(b *block, explicitIVLen int) (bool, alert) {
if hc.version < VersionTLS13 {
copy(hc.additionalData[:], hc.seq[:])
copy(hc.additionalData[8:], b.data[:3])
hc.additionalData[11] = byte(payloadLen >> 8)
hc.additionalData[12] = byte(payloadLen)
binary.BigEndian.PutUint16(hc.additionalData[11:], uint16(payloadLen))
additionalData = hc.additionalData[:]
}
b.resize(len(b.data) + c.Overhead())
} else {
// 1 byte of content type is appended to payload and encrypted
payload = append(payload, b.data[0])

if hc.version >= VersionTLS13 {
// opaque type
payload = payload[:len(payload)+1]
payload[len(payload)-1] = b.data[0]
// opaque_type
b.data[0] = byte(recordTypeApplicationData)
}

// Add AD header, see 5.2 of RFC8446
additionalData = make([]byte, 5)
additionalData[0] = b.data[0]
binary.BigEndian.PutUint16(additionalData[1:], VersionTLS12)
binary.BigEndian.PutUint16(additionalData[3:], uint16(len(payload)+c.Overhead()))

// make room for TLSCiphertext.encrypted_record
b.resize(len(payload) + recordHeaderLen + c.Overhead())
}
c.Seal(payload[:0], nonce, payload, additionalData)
case cbcMode:
blockSize := c.BlockSize()
@@ -1663,6 +1678,9 @@ func (c *Conn) ConnectionState() ConnectionState {
state.VerifiedChains = c.verifiedChains
state.SignedCertificateTimestamps = c.scts
state.OCSPResponse = c.ocspResponse
if c.verifiedDc != nil {
state.DelegatedCredential = c.verifiedDc.raw
}
state.HandshakeConfirmed = atomic.LoadInt32(&c.handshakeConfirmed) == 1
if !state.HandshakeConfirmed {
state.Unique0RTTToken = c.binder


+ 4
- 4
example_test.go ファイルの表示

@@ -155,8 +155,8 @@ func ExampleConfig_keyLogWriter_TLS13() {
// preferences.

// Output:
// CLIENT_HANDSHAKE_TRAFFIC_SECRET 0000000000000000000000000000000000000000000000000000000000000000 ab02b68658d18ef1a4056b3094fe511b43084d40e9a6518753a7f832da724292
// SERVER_HANDSHAKE_TRAFFIC_SECRET 0000000000000000000000000000000000000000000000000000000000000000 d2e96648d170e2524bee07b651f4cca932a52247493ca33cc0714260a7424b2d
// SERVER_TRAFFIC_SECRET_0 0000000000000000000000000000000000000000000000000000000000000000 371fab23269e3cd73496e0e78f3dbc487f7cd5a563cc9f8c1a71be242268c375
// CLIENT_TRAFFIC_SECRET_0 0000000000000000000000000000000000000000000000000000000000000000 ca30484e48ec9a6f3b05b41c7492dbed8dea8e92d2abece2824a96052ac8ed8d
// CLIENT_HANDSHAKE_TRAFFIC_SECRET 0000000000000000000000000000000000000000000000000000000000000000 16ca97d21087a14d406b2601b4713dd82b156cc01d54665baaa4bdb62b72b9a4
// SERVER_HANDSHAKE_TRAFFIC_SECRET 0000000000000000000000000000000000000000000000000000000000000000 102c68d960da4f5e2b76a99636ac07bb5774e43b8ce8c14aa4dfd9bf54d11754
// SERVER_TRAFFIC_SECRET_0 0000000000000000000000000000000000000000000000000000000000000000 f3208d533bb885f32f52142acb484eed104739970c2f426e72a1ee31f6d28650
// CLIENT_TRAFFIC_SECRET_0 0000000000000000000000000000000000000000000000000000000000000000 70de6b1936df7db171c02f9cfdb04dfa9405a891c959beb15b86f26b2057ba23
}

+ 52
- 2
handshake_client.go ファイルの表示

@@ -65,6 +65,7 @@ func makeClientHello(config *Config) (*clientHelloMsg, error) {
supportedPoints: []uint8{pointFormatUncompressed},
nextProtoNeg: len(config.NextProtos) > 0,
secureRenegotiationSupported: true,
delegatedCredential: config.AcceptDelegatedCredential,
alpnProtocols: config.NextProtos,
}
possibleCipherSuites := config.cipherSuites()
@@ -106,6 +107,7 @@ NextCipherSuite:
hello.vers = VersionTLS12
hello.supportedVersions = config.getSupportedVersions()
hello.supportedSignatureAlgorithms = supportedSignatureAlgorithms13
hello.supportedSignatureAlgorithmsCert = supportedSigAlgorithmsCert(supportedSignatureAlgorithms13)
}

return hello, nil
@@ -411,6 +413,50 @@ func (hs *clientHandshakeState) processCertsFromServer(certificates [][]byte) er
return nil
}

// processDelegatedCredentialFromServer unmarshals the delegated credential
// offered by the server (if present) and validates it using the peer
// certificate and the signature scheme (`scheme`) indicated by the server in
// the "signature_scheme" extension.
func (hs *clientHandshakeState) processDelegatedCredentialFromServer(serialized []byte, scheme SignatureScheme) error {
c := hs.c

var dc *delegatedCredential
var err error
if serialized != nil {
// Assert that the DC extension was indicated by the client.
if !hs.hello.delegatedCredential {
c.sendAlert(alertUnexpectedMessage)
return errors.New("tls: got delegated credential extension without indication")
}

// Parse the delegated credential.
dc, err = unmarshalDelegatedCredential(serialized)
if err != nil {
c.sendAlert(alertDecodeError)
return fmt.Errorf("tls: delegated credential: %s", err)
}
}

if dc != nil && !c.config.InsecureSkipVerify {
if v, err := dc.validate(c.peerCertificates[0], c.config.time()); err != nil {
c.sendAlert(alertIllegalParameter)
return fmt.Errorf("delegated credential: %s", err)
} else if !v {
c.sendAlert(alertIllegalParameter)
return errors.New("delegated credential: signature invalid")
} else if dc.cred.expectedVersion != hs.c.vers {
c.sendAlert(alertIllegalParameter)
return errors.New("delegated credential: protocol version mismatch")
} else if dc.cred.expectedCertVerifyAlgorithm != scheme {
c.sendAlert(alertIllegalParameter)
return errors.New("delegated credential: signature scheme mismatch")
}
}

c.verifiedDc = dc
return nil
}

func (hs *clientHandshakeState) doFullHandshake() error {
c := hs.c

@@ -476,10 +522,14 @@ func (hs *clientHandshakeState) doFullHandshake() error {

keyAgreement := hs.suite.ka(c.vers)

// Set the public key used to verify the handshake.
pk := c.peerCertificates[0].PublicKey

skx, ok := msg.(*serverKeyExchangeMsg)
if ok {
hs.finishedHash.Write(skx.marshal())
err = keyAgreement.processServerKeyExchange(c.config, hs.hello, hs.serverHello, c.peerCertificates[0], skx)

err = keyAgreement.processServerKeyExchange(c.config, hs.hello, hs.serverHello, pk, skx)
if err != nil {
c.sendAlert(alertUnexpectedMessage)
return err
@@ -528,7 +578,7 @@ func (hs *clientHandshakeState) doFullHandshake() error {
}
}

preMasterSecret, ckx, err := keyAgreement.generateClientKeyExchange(c.config, hs.hello, c.peerCertificates[0])
preMasterSecret, ckx, err := keyAgreement.generateClientKeyExchange(c.config, hs.hello, pk)
if err != nil {
c.sendAlert(alertInternalError)
return err


+ 156
- 85
handshake_messages.go ファイルの表示

@@ -6,81 +6,99 @@ package tls

import (
"bytes"
"encoding/binary"
"strings"
)

type clientHelloMsg struct {
raw []byte
rawTruncated []byte // for PSK binding
vers uint16
random []byte
sessionId []byte
cipherSuites []uint16
compressionMethods []uint8
nextProtoNeg bool
serverName string
ocspStapling bool
scts bool
supportedCurves []CurveID
supportedPoints []uint8
ticketSupported bool
sessionTicket []uint8
supportedSignatureAlgorithms []SignatureScheme
secureRenegotiation []byte
secureRenegotiationSupported bool
alpnProtocols []string
keyShares []keyShare
supportedVersions []uint16
psks []psk
pskKeyExchangeModes []uint8
earlyData bool
}

// Helpers

// Marshalling of signature_algorithms extension see https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
// for more details. Extension is serialized in data buffer
// Function advances data slice and returns it, so that it can be used for further processing
func marshalExtensionSignatureAlgorithms(data []byte, sigSchemes []SignatureScheme) []byte {
data[0] = byte(extensionSignatureAlgorithms >> 8)
data[1] = byte(extensionSignatureAlgorithms)
l := 2 + 2*len(sigSchemes)
data[2] = byte(l >> 8)
data[3] = byte(l)
data = data[4:]
// signAlgosCertList helper function returns either list of signature algorithms in case
// signature_algorithms_cert extension should be marshalled or nil in the other case.
// signAlgos is a list of algorithms from signature_algorithms extension. signAlgosCert is a list
// of algorithms from signature_algorithms_cert extension.
func signAlgosCertList(signAlgos, signAlgosCert []SignatureScheme) []SignatureScheme {
if eqSignatureAlgorithms(signAlgos, signAlgosCert) {
// ensure that only supported_algorithms extension is send if supported_algorithms_cert
// has identical content
return nil
}
return signAlgosCert
}

l -= 2
data[0] = byte(l >> 8)
data[1] = byte(l)
type clientHelloMsg struct {
raw []byte
rawTruncated []byte // for PSK binding
vers uint16
random []byte
sessionId []byte
cipherSuites []uint16
compressionMethods []uint8
nextProtoNeg bool
serverName string
ocspStapling bool
scts bool
supportedCurves []CurveID
supportedPoints []uint8
ticketSupported bool
sessionTicket []uint8
supportedSignatureAlgorithms []SignatureScheme
supportedSignatureAlgorithmsCert []SignatureScheme
secureRenegotiation []byte
secureRenegotiationSupported bool
alpnProtocols []string
keyShares []keyShare
supportedVersions []uint16
psks []psk
pskKeyExchangeModes []uint8
earlyData bool
delegatedCredential bool
}

// Function used for signature_algorithms and signature_algorithrms_cert
// extensions only (for more details, see TLS 1.3 draft 28, 4.2.3).
//
// It advances data slice and returns it, so that it can be used for further
// processing
func marshalExtensionSignatureAlgorithms(extension uint16, data []byte, schemes []SignatureScheme) []byte {
algNum := uint16(len(schemes))
if algNum == 0 {
return data
}

binary.BigEndian.PutUint16(data, extension)
data = data[2:]
binary.BigEndian.PutUint16(data, (2*algNum)+2) // +1 for length
data = data[2:]
for _, sigAlgo := range sigSchemes {
data[0] = byte(sigAlgo >> 8)
data[1] = byte(sigAlgo)
binary.BigEndian.PutUint16(data, (2 * algNum))
data = data[2:]

for _, algo := range schemes {
binary.BigEndian.PutUint16(data, uint16(algo))
data = data[2:]
}
return data
}

// Unmrshalling of signature_algorithms extension see https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
// for more details.
// Function used for unmarshalling signature_algorithms or signature_algorithms_cert extensions only
// (for more details, see TLS 1.3 draft 28, 4.2.3)
// In case of error function returns alertDecoderError otherwise filled SignatureScheme slice and alertSuccess
func unmarshalExtensionSignatureAlgorithms(data []byte, length int) ([]SignatureScheme, alert) {

if length < 2 || length&1 != 0 {
return nil, alertDecodeError
}

l := int(data[0])<<8 | int(data[1])
if l != length-2 {
algLen := binary.BigEndian.Uint16(data)
idx := 2

if int(algLen) != length-2 {
return nil, alertDecodeError
}
n := l / 2
d := data[2:]
sigSchemes := make([]SignatureScheme, n)
for i := range sigSchemes {
sigSchemes[i] = SignatureScheme(d[0])<<8 | SignatureScheme(d[1])
d = d[2:]

schemes := make([]SignatureScheme, algLen/2)
for i := range schemes {
schemes[i] = SignatureScheme(binary.BigEndian.Uint16(data[idx:]))
idx += 2
}
return sigSchemes, alertSuccess
return schemes, alertSuccess
}

func (m *clientHelloMsg) equal(i interface{}) bool {
@@ -104,12 +122,14 @@ func (m *clientHelloMsg) equal(i interface{}) bool {
m.ticketSupported == m1.ticketSupported &&
bytes.Equal(m.sessionTicket, m1.sessionTicket) &&
eqSignatureAlgorithms(m.supportedSignatureAlgorithms, m1.supportedSignatureAlgorithms) &&
eqSignatureAlgorithms(m.supportedSignatureAlgorithmsCert, m1.supportedSignatureAlgorithmsCert) &&
m.secureRenegotiationSupported == m1.secureRenegotiationSupported &&
bytes.Equal(m.secureRenegotiation, m1.secureRenegotiation) &&
eqStrings(m.alpnProtocols, m1.alpnProtocols) &&
eqKeyShares(m.keyShares, m1.keyShares) &&
eqUint16s(m.supportedVersions, m1.supportedVersions) &&
m.earlyData == m1.earlyData
m.earlyData == m1.earlyData &&
m.delegatedCredential == m1.delegatedCredential
}

func (m *clientHelloMsg) marshal() []byte {
@@ -120,6 +140,8 @@ func (m *clientHelloMsg) marshal() []byte {
length := 2 + 32 + 1 + len(m.sessionId) + 2 + len(m.cipherSuites)*2 + 1 + len(m.compressionMethods)
numExtensions := 0
extensionsLength := 0

// Indicates wether to send signature_algorithms_cert extension
if m.nextProtoNeg {
numExtensions++
}
@@ -147,6 +169,10 @@ func (m *clientHelloMsg) marshal() []byte {
extensionsLength += 2 + 2*len(m.supportedSignatureAlgorithms)
numExtensions++
}
if m.getSignatureAlgorithmsCert() != nil {
extensionsLength += 2 + 2*len(m.getSignatureAlgorithmsCert())
numExtensions++
}
if m.secureRenegotiationSupported {
extensionsLength += 1 + len(m.secureRenegotiation)
numExtensions++
@@ -179,6 +205,9 @@ func (m *clientHelloMsg) marshal() []byte {
if m.earlyData {
numExtensions++
}
if m.delegatedCredential {
numExtensions++
}
if numExtensions > 0 {
extensionsLength += 4 * numExtensions
length += 2 + extensionsLength
@@ -305,26 +334,15 @@ func (m *clientHelloMsg) marshal() []byte {
copy(z, m.sessionTicket)
z = z[len(m.sessionTicket):]
}
if len(m.supportedSignatureAlgorithms) > 0 {
// https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
// https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.3
z[0] = byte(extensionSignatureAlgorithms >> 8)
z[1] = byte(extensionSignatureAlgorithms)
l := 2 + 2*len(m.supportedSignatureAlgorithms)
z[2] = byte(l >> 8)
z[3] = byte(l)
z = z[4:]

l -= 2
z[0] = byte(l >> 8)
z[1] = byte(l)
z = z[2:]
for _, sigAlgo := range m.supportedSignatureAlgorithms {
z[0] = byte(sigAlgo >> 8)
z[1] = byte(sigAlgo)
z = z[2:]
}
if len(m.supportedSignatureAlgorithms) > 0 {
z = marshalExtensionSignatureAlgorithms(extensionSignatureAlgorithms, z, m.supportedSignatureAlgorithms)
}
if m.getSignatureAlgorithmsCert() != nil {
// Ensure only one list of algorithms is sent if supported_algorithms and supported_algorithms_cert are the same
z = marshalExtensionSignatureAlgorithms(extensionSignatureAlgorithmsCert, z, m.getSignatureAlgorithmsCert())
}

if m.secureRenegotiationSupported {
z[0] = byte(extensionRenegotiationInfo >> 8)
z[1] = byte(extensionRenegotiationInfo & 0xff)
@@ -407,6 +425,10 @@ func (m *clientHelloMsg) marshal() []byte {
z[1] = byte(extensionEarlyData)
z = z[4:]
}
if m.delegatedCredential {
binary.BigEndian.PutUint16(z, extensionDelegatedCredential)
z = z[4:]
}

m.raw = x

@@ -471,6 +493,7 @@ func (m *clientHelloMsg) unmarshal(data []byte) alert {
m.psks = nil
m.pskKeyExchangeModes = nil
m.earlyData = false
m.delegatedCredential = false

if len(data) == 0 {
// ClientHello is optionally followed by extension data
@@ -735,6 +758,9 @@ func (m *clientHelloMsg) unmarshal(data []byte) alert {
case extensionEarlyData:
// https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.8
m.earlyData = true
case extensionDelegatedCredential:
// https://tools.ietf.org/html/draft-ietf-tls-subcerts-02
m.delegatedCredential = true
}
data = data[length:]
bindersOffset += length
@@ -743,6 +769,10 @@ func (m *clientHelloMsg) unmarshal(data []byte) alert {
return alertSuccess
}

func (m *clientHelloMsg) getSignatureAlgorithmsCert() []SignatureScheme {
return signAlgosCertList(m.supportedSignatureAlgorithms, m.supportedSignatureAlgorithmsCert)
}

type serverHelloMsg struct {
raw []byte
vers uint16
@@ -976,7 +1006,6 @@ func (m *serverHelloMsg) marshal() []byte {
z = z[len(sct)+2:]
}
}

if m.keyShare.group != 0 {
z[0] = uint8(extensionKeyShare >> 8)
z[1] = uint8(extensionKeyShare)
@@ -1069,7 +1098,11 @@ func (m *serverHelloMsg) unmarshal(data []byte) alert {
if m.vers != VersionTLS12 {
return alertDecodeError
}
m.vers = uint16(svData[0])<<8 | uint16(svData[1])
rcvVer := binary.BigEndian.Uint16(svData[0:])
if rcvVer < VersionTLS13 {
return alertIllegalParameter
}
m.vers = rcvVer
}

for len(data) != 0 {
@@ -1406,9 +1439,10 @@ func (m *certificateMsg) unmarshal(data []byte) alert {
}

type certificateEntry struct {
data []byte
ocspStaple []byte
sctList [][]byte
data []byte
ocspStaple []byte
sctList [][]byte
delegatedCredential []byte
}

type certificateMsg13 struct {
@@ -1430,6 +1464,7 @@ func (m *certificateMsg13) equal(i interface{}) bool {
ok := bytes.Equal(m.certificates[i].data, m1.certificates[i].data)
ok = ok && bytes.Equal(m.certificates[i].ocspStaple, m1.certificates[i].ocspStaple)
ok = ok && eqByteSlices(m.certificates[i].sctList, m1.certificates[i].sctList)
ok = ok && bytes.Equal(m.certificates[i].delegatedCredential, m1.certificates[i].delegatedCredential)
if !ok {
return false
}
@@ -1456,6 +1491,9 @@ func (m *certificateMsg13) marshal() (x []byte) {
i += 2 + len(sct)
}
}
if len(cert.delegatedCredential) != 0 {
i += 4 + len(cert.delegatedCredential)
}
}

length := 3 + 3*len(m.certificates) + i
@@ -1530,6 +1568,15 @@ func (m *certificateMsg13) marshal() (x []byte) {
sctLenPos[2] = uint8(sctLen >> 8)
sctLenPos[3] = uint8(sctLen)
}
if len(cert.delegatedCredential) != 0 {
binary.BigEndian.PutUint16(z, extensionDelegatedCredential)
binary.BigEndian.PutUint16(z[2:], uint16(len(cert.delegatedCredential)))
z = z[4:]
copy(z, cert.delegatedCredential)
z = z[len(cert.delegatedCredential):]
extensionLen += 4 + len(cert.delegatedCredential)
}

extLenPos[0] = uint8(extensionLen >> 8)
extLenPos[1] = uint8(extensionLen)
}
@@ -1635,6 +1682,8 @@ func (m *certificateMsg13) unmarshal(data []byte) alert {
m.certificates[i].sctList = append(m.certificates[i].sctList, body[2:2+sctLen])
body = body[2+sctLen:]
}
case extensionDelegatedCredential:
m.certificates[i].delegatedCredential = body
}
}
}
@@ -2074,15 +2123,17 @@ func (m *certificateRequestMsg) unmarshal(data []byte) alert {
if len(data) != 0 {
return alertDecodeError
}

return alertSuccess
}

type certificateRequestMsg13 struct {
raw []byte

requestContext []byte
supportedSignatureAlgorithms []SignatureScheme
certificateAuthorities [][]byte
requestContext []byte
supportedSignatureAlgorithms []SignatureScheme
supportedSignatureAlgorithmsCert []SignatureScheme
certificateAuthorities [][]byte
}

func (m *certificateRequestMsg13) equal(i interface{}) bool {
@@ -2091,7 +2142,8 @@ func (m *certificateRequestMsg13) equal(i interface{}) bool {
bytes.Equal(m.raw, m1.raw) &&
bytes.Equal(m.requestContext, m1.requestContext) &&
eqByteSlices(m.certificateAuthorities, m1.certificateAuthorities) &&
eqSignatureAlgorithms(m.supportedSignatureAlgorithms, m1.supportedSignatureAlgorithms)
eqSignatureAlgorithms(m.supportedSignatureAlgorithms, m1.supportedSignatureAlgorithms) &&
eqSignatureAlgorithms(m.supportedSignatureAlgorithmsCert, m1.supportedSignatureAlgorithmsCert)
}

func (m *certificateRequestMsg13) marshal() (x []byte) {
@@ -2104,6 +2156,11 @@ func (m *certificateRequestMsg13) marshal() (x []byte) {
numExtensions := 1
extensionsLength := 2 + 2*len(m.supportedSignatureAlgorithms)

if m.getSignatureAlgorithmsCert() != nil {
numExtensions += 1
extensionsLength += 2 + 2*len(m.getSignatureAlgorithmsCert())
}

casLength := 0
if len(m.certificateAuthorities) > 0 {
for _, ca := range m.certificateAuthorities {
@@ -2131,7 +2188,11 @@ func (m *certificateRequestMsg13) marshal() (x []byte) {
z = z[2:]

// TODO: this function should be reused by CH
z = marshalExtensionSignatureAlgorithms(z, m.supportedSignatureAlgorithms)
z = marshalExtensionSignatureAlgorithms(extensionSignatureAlgorithms, z, m.supportedSignatureAlgorithms)

if m.getSignatureAlgorithmsCert() != nil {
z = marshalExtensionSignatureAlgorithms(extensionSignatureAlgorithmsCert, z, m.getSignatureAlgorithmsCert())
}
// certificate_authorities
if casLength > 0 {
z[0] = byte(extensionCAs >> 8)
@@ -2204,6 +2265,12 @@ func (m *certificateRequestMsg13) unmarshal(data []byte) alert {
if err != alertSuccess {
return err
}
case extensionSignatureAlgorithmsCert:
var err alert
m.supportedSignatureAlgorithmsCert, err = unmarshalExtensionSignatureAlgorithms(data, length)
if err != alertSuccess {
return err
}
case extensionCAs:
// TODO DRY: share code with CH
if length < 2 {
@@ -2240,6 +2307,10 @@ func (m *certificateRequestMsg13) unmarshal(data []byte) alert {
return alertSuccess
}

func (m *certificateRequestMsg13) getSignatureAlgorithmsCert() []SignatureScheme {
return signAlgosCertList(m.supportedSignatureAlgorithms, m.supportedSignatureAlgorithmsCert)
}

type certificateVerifyMsg struct {
raw []byte
hasSignatureAndHash bool


+ 46
- 15
handshake_server.go ファイルの表示

@@ -30,6 +30,11 @@ type serverHandshakeState struct {
clientHello *clientHelloMsg
hello *serverHelloMsg
cert *Certificate
privateKey crypto.PrivateKey

// A marshalled DelegatedCredential to be sent to the client in the
// handshake.
delegatedCredential []byte

// TLS 1.0-1.2 fields
ellipticOk bool
@@ -299,11 +304,36 @@ Curves:
c.sendAlert(alertInternalError)
return false, err
}
if hs.clientHello.scts && hs.hello != nil {

// Set the private key for this handshake to the certificate's secret key.
hs.privateKey = hs.cert.PrivateKey

if hs.clientHello.scts {
hs.hello.scts = hs.cert.SignedCertificateTimestamps
}

if priv, ok := hs.cert.PrivateKey.(crypto.Signer); ok {
// Set the private key to the DC private key if the client and server are
// willing to negotiate the delegated credential extension.
//
// Check to see if a DelegatedCredential is available and should be used.
// If one is available, the session is using TLS >= 1.2, and the client
// accepts the delegated credential extension, then set the handshake
// private key to the DC private key.
if c.config.GetDelegatedCredential != nil && hs.clientHello.delegatedCredential && c.vers >= VersionTLS12 {
dc, sk, err := c.config.GetDelegatedCredential(hs.clientHelloInfo(), c.vers)
if err != nil {
c.sendAlert(alertInternalError)
return false, err
}

// Set the handshake private key.
if dc != nil {
hs.privateKey = sk
hs.delegatedCredential = dc
}
}

if priv, ok := hs.privateKey.(crypto.Signer); ok {
switch priv.Public().(type) {
case *ecdsa.PublicKey:
hs.ecdsaOk = true
@@ -314,7 +344,7 @@ Curves:
return false, fmt.Errorf("tls: unsupported signing key type (%T)", priv.Public())
}
}
if priv, ok := hs.cert.PrivateKey.(crypto.Decrypter); ok {
if priv, ok := hs.privateKey.(crypto.Decrypter); ok {
switch priv.Public().(type) {
case *rsa.PublicKey:
hs.rsaDecryptOk = true
@@ -479,7 +509,7 @@ func (hs *serverHandshakeState) doFullHandshake() error {
}

keyAgreement := hs.suite.ka(c.vers)
skx, err := keyAgreement.generateServerKeyExchange(c.config, hs.cert, hs.clientHello, hs.hello)
skx, err := keyAgreement.generateServerKeyExchange(c.config, hs.privateKey, hs.clientHello, hs.hello)
if err != nil {
c.sendAlert(alertHandshakeFailure)
return err
@@ -572,7 +602,7 @@ func (hs *serverHandshakeState) doFullHandshake() error {
}
hs.finishedHash.Write(ckx.marshal())

preMasterSecret, err := keyAgreement.processClientKeyExchange(c.config, hs.cert, ckx, c.vers)
preMasterSecret, err := keyAgreement.processClientKeyExchange(c.config, hs.privateKey, ckx, c.vers)
if err != nil {
if err == errClientKeyExchange {
c.sendAlert(alertDecodeError)
@@ -880,16 +910,17 @@ func (hs *serverHandshakeState) clientHelloInfo() *ClientHelloInfo {
}

hs.cachedClientHelloInfo = &ClientHelloInfo{
CipherSuites: hs.clientHello.cipherSuites,
ServerName: hs.clientHello.serverName,
SupportedCurves: hs.clientHello.supportedCurves,
SupportedPoints: hs.clientHello.supportedPoints,
SignatureSchemes: hs.clientHello.supportedSignatureAlgorithms,
SupportedProtos: hs.clientHello.alpnProtocols,
SupportedVersions: supportedVersions,
Conn: hs.c.conn,
Offered0RTTData: hs.clientHello.earlyData,
Fingerprint: pskBinder,
CipherSuites: hs.clientHello.cipherSuites,
ServerName: hs.clientHello.serverName,
SupportedCurves: hs.clientHello.supportedCurves,
SupportedPoints: hs.clientHello.supportedPoints,
SignatureSchemes: hs.clientHello.supportedSignatureAlgorithms,
SupportedProtos: hs.clientHello.alpnProtocols,
SupportedVersions: supportedVersions,
Conn: hs.c.conn,
Offered0RTTData: hs.clientHello.earlyData,
AcceptsDelegatedCredential: hs.clientHello.delegatedCredential,
Fingerprint: pskBinder,
}

return hs.cachedClientHelloInfo


+ 4
- 6
handshake_server_test.go ファイルの表示

@@ -197,9 +197,9 @@ func TestDontSelectRSAWithECDSAKey(t *testing.T) {

func TestRenegotiationExtension(t *testing.T) {
clientHello := &clientHelloMsg{
vers: VersionTLS12,
compressionMethods: []uint8{compressionNone},
random: make([]byte, 32),
vers: VersionTLS12,
compressionMethods: []uint8{compressionNone},
random: make([]byte, 32),
secureRenegotiationSupported: true,
cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
}
@@ -394,8 +394,6 @@ func TestSCTHandshake(t *testing.T) {
PrivateKey: testRSAPrivateKey,
SignedCertificateTimestamps: expected,
}},
// See GH#76
MaxVersion: VersionTLS12,
}
clientConfig := &Config{
InsecureSkipVerify: true,
@@ -1004,7 +1002,7 @@ func TestFallbackSCSV(t *testing.T) {
name: "FallbackSCSV",
config: &serverConfig,
// OpenSSL 1.0.1j is needed for the -fallback_scsv option.
command: []string{"openssl", "s_client", "-fallback_scsv"},
command: []string{"openssl", "s_client", "-fallback_scsv"},
expectHandshakeErrorIncluding: "inappropriate protocol fallback",
}
runServerTestTLS11(t, test)


+ 13
- 14
key_agreement.go ファイルの表示

@@ -10,7 +10,6 @@ import (
"crypto/md5"
"crypto/rsa"
"crypto/sha1"
"crypto/x509"
"errors"
"io"
"math/big"
@@ -25,11 +24,11 @@ var errServerKeyExchange = errors.New("tls: invalid ServerKeyExchange message")
// encrypts the pre-master secret to the server's public key.
type rsaKeyAgreement struct{}

func (ka rsaKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) {
func (ka rsaKeyAgreement) generateServerKeyExchange(config *Config, sk crypto.PrivateKey, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) {
return nil, nil
}

func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, sk crypto.PrivateKey, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
if len(ckx.ciphertext) < 2 {
return nil, errClientKeyExchange
}
@@ -42,7 +41,7 @@ func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, cert *Certifi
}
ciphertext = ckx.ciphertext[2:]
}
priv, ok := cert.PrivateKey.(crypto.Decrypter)
priv, ok := sk.(crypto.Decrypter)
if !ok {
return nil, errors.New("tls: certificate private key does not implement crypto.Decrypter")
}
@@ -60,11 +59,11 @@ func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, cert *Certifi
return preMasterSecret, nil
}

func (ka rsaKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error {
func (ka rsaKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, pk crypto.PublicKey, skx *serverKeyExchangeMsg) error {
return errors.New("tls: unexpected ServerKeyExchange")
}

func (ka rsaKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) {
func (ka rsaKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, pk crypto.PublicKey) ([]byte, *clientKeyExchangeMsg, error) {
preMasterSecret := make([]byte, 48)
preMasterSecret[0] = byte(clientHello.vers >> 8)
preMasterSecret[1] = byte(clientHello.vers)
@@ -73,7 +72,7 @@ func (ka rsaKeyAgreement) generateClientKeyExchange(config *Config, clientHello
return nil, nil, err
}

encrypted, err := rsa.EncryptPKCS1v15(config.rand(), cert.PublicKey.(*rsa.PublicKey), preMasterSecret)
encrypted, err := rsa.EncryptPKCS1v15(config.rand(), pk.(*rsa.PublicKey), preMasterSecret)
if err != nil {
return nil, nil, err
}
@@ -156,7 +155,7 @@ type ecdheKeyAgreement struct {
x, y *big.Int
}

func (ka *ecdheKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) {
func (ka *ecdheKeyAgreement) generateServerKeyExchange(config *Config, sk crypto.PrivateKey, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) {
preferredCurves := config.curvePreferences()

NextCandidate:
@@ -207,7 +206,7 @@ NextCandidate:
serverECDHParams[3] = byte(len(ecdhePublic))
copy(serverECDHParams[4:], ecdhePublic)

priv, ok := cert.PrivateKey.(crypto.Signer)
priv, ok := sk.(crypto.Signer)
if !ok {
return nil, errors.New("tls: certificate private key does not implement crypto.Signer")
}
@@ -255,7 +254,7 @@ NextCandidate:
return skx, nil
}

func (ka *ecdheKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
func (ka *ecdheKeyAgreement) processClientKeyExchange(config *Config, sk crypto.PrivateKey, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
if len(ckx.ciphertext) == 0 || int(ckx.ciphertext[0]) != len(ckx.ciphertext)-1 {
return nil, errClientKeyExchange
}
@@ -291,7 +290,7 @@ func (ka *ecdheKeyAgreement) processClientKeyExchange(config *Config, cert *Cert
return preMasterSecret, nil
}

func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error {
func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, pk crypto.PublicKey, skx *serverKeyExchangeMsg) error {
if len(skx.key) < 4 {
return errServerKeyExchange
}
@@ -337,7 +336,7 @@ func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHell
return errServerKeyExchange
}
}
_, sigType, hashFunc, err := pickSignatureAlgorithm(cert.PublicKey, []SignatureScheme{signatureAlgorithm}, clientHello.supportedSignatureAlgorithms, ka.version)
_, sigType, hashFunc, err := pickSignatureAlgorithm(pk, []SignatureScheme{signatureAlgorithm}, clientHello.supportedSignatureAlgorithms, ka.version)
if err != nil {
return err
}
@@ -355,10 +354,10 @@ func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHell
if err != nil {
return err
}
return verifyHandshakeSignature(sigType, cert.PublicKey, hashFunc, digest, sig)
return verifyHandshakeSignature(sigType, pk, hashFunc, digest, sig)
}

func (ka *ecdheKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) {
func (ka *ecdheKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, pk crypto.PublicKey) ([]byte, *clientKeyExchangeMsg, error) {
if ka.curveid == 0 {
return nil, nil, errors.New("tls: missing ServerKeyExchange message")
}


+ 392
- 0
subcerts.go ファイルの表示

@@ -0,0 +1,392 @@
// Copyright 2018 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

// Delegated credentials for TLS
// (https://tools.ietf.org/html/draft-ietf-tls-subcerts-02) is an IETF Internet
// draft and proposed TLS extension. This allows a backend server to delegate
// TLS termination to a trusted frontend. If the client supports this extension,
// then the frontend may use a "delegated credential" as the signing key in the
// handshake. A delegated credential is a short lived key pair delegated to the
// server by an entity trusted by the client. Once issued, credentials can't be
// revoked; in order to mitigate risk in case the frontend is compromised, the
// credential is only valid for a short time (days, hours, or even minutes).
//
// This implements draft 02. This draft doesn't specify an object identifier for
// the X.509 extension; we use one assigned by Cloudflare. In addition, IANA has
// not assigned an extension ID for this extension; we picked up one that's not
// yet taken.
//
// TODO(cjpatton) Only ECDSA is supported with delegated credentials for now;
// we'd like to suppoort for EcDSA signatures once these have better support
// upstream.

import (
"bytes"
"crypto"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/x509"
"encoding/asn1"
"encoding/binary"
"errors"
"fmt"
"time"
)

const (
// length of the public key field
dcPubKeyFieldLen = 3
dcMaxTTLSeconds = 60 * 60 * 24 * 7 // 7 days
dcMaxTTL = time.Duration(dcMaxTTLSeconds * time.Second)
dcMaxPublicKeyLen = 1 << 24 // Bytes
dcMaxSignatureLen = 1 << 16 // Bytes
)

var errNoDelegationUsage = errors.New("certificate not authorized for delegation")

// delegationUsageId is the DelegationUsage X.509 extension OID
//
// NOTE(cjpatton) This OID is a child of Cloudflare's IANA-assigned OID.
var delegationUsageId = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 44363, 44}

// canDelegate returns true if a certificate can be used for delegated
// credentials.
func canDelegate(cert *x509.Certificate) bool {
// Check that the digitalSignature key usage is set.
if (cert.KeyUsage & x509.KeyUsageDigitalSignature) == 0 {
return false
}

// Check that the certificate has the DelegationUsage extension and that
// it's non-critical (per the spec).
for _, extension := range cert.Extensions {
if extension.Id.Equal(delegationUsageId) {
return true
}
}
return false
}

// credential stores the public components of a credential.
type credential struct {
// The serialized form of the credential.
raw []byte

// The amount of time for which the credential is valid. Specifically, the
// the credential expires `ValidTime` seconds after the `notBefore` of the
// delegation certificate. The delegator shall not issue delegated
// credentials that are valid for more than 7 days from the current time.
//
// When this data structure is serialized, this value is converted to a
// uint32 representing the duration in seconds.
validTime time.Duration

// The signature scheme associated with the delegated credential public key.
expectedCertVerifyAlgorithm SignatureScheme

// The version of TLS in which the credential will be used.
expectedVersion uint16

// The credential public key.
publicKey crypto.PublicKey
}

// isExpired returns true if the credential has expired. The end of the validity
// interval is defined as the delegator certificate's notBefore field (`start`)
// plus ValidTime seconds. This function simply checks that the current time
// (`now`) is before the end of the valdity interval.
func (cred *credential) isExpired(start, now time.Time) bool {
end := start.Add(cred.validTime)
return !now.Before(end)
}

// invalidTTL returns true if the credential's validity period is longer than the
// maximum permitted. This is defined by the certificate's notBefore field
// (`start`) plus the ValidTime, minus the current time (`now`).
func (cred *credential) invalidTTL(start, now time.Time) bool {
return cred.validTime > (now.Sub(start) + dcMaxTTL).Round(time.Second)
}

// marshalSubjectPublicKeyInfo returns a DER encoded SubjectPublicKeyInfo structure
// (as defined in the X.509 standard) for the credential.
func (cred *credential) marshalSubjectPublicKeyInfo() ([]byte, error) {
switch cred.expectedCertVerifyAlgorithm {
case ECDSAWithP256AndSHA256,
ECDSAWithP384AndSHA384,
ECDSAWithP521AndSHA512:
serializedPublicKey, err := x509.MarshalPKIXPublicKey(cred.publicKey)
if err != nil {
return nil, err
}
return serializedPublicKey, nil

default:
return nil, fmt.Errorf("unsupported signature scheme: 0x%04x", cred.expectedCertVerifyAlgorithm)
}
}

// marshal encodes a credential in the wire format specified in
// https://tools.ietf.org/html/draft-ietf-tls-subcerts-02.
func (cred *credential) marshal() ([]byte, error) {
// The number of bytes comprising the DC parameters, which includes the
// validity time (4 bytes), the signature scheme of the public key (2 bytes), and
// the protocol version (2 bytes).
paramsLen := 8

// The first 4 bytes are the valid_time, scheme, and version fields.
serialized := make([]byte, paramsLen+dcPubKeyFieldLen)
binary.BigEndian.PutUint32(serialized, uint32(cred.validTime/time.Second))
binary.BigEndian.PutUint16(serialized[4:], uint16(cred.expectedCertVerifyAlgorithm))
binary.BigEndian.PutUint16(serialized[6:], cred.expectedVersion)

// Encode the public key and assert that the encoding is no longer than 2^16
// bytes (per the spec).
serializedPublicKey, err := cred.marshalSubjectPublicKeyInfo()
if err != nil {
return nil, err
}
if len(serializedPublicKey) > dcMaxPublicKeyLen {
return nil, errors.New("public key is too long")
}

// The next 3 bytes are the length of the public key field, which may be up
// to 2^24 bytes long.
putUint24(serialized[paramsLen:], len(serializedPublicKey))

// The remaining bytes are the public key itself.
serialized = append(serialized, serializedPublicKey...)
cred.raw = serialized
return serialized, nil
}

// unmarshalCredential decodes a credential and returns it.
func unmarshalCredential(serialized []byte) (*credential, error) {
// The number of bytes comprising the DC parameters.
paramsLen := 8

if len(serialized) < paramsLen+dcPubKeyFieldLen {
return nil, errors.New("credential is too short")
}

// Parse the valid_time, scheme, and version fields.
validTime := time.Duration(binary.BigEndian.Uint32(serialized)) * time.Second
scheme := SignatureScheme(binary.BigEndian.Uint16(serialized[4:]))
version := binary.BigEndian.Uint16(serialized[6:])

// Parse the SubjectPublicKeyInfo.
pk, err := x509.ParsePKIXPublicKey(serialized[paramsLen+dcPubKeyFieldLen:])
if err != nil {
return nil, err
}

if _, ok := pk.(*ecdsa.PublicKey); !ok {
return nil, fmt.Errorf("unsupported delegation key type: %T", pk)
}

return &credential{
raw: serialized,
validTime: validTime,
expectedCertVerifyAlgorithm: scheme,
expectedVersion: version,
publicKey: pk,
}, nil
}

// getCredentialLen returns the number of bytes comprising the serialized
// credential that starts at the beginning of the input slice. It returns an
// error if the input is too short to contain a credential.
func getCredentialLen(serialized []byte) (int, error) {
paramsLen := 8
if len(serialized) < paramsLen+dcPubKeyFieldLen {
return 0, errors.New("credential is too short")
}
// First several bytes are the valid_time, scheme, and version fields.
serialized = serialized[paramsLen:]

// The next 3 bytes are the length of the serialized public key, which may
// be up to 2^24 bytes in length.
serializedPublicKeyLen := getUint24(serialized)
serialized = serialized[dcPubKeyFieldLen:]

if len(serialized) < serializedPublicKeyLen {
return 0, errors.New("public key of credential is too short")
}

return paramsLen + dcPubKeyFieldLen + serializedPublicKeyLen, nil
}

// delegatedCredential stores a credential and its delegation.
type delegatedCredential struct {
raw []byte

// The credential, which contains a public and its validity time.
cred *credential

// The signature scheme used to sign the credential.
algorithm SignatureScheme

// The credential's delegation.
signature []byte
}

// ensureCertificateHasLeaf parses the leaf certificate if needed.
func ensureCertificateHasLeaf(cert *Certificate) error {
var err error
if cert.Leaf == nil {
if len(cert.Certificate[0]) == 0 {
return errors.New("missing leaf certificate")
}
cert.Leaf, err = x509.ParseCertificate(cert.Certificate[0])
if err != nil {
return err
}
}
return nil
}

// validate checks that that the signature is valid, that the credential hasn't
// expired, and that the TTL is valid. It also checks that certificate can be
// used for delegation.
func (dc *delegatedCredential) validate(cert *x509.Certificate, now time.Time) (bool, error) {
// Check that the cert can delegate.
if !canDelegate(cert) {
return false, errNoDelegationUsage
}

if dc.cred.isExpired(cert.NotBefore, now) {
return false, errors.New("credential has expired")
}

if dc.cred.invalidTTL(cert.NotBefore, now) {
return false, errors.New("credential TTL is invalid")
}

// Prepare the credential for verification.
rawCred, err := dc.cred.marshal()
if err != nil {
return false, err
}
hash := getHash(dc.algorithm)
in := prepareDelegation(hash, rawCred, cert.Raw, dc.algorithm)

// TODO(any) This code overlaps significantly with verifyHandshakeSignature()
// in ../auth.go. This should be refactored.
switch dc.algorithm {
case ECDSAWithP256AndSHA256,
ECDSAWithP384AndSHA384,
ECDSAWithP521AndSHA512:
pk, ok := cert.PublicKey.(*ecdsa.PublicKey)
if !ok {
return false, errors.New("expected ECDSA public key")
}
sig := new(ecdsaSignature)
if _, err = asn1.Unmarshal(dc.signature, sig); err != nil {
return false, err
}
return ecdsa.Verify(pk, in, sig.R, sig.S), nil

default:
return false, fmt.Errorf(
"unsupported signature scheme: 0x%04x", dc.algorithm)
}
}

// unmarshalDelegatedCredential decodes a DelegatedCredential structure.
func unmarshalDelegatedCredential(serialized []byte) (*delegatedCredential, error) {
// Get the length of the serialized credential that begins at the start of
// the input slice.
serializedCredentialLen, err := getCredentialLen(serialized)
if err != nil {
return nil, err
}

// Parse the credential.
cred, err := unmarshalCredential(serialized[:serializedCredentialLen])
if err != nil {
return nil, err
}

// Parse the signature scheme.
serialized = serialized[serializedCredentialLen:]
if len(serialized) < 4 {
return nil, errors.New("delegated credential is too short")
}
scheme := SignatureScheme(binary.BigEndian.Uint16(serialized))

// Parse the signature length.
serialized = serialized[2:]
serializedSignatureLen := binary.BigEndian.Uint16(serialized)

// Prase the signature.
serialized = serialized[2:]
if len(serialized) < int(serializedSignatureLen) {
return nil, errors.New("signature of delegated credential is too short")
}
sig := serialized[:serializedSignatureLen]

return &delegatedCredential{
raw: serialized,
cred: cred,
algorithm: scheme,
signature: sig,
}, nil
}

// getCurve maps the SignatureScheme to its corresponding elliptic.Curve.
func getCurve(scheme SignatureScheme) elliptic.Curve {
switch scheme {
case ECDSAWithP256AndSHA256:
return elliptic.P256()
case ECDSAWithP384AndSHA384:
return elliptic.P384()
case ECDSAWithP521AndSHA512:
return elliptic.P521()
default:
return nil
}
}

// getHash maps the SignatureScheme to its corresponding hash function.
//
// TODO(any) This function overlaps with hashForSignatureScheme in 13.go.
func getHash(scheme SignatureScheme) crypto.Hash {
switch scheme {
case ECDSAWithP256AndSHA256:
return crypto.SHA256
case ECDSAWithP384AndSHA384:
return crypto.SHA384
case ECDSAWithP521AndSHA512:
return crypto.SHA512
default:
return 0 // Unknown hash function
}
}

// prepareDelegation returns a hash of the message that the delegator is to
// sign. The inputs are the credential (`cred`), the DER-encoded delegator
// certificate (`delegatorCert`) and the signature scheme of the delegator
// (`delegatorAlgorithm`).
func prepareDelegation(hash crypto.Hash, cred, delegatorCert []byte, delegatorAlgorithm SignatureScheme) []byte {
h := hash.New()

// The header.
h.Write(bytes.Repeat([]byte{0x20}, 64))
h.Write([]byte("TLS, server delegated credentials"))
h.Write([]byte{0x00})

// The delegation certificate.
h.Write(delegatorCert)

// The credential.
h.Write(cred)

// The delegator signature scheme.
var serializedScheme [2]byte
binary.BigEndian.PutUint16(serializedScheme[:], uint16(delegatorAlgorithm))
h.Write(serializedScheme[:])

return h.Sum(nil)
}

+ 423
- 0
subcerts_test.go ファイルの表示

@@ -0,0 +1,423 @@
// Copyright 2018 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"
"crypto/x509"
"encoding/asn1"
"encoding/pem"
"errors"
"fmt"
"testing"
"time"
)

// A PEM-encoded "delegation certificate", an X.509 certificate with the
// DelegationUsage extension. The extension is defined in
// specified in https://tools.ietf.org/html/draft-ietf-tls-subcerts-02.
const DcCertWithDelegationUsage = `-----BEGIN CERTIFICATE-----
MIIBejCCASGgAwIBAgIQXXtl0v50W2OadoW0QwLUlzAKBggqhkjOPQQDAjAUMRIw
EAYDVQQKEwlBY21lIEluYy4wHhcNMTgwNzMwMjAxMTE5WhcNMTgwODA2MjAxMTE5
WjAUMRIwEAYDVQQKEwlBY21lIEluYy4wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC
AATcQuuaUNJ3kqKGs4DBdJVd7zWzyGANT4uBNGVkZ2cgaDsdFnx99fGibfgoWer8
HLt9Z+S6Hs+8bDPBHNgTR/Lfo1UwUzAOBgNVHQ8BAf8EBAMCB4AwEwYDVR0lBAww
CgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADAPBgNVHREECDAGhwR/AAABMA0GCSsG
AQQBgtpLLAQAMAoGCCqGSM49BAMCA0cAMEQCIEMdIkwwmzQAJ6RSDT3wcrsySx2B
5Lvx5HGzc43Fgu9eAiAi4sFXnizFBVUL43qXZBq4ARw17o0JW3/7eec1xttQhw==
-----END CERTIFICATE-----
`

// The PEM-encoded "delegation key", the secret key associated with the
// delegation certificate. This is a key for ECDSA with P256 and SHA256.
const DcKeyWithDelegationUsage = `-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIAS/pGktmxK1hlt3gF4N2nkMrJnoZihvOO63nnNcxXQroAoGCCqGSM49
AwEHoUQDQgAE3ELrmlDSd5KihrOAwXSVXe81s8hgDU+LgTRlZGdnIGg7HRZ8ffXx
om34KFnq/By7fWfkuh7PvGwzwRzYE0fy3w==
-----END EC PRIVATE KEY-----
`

// A certificate without the DelegationUsage extension.
const DcCertWithoutDelegationUsage = `-----BEGIN CERTIFICATE-----
MIIBajCCAQ+gAwIBAgIRAMUg/VFqJaWWJwZ9iHoMjqIwCgYIKoZIzj0EAwIwEjEQ
MA4GA1UEChMHQWNtZSBDbzAeFw0xODA3MzAyMDExMTlaFw0xOTA3MzAyMDExMTla
MBIxEDAOBgNVBAoTB0FjbWUgQ28wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATA
n+oeWSvSNHhEskSRgkkerCQDoV/NA+r3S5AtCOFT5AYLt8xltSTWerFI/YlZLIcL
xlJPT7T+XpBnfS6xaAuxo0YwRDAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYI
KwYBBQUHAwEwDAYDVR0TAQH/BAIwADAPBgNVHREECDAGhwR/AAABMAoGCCqGSM49
BAMCA0kAMEYCIQCFGWnoJmwH1rxNCKBJWVDBKDTSsYhySRk4h9RPyR8bUwIhAJxc
KFyrowMTan791RJnyANH/4uYhmvkfhfrFGSTXUli
-----END CERTIFICATE-----
`

// The secret key associatted with DcCertWithoutDelegationUsage.
const DcKeyWithoutDelegationUsage = `-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIEP82pOhzx0tKkky9t0OmUo9MHgmfdAHxDN2cHmWGqOhoAoGCCqGSM49
AwEHoUQDQgAEwJ/qHlkr0jR4RLJEkYJJHqwkA6FfzQPq90uQLQjhU+QGC7fMZbUk
1nqxSP2JWSyHC8ZST0+0/l6QZ30usWgLsQ==
-----END EC PRIVATE KEY-----
`

// dcTestDC stores delegated credentials and their secret keys.
type dcTestDC struct {
Name string
Version int
Scheme int
DC []byte
PrivateKey []byte
}

// Test data used for testing the TLS handshake with the delegated credential
// extension. The PEM block encodes a DER encoded slice of dcTestDCs.

// Use with maxVersion == VersionTLS13Draft28.
//
// TODO(henrydcase): Remove this when we drop support for draft28.
const DcTestDataDraft28PEM = `-----BEGIN DC TEST DATA-----
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
1MBFxcFr
-----END DC TEST DATA-----
`

// Use with maxVersion == VersionTLS13.
const DcTestDataTLS13PEM = `-----BEGIN DC TEST DATA-----
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
jreml8HfVQ==
-----END DC TEST DATA-----`

// Parses the input PEM block containing the test DCs.
func dcLoadTestData(in []byte, out *[]dcTestDC) error {
block, _ := pem.Decode(in)
if block == nil {
return errors.New("failed to decode DC tests PEM block")
}

// Parse the DER-encoded test DCs.
_, err := asn1.Unmarshal(block.Bytes, out)
if err != nil {
return errors.New("failed to unmarshal DC test ASN.1 data")
}

// Check that the test data is for the right version. This should be
// maxVersion, defined in common.go.
for _, test := range *out {
dc, err := unmarshalDelegatedCredential(test.DC)
if err != nil {
return err
}

// Sanity check that test version matches the version encoded by the DC.
testVersion := uint16(test.Version)
if dc.cred.expectedVersion != testVersion {
return fmt.Errorf(
"test version doesn't match credential version: got: 0x0%04x; want: 0x%04x",
testVersion, dc.cred.expectedVersion)
}

// With the exception of "badvers" and "tsl12", all test DCs should have
// the expected verison.
if test.Name != "badvers" && test.Name != "tls12" && testVersion != maxVersion {
return fmt.Errorf(
"encountered test with wrong version: got: 0x0%04x; want: 0x%04x",
test.Version, maxVersion)
}
}
return nil
}

var dcTestDCs []dcTestDC
var dcTestConfig *Config
var dcTestDelegationCert Certificate
var dcTestCert Certificate
var dcTestNow time.Time

func init() {
// Load the DC test data.
var testData []byte
switch maxVersion {
case VersionTLS13Draft28:
testData = []byte(DcTestDataDraft28PEM)
case 0x0304: // TODO(henrydcase): Fix once the final version is implemented
testData = []byte(DcTestDataTLS13PEM)
default:
panic(fmt.Errorf("no test data for version %04x", maxVersion))
}
err := dcLoadTestData(testData, &dcTestDCs)
if err != nil {
panic(err)
}

// The base configuration for the client and server.
dcTestConfig = &Config{
Time: func() time.Time {
return dcTestNow
},
Rand: zeroSource{},
Certificates: nil,
MinVersion: VersionTLS10,
MaxVersion: VersionTLS13,
CipherSuites: allCipherSuites(),
}

// The delegation certificate.
dcTestDelegationCert, err = X509KeyPair([]byte(DcCertWithDelegationUsage), []byte(DcKeyWithDelegationUsage))
if err != nil {
panic(err)
}
dcTestDelegationCert.Leaf, err = x509.ParseCertificate(dcTestDelegationCert.Certificate[0])
if err != nil {
panic(err)
}

// A certificate without the the DelegationUsage extension for X.509.
dcTestCert, err = X509KeyPair([]byte(DcCertWithoutDelegationUsage), []byte(DcKeyWithoutDelegationUsage))
if err != nil {
panic(err)
}
dcTestCert.Leaf, err = x509.ParseCertificate(dcTestCert.Certificate[0])
if err != nil {
panic(err)
}

// For testing purposes, use the point at which the test DCs were generated
// as the current time. This is the same as the time at which the
// delegation certificate was generated.
dcTestNow = dcTestDelegationCert.Leaf.NotBefore

// Make these roots of these certificates the client's trusted CAs.
dcTestConfig.RootCAs = x509.NewCertPool()

raw := dcTestDelegationCert.Certificate[len(dcTestDelegationCert.Certificate)-1]
root, err := x509.ParseCertificate(raw)
if err != nil {
panic(err)
}
dcTestConfig.RootCAs.AddCert(root)

raw = dcTestCert.Certificate[len(dcTestCert.Certificate)-1]
root, err = x509.ParseCertificate(raw)
if err != nil {
panic(err)
}
dcTestConfig.RootCAs.AddCert(root)
}

// Executes the handshake with the given configuration and returns true if the
// delegated credential extension was successfully negotiated.
func testConnWithDC(t *testing.T, clientConfig, serverConfig *Config) (bool, error) {
ln := newLocalListener(t)
defer ln.Close()

// Listen for and serve a single client connection.
srvCh := make(chan *Conn, 1)
var serr error
go func() {
sconn, err := ln.Accept()
if err != nil {
serr = err
srvCh <- nil
return
}
srv := Server(sconn, serverConfig)
if err := srv.Handshake(); err != nil {
serr = fmt.Errorf("handshake: %v", err)
srvCh <- nil
return
}
srvCh <- srv
}()

// Dial the server.
cli, err := Dial("tcp", ln.Addr().String(), clientConfig)
if err != nil {
return false, err
}
defer cli.Close()

srv := <-srvCh
if srv == nil {
return false, serr
}

// Return true if the client's conn.dc structure was instantiated.
st := cli.ConnectionState()
return (st.DelegatedCredential != nil), nil
}

// Checks that the client suppports a version >= 1.2 and accepts delegated
// credentials. If so, it returns the delegation certificate; otherwise it
// returns a plain certificate.
func testServerGetCertificate(ch *ClientHelloInfo) (*Certificate, error) {
versOk := false
for _, vers := range ch.SupportedVersions {
versOk = versOk || (vers >= uint16(VersionTLS12))
}

if versOk && ch.AcceptsDelegatedCredential {
return &dcTestDelegationCert, nil
}
return &dcTestCert, nil
}

// Various test cases for handshakes involving DCs.
var dcTesters = []struct {
clientDC bool
serverDC bool
clientSkipVerify bool
clientMaxVers uint16
serverMaxVers uint16
nowOffset time.Duration
dcTestName string
expectSuccess bool
expectDC bool
name string
}{
{true, true, false, VersionTLS13, VersionTLS13, 0, "tls13p256", true, true, "tls13"},
{true, true, false, VersionTLS13, VersionTLS13, 0, "tls13p521", true, true, "tls13"},
{true, false, false, VersionTLS13, VersionTLS13, 0, "tls13p256", true, false, "server no dc"},
{true, true, false, VersionTLS12, VersionTLS13, 0, "tls13p256", true, false, "client old"},
{true, true, false, VersionTLS13, VersionTLS12, 0, "tls13p256", true, false, "server old"},
{true, true, false, VersionTLS13, VersionTLS13, 0, "badkey", false, false, "bad key"},
{true, true, true, VersionTLS13, VersionTLS13, 0, "badsig", true, true, "bad key, skip verify"},
{true, true, false, VersionTLS13, VersionTLS13, dcMaxTTL, "tls13", false, false, "expired dc"},
{true, true, false, VersionTLS13, VersionTLS13, 0, "badvers", false, false, "dc wrong version"},
{true, true, false, VersionTLS12, VersionTLS12, 0, "tls12", true, false, "tls12"},
}

// Tests the handshake with the delegated credential extension for each test
// case in dcTests.
func TestDCHandshake(t *testing.T) {
clientConfig := dcTestConfig.Clone()
serverConfig := dcTestConfig.Clone()
serverConfig.GetCertificate = testServerGetCertificate

for i, tester := range dcTesters {
clientConfig.MaxVersion = tester.clientMaxVers
serverConfig.MaxVersion = tester.serverMaxVers
clientConfig.InsecureSkipVerify = tester.clientSkipVerify
clientConfig.AcceptDelegatedCredential = tester.clientDC
clientConfig.Time = func() time.Time {
return dcTestNow.Add(time.Duration(tester.nowOffset))
}

if tester.serverDC {
serverConfig.GetDelegatedCredential = func(
ch *ClientHelloInfo, vers uint16) ([]byte, crypto.PrivateKey, error) {
if vers < VersionTLS13 {
return nil, nil, nil
}
for _, test := range dcTestDCs {
if test.Name == tester.dcTestName {
sk, err := x509.ParseECPrivateKey(test.PrivateKey)
if err != nil {
return nil, nil, err
}
return test.DC, sk, nil
}
}
return nil, nil, fmt.Errorf("Test DC with name '%s' not found", tester.dcTestName)
}
} else {
serverConfig.GetDelegatedCredential = nil
}

usedDC, err := testConnWithDC(t, clientConfig, serverConfig)
if err != nil && tester.expectSuccess {
t.Errorf("test #%d (%s) fails: %s", i+1, tester.name, err)
} else if err == nil && !tester.expectSuccess {
t.Errorf("test #%d (%s) succeeds; expected failure", i+1, tester.name)
}

if usedDC != tester.expectDC {
t.Errorf("test #%d (%s) usedDC = %v; expected %v", i+1, tester.name, usedDC, tester.expectDC)
}
}
}

+ 3
- 1
tls_test.go ファイルの表示

@@ -674,7 +674,7 @@ func TestCloneNonFuncFields(t *testing.T) {
switch fn := typ.Field(i).Name; fn {
case "Rand":
f.Set(reflect.ValueOf(io.Reader(os.Stdin)))
case "Time", "GetCertificate", "GetConfigForClient", "VerifyPeerCertificate", "GetClientCertificate":
case "Time", "GetCertificate", "GetConfigForClient", "VerifyPeerCertificate", "GetClientCertificate", "GetDelegatedCredential":
// DeepEqual can't compare functions. If you add a
// function field to this list, you must also change
// TestCloneFuncFields to ensure that the func field is
@@ -713,6 +713,8 @@ func TestCloneNonFuncFields(t *testing.T) {
f.Set(reflect.ValueOf(uint32(0)))
case "SessionTicketSealer":
// TODO
case "AcceptDelegatedCredential":
f.Set(reflect.ValueOf(false))
default:
t.Errorf("all fields must be accounted for, but saw unknown field %q", fn)
}


読み込み中…
キャンセル
保存