Compare commits

...

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)
}


불러오는 중...
취소
저장