From ed7304b30c86608628438c1c1b7349c923a4b9fb Mon Sep 17 00:00:00 2001 From: Christoph Blecker Date: Wed, 8 Aug 2018 21:22:01 -0700 Subject: [PATCH] Bump cfssl to 56268a6 --- Godeps/Godeps.json | 258 +-- Godeps/LICENSES | 64 + vendor/github.com/cloudflare/cfssl/api/BUILD | 1 + .../cloudflare/cfssl/api/client/client.go | 20 +- .../cloudflare/cfssl/api/health/BUILD | 24 + .../cloudflare/cfssl/api/health/health.go | 26 + .../cloudflare/cfssl/api/revoke/revoke.go | 2 +- .../github.com/cloudflare/cfssl/cli/config.go | 4 + .../cloudflare/cfssl/cli/serve/BUILD | 1 + .../cloudflare/cfssl/cli/serve/serve.go | 54 +- .../cloudflare/cfssl/cli/version/version.go | 2 +- .../cloudflare/cfssl/config/config.go | 20 +- .../cloudflare/cfssl/errors/error.go | 13 +- .../github.com/cloudflare/cfssl/helpers/BUILD | 1 + .../cloudflare/cfssl/helpers/derhelpers/BUILD | 10 +- .../cfssl/helpers/derhelpers/derhelpers.go | 22 +- .../cfssl/helpers/derhelpers/ed25519.go | 133 ++ .../cloudflare/cfssl/helpers/helpers.go | 97 +- .../cloudflare/cfssl/initca/initca.go | 4 +- .../github.com/cloudflare/cfssl/ocsp/ocsp.go | 6 +- vendor/github.com/cloudflare/cfssl/scan/BUILD | 6 +- .../cloudflare/cfssl/scan/connectivity.go | 5 +- .../cloudflare/cfssl/scan/crypto/tls/BUILD | 37 + .../cloudflare/cfssl/scan/crypto/tls/alert.go | 79 + .../cfssl/scan/crypto/tls/cfsslscan_common.go | 486 ++++++ .../scan/crypto/tls/cfsslscan_handshake.go | 109 ++ .../cfssl/scan/crypto/tls/cipher_suites.go | 289 ++++ .../cfssl/scan/crypto/tls/common.go | 714 ++++++++ .../cloudflare/cfssl/scan/crypto/tls/conn.go | 1091 ++++++++++++ .../cfssl/scan/crypto/tls/generate_cert.go | 161 ++ .../cfssl/scan/crypto/tls/handshake_client.go | 667 +++++++ .../scan/crypto/tls/handshake_messages.go | 1528 +++++++++++++++++ .../cfssl/scan/crypto/tls/handshake_server.go | 750 ++++++++ .../cfssl/scan/crypto/tls/key_agreement.go | 405 +++++ .../cloudflare/cfssl/scan/crypto/tls/prf.go | 368 ++++ .../cfssl/scan/crypto/tls/ticket.go | 204 +++ .../cloudflare/cfssl/scan/crypto/tls/tls.go | 298 ++++ .../github.com/cloudflare/cfssl/scan/pki.go | 2 +- .../cloudflare/cfssl/scan/scan_common.go | 2 +- .../cloudflare/cfssl/scan/tls_handshake.go | 4 +- .../cloudflare/cfssl/scan/tls_session.go | 2 +- .../cloudflare/cfssl/signer/local/local.go | 85 +- .../cloudflare/cfssl/signer/signer.go | 6 + .../cfssl/signer/universal/universal.go | 11 +- .../cfssl/ubiquity/ubiquity_platform.go | 2 +- 45 files changed, 7832 insertions(+), 241 deletions(-) create mode 100644 vendor/github.com/cloudflare/cfssl/api/health/BUILD create mode 100644 vendor/github.com/cloudflare/cfssl/api/health/health.go create mode 100644 vendor/github.com/cloudflare/cfssl/helpers/derhelpers/ed25519.go create mode 100644 vendor/github.com/cloudflare/cfssl/scan/crypto/tls/BUILD create mode 100644 vendor/github.com/cloudflare/cfssl/scan/crypto/tls/alert.go create mode 100644 vendor/github.com/cloudflare/cfssl/scan/crypto/tls/cfsslscan_common.go create mode 100644 vendor/github.com/cloudflare/cfssl/scan/crypto/tls/cfsslscan_handshake.go create mode 100644 vendor/github.com/cloudflare/cfssl/scan/crypto/tls/cipher_suites.go create mode 100644 vendor/github.com/cloudflare/cfssl/scan/crypto/tls/common.go create mode 100644 vendor/github.com/cloudflare/cfssl/scan/crypto/tls/conn.go create mode 100644 vendor/github.com/cloudflare/cfssl/scan/crypto/tls/generate_cert.go create mode 100644 vendor/github.com/cloudflare/cfssl/scan/crypto/tls/handshake_client.go create mode 100644 vendor/github.com/cloudflare/cfssl/scan/crypto/tls/handshake_messages.go create mode 100644 vendor/github.com/cloudflare/cfssl/scan/crypto/tls/handshake_server.go create mode 100644 vendor/github.com/cloudflare/cfssl/scan/crypto/tls/key_agreement.go create mode 100644 vendor/github.com/cloudflare/cfssl/scan/crypto/tls/prf.go create mode 100644 vendor/github.com/cloudflare/cfssl/scan/crypto/tls/ticket.go create mode 100644 vendor/github.com/cloudflare/cfssl/scan/crypto/tls/tls.go diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 429d1f51acb..789c95935a7 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -26,12 +26,12 @@ }, { "ImportPath": "cloud.google.com/go/compute/metadata", - "Comment": "v0.1.0-115-g3b1ae45", + "Comment": "v0.1.0-115-g3b1ae453", "Rev": "3b1ae45394a234c385be014e9a488f2bb6eef821" }, { "ImportPath": "cloud.google.com/go/internal", - "Comment": "v0.1.0-115-g3b1ae45", + "Comment": "v0.1.0-115-g3b1ae453", "Rev": "3b1ae45394a234c385be014e9a488f2bb6eef821" }, { @@ -436,308 +436,318 @@ }, { "ImportPath": "github.com/cloudflare/cfssl/api", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/api/bundle", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/api/certinfo", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/api/client", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/api/crl", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/api/gencrl", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/api/generator", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" + }, + { + "ImportPath": "github.com/cloudflare/cfssl/api/health", + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/api/info", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/api/initca", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/api/ocsp", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/api/revoke", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/api/scan", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/api/signhandler", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/auth", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/bundler", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/certdb", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/certdb/dbconf", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/certdb/sql", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/certinfo", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/cli", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/cli/bundle", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/cli/certinfo", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/cli/crl", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/cli/gencert", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/cli/gencrl", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/cli/gencsr", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/cli/genkey", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/cli/info", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/cli/ocspdump", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/cli/ocsprefresh", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/cli/ocspserve", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/cli/ocspsign", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/cli/printdefault", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/cli/revoke", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/cli/scan", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/cli/selfsign", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/cli/serve", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/cli/sign", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/cli/version", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/cmd/cfssl", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/cmd/cfssljson", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/config", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/crl", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/crypto/pkcs7", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/csr", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/errors", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/helpers", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/helpers/derhelpers", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/info", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/initca", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/log", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/ocsp", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/ocsp/config", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/revoke", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/scan", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" + }, + { + "ImportPath": "github.com/cloudflare/cfssl/scan/crypto/tls", + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/selfsign", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/signer", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/signer/local", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/signer/remote", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/signer/universal", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/cloudflare/cfssl/ubiquity", - "Comment": "1.3.1", - "Rev": "4e2dcbde500472449917533851bf4bae9bdff562" + "Comment": "1.3.2-21-g56268a6", + "Rev": "56268a613adfed278936377c18b1152d2c4ad5da" }, { "ImportPath": "github.com/clusterhq/flocker-go", diff --git a/Godeps/LICENSES b/Godeps/LICENSES index 70a92133662..bc72e69ea97 100644 --- a/Godeps/LICENSES +++ b/Godeps/LICENSES @@ -13681,6 +13681,38 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================================================ +================================================================================ += vendor/github.com/cloudflare/cfssl/api/health licensed under: = + +Copyright (c) 2014 CloudFlare Inc. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + += vendor/github.com/cloudflare/cfssl/LICENSE 9bd1e7022303d9bbc29fda142f3e4fd0 +================================================================================ + + ================================================================================ = vendor/github.com/cloudflare/cfssl/api/info licensed under: = @@ -15217,6 +15249,38 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================================================ +================================================================================ += vendor/github.com/cloudflare/cfssl/scan/crypto/tls licensed under: = + +Copyright (c) 2014 CloudFlare Inc. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + += vendor/github.com/cloudflare/cfssl/LICENSE 9bd1e7022303d9bbc29fda142f3e4fd0 +================================================================================ + + ================================================================================ = vendor/github.com/cloudflare/cfssl/selfsign licensed under: = diff --git a/vendor/github.com/cloudflare/cfssl/api/BUILD b/vendor/github.com/cloudflare/cfssl/api/BUILD index 269212e39f9..e33e14b278a 100644 --- a/vendor/github.com/cloudflare/cfssl/api/BUILD +++ b/vendor/github.com/cloudflare/cfssl/api/BUILD @@ -29,6 +29,7 @@ filegroup( "//vendor/github.com/cloudflare/cfssl/api/crl:all-srcs", "//vendor/github.com/cloudflare/cfssl/api/gencrl:all-srcs", "//vendor/github.com/cloudflare/cfssl/api/generator:all-srcs", + "//vendor/github.com/cloudflare/cfssl/api/health:all-srcs", "//vendor/github.com/cloudflare/cfssl/api/info:all-srcs", "//vendor/github.com/cloudflare/cfssl/api/initca:all-srcs", "//vendor/github.com/cloudflare/cfssl/api/ocsp:all-srcs", diff --git a/vendor/github.com/cloudflare/cfssl/api/client/client.go b/vendor/github.com/cloudflare/cfssl/api/client/client.go index 01e1491c6dd..3f48bb10546 100644 --- a/vendor/github.com/cloudflare/cfssl/api/client/client.go +++ b/vendor/github.com/cloudflare/cfssl/api/client/client.go @@ -105,14 +105,28 @@ func (srv *server) getURL(endpoint string) string { return fmt.Sprintf("%s/api/v1/cfssl/%s", srv.URL, endpoint) } -func (srv *server) createTransport() (transport *http.Transport) { - transport = new(http.Transport) +func (srv *server) createTransport() *http.Transport { + // Start with defaults from http.DefaultTransport + transport := &http.Transport{ + Proxy: http.ProxyFromEnvironment, + DialContext: (&net.Dialer{ + Timeout: 30 * time.Second, + KeepAlive: 30 * time.Second, + DualStack: true, + }).DialContext, + MaxIdleConns: 100, + IdleConnTimeout: 90 * time.Second, + TLSHandshakeTimeout: 10 * time.Second, + ExpectContinueTimeout: 1 * time.Second, + } // Setup HTTPS client tlsConfig := srv.TLSConfig tlsConfig.BuildNameToCertificate() transport.TLSClientConfig = tlsConfig // Setup Proxy - transport.Proxy = srv.proxy + if srv.proxy != nil { + transport.Proxy = srv.proxy + } return transport } diff --git a/vendor/github.com/cloudflare/cfssl/api/health/BUILD b/vendor/github.com/cloudflare/cfssl/api/health/BUILD new file mode 100644 index 00000000000..85ce393736d --- /dev/null +++ b/vendor/github.com/cloudflare/cfssl/api/health/BUILD @@ -0,0 +1,24 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = ["health.go"], + importmap = "k8s.io/kubernetes/vendor/github.com/cloudflare/cfssl/api/health", + importpath = "github.com/cloudflare/cfssl/api/health", + visibility = ["//visibility:public"], + deps = ["//vendor/github.com/cloudflare/cfssl/api:go_default_library"], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) diff --git a/vendor/github.com/cloudflare/cfssl/api/health/health.go b/vendor/github.com/cloudflare/cfssl/api/health/health.go new file mode 100644 index 00000000000..82be8c7727b --- /dev/null +++ b/vendor/github.com/cloudflare/cfssl/api/health/health.go @@ -0,0 +1,26 @@ +package health + +import ( + "encoding/json" + "net/http" + + "github.com/cloudflare/cfssl/api" +) + +// Response contains the response to the /health API +type Response struct { + Healthy bool `json:"healthy"` +} + +func healthHandler(w http.ResponseWriter, r *http.Request) error { + response := api.NewSuccessResponse(&Response{Healthy: true}) + return json.NewEncoder(w).Encode(response) +} + +// NewHealthCheck creates a new handler to serve health checks. +func NewHealthCheck() http.Handler { + return api.HTTPHandler{ + Handler: api.HandlerFunc(healthHandler), + Methods: []string{"GET"}, + } +} diff --git a/vendor/github.com/cloudflare/cfssl/api/revoke/revoke.go b/vendor/github.com/cloudflare/cfssl/api/revoke/revoke.go index 6e50da56679..923ef564ac5 100644 --- a/vendor/github.com/cloudflare/cfssl/api/revoke/revoke.go +++ b/vendor/github.com/cloudflare/cfssl/api/revoke/revoke.go @@ -113,7 +113,7 @@ func (h *Handler) Handle(w http.ResponseWriter, r *http.Request) error { return err } - // We parse the OCSP repsonse in order to get the next + // We parse the OCSP response in order to get the next // update time/expiry time ocspParsed, err := stdocsp.ParseResponse(ocspResponse, nil) if err != nil { diff --git a/vendor/github.com/cloudflare/cfssl/cli/config.go b/vendor/github.com/cloudflare/cfssl/cli/config.go index de7b45162e6..0f72b9ef891 100644 --- a/vendor/github.com/cloudflare/cfssl/cli/config.go +++ b/vendor/github.com/cloudflare/cfssl/cli/config.go @@ -30,6 +30,7 @@ type Config struct { IntBundleFile string Address string Port int + MinTLSVersion string Password string ConfigFile string CFG *config.Config @@ -68,6 +69,7 @@ type Config struct { AKI string DBConfigFile string CRLExpiration time.Duration + Disable string } // registerFlags defines all cfssl command flags and associates their values with variables. @@ -90,6 +92,7 @@ func registerFlags(c *Config, f *flag.FlagSet) { f.StringVar(&c.IntBundleFile, "int-bundle", "", "path to intermediate certificate store") f.StringVar(&c.Address, "address", "127.0.0.1", "Address to bind") f.IntVar(&c.Port, "port", 8888, "Port to bind") + f.StringVar(&c.MinTLSVersion, "min-tls-version", "", "Minimum version of TLS to use, defaults to 1.0") f.StringVar(&c.ConfigFile, "config", "", "path to configuration file") f.StringVar(&c.Profile, "profile", "", "signing profile to use") f.BoolVar(&c.IsCA, "initca", false, "initialise new CA") @@ -128,6 +131,7 @@ func registerFlags(c *Config, f *flag.FlagSet) { f.StringVar(&c.DBConfigFile, "db-config", "", "certificate db configuration file") f.DurationVar(&c.CRLExpiration, "expiry", 7*helpers.OneDay, "time from now after which the CRL will expire (default: one week)") f.IntVar(&log.Level, "loglevel", log.LevelInfo, "Log level (0 = DEBUG, 5 = FATAL)") + f.StringVar(&c.Disable, "disable", "", "endpoints to disable") } // RootFromConfig returns a universal signer Root structure that can diff --git a/vendor/github.com/cloudflare/cfssl/cli/serve/BUILD b/vendor/github.com/cloudflare/cfssl/cli/serve/BUILD index d75ffa78130..84ceb1c4bc4 100644 --- a/vendor/github.com/cloudflare/cfssl/cli/serve/BUILD +++ b/vendor/github.com/cloudflare/cfssl/cli/serve/BUILD @@ -14,6 +14,7 @@ go_library( "//vendor/github.com/cloudflare/cfssl/api/crl:go_default_library", "//vendor/github.com/cloudflare/cfssl/api/gencrl:go_default_library", "//vendor/github.com/cloudflare/cfssl/api/generator:go_default_library", + "//vendor/github.com/cloudflare/cfssl/api/health:go_default_library", "//vendor/github.com/cloudflare/cfssl/api/info:go_default_library", "//vendor/github.com/cloudflare/cfssl/api/initca:go_default_library", "//vendor/github.com/cloudflare/cfssl/api/ocsp:go_default_library", diff --git a/vendor/github.com/cloudflare/cfssl/cli/serve/serve.go b/vendor/github.com/cloudflare/cfssl/cli/serve/serve.go index fc8ae66105e..57c7ef59086 100644 --- a/vendor/github.com/cloudflare/cfssl/cli/serve/serve.go +++ b/vendor/github.com/cloudflare/cfssl/cli/serve/serve.go @@ -20,6 +20,7 @@ import ( "github.com/cloudflare/cfssl/api/crl" "github.com/cloudflare/cfssl/api/gencrl" "github.com/cloudflare/cfssl/api/generator" + "github.com/cloudflare/cfssl/api/health" "github.com/cloudflare/cfssl/api/info" "github.com/cloudflare/cfssl/api/initca" apiocsp "github.com/cloudflare/cfssl/api/ocsp" @@ -45,21 +46,21 @@ import ( var serverUsageText = `cfssl serve -- set up a HTTP server handles CF SSL requests Usage of serve: - cfssl serve [-address address] [-ca cert] [-ca-bundle bundle] \ + cfssl serve [-address address] [-min-tls-version version] [-ca cert] [-ca-bundle bundle] \ [-ca-key key] [-int-bundle bundle] [-int-dir dir] [-port port] \ [-metadata file] [-remote remote_host] [-config config] \ - [-responder cert] [-responder-key key] [-tls-cert cert] [-tls-key key] \ - [-mutual-tls-ca ca] [-mutual-tls-cn regex] \ + [-responder cert] [-responder-key key] \ + [-tls-cert cert] [-tls-key key] [-mutual-tls-ca ca] [-mutual-tls-cn regex] \ [-tls-remote-ca ca] [-mutual-tls-client-cert cert] [-mutual-tls-client-key key] \ - [-db-config db-config] + [-db-config db-config] [-disable endpoint[,endpoint]] Flags: ` // Flags used by 'cfssl serve' -var serverFlags = []string{"address", "port", "ca", "ca-key", "ca-bundle", "int-bundle", "int-dir", "metadata", - "remote", "config", "responder", "responder-key", "tls-key", "tls-cert", "mutual-tls-ca", "mutual-tls-cn", - "tls-remote-ca", "mutual-tls-client-cert", "mutual-tls-client-key", "db-config"} +var serverFlags = []string{"address", "port", "min-tls-version", "ca", "ca-key", "ca-bundle", "int-bundle", "int-dir", + "metadata", "remote", "config", "responder", "responder-key", "tls-key", "tls-cert", "mutual-tls-ca", + "mutual-tls-cn", "tls-remote-ca", "mutual-tls-client-cert", "mutual-tls-client-key", "db-config", "disable"} var ( conf cli.Config @@ -80,7 +81,7 @@ func v1APIPath(path string) string { } // httpBox implements http.FileSystem which allows the use of Box with a http.FileServer. -// Atempting to Open an API endpoint will result in an error. +// Attempting to Open an API endpoint will result in an error. type httpBox struct { *rice.Box redirects map[string]string @@ -241,13 +242,27 @@ var endpoints = map[string]func() (http.Handler, error){ return http.FileServer(staticBox), nil }, + + "health": func() (http.Handler, error) { + return health.NewHealthCheck(), nil + }, } // registerHandlers instantiates various handlers and associate them to corresponding endpoints. func registerHandlers() { + disabled := make(map[string]bool) + if conf.Disable != "" { + for _, endpoint := range strings.Split(conf.Disable, ",") { + disabled[endpoint] = true + } + } + for path, getHandler := range endpoints { log.Debugf("getHandler for %s", path) - if handler, err := getHandler(); err != nil { + + if _, ok := disabled[path]; ok { + log.Infof("endpoint '%s' is explicitly disabled", path) + } else if handler, err := getHandler(); err != nil { log.Warningf("endpoint '%s' is disabled: %v", path, err) } else { if path, handler, err = wrapHandler(path, handler, err); err != nil { @@ -298,6 +313,11 @@ func serverMain(args []string, c cli.Config) error { addr := net.JoinHostPort(conf.Address, strconv.Itoa(conf.Port)) + tlscfg := tls.Config{} + if conf.MinTLSVersion != "" { + tlscfg.MinVersion = helpers.StringTLSVersion(conf.MinTLSVersion) + } + if conf.TLSCertFile == "" || conf.TLSKeyFile == "" { log.Info("Now listening on ", addr) return http.ListenAndServe(addr, nil) @@ -308,12 +328,12 @@ func serverMain(args []string, c cli.Config) error { return fmt.Errorf("failed to load mutual TLS CA file: %s", err) } + tlscfg.ClientAuth = tls.RequireAndVerifyClientCert + tlscfg.ClientCAs = clientPool + server := http.Server{ - Addr: addr, - TLSConfig: &tls.Config{ - ClientAuth: tls.RequireAndVerifyClientCert, - ClientCAs: clientPool, - }, + Addr: addr, + TLSConfig: &tlscfg, } if conf.MutualTLSCNRegex != "" { @@ -338,7 +358,11 @@ func serverMain(args []string, c cli.Config) error { return server.ListenAndServeTLS(conf.TLSCertFile, conf.TLSKeyFile) } log.Info("Now listening on https://", addr) - return http.ListenAndServeTLS(addr, conf.TLSCertFile, conf.TLSKeyFile, nil) + server := http.Server{ + Addr: addr, + TLSConfig: &tlscfg, + } + return server.ListenAndServeTLS(conf.TLSCertFile, conf.TLSKeyFile) } diff --git a/vendor/github.com/cloudflare/cfssl/cli/version/version.go b/vendor/github.com/cloudflare/cfssl/cli/version/version.go index e20bc81f857..7353af44a8f 100644 --- a/vendor/github.com/cloudflare/cfssl/cli/version/version.go +++ b/vendor/github.com/cloudflare/cfssl/cli/version/version.go @@ -14,7 +14,7 @@ var version = struct { Minor int Patch int Revision string -}{1, 3, 0, "release"} +}{1, 3, 2, "release"} func versionString() string { return fmt.Sprintf("%d.%d.%d", version.Major, version.Minor, version.Patch) diff --git a/vendor/github.com/cloudflare/cfssl/config/config.go b/vendor/github.com/cloudflare/cfssl/config/config.go index d5eb7c3760f..b04ed40ed5f 100644 --- a/vendor/github.com/cloudflare/cfssl/config/config.go +++ b/vendor/github.com/cloudflare/cfssl/config/config.go @@ -551,16 +551,16 @@ func (p *Signing) Valid() bool { // KeyUsage contains a mapping of string names to key usages. var KeyUsage = map[string]x509.KeyUsage{ - "signing": x509.KeyUsageDigitalSignature, - "digital signature": x509.KeyUsageDigitalSignature, - "content committment": x509.KeyUsageContentCommitment, - "key encipherment": x509.KeyUsageKeyEncipherment, - "key agreement": x509.KeyUsageKeyAgreement, - "data encipherment": x509.KeyUsageDataEncipherment, - "cert sign": x509.KeyUsageCertSign, - "crl sign": x509.KeyUsageCRLSign, - "encipher only": x509.KeyUsageEncipherOnly, - "decipher only": x509.KeyUsageDecipherOnly, + "signing": x509.KeyUsageDigitalSignature, + "digital signature": x509.KeyUsageDigitalSignature, + "content commitment": x509.KeyUsageContentCommitment, + "key encipherment": x509.KeyUsageKeyEncipherment, + "key agreement": x509.KeyUsageKeyAgreement, + "data encipherment": x509.KeyUsageDataEncipherment, + "cert sign": x509.KeyUsageCertSign, + "crl sign": x509.KeyUsageCRLSign, + "encipher only": x509.KeyUsageEncipherOnly, + "decipher only": x509.KeyUsageDecipherOnly, } // ExtKeyUsage contains a mapping of string names to extended key diff --git a/vendor/github.com/cloudflare/cfssl/errors/error.go b/vendor/github.com/cloudflare/cfssl/errors/error.go index 607223765eb..9715a7cfbd2 100644 --- a/vendor/github.com/cloudflare/cfssl/errors/error.go +++ b/vendor/github.com/cloudflare/cfssl/errors/error.go @@ -194,6 +194,13 @@ const ( // CTClientConstructionFailed occurs when the construction of a new // github.com/google/certificate-transparency client fails. CTClientConstructionFailed + // PrecertMissingPoison occurs when a precert is passed to SignFromPrecert + // and is missing the CT poison extension. + PrecertMissingPoison + // PrecertInvalidPoison occurs when a precert is passed to SignFromPrecert + // and has a invalid CT poison extension value or the extension is not + // critical. + PrecertInvalidPoison ) // Certificate persistence related errors specified with CertStoreError @@ -369,6 +376,10 @@ func New(category Category, reason Reason) *Error { msg = "Certificate transparency parsing failed due to unknown error" case PrecertSubmissionFailed: msg = "Certificate transparency precertificate submission failed" + case PrecertMissingPoison: + msg = "Precertificate is missing CT poison extension" + case PrecertInvalidPoison: + msg = "Precertificate contains an invalid CT poison extension" default: panic(fmt.Sprintf("Unsupported CF-SSL error reason %d under category CTError.", reason)) } @@ -415,7 +426,7 @@ func Wrap(category Category, reason Reason, err error) *Error { } } case PrivateKeyError, IntermediatesError, RootError, PolicyError, DialError, - APIClientError, CSRError, CTError, CertStoreError: + APIClientError, CSRError, CTError, CertStoreError, OCSPError: // no-op, just use the error default: panic(fmt.Sprintf("Unsupported CFSSL error type: %d.", diff --git a/vendor/github.com/cloudflare/cfssl/helpers/BUILD b/vendor/github.com/cloudflare/cfssl/helpers/BUILD index d9728300571..f5bb2a5817c 100644 --- a/vendor/github.com/cloudflare/cfssl/helpers/BUILD +++ b/vendor/github.com/cloudflare/cfssl/helpers/BUILD @@ -13,6 +13,7 @@ go_library( "//vendor/github.com/cloudflare/cfssl/log:go_default_library", "//vendor/github.com/google/certificate-transparency-go:go_default_library", "//vendor/github.com/google/certificate-transparency-go/tls:go_default_library", + "//vendor/github.com/google/certificate-transparency-go/x509:go_default_library", "//vendor/golang.org/x/crypto/ocsp:go_default_library", "//vendor/golang.org/x/crypto/pkcs12:go_default_library", ], diff --git a/vendor/github.com/cloudflare/cfssl/helpers/derhelpers/BUILD b/vendor/github.com/cloudflare/cfssl/helpers/derhelpers/BUILD index d5fb457a8c5..6e91ceae90f 100644 --- a/vendor/github.com/cloudflare/cfssl/helpers/derhelpers/BUILD +++ b/vendor/github.com/cloudflare/cfssl/helpers/derhelpers/BUILD @@ -2,11 +2,17 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library") go_library( name = "go_default_library", - srcs = ["derhelpers.go"], + srcs = [ + "derhelpers.go", + "ed25519.go", + ], importmap = "k8s.io/kubernetes/vendor/github.com/cloudflare/cfssl/helpers/derhelpers", importpath = "github.com/cloudflare/cfssl/helpers/derhelpers", visibility = ["//visibility:public"], - deps = ["//vendor/github.com/cloudflare/cfssl/errors:go_default_library"], + deps = [ + "//vendor/github.com/cloudflare/cfssl/errors:go_default_library", + "//vendor/golang.org/x/crypto/ed25519:go_default_library", + ], ) filegroup( diff --git a/vendor/github.com/cloudflare/cfssl/helpers/derhelpers/derhelpers.go b/vendor/github.com/cloudflare/cfssl/helpers/derhelpers/derhelpers.go index bcc74185085..812664ceb76 100644 --- a/vendor/github.com/cloudflare/cfssl/helpers/derhelpers/derhelpers.go +++ b/vendor/github.com/cloudflare/cfssl/helpers/derhelpers/derhelpers.go @@ -9,10 +9,11 @@ import ( "crypto/x509" cferr "github.com/cloudflare/cfssl/errors" + "golang.org/x/crypto/ed25519" ) -// ParsePrivateKeyDER parses a PKCS #1, PKCS #8, or elliptic curve -// DER-encoded private key. The key must not be in PEM format. +// ParsePrivateKeyDER parses a PKCS #1, PKCS #8, ECDSA, or Ed25519 DER-encoded +// private key. The key must not be in PEM format. func ParsePrivateKeyDER(keyDER []byte) (key crypto.Signer, err error) { generalKey, err := x509.ParsePKCS8PrivateKey(keyDER) if err != nil { @@ -20,12 +21,15 @@ func ParsePrivateKeyDER(keyDER []byte) (key crypto.Signer, err error) { if err != nil { generalKey, err = x509.ParseECPrivateKey(keyDER) if err != nil { - // We don't include the actual error into - // the final error. The reason might be - // we don't want to leak any info about - // the private key. - return nil, cferr.New(cferr.PrivateKeyError, - cferr.ParseFailed) + generalKey, err = ParseEd25519PrivateKey(keyDER) + if err != nil { + // We don't include the actual error into + // the final error. The reason might be + // we don't want to leak any info about + // the private key. + return nil, cferr.New(cferr.PrivateKeyError, + cferr.ParseFailed) + } } } } @@ -35,6 +39,8 @@ func ParsePrivateKeyDER(keyDER []byte) (key crypto.Signer, err error) { return generalKey.(*rsa.PrivateKey), nil case *ecdsa.PrivateKey: return generalKey.(*ecdsa.PrivateKey), nil + case ed25519.PrivateKey: + return generalKey.(ed25519.PrivateKey), nil } // should never reach here diff --git a/vendor/github.com/cloudflare/cfssl/helpers/derhelpers/ed25519.go b/vendor/github.com/cloudflare/cfssl/helpers/derhelpers/ed25519.go new file mode 100644 index 00000000000..9220f3e5fae --- /dev/null +++ b/vendor/github.com/cloudflare/cfssl/helpers/derhelpers/ed25519.go @@ -0,0 +1,133 @@ +package derhelpers + +import ( + "crypto" + "crypto/x509/pkix" + "encoding/asn1" + "errors" + + "golang.org/x/crypto/ed25519" +) + +var errEd25519WrongID = errors.New("incorrect object identifier") +var errEd25519WrongKeyType = errors.New("incorrect key type") + +// ed25519OID is the OID for the Ed25519 signature scheme: see +// https://datatracker.ietf.org/doc/draft-ietf-curdle-pkix-04. +var ed25519OID = asn1.ObjectIdentifier{1, 3, 101, 112} + +// subjectPublicKeyInfo reflects the ASN.1 object defined in the X.509 standard. +// +// This is defined in crypto/x509 as "publicKeyInfo". +type subjectPublicKeyInfo struct { + Algorithm pkix.AlgorithmIdentifier + PublicKey asn1.BitString +} + +// MarshalEd25519PublicKey creates a DER-encoded SubjectPublicKeyInfo for an +// ed25519 public key, as defined in +// https://tools.ietf.org/html/draft-ietf-curdle-pkix-04. This is analagous to +// MarshalPKIXPublicKey in crypto/x509, which doesn't currently support Ed25519. +func MarshalEd25519PublicKey(pk crypto.PublicKey) ([]byte, error) { + pub, ok := pk.(ed25519.PublicKey) + if !ok { + return nil, errEd25519WrongKeyType + } + + spki := subjectPublicKeyInfo{ + Algorithm: pkix.AlgorithmIdentifier{ + Algorithm: ed25519OID, + }, + PublicKey: asn1.BitString{ + BitLength: len(pub) * 8, + Bytes: pub, + }, + } + + return asn1.Marshal(spki) +} + +// ParseEd25519PublicKey returns the Ed25519 public key encoded by the input. +func ParseEd25519PublicKey(der []byte) (crypto.PublicKey, error) { + var spki subjectPublicKeyInfo + if rest, err := asn1.Unmarshal(der, &spki); err != nil { + return nil, err + } else if len(rest) > 0 { + return nil, errors.New("SubjectPublicKeyInfo too long") + } + + if !spki.Algorithm.Algorithm.Equal(ed25519OID) { + return nil, errEd25519WrongID + } + + if spki.PublicKey.BitLength != ed25519.PublicKeySize*8 { + return nil, errors.New("SubjectPublicKeyInfo PublicKey length mismatch") + } + + return ed25519.PublicKey(spki.PublicKey.Bytes), nil +} + +// oneAsymmetricKey reflects the ASN.1 structure for storing private keys in +// https://tools.ietf.org/html/draft-ietf-curdle-pkix-04, excluding the optional +// fields, which we don't use here. +// +// This is identical to pkcs8 in crypto/x509. +type oneAsymmetricKey struct { + Version int + Algorithm pkix.AlgorithmIdentifier + PrivateKey []byte +} + +// curvePrivateKey is the innter type of the PrivateKey field of +// oneAsymmetricKey. +type curvePrivateKey []byte + +// MarshalEd25519PrivateKey returns a DER encdoing of the input private key as +// specified in https://tools.ietf.org/html/draft-ietf-curdle-pkix-04. +func MarshalEd25519PrivateKey(sk crypto.PrivateKey) ([]byte, error) { + priv, ok := sk.(ed25519.PrivateKey) + if !ok { + return nil, errEd25519WrongKeyType + } + + // Marshal the innter CurvePrivateKey. + curvePrivateKey, err := asn1.Marshal(priv.Seed()) + if err != nil { + return nil, err + } + + // Marshal the OneAsymmetricKey. + asym := oneAsymmetricKey{ + Version: 0, + Algorithm: pkix.AlgorithmIdentifier{ + Algorithm: ed25519OID, + }, + PrivateKey: curvePrivateKey, + } + return asn1.Marshal(asym) +} + +// ParseEd25519PrivateKey returns the Ed25519 private key encoded by the input. +func ParseEd25519PrivateKey(der []byte) (crypto.PrivateKey, error) { + asym := new(oneAsymmetricKey) + if rest, err := asn1.Unmarshal(der, asym); err != nil { + return nil, err + } else if len(rest) > 0 { + return nil, errors.New("OneAsymmetricKey too long") + } + + // Check that the key type is correct. + if !asym.Algorithm.Algorithm.Equal(ed25519OID) { + return nil, errEd25519WrongID + } + + // Unmarshal the inner CurvePrivateKey. + seed := new(curvePrivateKey) + if rest, err := asn1.Unmarshal(asym.PrivateKey, seed); err != nil { + return nil, err + } else if len(rest) > 0 { + return nil, errors.New("CurvePrivateKey too long") + } + + return ed25519.NewKeyFromSeed(*seed), nil +} diff --git a/vendor/github.com/cloudflare/cfssl/helpers/helpers.go b/vendor/github.com/cloudflare/cfssl/helpers/helpers.go index c9506077a44..534d0715618 100644 --- a/vendor/github.com/cloudflare/cfssl/helpers/helpers.go +++ b/vendor/github.com/cloudflare/cfssl/helpers/helpers.go @@ -12,16 +12,15 @@ import ( "crypto/x509" "crypto/x509/pkix" "encoding/asn1" - "encoding/binary" "encoding/pem" "errors" "fmt" - "io" "io/ioutil" "os" "github.com/google/certificate-transparency-go" cttls "github.com/google/certificate-transparency-go/tls" + ctx509 "github.com/google/certificate-transparency-go/x509" "golang.org/x/crypto/ocsp" "strings" @@ -185,7 +184,20 @@ func HashAlgoString(alg x509.SignatureAlgorithm) string { } } -// EncodeCertificatesPEM encodes a number of x509 certficates to PEM +// StringTLSVersion returns underlying enum values from human names for TLS +// versions, defaults to current golang default of TLS 1.0 +func StringTLSVersion(version string) uint16 { + switch version { + case "1.2": + return tls.VersionTLS12 + case "1.1": + return tls.VersionTLS11 + default: + return tls.VersionTLS10 + } +} + +// EncodeCertificatesPEM encodes a number of x509 certificates to PEM func EncodeCertificatesPEM(certs []*x509.Certificate) []byte { var buffer bytes.Buffer for _, cert := range certs { @@ -198,7 +210,7 @@ func EncodeCertificatesPEM(certs []*x509.Certificate) []byte { return buffer.Bytes() } -// EncodeCertificatePEM encodes a single x509 certficates to PEM +// EncodeCertificatePEM encodes a single x509 certificates to PEM func EncodeCertificatePEM(cert *x509.Certificate) []byte { return EncodeCertificatesPEM([]*x509.Certificate{cert}) } @@ -408,7 +420,7 @@ func ParseCSR(in []byte) (csr *x509.CertificateRequest, rest []byte, err error) return csr, rest, nil } -// ParseCSRPEM parses a PEM-encoded certificiate signing request. +// ParseCSRPEM parses a PEM-encoded certificate signing request. // It does not check the signature. This is useful for dumping data from a CSR // locally. func ParseCSRPEM(csrPEM []byte) (*x509.CertificateRequest, error) { @@ -484,64 +496,40 @@ func CreateTLSConfig(remoteCAs *x509.CertPool, cert *tls.Certificate) *tls.Confi // SerializeSCTList serializes a list of SCTs. func SerializeSCTList(sctList []ct.SignedCertificateTimestamp) ([]byte, error) { - var buf bytes.Buffer + list := ctx509.SignedCertificateTimestampList{} for _, sct := range sctList { - sct, err := cttls.Marshal(sct) + sctBytes, err := cttls.Marshal(sct) if err != nil { return nil, err } - binary.Write(&buf, binary.BigEndian, uint16(len(sct))) - buf.Write(sct) + list.SCTList = append(list.SCTList, ctx509.SerializedSCT{Val: sctBytes}) } - - var sctListLengthField = make([]byte, 2) - binary.BigEndian.PutUint16(sctListLengthField, uint16(buf.Len())) - return bytes.Join([][]byte{sctListLengthField, buf.Bytes()}, nil), nil + return cttls.Marshal(list) } // DeserializeSCTList deserializes a list of SCTs. -func DeserializeSCTList(serializedSCTList []byte) (*[]ct.SignedCertificateTimestamp, error) { - sctList := new([]ct.SignedCertificateTimestamp) - sctReader := bytes.NewBuffer(serializedSCTList) - - var sctListLen uint16 - err := binary.Read(sctReader, binary.BigEndian, &sctListLen) +func DeserializeSCTList(serializedSCTList []byte) ([]ct.SignedCertificateTimestamp, error) { + var sctList ctx509.SignedCertificateTimestampList + rest, err := cttls.Unmarshal(serializedSCTList, &sctList) if err != nil { - if err == io.EOF { - return sctList, cferr.Wrap(cferr.CTError, cferr.Unknown, - errors.New("serialized SCT list could not be read")) - } - return sctList, cferr.Wrap(cferr.CTError, cferr.Unknown, err) + return nil, err } - if sctReader.Len() != int(sctListLen) { - return sctList, errors.New("SCT length field and SCT length don't match") + if len(rest) != 0 { + return nil, cferr.Wrap(cferr.CTError, cferr.Unknown, errors.New("serialized SCT list contained trailing garbage")) } - - for err != io.EOF { - var sctLen uint16 - err = binary.Read(sctReader, binary.BigEndian, &sctLen) - if err != nil { - if err == io.EOF { - return sctList, nil - } - return sctList, cferr.Wrap(cferr.CTError, cferr.Unknown, err) - } - - if sctReader.Len() < int(sctLen) { - return sctList, errors.New("SCT length field and SCT length don't match") - } - - serializedSCT := sctReader.Next(int(sctLen)) + list := make([]ct.SignedCertificateTimestamp, len(sctList.SCTList)) + for i, serializedSCT := range sctList.SCTList { var sct ct.SignedCertificateTimestamp - if _, err := cttls.Unmarshal(serializedSCT, &sct); err != nil { - return sctList, cferr.Wrap(cferr.CTError, cferr.Unknown, err) + rest, err := cttls.Unmarshal(serializedSCT.Val, &sct) + if err != nil { + return nil, err } - - temp := append(*sctList, sct) - sctList = &temp + if len(rest) != 0 { + return nil, cferr.Wrap(cferr.CTError, cferr.Unknown, errors.New("serialized SCT contained trailing garbage")) + } + list[i] = sct } - - return sctList, cferr.Wrap(cferr.CTError, cferr.Unknown, err) + return list, nil } // SCTListFromOCSPResponse extracts the SCTList from an ocsp.Response, @@ -560,22 +548,21 @@ func SCTListFromOCSPResponse(response *ocsp.Response) ([]ct.SignedCertificateTim } // This code block extracts the sctList from the SCT extension. - var emptySCTList []ct.SignedCertificateTimestamp - sctList := &emptySCTList + var sctList []ct.SignedCertificateTimestamp var err error if numBytes := len(SCTListExtension.Value); numBytes != 0 { - serializedSCTList := new([]byte) + var serializedSCTList []byte rest := make([]byte, numBytes) copy(rest, SCTListExtension.Value) for len(rest) != 0 { - rest, err = asn1.Unmarshal(rest, serializedSCTList) + rest, err = asn1.Unmarshal(rest, &serializedSCTList) if err != nil { return nil, cferr.Wrap(cferr.CTError, cferr.Unknown, err) } } - sctList, err = DeserializeSCTList(*serializedSCTList) + sctList, err = DeserializeSCTList(serializedSCTList) } - return *sctList, err + return sctList, err } // ReadBytes reads a []byte either from a file or an environment variable. diff --git a/vendor/github.com/cloudflare/cfssl/initca/initca.go b/vendor/github.com/cloudflare/cfssl/initca/initca.go index 89fcfb54b92..2cdc0925f18 100644 --- a/vendor/github.com/cloudflare/cfssl/initca/initca.go +++ b/vendor/github.com/cloudflare/cfssl/initca/initca.go @@ -113,7 +113,7 @@ func NewFromPEM(req *csr.CertificateRequest, keyFile string) (cert, csrPEM []byt // RenewFromPEM re-creates a root certificate from the CA cert and key // files. The resulting root certificate will have the input CA certificate -// as the template and have the same expiry length. E.g. the exsiting CA +// as the template and have the same expiry length. E.g. the existing CA // is valid for a year from Jan 01 2015 to Jan 01 2016, the renewed certificate // will be valid from now and expire in one year as well. func RenewFromPEM(caFile, keyFile string) ([]byte, error) { @@ -178,7 +178,7 @@ func NewFromSigner(req *csr.CertificateRequest, priv crypto.Signer) (cert, csrPE // RenewFromSigner re-creates a root certificate from the CA cert and crypto.Signer. // The resulting root certificate will have ca certificate -// as the template and have the same expiry length. E.g. the exsiting CA +// as the template and have the same expiry length. E.g. the existing CA // is valid for a year from Jan 01 2015 to Jan 01 2016, the renewed certificate // will be valid from now and expire in one year as well. func RenewFromSigner(ca *x509.Certificate, priv crypto.Signer) ([]byte, error) { diff --git a/vendor/github.com/cloudflare/cfssl/ocsp/ocsp.go b/vendor/github.com/cloudflare/cfssl/ocsp/ocsp.go index a78b69c2e8f..dfb2c2016b3 100644 --- a/vendor/github.com/cloudflare/cfssl/ocsp/ocsp.go +++ b/vendor/github.com/cloudflare/cfssl/ocsp/ocsp.go @@ -164,8 +164,10 @@ func (s StandardSigner) Sign(req SignRequest) ([]byte, error) { if bytes.Compare(req.Certificate.RawIssuer, s.issuer.RawSubject) != 0 { return nil, cferr.New(cferr.OCSPError, cferr.IssuerMismatch) } - if req.Certificate.CheckSignatureFrom(s.issuer) != nil { - return nil, cferr.New(cferr.OCSPError, cferr.IssuerMismatch) + + err := req.Certificate.CheckSignatureFrom(s.issuer) + if err != nil { + return nil, cferr.Wrap(cferr.OCSPError, cferr.VerifyFailed, err) } var thisUpdate, nextUpdate time.Time diff --git a/vendor/github.com/cloudflare/cfssl/scan/BUILD b/vendor/github.com/cloudflare/cfssl/scan/BUILD index 5ac552297f0..7d7b4b26504 100644 --- a/vendor/github.com/cloudflare/cfssl/scan/BUILD +++ b/vendor/github.com/cloudflare/cfssl/scan/BUILD @@ -18,6 +18,7 @@ go_library( "//vendor/github.com/cloudflare/cfssl/helpers:go_default_library", "//vendor/github.com/cloudflare/cfssl/log:go_default_library", "//vendor/github.com/cloudflare/cfssl/revoke:go_default_library", + "//vendor/github.com/cloudflare/cfssl/scan/crypto/tls:go_default_library", ], ) @@ -30,7 +31,10 @@ filegroup( filegroup( name = "all-srcs", - srcs = [":package-srcs"], + srcs = [ + ":package-srcs", + "//vendor/github.com/cloudflare/cfssl/scan/crypto/tls:all-srcs", + ], tags = ["automanaged"], visibility = ["//visibility:public"], ) diff --git a/vendor/github.com/cloudflare/cfssl/scan/connectivity.go b/vendor/github.com/cloudflare/cfssl/scan/connectivity.go index a421bffe385..d6e0edae88a 100644 --- a/vendor/github.com/cloudflare/cfssl/scan/connectivity.go +++ b/vendor/github.com/cloudflare/cfssl/scan/connectivity.go @@ -2,11 +2,12 @@ package scan import ( "bufio" - "crypto/tls" "errors" "fmt" "io" "net" + + "github.com/cloudflare/cfssl/scan/crypto/tls" ) // Connectivity contains scanners testing basic connectivity to the host @@ -53,7 +54,7 @@ var ( ) func initOnCloudFlareScan() ([]*net.IPNet, error) { - // Propogate previous errors and don't attempt to re-download. + // Propagate previous errors and don't attempt to re-download. if cfNetsErr != nil { return nil, cfNetsErr } diff --git a/vendor/github.com/cloudflare/cfssl/scan/crypto/tls/BUILD b/vendor/github.com/cloudflare/cfssl/scan/crypto/tls/BUILD new file mode 100644 index 00000000000..3b4610eac10 --- /dev/null +++ b/vendor/github.com/cloudflare/cfssl/scan/crypto/tls/BUILD @@ -0,0 +1,37 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = [ + "alert.go", + "cfsslscan_common.go", + "cfsslscan_handshake.go", + "cipher_suites.go", + "common.go", + "conn.go", + "handshake_client.go", + "handshake_messages.go", + "handshake_server.go", + "key_agreement.go", + "prf.go", + "ticket.go", + "tls.go", + ], + importmap = "k8s.io/kubernetes/vendor/github.com/cloudflare/cfssl/scan/crypto/tls", + importpath = "github.com/cloudflare/cfssl/scan/crypto/tls", + visibility = ["//visibility:public"], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) diff --git a/vendor/github.com/cloudflare/cfssl/scan/crypto/tls/alert.go b/vendor/github.com/cloudflare/cfssl/scan/crypto/tls/alert.go new file mode 100644 index 00000000000..3de4834d3f5 --- /dev/null +++ b/vendor/github.com/cloudflare/cfssl/scan/crypto/tls/alert.go @@ -0,0 +1,79 @@ +// Copyright 2009 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 "strconv" + +type alert uint8 + +const ( + // alert level + alertLevelWarning = 1 + alertLevelError = 2 +) + +const ( + alertCloseNotify alert = 0 + alertUnexpectedMessage alert = 10 + alertBadRecordMAC alert = 20 + alertDecryptionFailed alert = 21 + alertRecordOverflow alert = 22 + alertDecompressionFailure alert = 30 + alertHandshakeFailure alert = 40 + alertBadCertificate alert = 42 + alertUnsupportedCertificate alert = 43 + alertCertificateRevoked alert = 44 + alertCertificateExpired alert = 45 + alertCertificateUnknown alert = 46 + alertIllegalParameter alert = 47 + alertUnknownCA alert = 48 + alertAccessDenied alert = 49 + alertDecodeError alert = 50 + alertDecryptError alert = 51 + alertProtocolVersion alert = 70 + alertInsufficientSecurity alert = 71 + alertInternalError alert = 80 + alertInappropriateFallback alert = 86 + alertUserCanceled alert = 90 + alertNoRenegotiation alert = 100 +) + +var alertText = map[alert]string{ + alertCloseNotify: "close notify", + alertUnexpectedMessage: "unexpected message", + alertBadRecordMAC: "bad record MAC", + alertDecryptionFailed: "decryption failed", + alertRecordOverflow: "record overflow", + alertDecompressionFailure: "decompression failure", + alertHandshakeFailure: "handshake failure", + alertBadCertificate: "bad certificate", + alertUnsupportedCertificate: "unsupported certificate", + alertCertificateRevoked: "revoked certificate", + alertCertificateExpired: "expired certificate", + alertCertificateUnknown: "unknown certificate", + alertIllegalParameter: "illegal parameter", + alertUnknownCA: "unknown certificate authority", + alertAccessDenied: "access denied", + alertDecodeError: "error decoding message", + alertDecryptError: "error decrypting message", + alertProtocolVersion: "protocol version not supported", + alertInsufficientSecurity: "insufficient security level", + alertInternalError: "internal error", + alertInappropriateFallback: "inappropriate fallback", + alertUserCanceled: "user canceled", + alertNoRenegotiation: "no renegotiation", +} + +func (e alert) String() string { + s, ok := alertText[e] + if ok { + return s + } + return "alert(" + strconv.Itoa(int(e)) + ")" +} + +func (e alert) Error() string { + return e.String() +} diff --git a/vendor/github.com/cloudflare/cfssl/scan/crypto/tls/cfsslscan_common.go b/vendor/github.com/cloudflare/cfssl/scan/crypto/tls/cfsslscan_common.go new file mode 100644 index 00000000000..bbcd2cd8640 --- /dev/null +++ b/vendor/github.com/cloudflare/cfssl/scan/crypto/tls/cfsslscan_common.go @@ -0,0 +1,486 @@ +package tls + +import ( + "fmt" +) + +type hashAlgID uint8 + +const ( + HashNone hashAlgID = iota + HashMD5 + HashSHA1 + HashSHA224 + HashSHA256 + HashSHA384 + HashSHA512 +) + +func (h hashAlgID) String() string { + switch h { + case HashNone: + return "None" + case HashMD5: + return "MD5" + case HashSHA1: + return "SHA1" + case HashSHA224: + return "SHA224" + case HashSHA256: + return "SHA256" + case HashSHA384: + return "SHA384" + case HashSHA512: + return "SHA512" + default: + return "Unknown" + } +} + +type sigAlgID uint8 + +// Signature algorithms for TLS 1.2 (See RFC 5246, section A.4.1) +const ( + SigAnon sigAlgID = iota + SigRSA + SigDSA + SigECDSA +) + +func (sig sigAlgID) String() string { + switch sig { + case SigAnon: + return "Anon" + case SigRSA: + return "RSA" + case SigDSA: + return "DSA" + case SigECDSA: + return "ECDSA" + default: + return "Unknown" + } +} + +// SignatureAndHash mirrors the TLS 1.2, SignatureAndHashAlgorithm struct. See +// RFC 5246, section A.4.1. +type SignatureAndHash struct { + h hashAlgID + s sigAlgID +} + +func (sigAlg SignatureAndHash) String() string { + return fmt.Sprintf("{%s,%s}", sigAlg.s, sigAlg.h) +} + +func (sigAlg SignatureAndHash) MarshalJSON() ([]byte, error) { + return []byte(fmt.Sprintf(`{"signature":"%s","hash":"%s"}`, sigAlg.s, sigAlg.h)), nil +} + +func (sigAlg SignatureAndHash) internal() signatureAndHash { + return signatureAndHash{uint8(sigAlg.h), uint8(sigAlg.s)} +} + +// defaultSignatureAndHashAlgorithms contains the default signature and hash +// algorithm paris supported by `crypto/tls` +var defaultSignatureAndHashAlgorithms []signatureAndHash + +// AllSignatureAndHashAlgorithms contains all possible signature and +// hash algorithm pairs that the can be advertised in a TLS 1.2 ClientHello. +var AllSignatureAndHashAlgorithms []SignatureAndHash + +func init() { + defaultSignatureAndHashAlgorithms = supportedSignatureAlgorithms + for _, sighash := range supportedSignatureAlgorithms { + AllSignatureAndHashAlgorithms = append(AllSignatureAndHashAlgorithms, + SignatureAndHash{hashAlgID(sighash.hash), sigAlgID(sighash.signature)}) + } +} + +// TLSVersions is a list of the current SSL/TLS Versions implemented by Go +var Versions = map[uint16]string{ + VersionSSL30: "SSL 3.0", + VersionTLS10: "TLS 1.0", + VersionTLS11: "TLS 1.1", + VersionTLS12: "TLS 1.2", +} + +// CipherSuite describes an individual cipher suite, with long and short names +// and security properties. +type CipherSuite struct { + Name, ShortName string + // ForwardSecret cipher suites negotiate ephemeral keys, allowing forward secrecy. + ForwardSecret bool + EllipticCurve bool +} + +// Returns the (short) name of the cipher suite. +func (c CipherSuite) String() string { + if c.ShortName != "" { + return c.ShortName + } + return c.Name +} + +// CipherSuites contains all values in the TLS Cipher Suite Registry +// https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml +var CipherSuites = map[uint16]CipherSuite{ + 0X0000: {Name: "TLS_NULL_WITH_NULL_NULL"}, + 0X0001: {Name: "TLS_RSA_WITH_NULL_MD5"}, + 0X0002: {Name: "TLS_RSA_WITH_NULL_SHA"}, + 0X0003: {Name: "TLS_RSA_EXPORT_WITH_RC4_40_MD5", ShortName: "EXP-RC4-MD5"}, + 0X0004: {Name: "TLS_RSA_WITH_RC4_128_MD5", ShortName: "RC4-MD5"}, + 0X0005: {Name: "TLS_RSA_WITH_RC4_128_SHA", ShortName: "RC4-SHA"}, + 0X0006: {Name: "TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5", ShortName: "EXP-RC2-CBC-MD5"}, + 0X0007: {Name: "TLS_RSA_WITH_IDEA_CBC_SHA", ShortName: "IDEA-CBC-SHA"}, + 0X0008: {Name: "TLS_RSA_EXPORT_WITH_DES40_CBC_SHA", ShortName: "EXP-DES-CBC-SHA"}, + 0X0009: {Name: "TLS_RSA_WITH_DES_CBC_SHA", ShortName: "DES-CBC-SHA"}, + 0X000A: {Name: "TLS_RSA_WITH_3DES_EDE_CBC_SHA", ShortName: "DES-CBC3-SHA"}, + 0X000B: {Name: "TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA", ShortName: "EXP-DH-DSS-DES-CBC-SHA"}, + 0X000C: {Name: "TLS_DH_DSS_WITH_DES_CBC_SHA", ShortName: "DH-DSS-DES-CBC-SHA"}, + 0X000D: {Name: "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA", ShortName: "DH-DSS-DES-CBC3-SHA"}, + 0X000E: {Name: "TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA", ShortName: "EXP-DH-RSA-DES-CBC-SHA"}, + 0X000F: {Name: "TLS_DH_RSA_WITH_DES_CBC_SHA", ShortName: "DH-RSA-DES-CBC-SHA"}, + 0X0010: {Name: "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA", ShortName: "DH-RSA-DES-CBC3-SHA"}, + 0X0011: {Name: "TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", ShortName: "EXP-EDH-DSS-DES-CBC-SHA", ForwardSecret: true}, + 0X0012: {Name: "TLS_DHE_DSS_WITH_DES_CBC_SHA", ShortName: "EDH-DSS-DES-CBC-SHA", ForwardSecret: true}, + 0X0013: {Name: "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA", ShortName: "EDH-DSS-DES-CBC3-SHA", ForwardSecret: true}, + 0X0014: {Name: "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", ShortName: "EXP-EDH-RSA-DES-CBC-SHA", ForwardSecret: true}, + 0X0015: {Name: "TLS_DHE_RSA_WITH_DES_CBC_SHA", ShortName: "EDH-RSA-DES-CBC-SHA", ForwardSecret: true}, + 0X0016: {Name: "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA", ShortName: "EDH-RSA-DES-CBC3-SHA", ForwardSecret: true}, + 0X0017: {Name: "TLS_DH_anon_EXPORT_WITH_RC4_40_MD5"}, + 0X0018: {Name: "TLS_DH_anon_WITH_RC4_128_MD5"}, + 0X0019: {Name: "TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA"}, + 0X001A: {Name: "TLS_DH_anon_WITH_DES_CBC_SHA"}, + 0X001B: {Name: "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA"}, + 0X001E: {Name: "TLS_KRB5_WITH_DES_CBC_SHA"}, + 0X001F: {Name: "TLS_KRB5_WITH_3DES_EDE_CBC_SHA"}, + 0X0020: {Name: "TLS_KRB5_WITH_RC4_128_SHA"}, + 0X0021: {Name: "TLS_KRB5_WITH_IDEA_CBC_SHA"}, + 0X0022: {Name: "TLS_KRB5_WITH_DES_CBC_MD5"}, + 0X0023: {Name: "TLS_KRB5_WITH_3DES_EDE_CBC_MD5"}, + 0X0024: {Name: "TLS_KRB5_WITH_RC4_128_MD5"}, + 0X0025: {Name: "TLS_KRB5_WITH_IDEA_CBC_MD5"}, + 0X0026: {Name: "TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA"}, + 0X0027: {Name: "TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA"}, + 0X0028: {Name: "TLS_KRB5_EXPORT_WITH_RC4_40_SHA"}, + 0X0029: {Name: "TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5"}, + 0X002A: {Name: "TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5"}, + 0X002B: {Name: "TLS_KRB5_EXPORT_WITH_RC4_40_MD5"}, + 0X002C: {Name: "TLS_PSK_WITH_NULL_SHA"}, + 0X002D: {Name: "TLS_DHE_PSK_WITH_NULL_SHA", ForwardSecret: true}, + 0X002E: {Name: "TLS_RSA_PSK_WITH_NULL_SHA"}, + 0X002F: {Name: "TLS_RSA_WITH_AES_128_CBC_SHA", ShortName: "AES128-SHA"}, + 0X0030: {Name: "TLS_DH_DSS_WITH_AES_128_CBC_SHA", ShortName: "DH-DSS-AES128-SHA"}, + 0X0031: {Name: "TLS_DH_RSA_WITH_AES_128_CBC_SHA", ShortName: "DH-RSA-AES128-SHA"}, + 0X0032: {Name: "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", ShortName: "DHE-DSS-AES128-SHA", ForwardSecret: true}, + 0X0033: {Name: "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", ShortName: "DHE-RSA-AES128-SHA", ForwardSecret: true}, + 0X0034: {Name: "TLS_DH_anon_WITH_AES_128_CBC_SHA"}, + 0X0035: {Name: "TLS_RSA_WITH_AES_256_CBC_SHA", ShortName: "AES256-SHA"}, + 0X0036: {Name: "TLS_DH_DSS_WITH_AES_256_CBC_SHA", ShortName: "DH-DSS-AES256-SHA"}, + 0X0037: {Name: "TLS_DH_RSA_WITH_AES_256_CBC_SHA", ShortName: "DH-RSA-AES256-SHA"}, + 0X0038: {Name: "TLS_DHE_DSS_WITH_AES_256_CBC_SHA", ShortName: "DHE-DSS-AES256-SHA", ForwardSecret: true}, + 0X0039: {Name: "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", ShortName: "DHE-RSA-AES256-SHA", ForwardSecret: true}, + 0X003A: {Name: "TLS_DH_anon_WITH_AES_256_CBC_SHA"}, + 0X003B: {Name: "TLS_RSA_WITH_NULL_SHA256"}, + 0X003C: {Name: "TLS_RSA_WITH_AES_128_CBC_SHA256", ShortName: "AES128-SHA256"}, + 0X003D: {Name: "TLS_RSA_WITH_AES_256_CBC_SHA256", ShortName: "AES256-SHA256"}, + 0X003E: {Name: "TLS_DH_DSS_WITH_AES_128_CBC_SHA256", ShortName: "DH-DSS-AES128-SHA256"}, + 0X003F: {Name: "TLS_DH_RSA_WITH_AES_128_CBC_SHA256", ShortName: "DH-RSA-AES128-SHA256"}, + 0X0040: {Name: "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256", ShortName: "DHE-DSS-AES128-SHA256", ForwardSecret: true}, + 0X0041: {Name: "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA", ShortName: "CAMELLIA128-SHA"}, + 0X0042: {Name: "TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA", ShortName: "DH-DSS-CAMELLIA128-SHA"}, + 0X0043: {Name: "TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA", ShortName: "DH-RSA-CAMELLIA128-SHA"}, + 0X0044: {Name: "TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA", ShortName: "DHE-DSS-CAMELLIA128-SHA", ForwardSecret: true}, + 0X0045: {Name: "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA", ShortName: "DHE-RSA-CAMELLIA128-SHA", ForwardSecret: true}, + 0X0046: {Name: "TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA"}, + 0X0067: {Name: "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256", ShortName: "DHE-RSA-AES128-SHA256", ForwardSecret: true}, + 0X0068: {Name: "TLS_DH_DSS_WITH_AES_256_CBC_SHA256", ShortName: "DH-DSS-AES256-SHA256"}, + 0X0069: {Name: "TLS_DH_RSA_WITH_AES_256_CBC_SHA256", ShortName: "DH-RSA-AES256-SHA256"}, + 0X006A: {Name: "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256", ShortName: "DHE-DSS-AES256-SHA256", ForwardSecret: true}, + 0X006B: {Name: "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256", ShortName: "DHE-RSA-AES256-SHA256", ForwardSecret: true}, + 0X006C: {Name: "TLS_DH_anon_WITH_AES_128_CBC_SHA256"}, + 0X006D: {Name: "TLS_DH_anon_WITH_AES_256_CBC_SHA256"}, + 0X0084: {Name: "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA", ShortName: "CAMELLIA256-SHA"}, + 0X0085: {Name: "TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA", ShortName: "DH-DSS-CAMELLIA256-SHA"}, + 0X0086: {Name: "TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA", ShortName: "DH-RSA-CAMELLIA256-SHA"}, + 0X0087: {Name: "TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA", ShortName: "DHE-DSS-CAMELLIA256-SHA", ForwardSecret: true}, + 0X0088: {Name: "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA", ShortName: "DHE-RSA-CAMELLIA256-SHA", ForwardSecret: true}, + 0X0089: {Name: "TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA"}, + 0X008A: {Name: "TLS_PSK_WITH_RC4_128_SHA", ShortName: "PSK-RC4-SHA"}, + 0X008B: {Name: "TLS_PSK_WITH_3DES_EDE_CBC_SHA", ShortName: "PSK-3DES-EDE-CBC-SHA"}, + 0X008C: {Name: "TLS_PSK_WITH_AES_128_CBC_SHA", ShortName: "PSK-AES128-CBC-SHA"}, + 0X008D: {Name: "TLS_PSK_WITH_AES_256_CBC_SHA", ShortName: "PSK-AES256-CBC-SHA"}, + 0X008E: {Name: "TLS_DHE_PSK_WITH_RC4_128_SHA", ForwardSecret: true}, + 0X008F: {Name: "TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA", ForwardSecret: true}, + 0X0090: {Name: "TLS_DHE_PSK_WITH_AES_128_CBC_SHA", ForwardSecret: true}, + 0X0091: {Name: "TLS_DHE_PSK_WITH_AES_256_CBC_SHA", ForwardSecret: true}, + 0X0092: {Name: "TLS_RSA_PSK_WITH_RC4_128_SHA"}, + 0X0093: {Name: "TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA"}, + 0X0094: {Name: "TLS_RSA_PSK_WITH_AES_128_CBC_SHA"}, + 0X0095: {Name: "TLS_RSA_PSK_WITH_AES_256_CBC_SHA"}, + 0X0096: {Name: "TLS_RSA_WITH_SEED_CBC_SHA", ShortName: "SEED-SHA"}, + 0X0097: {Name: "TLS_DH_DSS_WITH_SEED_CBC_SHA", ShortName: "DH-DSS-SEED-SHA"}, + 0X0098: {Name: "TLS_DH_RSA_WITH_SEED_CBC_SHA", ShortName: "DH-RSA-SEED-SHA"}, + 0X0099: {Name: "TLS_DHE_DSS_WITH_SEED_CBC_SHA", ShortName: "DHE-DSS-SEED-SHA", ForwardSecret: true}, + 0X009A: {Name: "TLS_DHE_RSA_WITH_SEED_CBC_SHA", ShortName: "DHE-RSA-SEED-SHA", ForwardSecret: true}, + 0X009B: {Name: "TLS_DH_anon_WITH_SEED_CBC_SHA"}, + 0X009C: {Name: "TLS_RSA_WITH_AES_128_GCM_SHA256", ShortName: "AES128-GCM-SHA256"}, + 0X009D: {Name: "TLS_RSA_WITH_AES_256_GCM_SHA384", ShortName: "AES256-GCM-SHA384"}, + 0X009E: {Name: "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", ShortName: "DHE-RSA-AES128-GCM-SHA256", ForwardSecret: true}, + 0X009F: {Name: "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", ShortName: "DHE-RSA-AES256-GCM-SHA384", ForwardSecret: true}, + 0X00A0: {Name: "TLS_DH_RSA_WITH_AES_128_GCM_SHA256", ShortName: "DH-RSA-AES128-GCM-SHA256"}, + 0X00A1: {Name: "TLS_DH_RSA_WITH_AES_256_GCM_SHA384", ShortName: "DH-RSA-AES256-GCM-SHA384"}, + 0X00A2: {Name: "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", ShortName: "DHE-DSS-AES128-GCM-SHA256", ForwardSecret: true}, + 0X00A3: {Name: "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", ShortName: "DHE-DSS-AES256-GCM-SHA384", ForwardSecret: true}, + 0X00A4: {Name: "TLS_DH_DSS_WITH_AES_128_GCM_SHA256", ShortName: "DH-DSS-AES128-GCM-SHA256"}, + 0X00A5: {Name: "TLS_DH_DSS_WITH_AES_256_GCM_SHA384", ShortName: "DH-DSS-AES256-GCM-SHA384"}, + 0X00A6: {Name: "TLS_DH_anon_WITH_AES_128_GCM_SHA256"}, + 0X00A7: {Name: "TLS_DH_anon_WITH_AES_256_GCM_SHA384"}, + 0X00A8: {Name: "TLS_PSK_WITH_AES_128_GCM_SHA256"}, + 0X00A9: {Name: "TLS_PSK_WITH_AES_256_GCM_SHA384"}, + 0X00AA: {Name: "TLS_DHE_PSK_WITH_AES_128_GCM_SHA256", ForwardSecret: true}, + 0X00AB: {Name: "TLS_DHE_PSK_WITH_AES_256_GCM_SHA384", ForwardSecret: true}, + 0X00AC: {Name: "TLS_RSA_PSK_WITH_AES_128_GCM_SHA256"}, + 0X00AD: {Name: "TLS_RSA_PSK_WITH_AES_256_GCM_SHA384"}, + 0X00AE: {Name: "TLS_PSK_WITH_AES_128_CBC_SHA256"}, + 0X00AF: {Name: "TLS_PSK_WITH_AES_256_CBC_SHA384"}, + 0X00B0: {Name: "TLS_PSK_WITH_NULL_SHA256"}, + 0X00B1: {Name: "TLS_PSK_WITH_NULL_SHA384"}, + 0X00B2: {Name: "TLS_DHE_PSK_WITH_AES_128_CBC_SHA256", ForwardSecret: true}, + 0X00B3: {Name: "TLS_DHE_PSK_WITH_AES_256_CBC_SHA384", ForwardSecret: true}, + 0X00B4: {Name: "TLS_DHE_PSK_WITH_NULL_SHA256", ForwardSecret: true}, + 0X00B5: {Name: "TLS_DHE_PSK_WITH_NULL_SHA384", ForwardSecret: true}, + 0X00B6: {Name: "TLS_RSA_PSK_WITH_AES_128_CBC_SHA256"}, + 0X00B7: {Name: "TLS_RSA_PSK_WITH_AES_256_CBC_SHA384"}, + 0X00B8: {Name: "TLS_RSA_PSK_WITH_NULL_SHA256"}, + 0X00B9: {Name: "TLS_RSA_PSK_WITH_NULL_SHA384"}, + 0X00BA: {Name: "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256"}, + 0X00BB: {Name: "TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256"}, + 0X00BC: {Name: "TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256"}, + 0X00BD: {Name: "TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256", ForwardSecret: true}, + 0X00BE: {Name: "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256", ForwardSecret: true}, + 0X00BF: {Name: "TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256"}, + 0X00C0: {Name: "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256"}, + 0X00C1: {Name: "TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256"}, + 0X00C2: {Name: "TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256"}, + 0X00C3: {Name: "TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256", ForwardSecret: true}, + 0X00C4: {Name: "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256", ForwardSecret: true}, + 0X00C5: {Name: "TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256"}, + 0X00FF: {Name: "TLS_EMPTY_RENEGOTIATION_INFO_SCSV"}, + 0XC001: {Name: "TLS_ECDH_ECDSA_WITH_NULL_SHA", EllipticCurve: true}, + 0XC002: {Name: "TLS_ECDH_ECDSA_WITH_RC4_128_SHA", ShortName: "ECDH-ECDSA-RC4-SHA", EllipticCurve: true}, + 0XC003: {Name: "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA", ShortName: "ECDH-ECDSA-DES-CBC3-SHA", EllipticCurve: true}, + 0XC004: {Name: "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA", ShortName: "ECDH-ECDSA-AES128-SHA", EllipticCurve: true}, + 0XC005: {Name: "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA", ShortName: "ECDH-ECDSA-AES256-SHA", EllipticCurve: true}, + 0XC006: {Name: "TLS_ECDHE_ECDSA_WITH_NULL_SHA", ForwardSecret: true, EllipticCurve: true}, + 0XC007: {Name: "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", ShortName: "ECDHE-ECDSA-RC4-SHA", ForwardSecret: true, EllipticCurve: true}, + 0XC008: {Name: "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", ShortName: "ECDHE-ECDSA-DES-CBC3-SHA", ForwardSecret: true, EllipticCurve: true}, + 0XC009: {Name: "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", ShortName: "ECDHE-ECDSA-AES128-SHA", ForwardSecret: true, EllipticCurve: true}, + 0XC00A: {Name: "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", ShortName: "ECDHE-ECDSA-AES256-SHA", ForwardSecret: true, EllipticCurve: true}, + 0XC00B: {Name: "TLS_ECDH_RSA_WITH_NULL_SHA", EllipticCurve: true}, + 0XC00C: {Name: "TLS_ECDH_RSA_WITH_RC4_128_SHA", ShortName: "ECDH-RSA-RC4-SHA", EllipticCurve: true}, + 0XC00D: {Name: "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA", ShortName: "ECDH-RSA-DES-CBC3-SHA", EllipticCurve: true}, + 0XC00E: {Name: "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA", ShortName: "ECDH-RSA-AES128-SHA", EllipticCurve: true}, + 0XC00F: {Name: "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA", ShortName: "ECDH-RSA-AES256-SHA", EllipticCurve: true}, + 0XC010: {Name: "TLS_ECDHE_RSA_WITH_NULL_SHA", ForwardSecret: true, EllipticCurve: true}, + 0XC011: {Name: "TLS_ECDHE_RSA_WITH_RC4_128_SHA", ShortName: "ECDHE-RSA-RC4-SHA", ForwardSecret: true, EllipticCurve: true}, + 0XC012: {Name: "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", ShortName: "ECDHE-RSA-DES-CBC3-SHA", ForwardSecret: true, EllipticCurve: true}, + 0XC013: {Name: "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", ShortName: "ECDHE-RSA-AES128-SHA", ForwardSecret: true, EllipticCurve: true}, + 0XC014: {Name: "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", ShortName: "ECDHE-RSA-AES256-SHA", ForwardSecret: true, EllipticCurve: true}, + 0XC015: {Name: "TLS_ECDH_anon_WITH_NULL_SHA", EllipticCurve: true}, + 0XC016: {Name: "TLS_ECDH_anon_WITH_RC4_128_SHA", EllipticCurve: true}, + 0XC017: {Name: "TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA", EllipticCurve: true}, + 0XC018: {Name: "TLS_ECDH_anon_WITH_AES_128_CBC_SHA", EllipticCurve: true}, + 0XC019: {Name: "TLS_ECDH_anon_WITH_AES_256_CBC_SHA", EllipticCurve: true}, + 0XC01A: {Name: "TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA", ShortName: "SRP-3DES-EDE-CBC-SHA"}, + 0XC01B: {Name: "TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA", ShortName: "SRP-RSA-3DES-EDE-CBC-SHA"}, + 0XC01C: {Name: "TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA", ShortName: "SRP-DSS-3DES-EDE-CBC-SHA"}, + 0XC01D: {Name: "TLS_SRP_SHA_WITH_AES_128_CBC_SHA", ShortName: "SRP-AES-128-CBC-SHA"}, + 0XC01E: {Name: "TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA", ShortName: "SRP-RSA-AES-128-CBC-SHA"}, + 0XC01F: {Name: "TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA", ShortName: "SRP-DSS-AES-128-CBC-SHA"}, + 0XC020: {Name: "TLS_SRP_SHA_WITH_AES_256_CBC_SHA", ShortName: "SRP-AES-256-CBC-SHA"}, + 0XC021: {Name: "TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA", ShortName: "SRP-RSA-AES-256-CBC-SHA"}, + 0XC022: {Name: "TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA", ShortName: "SRP-DSS-AES-256-CBC-SHA"}, + 0XC023: {Name: "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", ShortName: "ECDHE-ECDSA-AES128-SHA256", ForwardSecret: true, EllipticCurve: true}, + 0XC024: {Name: "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", ShortName: "ECDHE-ECDSA-AES256-SHA384", ForwardSecret: true, EllipticCurve: true}, + 0XC025: {Name: "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256", ShortName: "ECDH-ECDSA-AES128-SHA256", EllipticCurve: true}, + 0XC026: {Name: "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384", ShortName: "ECDH-ECDSA-AES256-SHA384", EllipticCurve: true}, + 0XC027: {Name: "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", ShortName: "ECDHE-RSA-AES128-SHA256", ForwardSecret: true, EllipticCurve: true}, + 0XC028: {Name: "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", ShortName: "ECDHE-RSA-AES256-SHA384", ForwardSecret: true, EllipticCurve: true}, + 0XC029: {Name: "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256", ShortName: "ECDH-RSA-AES128-SHA256", EllipticCurve: true}, + 0XC02A: {Name: "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384", ShortName: "ECDH-RSA-AES256-SHA384", EllipticCurve: true}, + 0XC02B: {Name: "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", ShortName: "ECDHE-ECDSA-AES128-GCM-SHA256", ForwardSecret: true, EllipticCurve: true}, + 0XC02C: {Name: "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", ShortName: "ECDHE-ECDSA-AES256-GCM-SHA384", ForwardSecret: true, EllipticCurve: true}, + 0XC02D: {Name: "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", ShortName: "ECDH-ECDSA-AES128-GCM-SHA256", EllipticCurve: true}, + 0XC02E: {Name: "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", ShortName: "ECDH-ECDSA-AES256-GCM-SHA384", EllipticCurve: true}, + 0XC02F: {Name: "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", ShortName: "ECDHE-RSA-AES128-GCM-SHA256", ForwardSecret: true, EllipticCurve: true}, + 0XC030: {Name: "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", ShortName: "ECDHE-RSA-AES256-GCM-SHA384", ForwardSecret: true, EllipticCurve: true}, + 0XC031: {Name: "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", ShortName: "ECDH-RSA-AES128-GCM-SHA256", EllipticCurve: true}, + 0XC032: {Name: "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", ShortName: "ECDH-RSA-AES256-GCM-SHA384", EllipticCurve: true}, + 0XC033: {Name: "TLS_ECDHE_PSK_WITH_RC4_128_SHA", ForwardSecret: true, EllipticCurve: true}, + 0XC034: {Name: "TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA", ForwardSecret: true, EllipticCurve: true}, + 0XC035: {Name: "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA", ForwardSecret: true, EllipticCurve: true}, + 0XC036: {Name: "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA", ForwardSecret: true, EllipticCurve: true}, + 0XC037: {Name: "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256", ForwardSecret: true, EllipticCurve: true}, + 0XC038: {Name: "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384", ForwardSecret: true, EllipticCurve: true}, + 0XC039: {Name: "TLS_ECDHE_PSK_WITH_NULL_SHA", ForwardSecret: true, EllipticCurve: true}, + 0XC03A: {Name: "TLS_ECDHE_PSK_WITH_NULL_SHA256", ForwardSecret: true, EllipticCurve: true}, + 0XC03B: {Name: "TLS_ECDHE_PSK_WITH_NULL_SHA384", ForwardSecret: true, EllipticCurve: true}, + 0XC03C: {Name: "TLS_RSA_WITH_ARIA_128_CBC_SHA256"}, + 0XC03D: {Name: "TLS_RSA_WITH_ARIA_256_CBC_SHA384"}, + 0XC03E: {Name: "TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256"}, + 0XC03F: {Name: "TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384"}, + 0XC040: {Name: "TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256"}, + 0XC041: {Name: "TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384"}, + 0XC042: {Name: "TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256", ForwardSecret: true}, + 0XC043: {Name: "TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384", ForwardSecret: true}, + 0XC044: {Name: "TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256", ForwardSecret: true}, + 0XC045: {Name: "TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384", ForwardSecret: true}, + 0XC046: {Name: "TLS_DH_anon_WITH_ARIA_128_CBC_SHA256"}, + 0XC047: {Name: "TLS_DH_anon_WITH_ARIA_256_CBC_SHA384"}, + 0XC048: {Name: "TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256", ForwardSecret: true, EllipticCurve: true}, + 0XC049: {Name: "TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384", ForwardSecret: true, EllipticCurve: true}, + 0XC04A: {Name: "TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256", EllipticCurve: true}, + 0XC04B: {Name: "TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384", EllipticCurve: true}, + 0XC04C: {Name: "TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256", ForwardSecret: true, EllipticCurve: true}, + 0XC04D: {Name: "TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384", ForwardSecret: true, EllipticCurve: true}, + 0XC04E: {Name: "TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256", EllipticCurve: true}, + 0XC04F: {Name: "TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384", EllipticCurve: true}, + 0XC050: {Name: "TLS_RSA_WITH_ARIA_128_GCM_SHA256"}, + 0XC051: {Name: "TLS_RSA_WITH_ARIA_256_GCM_SHA384"}, + 0XC052: {Name: "TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256", ForwardSecret: true}, + 0XC053: {Name: "TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384", ForwardSecret: true}, + 0XC054: {Name: "TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256"}, + 0XC055: {Name: "TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384"}, + 0XC056: {Name: "TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256", ForwardSecret: true}, + 0XC057: {Name: "TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384", ForwardSecret: true}, + 0XC058: {Name: "TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256"}, + 0XC059: {Name: "TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384"}, + 0XC05A: {Name: "TLS_DH_anon_WITH_ARIA_128_GCM_SHA256"}, + 0XC05B: {Name: "TLS_DH_anon_WITH_ARIA_256_GCM_SHA384"}, + 0XC05C: {Name: "TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256", ForwardSecret: true, EllipticCurve: true}, + 0XC05D: {Name: "TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384", ForwardSecret: true, EllipticCurve: true}, + 0XC05E: {Name: "TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256", EllipticCurve: true}, + 0XC05F: {Name: "TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384", EllipticCurve: true}, + 0XC060: {Name: "TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256", ForwardSecret: true, EllipticCurve: true}, + 0XC061: {Name: "TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384", ForwardSecret: true, EllipticCurve: true}, + 0XC062: {Name: "TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256", EllipticCurve: true}, + 0XC063: {Name: "TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384", EllipticCurve: true}, + 0XC064: {Name: "TLS_PSK_WITH_ARIA_128_CBC_SHA256"}, + 0XC065: {Name: "TLS_PSK_WITH_ARIA_256_CBC_SHA384"}, + 0XC066: {Name: "TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256", ForwardSecret: true}, + 0XC067: {Name: "TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384", ForwardSecret: true}, + 0XC068: {Name: "TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256"}, + 0XC069: {Name: "TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384"}, + 0XC06A: {Name: "TLS_PSK_WITH_ARIA_128_GCM_SHA256"}, + 0XC06B: {Name: "TLS_PSK_WITH_ARIA_256_GCM_SHA384"}, + 0XC06C: {Name: "TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256", ForwardSecret: true}, + 0XC06D: {Name: "TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384", ForwardSecret: true}, + 0XC06E: {Name: "TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256"}, + 0XC06F: {Name: "TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384"}, + 0XC070: {Name: "TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256", ForwardSecret: true, EllipticCurve: true}, + 0XC071: {Name: "TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384", ForwardSecret: true, EllipticCurve: true}, + 0XC072: {Name: "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256", ForwardSecret: true, EllipticCurve: true}, + 0XC073: {Name: "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384", ForwardSecret: true, EllipticCurve: true}, + 0XC074: {Name: "TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256", EllipticCurve: true}, + 0XC075: {Name: "TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384", EllipticCurve: true}, + 0XC076: {Name: "TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256", ForwardSecret: true, EllipticCurve: true}, + 0XC077: {Name: "TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384", ForwardSecret: true, EllipticCurve: true}, + 0XC078: {Name: "TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256", EllipticCurve: true}, + 0XC079: {Name: "TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384", EllipticCurve: true}, + 0XC07A: {Name: "TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256"}, + 0XC07B: {Name: "TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384"}, + 0XC07C: {Name: "TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256", ForwardSecret: true}, + 0XC07D: {Name: "TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384", ForwardSecret: true}, + 0XC07E: {Name: "TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256"}, + 0XC07F: {Name: "TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384"}, + 0XC080: {Name: "TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256", ForwardSecret: true}, + 0XC081: {Name: "TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384", ForwardSecret: true}, + 0XC082: {Name: "TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256"}, + 0XC083: {Name: "TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384"}, + 0XC084: {Name: "TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256"}, + 0XC085: {Name: "TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384"}, + 0XC086: {Name: "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256", ForwardSecret: true, EllipticCurve: true}, + 0XC087: {Name: "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384", ForwardSecret: true, EllipticCurve: true}, + 0XC088: {Name: "TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256", EllipticCurve: true}, + 0XC089: {Name: "TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384", EllipticCurve: true}, + 0XC08A: {Name: "TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256", ForwardSecret: true, EllipticCurve: true}, + 0XC08B: {Name: "TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384", ForwardSecret: true, EllipticCurve: true}, + 0XC08C: {Name: "TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256", EllipticCurve: true}, + 0XC08D: {Name: "TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384", EllipticCurve: true}, + 0XC08E: {Name: "TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256"}, + 0XC08F: {Name: "TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384"}, + 0XC090: {Name: "TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256", ForwardSecret: true}, + 0XC091: {Name: "TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384", ForwardSecret: true}, + 0XC092: {Name: "TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256"}, + 0XC093: {Name: "TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384"}, + 0XC094: {Name: "TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256"}, + 0XC095: {Name: "TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384"}, + 0XC096: {Name: "TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256", ForwardSecret: true}, + 0XC097: {Name: "TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384", ForwardSecret: true}, + 0XC098: {Name: "TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256"}, + 0XC099: {Name: "TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384"}, + 0XC09A: {Name: "TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256", ForwardSecret: true, EllipticCurve: true}, + 0XC09B: {Name: "TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384", ForwardSecret: true, EllipticCurve: true}, + 0XC09C: {Name: "TLS_RSA_WITH_AES_128_CCM"}, + 0XC09D: {Name: "TLS_RSA_WITH_AES_256_CCM"}, + 0XC09E: {Name: "TLS_DHE_RSA_WITH_AES_128_CCM", ForwardSecret: true}, + 0XC09F: {Name: "TLS_DHE_RSA_WITH_AES_256_CCM", ForwardSecret: true}, + 0XC0A0: {Name: "TLS_RSA_WITH_AES_128_CCM_8"}, + 0XC0A1: {Name: "TLS_RSA_WITH_AES_256_CCM_8"}, + 0XC0A2: {Name: "TLS_DHE_RSA_WITH_AES_128_CCM_8", ForwardSecret: true}, + 0XC0A3: {Name: "TLS_DHE_RSA_WITH_AES_256_CCM_8", ForwardSecret: true}, + 0XC0A4: {Name: "TLS_PSK_WITH_AES_128_CCM"}, + 0XC0A5: {Name: "TLS_PSK_WITH_AES_256_CCM"}, + 0XC0A6: {Name: "TLS_DHE_PSK_WITH_AES_128_CCM", ForwardSecret: true}, + 0XC0A7: {Name: "TLS_DHE_PSK_WITH_AES_256_CCM", ForwardSecret: true}, + 0XC0A8: {Name: "TLS_PSK_WITH_AES_128_CCM_8"}, + 0XC0A9: {Name: "TLS_PSK_WITH_AES_256_CCM_8"}, + 0XC0AA: {Name: "TLS_PSK_DHE_WITH_AES_128_CCM_8", ForwardSecret: true}, + 0XC0AB: {Name: "TLS_PSK_DHE_WITH_AES_256_CCM_8", ForwardSecret: true}, + 0XC0AC: {Name: "TLS_ECDHE_ECDSA_WITH_AES_128_CCM", ForwardSecret: true, EllipticCurve: true}, + 0XC0AD: {Name: "TLS_ECDHE_ECDSA_WITH_AES_256_CCM", ForwardSecret: true, EllipticCurve: true}, + 0XC0AE: {Name: "TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8", ForwardSecret: true, EllipticCurve: true}, + 0XC0AF: {Name: "TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8", ForwardSecret: true, EllipticCurve: true}, + // Non-IANA standardized cipher suites: + // ChaCha20, Poly1305 cipher suites are defined in + // https://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04 + 0XCC13: {Name: "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", ForwardSecret: true, EllipticCurve: true}, + 0XCC14: {Name: "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", ForwardSecret: true, EllipticCurve: true}, + 0XCC15: {Name: "TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256", ForwardSecret: true, EllipticCurve: true}, +} + +var Curves = map[CurveID]string{ + 0: "Unassigned", + 1: "sect163k1", + 2: "sect163r1", + 3: "sect163r2", + 4: "sect193r1", + 5: "sect193r2", + 6: "sect233k1", + 7: "sect233r1", + 8: "sect239k1", + 9: "sect283k1", + 10: "sect283r1", + 11: "sect409k1", + 12: "sect409r1", + 13: "sect571k1", + 14: "sect571r1", + 15: "secp160k1", + 16: "secp160r1", + 17: "secp160r2", + 18: "secp192k1", + 19: "secp192r1", + 20: "secp224k1", + 21: "secp224r1", + 22: "secp256k1", + 23: "secp256r1", + 24: "secp384r1", + 25: "secp521r1", + 26: "brainpoolP256r1", + 27: "brainpoolP384r1", + 28: "brainpoolP512r1", + 65281: "arbitrary_explicit_prime_curves", + 65282: "arbitrary_explicit_char2_curves", +} diff --git a/vendor/github.com/cloudflare/cfssl/scan/crypto/tls/cfsslscan_handshake.go b/vendor/github.com/cloudflare/cfssl/scan/crypto/tls/cfsslscan_handshake.go new file mode 100644 index 00000000000..16b9262853a --- /dev/null +++ b/vendor/github.com/cloudflare/cfssl/scan/crypto/tls/cfsslscan_handshake.go @@ -0,0 +1,109 @@ +package tls + +// SayHello constructs a simple Client Hello to a server, parses its serverHelloMsg response +// and returns the negotiated ciphersuite ID, and, if an EC cipher suite, the curve ID +func (c *Conn) SayHello(newSigAls []SignatureAndHash) (cipherID, curveType uint16, curveID CurveID, version uint16, certs [][]byte, err error) { + // Set the supported signatures and hashes to the set `newSigAls` + supportedSignatureAlgorithms := make([]signatureAndHash, len(newSigAls)) + for i := range newSigAls { + supportedSignatureAlgorithms[i] = newSigAls[i].internal() + } + + hello := &clientHelloMsg{ + vers: c.config.maxVersion(), + compressionMethods: []uint8{compressionNone}, + random: make([]byte, 32), + ocspStapling: true, + serverName: c.config.ServerName, + supportedCurves: c.config.curvePreferences(), + supportedPoints: []uint8{pointFormatUncompressed}, + nextProtoNeg: len(c.config.NextProtos) > 0, + secureRenegotiation: true, + cipherSuites: c.config.cipherSuites(), + signatureAndHashes: supportedSignatureAlgorithms, + } + serverHello, err := c.sayHello(hello) + if err != nil { + return + } + // Prime the connection, if necessary, for key + // exchange messages by reading off the certificate + // message and, if necessary, the OCSP stapling + // message + var msg interface{} + msg, err = c.readHandshake() + if err != nil { + return + } + certMsg, ok := msg.(*certificateMsg) + if !ok || len(certMsg.certificates) == 0 { + err = unexpectedMessageError(certMsg, msg) + return + } + certs = certMsg.certificates + + if serverHello.ocspStapling { + msg, err = c.readHandshake() + if err != nil { + return + } + certStatusMsg, ok := msg.(*certificateStatusMsg) + if !ok { + err = unexpectedMessageError(certStatusMsg, msg) + return + } + } + + if CipherSuites[serverHello.cipherSuite].EllipticCurve { + + var skx *serverKeyExchangeMsg + skx, err = c.exchangeKeys() + if err != nil { + return + } + if skx.raw[0] != typeServerKeyExchange { + err = unexpectedMessageError(skx, msg) + return + } + if len(skx.key) < 4 { + err = unexpectedMessageError(skx, msg) + return + } + curveType = uint16(skx.key[0]) + // If we have a named curve, report which one it is. + if curveType == 3 { + curveID = CurveID(skx.key[1])<<8 | CurveID(skx.key[2]) + } + } + cipherID, version = serverHello.cipherSuite, serverHello.vers + + return +} + +// sayHello is the backend to SayHello that returns a full serverHelloMsg for processing. +func (c *Conn) sayHello(hello *clientHelloMsg) (serverHello *serverHelloMsg, err error) { + c.writeRecord(recordTypeHandshake, hello.marshal()) + msg, err := c.readHandshake() + if err != nil { + return + } + serverHello, ok := msg.(*serverHelloMsg) + if !ok { + return nil, unexpectedMessageError(serverHello, msg) + } + return +} + +// exchangeKeys continues the handshake to receive the serverKeyExchange message, +// from which we can extract elliptic curve parameters +func (c *Conn) exchangeKeys() (serverKeyExchange *serverKeyExchangeMsg, err error) { + msg, err := c.readHandshake() + if err != nil { + return + } + serverKeyExchange, ok := msg.(*serverKeyExchangeMsg) + if !ok { + return nil, unexpectedMessageError(serverKeyExchange, msg) + } + return +} diff --git a/vendor/github.com/cloudflare/cfssl/scan/crypto/tls/cipher_suites.go b/vendor/github.com/cloudflare/cfssl/scan/crypto/tls/cipher_suites.go new file mode 100644 index 00000000000..869ffa50bd3 --- /dev/null +++ b/vendor/github.com/cloudflare/cfssl/scan/crypto/tls/cipher_suites.go @@ -0,0 +1,289 @@ +// Copyright 2010 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/aes" + "crypto/cipher" + "crypto/des" + "crypto/hmac" + "crypto/rc4" + "crypto/sha1" + "crypto/x509" + "hash" +) + +// a keyAgreement implements the client and server side of a TLS key agreement +// protocol by generating and processing key exchange messages. +type keyAgreement interface { + // On the server side, the first two methods are called in order. + + // 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) + + // 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) +} + +const ( + // suiteECDH indicates that the cipher suite involves elliptic curve + // Diffie-Hellman. This means that it should only be selected when the + // client indicates that it supports ECC with a curve and point format + // that we're happy with. + suiteECDHE = 1 << iota + // suiteECDSA indicates that the cipher suite involves an ECDSA + // signature and therefore may only be selected when the server's + // certificate is ECDSA. If this is not set then the cipher suite is + // RSA based. + suiteECDSA + // suiteTLS12 indicates that the cipher suite should only be advertised + // and accepted when using TLS 1.2. + suiteTLS12 + // suiteSHA384 indicates that the cipher suite uses SHA384 as the + // handshake hash. + suiteSHA384 + // suiteDefaultOff indicates that this cipher suite is not included by + // default. + suiteDefaultOff +) + +// A cipherSuite is a specific combination of key agreement, cipher and MAC +// function. All cipher suites currently assume RSA key agreement. +type cipherSuite struct { + id uint16 + // the lengths, in bytes, of the key material needed for each component. + keyLen int + macLen int + ivLen int + ka func(version uint16) keyAgreement + // flags is a bitmask of the suite* values, above. + flags int + cipher func(key, iv []byte, isRead bool) interface{} + mac func(version uint16, macKey []byte) macFunction + aead func(key, fixedNonce []byte) cipher.AEAD +} + +var cipherSuites = []*cipherSuite{ + // Ciphersuite order is chosen so that ECDHE comes before plain RSA + // and RC4 comes before AES (because of the Lucky13 attack). + {TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadAESGCM}, + {TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12, nil, nil, aeadAESGCM}, + {TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM}, + {TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM}, + {TLS_ECDHE_RSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheRSAKA, suiteECDHE | suiteDefaultOff, cipherRC4, macSHA1, nil}, + {TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteDefaultOff, cipherRC4, macSHA1, nil}, + {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil}, + {TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherAES, macSHA1, nil}, + {TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil}, + {TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherAES, macSHA1, nil}, + {TLS_RSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, rsaKA, suiteTLS12, nil, nil, aeadAESGCM}, + {TLS_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, rsaKA, suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM}, + {TLS_RSA_WITH_RC4_128_SHA, 16, 20, 0, rsaKA, suiteDefaultOff, cipherRC4, macSHA1, nil}, + {TLS_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil}, + {TLS_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil}, + {TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, ecdheRSAKA, suiteECDHE, cipher3DES, macSHA1, nil}, + {TLS_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, rsaKA, 0, cipher3DES, macSHA1, nil}, +} + +func cipherRC4(key, iv []byte, isRead bool) interface{} { + cipher, _ := rc4.NewCipher(key) + return cipher +} + +func cipher3DES(key, iv []byte, isRead bool) interface{} { + block, _ := des.NewTripleDESCipher(key) + if isRead { + return cipher.NewCBCDecrypter(block, iv) + } + return cipher.NewCBCEncrypter(block, iv) +} + +func cipherAES(key, iv []byte, isRead bool) interface{} { + block, _ := aes.NewCipher(key) + if isRead { + return cipher.NewCBCDecrypter(block, iv) + } + return cipher.NewCBCEncrypter(block, iv) +} + +// macSHA1 returns a macFunction for the given protocol version. +func macSHA1(version uint16, key []byte) macFunction { + if version == VersionSSL30 { + mac := ssl30MAC{ + h: sha1.New(), + key: make([]byte, len(key)), + } + copy(mac.key, key) + return mac + } + return tls10MAC{hmac.New(sha1.New, key)} +} + +type macFunction interface { + Size() int + MAC(digestBuf, seq, header, data []byte) []byte +} + +// fixedNonceAEAD wraps an AEAD and prefixes a fixed portion of the nonce to +// each call. +type fixedNonceAEAD struct { + // sealNonce and openNonce are buffers where the larger nonce will be + // constructed. Since a seal and open operation may be running + // concurrently, there is a separate buffer for each. + sealNonce, openNonce []byte + aead cipher.AEAD +} + +func (f *fixedNonceAEAD) NonceSize() int { return 8 } +func (f *fixedNonceAEAD) Overhead() int { return f.aead.Overhead() } + +func (f *fixedNonceAEAD) Seal(out, nonce, plaintext, additionalData []byte) []byte { + copy(f.sealNonce[len(f.sealNonce)-8:], nonce) + return f.aead.Seal(out, f.sealNonce, plaintext, additionalData) +} + +func (f *fixedNonceAEAD) Open(out, nonce, plaintext, additionalData []byte) ([]byte, error) { + copy(f.openNonce[len(f.openNonce)-8:], nonce) + return f.aead.Open(out, f.openNonce, plaintext, additionalData) +} + +func aeadAESGCM(key, fixedNonce []byte) cipher.AEAD { + aes, err := aes.NewCipher(key) + if err != nil { + panic(err) + } + aead, err := cipher.NewGCM(aes) + if err != nil { + panic(err) + } + + nonce1, nonce2 := make([]byte, 12), make([]byte, 12) + copy(nonce1, fixedNonce) + copy(nonce2, fixedNonce) + + return &fixedNonceAEAD{nonce1, nonce2, aead} +} + +// ssl30MAC implements the SSLv3 MAC function, as defined in +// www.mozilla.org/projects/security/pki/nss/ssl/draft302.txt section 5.2.3.1 +type ssl30MAC struct { + h hash.Hash + key []byte +} + +func (s ssl30MAC) Size() int { + return s.h.Size() +} + +var ssl30Pad1 = [48]byte{0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36} + +var ssl30Pad2 = [48]byte{0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c} + +func (s ssl30MAC) MAC(digestBuf, seq, header, data []byte) []byte { + padLength := 48 + if s.h.Size() == 20 { + padLength = 40 + } + + s.h.Reset() + s.h.Write(s.key) + s.h.Write(ssl30Pad1[:padLength]) + s.h.Write(seq) + s.h.Write(header[:1]) + s.h.Write(header[3:5]) + s.h.Write(data) + digestBuf = s.h.Sum(digestBuf[:0]) + + s.h.Reset() + s.h.Write(s.key) + s.h.Write(ssl30Pad2[:padLength]) + s.h.Write(digestBuf) + return s.h.Sum(digestBuf[:0]) +} + +// tls10MAC implements the TLS 1.0 MAC function. RFC 2246, section 6.2.3. +type tls10MAC struct { + h hash.Hash +} + +func (s tls10MAC) Size() int { + return s.h.Size() +} + +func (s tls10MAC) MAC(digestBuf, seq, header, data []byte) []byte { + s.h.Reset() + s.h.Write(seq) + s.h.Write(header) + s.h.Write(data) + return s.h.Sum(digestBuf[:0]) +} + +func rsaKA(version uint16) keyAgreement { + return rsaKeyAgreement{} +} + +func ecdheECDSAKA(version uint16) keyAgreement { + return &ecdheKeyAgreement{ + sigType: signatureECDSA, + version: version, + } +} + +func ecdheRSAKA(version uint16) keyAgreement { + return &ecdheKeyAgreement{ + sigType: signatureRSA, + version: version, + } +} + +// mutualCipherSuite returns a cipherSuite given a list of supported +// ciphersuites and the id requested by the peer. +func mutualCipherSuite(have []uint16, want uint16) *cipherSuite { + for _, id := range have { + if id == want { + for _, suite := range cipherSuites { + if suite.id == want { + return suite + } + } + return nil + } + } + return nil +} + +// A list of the possible cipher suite ids. Taken from +// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml +const ( + TLS_RSA_WITH_RC4_128_SHA uint16 = 0x0005 + TLS_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0x000a + TLS_RSA_WITH_AES_128_CBC_SHA uint16 = 0x002f + TLS_RSA_WITH_AES_256_CBC_SHA uint16 = 0x0035 + TLS_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0x009c + TLS_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0x009d + TLS_ECDHE_ECDSA_WITH_RC4_128_SHA uint16 = 0xc007 + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA uint16 = 0xc009 + TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA uint16 = 0xc00a + TLS_ECDHE_RSA_WITH_RC4_128_SHA uint16 = 0xc011 + TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0xc012 + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA uint16 = 0xc013 + TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA uint16 = 0xc014 + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0xc02f + TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 uint16 = 0xc02b + TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0xc030 + TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 uint16 = 0xc02c + + // TLS_FALLBACK_SCSV isn't a standard cipher suite but an indicator + // that the client is doing version fallback. See + // https://tools.ietf.org/html/draft-ietf-tls-downgrade-scsv-00. + TLS_FALLBACK_SCSV uint16 = 0x5600 +) diff --git a/vendor/github.com/cloudflare/cfssl/scan/crypto/tls/common.go b/vendor/github.com/cloudflare/cfssl/scan/crypto/tls/common.go new file mode 100644 index 00000000000..c68ebfe188b --- /dev/null +++ b/vendor/github.com/cloudflare/cfssl/scan/crypto/tls/common.go @@ -0,0 +1,714 @@ +// Copyright 2009 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 ( + "container/list" + "crypto" + "crypto/rand" + "crypto/sha512" + "crypto/x509" + "errors" + "fmt" + "io" + "math/big" + "strings" + "sync" + "time" +) + +const ( + VersionSSL30 = 0x0300 + VersionTLS10 = 0x0301 + VersionTLS11 = 0x0302 + VersionTLS12 = 0x0303 +) + +const ( + maxPlaintext = 16384 // maximum plaintext payload length + maxCiphertext = 16384 + 2048 // maximum ciphertext payload length + recordHeaderLen = 5 // record header length + maxHandshake = 65536 // maximum handshake we support (protocol max is 16 MB) + + minVersion = VersionTLS10 + maxVersion = VersionTLS12 +) + +// TLS record types. +type recordType uint8 + +const ( + recordTypeChangeCipherSpec recordType = 20 + recordTypeAlert recordType = 21 + recordTypeHandshake recordType = 22 + recordTypeApplicationData recordType = 23 +) + +// TLS handshake message types. +const ( + typeClientHello uint8 = 1 + typeServerHello uint8 = 2 + typeNewSessionTicket uint8 = 4 + typeCertificate uint8 = 11 + typeServerKeyExchange uint8 = 12 + typeCertificateRequest uint8 = 13 + typeServerHelloDone uint8 = 14 + typeCertificateVerify uint8 = 15 + typeClientKeyExchange uint8 = 16 + typeFinished uint8 = 20 + typeCertificateStatus uint8 = 22 + typeNextProtocol uint8 = 67 // Not IANA assigned +) + +// TLS compression types. +const ( + compressionNone uint8 = 0 +) + +// TLS extension numbers +const ( + extensionServerName uint16 = 0 + extensionStatusRequest uint16 = 5 + extensionSupportedCurves uint16 = 10 + extensionSupportedPoints uint16 = 11 + extensionSignatureAlgorithms uint16 = 13 + extensionALPN uint16 = 16 + extensionSCT uint16 = 18 // https://tools.ietf.org/html/rfc6962#section-6 + extensionSessionTicket uint16 = 35 + extensionNextProtoNeg uint16 = 13172 // not IANA assigned + extensionRenegotiationInfo uint16 = 0xff01 +) + +// TLS signaling cipher suite values +const ( + scsvRenegotiation uint16 = 0x00ff +) + +// CurveID is the type of a TLS identifier for an elliptic curve. See +// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-8 +type CurveID uint16 + +const ( + CurveP256 CurveID = 23 + CurveP384 CurveID = 24 + CurveP521 CurveID = 25 +) + +// TLS Elliptic Curve Point Formats +// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-9 +const ( + pointFormatUncompressed uint8 = 0 +) + +// TLS CertificateStatusType (RFC 3546) +const ( + statusTypeOCSP uint8 = 1 +) + +// Certificate types (for certificateRequestMsg) +const ( + certTypeRSASign = 1 // A certificate containing an RSA key + certTypeDSSSign = 2 // A certificate containing a DSA key + certTypeRSAFixedDH = 3 // A certificate containing a static DH key + certTypeDSSFixedDH = 4 // A certificate containing a static DH key + + // See RFC4492 sections 3 and 5.5. + certTypeECDSASign = 64 // A certificate containing an ECDSA-capable public key, signed with ECDSA. + certTypeRSAFixedECDH = 65 // A certificate containing an ECDH-capable public key, signed with RSA. + certTypeECDSAFixedECDH = 66 // A certificate containing an ECDH-capable public key, signed with ECDSA. + + // Rest of these are reserved by the TLS spec +) + +// Hash functions for TLS 1.2 (See RFC 5246, section A.4.1) +const ( + hashSHA1 uint8 = 2 + hashSHA256 uint8 = 4 + hashSHA384 uint8 = 5 +) + +// Signature algorithms for TLS 1.2 (See RFC 5246, section A.4.1) +const ( + signatureRSA uint8 = 1 + signatureECDSA uint8 = 3 +) + +// signatureAndHash mirrors the TLS 1.2, SignatureAndHashAlgorithm struct. See +// RFC 5246, section A.4.1. +type signatureAndHash struct { + hash, signature uint8 +} + +// supportedSignatureAlgorithms contains the signature and hash algorithms that +// the code advertises as supported in a TLS 1.2 ClientHello and in a TLS 1.2 +// CertificateRequest. +var supportedSignatureAlgorithms = []signatureAndHash{ + {hashSHA256, signatureRSA}, + {hashSHA256, signatureECDSA}, + {hashSHA384, signatureRSA}, + {hashSHA384, signatureECDSA}, + {hashSHA1, signatureRSA}, + {hashSHA1, signatureECDSA}, +} + +// ConnectionState records basic TLS details about the connection. +type ConnectionState struct { + Version uint16 // TLS version used by the connection (e.g. VersionTLS12) + HandshakeComplete bool // TLS handshake is complete + DidResume bool // connection resumes a previous TLS connection + CipherSuite uint16 // cipher suite in use (TLS_RSA_WITH_RC4_128_SHA, ...) + NegotiatedProtocol string // negotiated next protocol (from Config.NextProtos) + NegotiatedProtocolIsMutual bool // negotiated protocol was advertised by server + ServerName string // server name requested by client, if any (server side only) + PeerCertificates []*x509.Certificate // certificate chain presented by remote peer + 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 + + // TLSUnique contains the "tls-unique" channel binding value (see RFC + // 5929, section 3). For resumed sessions this value will be nil + // because resumption does not include enough context (see + // https://secure-resumption.com/#channelbindings). This will change in + // future versions of Go once the TLS master-secret fix has been + // standardized and implemented. + TLSUnique []byte +} + +// ClientAuthType declares the policy the server will follow for +// TLS Client Authentication. +type ClientAuthType int + +const ( + NoClientCert ClientAuthType = iota + RequestClientCert + RequireAnyClientCert + VerifyClientCertIfGiven + RequireAndVerifyClientCert +) + +// ClientSessionState contains the state needed by clients to resume TLS +// sessions. +type ClientSessionState struct { + sessionTicket []uint8 // Encrypted ticket used for session resumption with server + vers uint16 // SSL/TLS version negotiated for the session + cipherSuite uint16 // Ciphersuite negotiated for the session + masterSecret []byte // MasterSecret generated by client on a full handshake + serverCertificates []*x509.Certificate // Certificate chain presented by the server + verifiedChains [][]*x509.Certificate // Certificate chains we built for verification +} + +// ClientSessionCache is a cache of ClientSessionState objects that can be used +// by a client to resume a TLS session with a given server. ClientSessionCache +// implementations should expect to be called concurrently from different +// goroutines. +type ClientSessionCache interface { + // Get searches for a ClientSessionState associated with the given key. + // On return, ok is true if one was found. + Get(sessionKey string) (session *ClientSessionState, ok bool) + + // Put adds the ClientSessionState to the cache with the given key. + Put(sessionKey string, cs *ClientSessionState) +} + +// ClientHelloInfo contains information from a ClientHello message in order to +// guide certificate selection in the GetCertificate callback. +type ClientHelloInfo struct { + // CipherSuites lists the CipherSuites supported by the client (e.g. + // TLS_RSA_WITH_RC4_128_SHA). + CipherSuites []uint16 + + // ServerName indicates the name of the server requested by the client + // in order to support virtual hosting. ServerName is only set if the + // client is using SNI (see + // http://tools.ietf.org/html/rfc4366#section-3.1). + ServerName string + + // SupportedCurves lists the elliptic curves supported by the client. + // SupportedCurves is set only if the Supported Elliptic Curves + // Extension is being used (see + // http://tools.ietf.org/html/rfc4492#section-5.1.1). + SupportedCurves []CurveID + + // SupportedPoints lists the point formats supported by the client. + // SupportedPoints is set only if the Supported Point Formats Extension + // is being used (see + // http://tools.ietf.org/html/rfc4492#section-5.1.2). + SupportedPoints []uint8 +} + +// A Config structure is used to configure a TLS client or server. +// After one has been passed to a TLS function it must not be +// modified. A Config may be reused; the tls package will also not +// modify it. +type Config struct { + // Rand provides the source of entropy for nonces and RSA blinding. + // If Rand is nil, TLS uses the cryptographic random reader in package + // crypto/rand. + // The Reader must be safe for use by multiple goroutines. + Rand io.Reader + + // Time returns the current time as the number of seconds since the epoch. + // If Time is nil, TLS uses time.Now. + Time func() time.Time + + // Certificates contains one or more certificate chains + // to present to the other side of the connection. + // Server configurations must include at least one certificate + // or else set GetCertificate. + Certificates []Certificate + + // NameToCertificate maps from a certificate name to an element of + // Certificates. Note that a certificate name can be of the form + // '*.example.com' and so doesn't have to be a domain name as such. + // See Config.BuildNameToCertificate + // The nil value causes the first element of Certificates to be used + // for all connections. + NameToCertificate map[string]*Certificate + + // GetCertificate returns a Certificate based on the given + // ClientHelloInfo. It will only be called if the client supplies SNI + // information or if Certificates is empty. + // + // If GetCertificate is nil or returns nil, then the certificate is + // retrieved from NameToCertificate. If NameToCertificate is nil, the + // first element of Certificates will be used. + GetCertificate func(clientHello *ClientHelloInfo) (*Certificate, error) + + // RootCAs defines the set of root certificate authorities + // that clients use when verifying server certificates. + // If RootCAs is nil, TLS uses the host's root CA set. + RootCAs *x509.CertPool + + // NextProtos is a list of supported, application level protocols. + NextProtos []string + + // ServerName is used to verify the hostname on the returned + // certificates unless InsecureSkipVerify is given. It is also included + // in the client's handshake to support virtual hosting unless it is + // an IP address. + ServerName string + + // ClientAuth determines the server's policy for + // TLS Client Authentication. The default is NoClientCert. + ClientAuth ClientAuthType + + // ClientCAs defines the set of root certificate authorities + // that servers use if required to verify a client certificate + // by the policy in ClientAuth. + ClientCAs *x509.CertPool + + // InsecureSkipVerify controls whether a client verifies the + // server's certificate chain and host name. + // If InsecureSkipVerify is true, TLS accepts any certificate + // presented by the server and any host name in that certificate. + // In this mode, TLS is susceptible to man-in-the-middle attacks. + // This should be used only for testing. + InsecureSkipVerify bool + + // CipherSuites is a list of supported cipher suites. If CipherSuites + // is nil, TLS uses a list of suites supported by the implementation. + CipherSuites []uint16 + + // PreferServerCipherSuites controls whether the server selects the + // client's most preferred ciphersuite, or the server's most preferred + // ciphersuite. If true then the server's preference, as expressed in + // the order of elements in CipherSuites, is used. + PreferServerCipherSuites bool + + // SessionTicketsDisabled may be set to true to disable session ticket + // (resumption) support. + SessionTicketsDisabled bool + + // SessionTicketKey is used by TLS servers to provide session + // resumption. See RFC 5077. If zero, it will be filled with + // random data before the first server handshake. + // + // If multiple servers are terminating connections for the same host + // they should all have the same SessionTicketKey. If the + // SessionTicketKey leaks, previously recorded and future TLS + // connections using that key are compromised. + SessionTicketKey [32]byte + + // SessionCache is a cache of ClientSessionState entries for TLS session + // resumption. + ClientSessionCache ClientSessionCache + + // MinVersion contains the minimum SSL/TLS version that is acceptable. + // If zero, then TLS 1.0 is taken as the minimum. + MinVersion uint16 + + // MaxVersion contains the maximum SSL/TLS version that is acceptable. + // If zero, then the maximum version supported by this package is used, + // which is currently TLS 1.2. + MaxVersion uint16 + + // CurvePreferences contains the elliptic curves that will be used in + // an ECDHE handshake, in preference order. If empty, the default will + // be used. + CurvePreferences []CurveID + + serverInitOnce sync.Once // guards calling (*Config).serverInit + + // mutex protects sessionTicketKeys + mutex sync.RWMutex + // sessionTicketKeys contains zero or more ticket keys. If the length + // is zero, SessionTicketsDisabled must be true. The first key is used + // for new tickets and any subsequent keys can be used to decrypt old + // tickets. + sessionTicketKeys []ticketKey +} + +// ticketKeyNameLen is the number of bytes of identifier that is prepended to +// an encrypted session ticket in order to identify the key used to encrypt it. +const ticketKeyNameLen = 16 + +// ticketKey is the internal representation of a session ticket key. +type ticketKey struct { + // keyName is an opaque byte string that serves to identify the session + // ticket key. It's exposed as plaintext in every session ticket. + keyName [ticketKeyNameLen]byte + aesKey [16]byte + hmacKey [16]byte +} + +// ticketKeyFromBytes converts from the external representation of a session +// ticket key to a ticketKey. Externally, session ticket keys are 32 random +// bytes and this function expands that into sufficient name and key material. +func ticketKeyFromBytes(b [32]byte) (key ticketKey) { + hashed := sha512.Sum512(b[:]) + copy(key.keyName[:], hashed[:ticketKeyNameLen]) + copy(key.aesKey[:], hashed[ticketKeyNameLen:ticketKeyNameLen+16]) + copy(key.hmacKey[:], hashed[ticketKeyNameLen+16:ticketKeyNameLen+32]) + return key +} + +func (c *Config) serverInit() { + if c.SessionTicketsDisabled { + return + } + + alreadySet := false + for _, b := range c.SessionTicketKey { + if b != 0 { + alreadySet = true + break + } + } + + if !alreadySet { + if _, err := io.ReadFull(c.rand(), c.SessionTicketKey[:]); err != nil { + c.SessionTicketsDisabled = true + return + } + } + + c.sessionTicketKeys = []ticketKey{ticketKeyFromBytes(c.SessionTicketKey)} +} + +func (c *Config) ticketKeys() []ticketKey { + c.mutex.RLock() + // c.sessionTicketKeys is constant once created. SetSessionTicketKeys + // will only update it by replacing it with a new value. + ret := c.sessionTicketKeys + c.mutex.RUnlock() + return ret +} + +// SetSessionTicketKeys updates the session ticket keys for a server. The first +// key will be used when creating new tickets, while all keys can be used for +// decrypting tickets. It is safe to call this function while the server is +// running in order to rotate the session ticket keys. The function will panic +// if keys is empty. +func (c *Config) SetSessionTicketKeys(keys [][32]byte) { + if len(keys) == 0 { + panic("tls: keys must have at least one key") + } + + newKeys := make([]ticketKey, len(keys)) + for i, bytes := range keys { + newKeys[i] = ticketKeyFromBytes(bytes) + } + + c.mutex.Lock() + c.sessionTicketKeys = newKeys + c.mutex.Unlock() +} + +func (c *Config) rand() io.Reader { + r := c.Rand + if r == nil { + return rand.Reader + } + return r +} + +func (c *Config) time() time.Time { + t := c.Time + if t == nil { + t = time.Now + } + return t() +} + +func (c *Config) cipherSuites() []uint16 { + s := c.CipherSuites + if s == nil { + s = defaultCipherSuites() + } + return s +} + +func (c *Config) minVersion() uint16 { + if c == nil || c.MinVersion == 0 { + return minVersion + } + return c.MinVersion +} + +func (c *Config) maxVersion() uint16 { + if c == nil || c.MaxVersion == 0 { + return maxVersion + } + return c.MaxVersion +} + +var defaultCurvePreferences = []CurveID{CurveP256, CurveP384, CurveP521} + +func (c *Config) curvePreferences() []CurveID { + if c == nil || len(c.CurvePreferences) == 0 { + return defaultCurvePreferences + } + return c.CurvePreferences +} + +// mutualVersion returns the protocol version to use given the advertised +// version of the peer. +func (c *Config) mutualVersion(vers uint16) (uint16, bool) { + minVersion := c.minVersion() + maxVersion := c.maxVersion() + + if vers < minVersion { + return 0, false + } + if vers > maxVersion { + vers = maxVersion + } + return vers, true +} + +// getCertificate returns the best certificate for the given ClientHelloInfo, +// defaulting to the first element of c.Certificates. +func (c *Config) getCertificate(clientHello *ClientHelloInfo) (*Certificate, error) { + if c.GetCertificate != nil && + (len(c.Certificates) == 0 || len(clientHello.ServerName) > 0) { + cert, err := c.GetCertificate(clientHello) + if cert != nil || err != nil { + return cert, err + } + } + + if len(c.Certificates) == 0 { + return nil, errors.New("crypto/tls: no certificates configured") + } + + if len(c.Certificates) == 1 || c.NameToCertificate == nil { + // There's only one choice, so no point doing any work. + return &c.Certificates[0], nil + } + + name := strings.ToLower(clientHello.ServerName) + for len(name) > 0 && name[len(name)-1] == '.' { + name = name[:len(name)-1] + } + + if cert, ok := c.NameToCertificate[name]; ok { + return cert, nil + } + + // try replacing labels in the name with wildcards until we get a + // match. + labels := strings.Split(name, ".") + for i := range labels { + labels[i] = "*" + candidate := strings.Join(labels, ".") + if cert, ok := c.NameToCertificate[candidate]; ok { + return cert, nil + } + } + + // If nothing matches, return the first certificate. + return &c.Certificates[0], nil +} + +// BuildNameToCertificate parses c.Certificates and builds c.NameToCertificate +// from the CommonName and SubjectAlternateName fields of each of the leaf +// certificates. +func (c *Config) BuildNameToCertificate() { + c.NameToCertificate = make(map[string]*Certificate) + for i := range c.Certificates { + cert := &c.Certificates[i] + x509Cert, err := x509.ParseCertificate(cert.Certificate[0]) + if err != nil { + continue + } + if len(x509Cert.Subject.CommonName) > 0 { + c.NameToCertificate[x509Cert.Subject.CommonName] = cert + } + for _, san := range x509Cert.DNSNames { + c.NameToCertificate[san] = cert + } + } +} + +// A Certificate is a chain of one or more certificates, leaf first. +type Certificate struct { + Certificate [][]byte + // PrivateKey contains the private key corresponding to the public key + // in Leaf. For a server, this must implement crypto.Signer and/or + // crypto.Decrypter, with an RSA or ECDSA PublicKey. For a client + // (performing client authentication), this must be a crypto.Signer + // with an RSA or ECDSA PublicKey. + PrivateKey crypto.PrivateKey + // OCSPStaple contains an optional OCSP response which will be served + // to clients that request it. + OCSPStaple []byte + // SignedCertificateTimestamps contains an optional list of Signed + // Certificate Timestamps which will be served to clients that request it. + SignedCertificateTimestamps [][]byte + // Leaf is the parsed form of the leaf certificate, which may be + // initialized using x509.ParseCertificate to reduce per-handshake + // processing for TLS clients doing client authentication. If nil, the + // leaf certificate will be parsed as needed. + Leaf *x509.Certificate +} + +// A TLS record. +type record struct { + contentType recordType + major, minor uint8 + payload []byte +} + +type handshakeMessage interface { + marshal() []byte + unmarshal([]byte) bool +} + +// lruSessionCache is a ClientSessionCache implementation that uses an LRU +// caching strategy. +type lruSessionCache struct { + sync.Mutex + + m map[string]*list.Element + q *list.List + capacity int +} + +type lruSessionCacheEntry struct { + sessionKey string + state *ClientSessionState +} + +// NewLRUClientSessionCache returns a ClientSessionCache with the given +// capacity that uses an LRU strategy. If capacity is < 1, a default capacity +// is used instead. +func NewLRUClientSessionCache(capacity int) ClientSessionCache { + const defaultSessionCacheCapacity = 64 + + if capacity < 1 { + capacity = defaultSessionCacheCapacity + } + return &lruSessionCache{ + m: make(map[string]*list.Element), + q: list.New(), + capacity: capacity, + } +} + +// Put adds the provided (sessionKey, cs) pair to the cache. +func (c *lruSessionCache) Put(sessionKey string, cs *ClientSessionState) { + c.Lock() + defer c.Unlock() + + if elem, ok := c.m[sessionKey]; ok { + entry := elem.Value.(*lruSessionCacheEntry) + entry.state = cs + c.q.MoveToFront(elem) + return + } + + if c.q.Len() < c.capacity { + entry := &lruSessionCacheEntry{sessionKey, cs} + c.m[sessionKey] = c.q.PushFront(entry) + return + } + + elem := c.q.Back() + entry := elem.Value.(*lruSessionCacheEntry) + delete(c.m, entry.sessionKey) + entry.sessionKey = sessionKey + entry.state = cs + c.q.MoveToFront(elem) + c.m[sessionKey] = elem +} + +// Get returns the ClientSessionState value associated with a given key. It +// returns (nil, false) if no value is found. +func (c *lruSessionCache) Get(sessionKey string) (*ClientSessionState, bool) { + c.Lock() + defer c.Unlock() + + if elem, ok := c.m[sessionKey]; ok { + c.q.MoveToFront(elem) + return elem.Value.(*lruSessionCacheEntry).state, true + } + return nil, false +} + +// TODO(jsing): Make these available to both crypto/x509 and crypto/tls. +type dsaSignature struct { + R, S *big.Int +} + +type ecdsaSignature dsaSignature + +var emptyConfig Config + +func defaultConfig() *Config { + return &emptyConfig +} + +var ( + once sync.Once + varDefaultCipherSuites []uint16 +) + +func defaultCipherSuites() []uint16 { + once.Do(initDefaultCipherSuites) + return varDefaultCipherSuites +} + +func initDefaultCipherSuites() { + varDefaultCipherSuites = make([]uint16, 0, len(cipherSuites)) + for _, suite := range cipherSuites { + if suite.flags&suiteDefaultOff != 0 { + continue + } + varDefaultCipherSuites = append(varDefaultCipherSuites, suite.id) + } +} + +func unexpectedMessageError(wanted, got interface{}) error { + return fmt.Errorf("tls: received unexpected handshake message of type %T when waiting for %T", got, wanted) +} + +func isSupportedSignatureAndHash(sigHash signatureAndHash, sigHashes []signatureAndHash) bool { + for _, s := range sigHashes { + if s == sigHash { + return true + } + } + return false +} diff --git a/vendor/github.com/cloudflare/cfssl/scan/crypto/tls/conn.go b/vendor/github.com/cloudflare/cfssl/scan/crypto/tls/conn.go new file mode 100644 index 00000000000..03775685fb6 --- /dev/null +++ b/vendor/github.com/cloudflare/cfssl/scan/crypto/tls/conn.go @@ -0,0 +1,1091 @@ +// Copyright 2010 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. + +// TLS low level connection and record layer + +package tls + +import ( + "bytes" + "crypto/cipher" + "crypto/subtle" + "crypto/x509" + "errors" + "fmt" + "io" + "net" + "sync" + "sync/atomic" + "time" +) + +// A Conn represents a secured connection. +// It implements the net.Conn interface. +type Conn struct { + // constant + conn net.Conn + isClient bool + + // constant after handshake; protected by handshakeMutex + handshakeMutex sync.Mutex // handshakeMutex < in.Mutex, out.Mutex, errMutex + handshakeErr error // error resulting from handshake + vers uint16 // TLS version + haveVers bool // version has been negotiated + config *Config // configuration passed to constructor + handshakeComplete bool + didResume bool // whether this connection was a session resumption + cipherSuite uint16 + ocspResponse []byte // stapled OCSP response + 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 + // serverName contains the server name indicated by the client, if any. + serverName string + // firstFinished contains the first Finished hash sent during the + // handshake. This is the "tls-unique" channel binding value. + firstFinished [12]byte + + clientProtocol string + clientProtocolFallback bool + + // input/output + in, out halfConn // in.Mutex < out.Mutex + rawInput *block // raw input, right off the wire + input *block // application data waiting to be read + hand bytes.Buffer // handshake data waiting to be read + + // activeCall is an atomic int32; the low bit is whether Close has + // been called. the rest of the bits are the number of goroutines + // in Conn.Write. + activeCall int32 + + tmp [16]byte +} + +// Access to net.Conn methods. +// Cannot just embed net.Conn because that would +// export the struct field too. + +// LocalAddr returns the local network address. +func (c *Conn) LocalAddr() net.Addr { + return c.conn.LocalAddr() +} + +// RemoteAddr returns the remote network address. +func (c *Conn) RemoteAddr() net.Addr { + return c.conn.RemoteAddr() +} + +// SetDeadline sets the read and write deadlines associated with the connection. +// A zero value for t means Read and Write will not time out. +// After a Write has timed out, the TLS state is corrupt and all future writes will return the same error. +func (c *Conn) SetDeadline(t time.Time) error { + return c.conn.SetDeadline(t) +} + +// SetReadDeadline sets the read deadline on the underlying connection. +// A zero value for t means Read will not time out. +func (c *Conn) SetReadDeadline(t time.Time) error { + return c.conn.SetReadDeadline(t) +} + +// SetWriteDeadline sets the write deadline on the underlying connection. +// A zero value for t means Write will not time out. +// After a Write has timed out, the TLS state is corrupt and all future writes will return the same error. +func (c *Conn) SetWriteDeadline(t time.Time) error { + return c.conn.SetWriteDeadline(t) +} + +// A halfConn represents one direction of the record layer +// connection, either sending or receiving. +type halfConn struct { + sync.Mutex + + err error // first permanent error + version uint16 // protocol version + cipher interface{} // cipher algorithm + mac macFunction + seq [8]byte // 64-bit sequence number + bfree *block // list of free blocks + additionalData [13]byte // to avoid allocs; interface method args escape + + nextCipher interface{} // next encryption state + nextMac macFunction // next MAC algorithm + + // used to save allocating a new buffer for each MAC. + inDigestBuf, outDigestBuf []byte +} + +func (hc *halfConn) setErrorLocked(err error) error { + hc.err = err + return err +} + +func (hc *halfConn) error() error { + hc.Lock() + err := hc.err + hc.Unlock() + return err +} + +// prepareCipherSpec sets the encryption and MAC states +// that a subsequent changeCipherSpec will use. +func (hc *halfConn) prepareCipherSpec(version uint16, cipher interface{}, mac macFunction) { + hc.version = version + hc.nextCipher = cipher + hc.nextMac = mac +} + +// changeCipherSpec changes the encryption and MAC states +// to the ones previously passed to prepareCipherSpec. +func (hc *halfConn) changeCipherSpec() error { + if hc.nextCipher == nil { + return alertInternalError + } + hc.cipher = hc.nextCipher + hc.mac = hc.nextMac + hc.nextCipher = nil + hc.nextMac = nil + for i := range hc.seq { + hc.seq[i] = 0 + } + return nil +} + +// incSeq increments the sequence number. +func (hc *halfConn) incSeq() { + for i := 7; i >= 0; i-- { + hc.seq[i]++ + if hc.seq[i] != 0 { + return + } + } + + // Not allowed to let sequence number wrap. + // Instead, must renegotiate before it does. + // Not likely enough to bother. + panic("TLS: sequence number wraparound") +} + +// resetSeq resets the sequence number to zero. +func (hc *halfConn) resetSeq() { + for i := range hc.seq { + hc.seq[i] = 0 + } +} + +// removePadding returns an unpadded slice, in constant time, which is a prefix +// of the input. It also returns a byte which is equal to 255 if the padding +// was valid and 0 otherwise. See RFC 2246, section 6.2.3.2 +func removePadding(payload []byte) ([]byte, byte) { + if len(payload) < 1 { + return payload, 0 + } + + paddingLen := payload[len(payload)-1] + t := uint(len(payload)-1) - uint(paddingLen) + // if len(payload) >= (paddingLen - 1) then the MSB of t is zero + good := byte(int32(^t) >> 31) + + toCheck := 255 // the maximum possible padding length + // The length of the padded data is public, so we can use an if here + if toCheck+1 > len(payload) { + toCheck = len(payload) - 1 + } + + for i := 0; i < toCheck; i++ { + t := uint(paddingLen) - uint(i) + // if i <= paddingLen then the MSB of t is zero + mask := byte(int32(^t) >> 31) + b := payload[len(payload)-1-i] + good &^= mask&paddingLen ^ mask&b + } + + // We AND together the bits of good and replicate the result across + // all the bits. + good &= good << 4 + good &= good << 2 + good &= good << 1 + good = uint8(int8(good) >> 7) + + toRemove := good&paddingLen + 1 + return payload[:len(payload)-int(toRemove)], good +} + +// removePaddingSSL30 is a replacement for removePadding in the case that the +// protocol version is SSLv3. In this version, the contents of the padding +// are random and cannot be checked. +func removePaddingSSL30(payload []byte) ([]byte, byte) { + if len(payload) < 1 { + return payload, 0 + } + + paddingLen := int(payload[len(payload)-1]) + 1 + if paddingLen > len(payload) { + return payload, 0 + } + + return payload[:len(payload)-paddingLen], 255 +} + +func roundUp(a, b int) int { + return a + (b-a%b)%b +} + +// cbcMode is an interface for block ciphers using cipher block chaining. +type cbcMode interface { + cipher.BlockMode + SetIV([]byte) +} + +// decrypt checks and strips the mac and decrypts the data in b. Returns a +// success boolean, the number of bytes to skip from the start of the record in +// order to get the application payload, and an optional alert value. +func (hc *halfConn) decrypt(b *block) (ok bool, prefixLen int, alertValue alert) { + // pull out payload + payload := b.data[recordHeaderLen:] + + macSize := 0 + if hc.mac != nil { + macSize = hc.mac.Size() + } + + paddingGood := byte(255) + explicitIVLen := 0 + + // decrypt + if hc.cipher != nil { + switch c := hc.cipher.(type) { + case cipher.Stream: + c.XORKeyStream(payload, payload) + case cipher.AEAD: + explicitIVLen = 8 + if len(payload) < explicitIVLen { + return false, 0, alertBadRecordMAC + } + nonce := payload[:8] + payload = payload[8:] + + copy(hc.additionalData[:], hc.seq[:]) + copy(hc.additionalData[8:], b.data[:3]) + n := len(payload) - c.Overhead() + hc.additionalData[11] = byte(n >> 8) + hc.additionalData[12] = byte(n) + var err error + payload, err = c.Open(payload[:0], nonce, payload, hc.additionalData[:]) + if err != nil { + return false, 0, alertBadRecordMAC + } + b.resize(recordHeaderLen + explicitIVLen + len(payload)) + case cbcMode: + blockSize := c.BlockSize() + if hc.version >= VersionTLS11 { + explicitIVLen = blockSize + } + + if len(payload)%blockSize != 0 || len(payload) < roundUp(explicitIVLen+macSize+1, blockSize) { + return false, 0, alertBadRecordMAC + } + + if explicitIVLen > 0 { + c.SetIV(payload[:explicitIVLen]) + payload = payload[explicitIVLen:] + } + c.CryptBlocks(payload, payload) + if hc.version == VersionSSL30 { + payload, paddingGood = removePaddingSSL30(payload) + } else { + payload, paddingGood = removePadding(payload) + } + b.resize(recordHeaderLen + explicitIVLen + len(payload)) + + // note that we still have a timing side-channel in the + // MAC check, below. An attacker can align the record + // so that a correct padding will cause one less hash + // block to be calculated. Then they can iteratively + // decrypt a record by breaking each byte. See + // "Password Interception in a SSL/TLS Channel", Brice + // Canvel et al. + // + // However, our behavior matches OpenSSL, so we leak + // only as much as they do. + default: + panic("unknown cipher type") + } + } + + // check, strip mac + if hc.mac != nil { + if len(payload) < macSize { + return false, 0, alertBadRecordMAC + } + + // strip mac off payload, b.data + n := len(payload) - macSize + b.data[3] = byte(n >> 8) + b.data[4] = byte(n) + b.resize(recordHeaderLen + explicitIVLen + n) + remoteMAC := payload[n:] + localMAC := hc.mac.MAC(hc.inDigestBuf, hc.seq[0:], b.data[:recordHeaderLen], payload[:n]) + + if subtle.ConstantTimeCompare(localMAC, remoteMAC) != 1 || paddingGood != 255 { + return false, 0, alertBadRecordMAC + } + hc.inDigestBuf = localMAC + } + hc.incSeq() + + return true, recordHeaderLen + explicitIVLen, 0 +} + +// padToBlockSize calculates the needed padding block, if any, for a payload. +// On exit, prefix aliases payload and extends to the end of the last full +// block of payload. finalBlock is a fresh slice which contains the contents of +// any suffix of payload as well as the needed padding to make finalBlock a +// full block. +func padToBlockSize(payload []byte, blockSize int) (prefix, finalBlock []byte) { + overrun := len(payload) % blockSize + paddingLen := blockSize - overrun + prefix = payload[:len(payload)-overrun] + finalBlock = make([]byte, blockSize) + copy(finalBlock, payload[len(payload)-overrun:]) + for i := overrun; i < blockSize; i++ { + finalBlock[i] = byte(paddingLen - 1) + } + return +} + +// encrypt encrypts and macs the data in b. +func (hc *halfConn) encrypt(b *block, explicitIVLen int) (bool, alert) { + // mac + if hc.mac != nil { + mac := hc.mac.MAC(hc.outDigestBuf, hc.seq[0:], b.data[:recordHeaderLen], b.data[recordHeaderLen+explicitIVLen:]) + + n := len(b.data) + b.resize(n + len(mac)) + copy(b.data[n:], mac) + hc.outDigestBuf = mac + } + + payload := b.data[recordHeaderLen:] + + // encrypt + if hc.cipher != nil { + switch c := hc.cipher.(type) { + case cipher.Stream: + c.XORKeyStream(payload, payload) + case cipher.AEAD: + payloadLen := len(b.data) - recordHeaderLen - explicitIVLen + b.resize(len(b.data) + c.Overhead()) + nonce := b.data[recordHeaderLen : recordHeaderLen+explicitIVLen] + payload := b.data[recordHeaderLen+explicitIVLen:] + payload = payload[:payloadLen] + + copy(hc.additionalData[:], hc.seq[:]) + copy(hc.additionalData[8:], b.data[:3]) + hc.additionalData[11] = byte(payloadLen >> 8) + hc.additionalData[12] = byte(payloadLen) + + c.Seal(payload[:0], nonce, payload, hc.additionalData[:]) + case cbcMode: + blockSize := c.BlockSize() + if explicitIVLen > 0 { + c.SetIV(payload[:explicitIVLen]) + payload = payload[explicitIVLen:] + } + prefix, finalBlock := padToBlockSize(payload, blockSize) + b.resize(recordHeaderLen + explicitIVLen + len(prefix) + len(finalBlock)) + c.CryptBlocks(b.data[recordHeaderLen+explicitIVLen:], prefix) + c.CryptBlocks(b.data[recordHeaderLen+explicitIVLen+len(prefix):], finalBlock) + default: + panic("unknown cipher type") + } + } + + // update length to include MAC and any block padding needed. + n := len(b.data) - recordHeaderLen + b.data[3] = byte(n >> 8) + b.data[4] = byte(n) + hc.incSeq() + + return true, 0 +} + +// A block is a simple data buffer. +type block struct { + data []byte + off int // index for Read + link *block +} + +// resize resizes block to be n bytes, growing if necessary. +func (b *block) resize(n int) { + if n > cap(b.data) { + b.reserve(n) + } + b.data = b.data[0:n] +} + +// reserve makes sure that block contains a capacity of at least n bytes. +func (b *block) reserve(n int) { + if cap(b.data) >= n { + return + } + m := cap(b.data) + if m == 0 { + m = 1024 + } + for m < n { + m *= 2 + } + data := make([]byte, len(b.data), m) + copy(data, b.data) + b.data = data +} + +// readFromUntil reads from r into b until b contains at least n bytes +// or else returns an error. +func (b *block) readFromUntil(r io.Reader, n int) error { + // quick case + if len(b.data) >= n { + return nil + } + + // read until have enough. + b.reserve(n) + for { + m, err := r.Read(b.data[len(b.data):cap(b.data)]) + b.data = b.data[0 : len(b.data)+m] + if len(b.data) >= n { + // TODO(bradfitz,agl): slightly suspicious + // that we're throwing away r.Read's err here. + break + } + if err != nil { + return err + } + } + return nil +} + +func (b *block) Read(p []byte) (n int, err error) { + n = copy(p, b.data[b.off:]) + b.off += n + return +} + +// newBlock allocates a new block, from hc's free list if possible. +func (hc *halfConn) newBlock() *block { + b := hc.bfree + if b == nil { + return new(block) + } + hc.bfree = b.link + b.link = nil + b.resize(0) + return b +} + +// freeBlock returns a block to hc's free list. +// The protocol is such that each side only has a block or two on +// its free list at a time, so there's no need to worry about +// trimming the list, etc. +func (hc *halfConn) freeBlock(b *block) { + b.link = hc.bfree + hc.bfree = b +} + +// splitBlock splits a block after the first n bytes, +// returning a block with those n bytes and a +// block with the remainder. the latter may be nil. +func (hc *halfConn) splitBlock(b *block, n int) (*block, *block) { + if len(b.data) <= n { + return b, nil + } + bb := hc.newBlock() + bb.resize(len(b.data) - n) + copy(bb.data, b.data[n:]) + b.data = b.data[0:n] + return b, bb +} + +// RecordHeaderError results when a TLS record header is invalid. +type RecordHeaderError struct { + // Msg contains a human readable string that describes the error. + Msg string + // RecordHeader contains the five bytes of TLS record header that + // triggered the error. + RecordHeader [5]byte +} + +func (e RecordHeaderError) Error() string { return "tls: " + e.Msg } + +func (c *Conn) newRecordHeaderError(msg string) (err RecordHeaderError) { + err.Msg = msg + copy(err.RecordHeader[:], c.rawInput.data) + return err +} + +// readRecord reads the next TLS record from the connection +// and updates the record layer state. +// c.in.Mutex <= L; c.input == nil. +func (c *Conn) readRecord(want recordType) error { + // Caller must be in sync with connection: + // handshake data if handshake not yet completed, + // else application data. (We don't support renegotiation.) + switch want { + default: + c.sendAlert(alertInternalError) + return c.in.setErrorLocked(errors.New("tls: unknown record type requested")) + case recordTypeHandshake, recordTypeChangeCipherSpec: + if c.handshakeComplete { + c.sendAlert(alertInternalError) + return c.in.setErrorLocked(errors.New("tls: handshake or ChangeCipherSpec requested after handshake complete")) + } + case recordTypeApplicationData: + if !c.handshakeComplete { + c.sendAlert(alertInternalError) + return c.in.setErrorLocked(errors.New("tls: application data record requested before handshake complete")) + } + } + +Again: + if c.rawInput == nil { + c.rawInput = c.in.newBlock() + } + b := c.rawInput + + // Read header, payload. + if err := b.readFromUntil(c.conn, recordHeaderLen); err != nil { + // RFC suggests that EOF without an alertCloseNotify is + // an error, but popular web sites seem to do this, + // so we can't make it an error. + // if err == io.EOF { + // err = io.ErrUnexpectedEOF + // } + if e, ok := err.(net.Error); !ok || !e.Temporary() { + c.in.setErrorLocked(err) + } + return err + } + typ := recordType(b.data[0]) + + // No valid TLS record has a type of 0x80, however SSLv2 handshakes + // start with a uint16 length where the MSB is set and the first record + // is always < 256 bytes long. Therefore typ == 0x80 strongly suggests + // an SSLv2 client. + if want == recordTypeHandshake && typ == 0x80 { + c.sendAlert(alertProtocolVersion) + return c.in.setErrorLocked(c.newRecordHeaderError("unsupported SSLv2 handshake received")) + } + + vers := uint16(b.data[1])<<8 | uint16(b.data[2]) + n := int(b.data[3])<<8 | int(b.data[4]) + if c.haveVers && vers != c.vers { + c.sendAlert(alertProtocolVersion) + msg := fmt.Sprintf("received record with version %x when expecting version %x", vers, c.vers) + return c.in.setErrorLocked(c.newRecordHeaderError(msg)) + } + if n > maxCiphertext { + c.sendAlert(alertRecordOverflow) + msg := fmt.Sprintf("oversized record received with length %d", n) + return c.in.setErrorLocked(c.newRecordHeaderError(msg)) + } + if !c.haveVers { + // First message, be extra suspicious: this might not be a TLS + // client. Bail out before reading a full 'body', if possible. + // The current max version is 3.3 so if the version is >= 16.0, + // it's probably not real. + if (typ != recordTypeAlert && typ != want) || vers >= 0x1000 { + c.sendAlert(alertUnexpectedMessage) + return c.in.setErrorLocked(c.newRecordHeaderError("first record does not look like a TLS handshake")) + } + } + if err := b.readFromUntil(c.conn, recordHeaderLen+n); err != nil { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + if e, ok := err.(net.Error); !ok || !e.Temporary() { + c.in.setErrorLocked(err) + } + return err + } + + // Process message. + b, c.rawInput = c.in.splitBlock(b, recordHeaderLen+n) + ok, off, err := c.in.decrypt(b) + if !ok { + c.in.setErrorLocked(c.sendAlert(err)) + } + b.off = off + data := b.data[b.off:] + if len(data) > maxPlaintext { + err := c.sendAlert(alertRecordOverflow) + c.in.freeBlock(b) + return c.in.setErrorLocked(err) + } + + switch typ { + default: + c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) + + case recordTypeAlert: + if len(data) != 2 { + c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) + break + } + if alert(data[1]) == alertCloseNotify { + c.in.setErrorLocked(io.EOF) + break + } + switch data[0] { + case alertLevelWarning: + // drop on the floor + c.in.freeBlock(b) + goto Again + case alertLevelError: + c.in.setErrorLocked(&net.OpError{Op: "remote error", Err: alert(data[1])}) + default: + c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) + } + + case recordTypeChangeCipherSpec: + if typ != want || len(data) != 1 || data[0] != 1 { + c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) + break + } + err := c.in.changeCipherSpec() + if err != nil { + c.in.setErrorLocked(c.sendAlert(err.(alert))) + } + + case recordTypeApplicationData: + if typ != want { + c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) + break + } + c.input = b + b = nil + + case recordTypeHandshake: + // TODO(rsc): Should at least pick off connection close. + if typ != want { + return c.in.setErrorLocked(c.sendAlert(alertNoRenegotiation)) + } + c.hand.Write(data) + } + + if b != nil { + c.in.freeBlock(b) + } + return c.in.err +} + +// sendAlert sends a TLS alert message. +// c.out.Mutex <= L. +func (c *Conn) sendAlertLocked(err alert) error { + switch err { + case alertNoRenegotiation, alertCloseNotify: + c.tmp[0] = alertLevelWarning + default: + c.tmp[0] = alertLevelError + } + c.tmp[1] = byte(err) + c.writeRecord(recordTypeAlert, c.tmp[0:2]) + // closeNotify is a special case in that it isn't an error: + if err != alertCloseNotify { + return c.out.setErrorLocked(&net.OpError{Op: "local error", Err: err}) + } + return nil +} + +// sendAlert sends a TLS alert message. +// L < c.out.Mutex. +func (c *Conn) sendAlert(err alert) error { + c.out.Lock() + defer c.out.Unlock() + return c.sendAlertLocked(err) +} + +// writeRecord writes a TLS record with the given type and payload +// to the connection and updates the record layer state. +// c.out.Mutex <= L. +func (c *Conn) writeRecord(typ recordType, data []byte) (n int, err error) { + b := c.out.newBlock() + for len(data) > 0 { + m := len(data) + if m > maxPlaintext { + m = maxPlaintext + } + explicitIVLen := 0 + explicitIVIsSeq := false + + var cbc cbcMode + if c.out.version >= VersionTLS11 { + var ok bool + if cbc, ok = c.out.cipher.(cbcMode); ok { + explicitIVLen = cbc.BlockSize() + } + } + if explicitIVLen == 0 { + if _, ok := c.out.cipher.(cipher.AEAD); ok { + explicitIVLen = 8 + // The AES-GCM construction in TLS has an + // explicit nonce so that the nonce can be + // random. However, the nonce is only 8 bytes + // which is too small for a secure, random + // nonce. Therefore we use the sequence number + // as the nonce. + explicitIVIsSeq = true + } + } + b.resize(recordHeaderLen + explicitIVLen + m) + b.data[0] = byte(typ) + vers := c.vers + if vers == 0 { + // Some TLS servers fail if the record version is + // greater than TLS 1.0 for the initial ClientHello. + vers = VersionTLS10 + } + b.data[1] = byte(vers >> 8) + b.data[2] = byte(vers) + b.data[3] = byte(m >> 8) + b.data[4] = byte(m) + if explicitIVLen > 0 { + explicitIV := b.data[recordHeaderLen : recordHeaderLen+explicitIVLen] + if explicitIVIsSeq { + copy(explicitIV, c.out.seq[:]) + } else { + if _, err = io.ReadFull(c.config.rand(), explicitIV); err != nil { + break + } + } + } + copy(b.data[recordHeaderLen+explicitIVLen:], data) + c.out.encrypt(b, explicitIVLen) + _, err = c.conn.Write(b.data) + if err != nil { + break + } + n += m + data = data[m:] + } + c.out.freeBlock(b) + + if typ == recordTypeChangeCipherSpec { + err = c.out.changeCipherSpec() + if err != nil { + // Cannot call sendAlert directly, + // because we already hold c.out.Mutex. + c.tmp[0] = alertLevelError + c.tmp[1] = byte(err.(alert)) + c.writeRecord(recordTypeAlert, c.tmp[0:2]) + return n, c.out.setErrorLocked(&net.OpError{Op: "local error", Err: err}) + } + } + return +} + +// readHandshake reads the next handshake message from +// the record layer. +// c.in.Mutex < L; c.out.Mutex < L. +func (c *Conn) readHandshake() (interface{}, error) { + for c.hand.Len() < 4 { + if err := c.in.err; err != nil { + return nil, err + } + if err := c.readRecord(recordTypeHandshake); err != nil { + return nil, err + } + } + + data := c.hand.Bytes() + n := int(data[1])<<16 | int(data[2])<<8 | int(data[3]) + if n > maxHandshake { + return nil, c.in.setErrorLocked(c.sendAlert(alertInternalError)) + } + for c.hand.Len() < 4+n { + if err := c.in.err; err != nil { + return nil, err + } + if err := c.readRecord(recordTypeHandshake); err != nil { + return nil, err + } + } + data = c.hand.Next(4 + n) + var m handshakeMessage + switch data[0] { + case typeClientHello: + m = new(clientHelloMsg) + case typeServerHello: + m = new(serverHelloMsg) + case typeNewSessionTicket: + m = new(newSessionTicketMsg) + case typeCertificate: + m = new(certificateMsg) + case typeCertificateRequest: + m = &certificateRequestMsg{ + hasSignatureAndHash: c.vers >= VersionTLS12, + } + case typeCertificateStatus: + m = new(certificateStatusMsg) + case typeServerKeyExchange: + m = new(serverKeyExchangeMsg) + case typeServerHelloDone: + m = new(serverHelloDoneMsg) + case typeClientKeyExchange: + m = new(clientKeyExchangeMsg) + case typeCertificateVerify: + m = &certificateVerifyMsg{ + hasSignatureAndHash: c.vers >= VersionTLS12, + } + case typeNextProtocol: + m = new(nextProtoMsg) + case typeFinished: + m = new(finishedMsg) + default: + return nil, c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) + } + + // The handshake message unmarshallers + // expect to be able to keep references to data, + // so pass in a fresh copy that won't be overwritten. + data = append([]byte(nil), data...) + + if !m.unmarshal(data) { + return nil, c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) + } + return m, nil +} + +var errClosed = errors.New("crypto/tls: use of closed connection") + +// Write writes data to the connection. +func (c *Conn) Write(b []byte) (int, error) { + // interlock with Close below + for { + x := atomic.LoadInt32(&c.activeCall) + if x&1 != 0 { + return 0, errClosed + } + if atomic.CompareAndSwapInt32(&c.activeCall, x, x+2) { + defer atomic.AddInt32(&c.activeCall, -2) + break + } + } + + if err := c.Handshake(); err != nil { + return 0, err + } + + c.out.Lock() + defer c.out.Unlock() + + if err := c.out.err; err != nil { + return 0, err + } + + if !c.handshakeComplete { + return 0, alertInternalError + } + + // SSL 3.0 and TLS 1.0 are susceptible to a chosen-plaintext + // attack when using block mode ciphers due to predictable IVs. + // This can be prevented by splitting each Application Data + // record into two records, effectively randomizing the IV. + // + // http://www.openssl.org/~bodo/tls-cbc.txt + // https://bugzilla.mozilla.org/show_bug.cgi?id=665814 + // http://www.imperialviolet.org/2012/01/15/beastfollowup.html + + var m int + if len(b) > 1 && c.vers <= VersionTLS10 { + if _, ok := c.out.cipher.(cipher.BlockMode); ok { + n, err := c.writeRecord(recordTypeApplicationData, b[:1]) + if err != nil { + return n, c.out.setErrorLocked(err) + } + m, b = 1, b[1:] + } + } + + n, err := c.writeRecord(recordTypeApplicationData, b) + return n + m, c.out.setErrorLocked(err) +} + +// Read can be made to time out and return a net.Error with Timeout() == true +// after a fixed time limit; see SetDeadline and SetReadDeadline. +func (c *Conn) Read(b []byte) (n int, err error) { + if err = c.Handshake(); err != nil { + return + } + if len(b) == 0 { + // Put this after Handshake, in case people were calling + // Read(nil) for the side effect of the Handshake. + return + } + + c.in.Lock() + defer c.in.Unlock() + + // Some OpenSSL servers send empty records in order to randomize the + // CBC IV. So this loop ignores a limited number of empty records. + const maxConsecutiveEmptyRecords = 100 + for emptyRecordCount := 0; emptyRecordCount <= maxConsecutiveEmptyRecords; emptyRecordCount++ { + for c.input == nil && c.in.err == nil { + if err := c.readRecord(recordTypeApplicationData); err != nil { + // Soft error, like EAGAIN + return 0, err + } + } + if err := c.in.err; err != nil { + return 0, err + } + + n, err = c.input.Read(b) + if c.input.off >= len(c.input.data) { + c.in.freeBlock(c.input) + c.input = nil + } + + // If a close-notify alert is waiting, read it so that + // we can return (n, EOF) instead of (n, nil), to signal + // to the HTTP response reading goroutine that the + // connection is now closed. This eliminates a race + // where the HTTP response reading goroutine would + // otherwise not observe the EOF until its next read, + // by which time a client goroutine might have already + // tried to reuse the HTTP connection for a new + // request. + // See https://codereview.appspot.com/76400046 + // and https://golang.org/issue/3514 + if ri := c.rawInput; ri != nil && + n != 0 && err == nil && + c.input == nil && len(ri.data) > 0 && recordType(ri.data[0]) == recordTypeAlert { + if recErr := c.readRecord(recordTypeApplicationData); recErr != nil { + err = recErr // will be io.EOF on closeNotify + } + } + + if n != 0 || err != nil { + return n, err + } + } + + return 0, io.ErrNoProgress +} + +// Close closes the connection. +func (c *Conn) Close() error { + // Interlock with Conn.Write above. + var x int32 + for { + x = atomic.LoadInt32(&c.activeCall) + if x&1 != 0 { + return errClosed + } + if atomic.CompareAndSwapInt32(&c.activeCall, x, x|1) { + break + } + } + if x != 0 { + // io.Writer and io.Closer should not be used concurrently. + // If Close is called while a Write is currently in-flight, + // interpret that as a sign that this Close is really just + // being used to break the Write and/or clean up resources and + // avoid sending the alertCloseNotify, which may block + // waiting on handshakeMutex or the c.out mutex. + return c.conn.Close() + } + + var alertErr error + + c.handshakeMutex.Lock() + defer c.handshakeMutex.Unlock() + if c.handshakeComplete { + alertErr = c.sendAlert(alertCloseNotify) + } + + if err := c.conn.Close(); err != nil { + return err + } + return alertErr +} + +// Handshake runs the client or server handshake +// protocol if it has not yet been run. +// Most uses of this package need not call Handshake +// explicitly: the first Read or Write will call it automatically. +func (c *Conn) Handshake() error { + c.handshakeMutex.Lock() + defer c.handshakeMutex.Unlock() + if err := c.handshakeErr; err != nil { + return err + } + if c.handshakeComplete { + return nil + } + + if c.isClient { + c.handshakeErr = c.clientHandshake() + } else { + c.handshakeErr = c.serverHandshake() + } + return c.handshakeErr +} + +// ConnectionState returns basic TLS details about the connection. +func (c *Conn) ConnectionState() ConnectionState { + c.handshakeMutex.Lock() + defer c.handshakeMutex.Unlock() + + var state ConnectionState + state.HandshakeComplete = c.handshakeComplete + if c.handshakeComplete { + state.Version = c.vers + state.NegotiatedProtocol = c.clientProtocol + state.DidResume = c.didResume + state.NegotiatedProtocolIsMutual = !c.clientProtocolFallback + state.CipherSuite = c.cipherSuite + state.PeerCertificates = c.peerCertificates + state.VerifiedChains = c.verifiedChains + state.ServerName = c.serverName + state.SignedCertificateTimestamps = c.scts + state.OCSPResponse = c.ocspResponse + if !c.didResume { + state.TLSUnique = c.firstFinished[:] + } + } + + return state +} + +// OCSPResponse returns the stapled OCSP response from the TLS server, if +// any. (Only valid for client connections.) +func (c *Conn) OCSPResponse() []byte { + c.handshakeMutex.Lock() + defer c.handshakeMutex.Unlock() + + return c.ocspResponse +} + +// VerifyHostname checks that the peer certificate chain is valid for +// connecting to host. If so, it returns nil; if not, it returns an error +// describing the problem. +func (c *Conn) VerifyHostname(host string) error { + c.handshakeMutex.Lock() + defer c.handshakeMutex.Unlock() + if !c.isClient { + return errors.New("tls: VerifyHostname called on TLS server connection") + } + if !c.handshakeComplete { + return errors.New("tls: handshake has not yet been performed") + } + if len(c.verifiedChains) == 0 { + return errors.New("tls: handshake did not verify certificate chain") + } + return c.peerCertificates[0].VerifyHostname(host) +} diff --git a/vendor/github.com/cloudflare/cfssl/scan/crypto/tls/generate_cert.go b/vendor/github.com/cloudflare/cfssl/scan/crypto/tls/generate_cert.go new file mode 100644 index 00000000000..83f9916ff9d --- /dev/null +++ b/vendor/github.com/cloudflare/cfssl/scan/crypto/tls/generate_cert.go @@ -0,0 +1,161 @@ +// Copyright 2009 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. + +// +build ignore + +// Generate a self-signed X.509 certificate for a TLS server. Outputs to +// 'cert.pem' and 'key.pem' and will overwrite existing files. + +package main + +import ( + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "flag" + "fmt" + "log" + "math/big" + "net" + "os" + "strings" + "time" +) + +var ( + host = flag.String("host", "", "Comma-separated hostnames and IPs to generate a certificate for") + validFrom = flag.String("start-date", "", "Creation date formatted as Jan 1 15:04:05 2011") + validFor = flag.Duration("duration", 365*24*time.Hour, "Duration that certificate is valid for") + isCA = flag.Bool("ca", false, "whether this cert should be its own Certificate Authority") + rsaBits = flag.Int("rsa-bits", 2048, "Size of RSA key to generate. Ignored if --ecdsa-curve is set") + ecdsaCurve = flag.String("ecdsa-curve", "", "ECDSA curve to use to generate a key. Valid values are P224, P256, P384, P521") +) + +func publicKey(priv interface{}) interface{} { + switch k := priv.(type) { + case *rsa.PrivateKey: + return &k.PublicKey + case *ecdsa.PrivateKey: + return &k.PublicKey + default: + return nil + } +} + +func pemBlockForKey(priv interface{}) *pem.Block { + switch k := priv.(type) { + case *rsa.PrivateKey: + return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)} + case *ecdsa.PrivateKey: + b, err := x509.MarshalECPrivateKey(k) + if err != nil { + fmt.Fprintf(os.Stderr, "Unable to marshal ECDSA private key: %v", err) + os.Exit(2) + } + return &pem.Block{Type: "EC PRIVATE KEY", Bytes: b} + default: + return nil + } +} + +func main() { + flag.Parse() + + if len(*host) == 0 { + log.Fatalf("Missing required --host parameter") + } + + var priv interface{} + var err error + switch *ecdsaCurve { + case "": + priv, err = rsa.GenerateKey(rand.Reader, *rsaBits) + case "P224": + priv, err = ecdsa.GenerateKey(elliptic.P224(), rand.Reader) + case "P256": + priv, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + case "P384": + priv, err = ecdsa.GenerateKey(elliptic.P384(), rand.Reader) + case "P521": + priv, err = ecdsa.GenerateKey(elliptic.P521(), rand.Reader) + default: + fmt.Fprintf(os.Stderr, "Unrecognized elliptic curve: %q", *ecdsaCurve) + os.Exit(1) + } + if err != nil { + log.Fatalf("failed to generate private key: %s", err) + } + + var notBefore time.Time + if len(*validFrom) == 0 { + notBefore = time.Now() + } else { + notBefore, err = time.Parse("Jan 2 15:04:05 2006", *validFrom) + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to parse creation date: %s\n", err) + os.Exit(1) + } + } + + notAfter := notBefore.Add(*validFor) + + serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) + serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) + if err != nil { + log.Fatalf("failed to generate serial number: %s", err) + } + + template := x509.Certificate{ + SerialNumber: serialNumber, + Subject: pkix.Name{ + Organization: []string{"Acme Co"}, + }, + NotBefore: notBefore, + NotAfter: notAfter, + + KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, + BasicConstraintsValid: true, + } + + hosts := strings.Split(*host, ",") + for _, h := range hosts { + if ip := net.ParseIP(h); ip != nil { + template.IPAddresses = append(template.IPAddresses, ip) + } else { + template.DNSNames = append(template.DNSNames, h) + } + } + + if *isCA { + template.IsCA = true + template.KeyUsage |= x509.KeyUsageCertSign + } + + derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, publicKey(priv), priv) + if err != nil { + log.Fatalf("Failed to create certificate: %s", err) + } + + certOut, err := os.Create("cert.pem") + if err != nil { + log.Fatalf("failed to open cert.pem for writing: %s", err) + } + pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}) + certOut.Close() + log.Print("written cert.pem\n") + + keyOut, err := os.OpenFile("key.pem", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) + if err != nil { + log.Print("failed to open key.pem for writing:", err) + return + } + pem.Encode(keyOut, pemBlockForKey(priv)) + keyOut.Close() + log.Print("written key.pem\n") +} diff --git a/vendor/github.com/cloudflare/cfssl/scan/crypto/tls/handshake_client.go b/vendor/github.com/cloudflare/cfssl/scan/crypto/tls/handshake_client.go new file mode 100644 index 00000000000..3c996acf878 --- /dev/null +++ b/vendor/github.com/cloudflare/cfssl/scan/crypto/tls/handshake_client.go @@ -0,0 +1,667 @@ +// Copyright 2009 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 ( + "bytes" + "crypto" + "crypto/ecdsa" + "crypto/rsa" + "crypto/subtle" + "crypto/x509" + "errors" + "fmt" + "io" + "net" + "strconv" +) + +type clientHandshakeState struct { + c *Conn + serverHello *serverHelloMsg + hello *clientHelloMsg + suite *cipherSuite + finishedHash finishedHash + masterSecret []byte + session *ClientSessionState +} + +func (c *Conn) clientHandshake() error { + if c.config == nil { + c.config = defaultConfig() + } + + if len(c.config.ServerName) == 0 && !c.config.InsecureSkipVerify { + return errors.New("tls: either ServerName or InsecureSkipVerify must be specified in the tls.Config") + } + + nextProtosLength := 0 + for _, proto := range c.config.NextProtos { + if l := len(proto); l == 0 || l > 255 { + return errors.New("tls: invalid NextProtos value") + } else { + nextProtosLength += 1 + l + } + } + if nextProtosLength > 0xffff { + return errors.New("tls: NextProtos values too large") + } + + sni := c.config.ServerName + // IP address literals are not permitted as SNI values. See + // https://tools.ietf.org/html/rfc6066#section-3. + if net.ParseIP(sni) != nil { + sni = "" + } + + hello := &clientHelloMsg{ + vers: c.config.maxVersion(), + compressionMethods: []uint8{compressionNone}, + random: make([]byte, 32), + ocspStapling: true, + scts: true, + serverName: sni, + supportedCurves: c.config.curvePreferences(), + supportedPoints: []uint8{pointFormatUncompressed}, + nextProtoNeg: len(c.config.NextProtos) > 0, + secureRenegotiation: true, + alpnProtocols: c.config.NextProtos, + } + + possibleCipherSuites := c.config.cipherSuites() + hello.cipherSuites = make([]uint16, 0, len(possibleCipherSuites)) + +NextCipherSuite: + for _, suiteId := range possibleCipherSuites { + for _, suite := range cipherSuites { + if suite.id != suiteId { + continue + } + // Don't advertise TLS 1.2-only cipher suites unless + // we're attempting TLS 1.2. + if hello.vers < VersionTLS12 && suite.flags&suiteTLS12 != 0 { + continue + } + hello.cipherSuites = append(hello.cipherSuites, suiteId) + continue NextCipherSuite + } + } + + _, err := io.ReadFull(c.config.rand(), hello.random) + if err != nil { + c.sendAlert(alertInternalError) + return errors.New("tls: short read from Rand: " + err.Error()) + } + + if hello.vers >= VersionTLS12 { + hello.signatureAndHashes = supportedSignatureAlgorithms + } + + var session *ClientSessionState + var cacheKey string + sessionCache := c.config.ClientSessionCache + if c.config.SessionTicketsDisabled { + sessionCache = nil + } + + if sessionCache != nil { + hello.ticketSupported = true + + // Try to resume a previously negotiated TLS session, if + // available. + cacheKey = clientSessionCacheKey(c.conn.RemoteAddr(), c.config) + candidateSession, ok := sessionCache.Get(cacheKey) + if ok { + // Check that the ciphersuite/version used for the + // previous session are still valid. + cipherSuiteOk := false + for _, id := range hello.cipherSuites { + if id == candidateSession.cipherSuite { + cipherSuiteOk = true + break + } + } + + versOk := candidateSession.vers >= c.config.minVersion() && + candidateSession.vers <= c.config.maxVersion() + if versOk && cipherSuiteOk { + session = candidateSession + } + } + } + + if session != nil { + hello.sessionTicket = session.sessionTicket + // A random session ID is used to detect when the + // server accepted the ticket and is resuming a session + // (see RFC 5077). + hello.sessionId = make([]byte, 16) + if _, err := io.ReadFull(c.config.rand(), hello.sessionId); err != nil { + c.sendAlert(alertInternalError) + return errors.New("tls: short read from Rand: " + err.Error()) + } + } + + c.writeRecord(recordTypeHandshake, hello.marshal()) + + msg, err := c.readHandshake() + if err != nil { + return err + } + serverHello, ok := msg.(*serverHelloMsg) + if !ok { + c.sendAlert(alertUnexpectedMessage) + return unexpectedMessageError(serverHello, msg) + } + + vers, ok := c.config.mutualVersion(serverHello.vers) + if !ok || vers < VersionTLS10 { + // TLS 1.0 is the minimum version supported as a client. + c.sendAlert(alertProtocolVersion) + return fmt.Errorf("tls: server selected unsupported protocol version %x", serverHello.vers) + } + c.vers = vers + c.haveVers = true + + suite := mutualCipherSuite(hello.cipherSuites, serverHello.cipherSuite) + if suite == nil { + c.sendAlert(alertHandshakeFailure) + return errors.New("tls: server chose an unconfigured cipher suite") + } + + hs := &clientHandshakeState{ + c: c, + serverHello: serverHello, + hello: hello, + suite: suite, + finishedHash: newFinishedHash(c.vers, suite), + session: session, + } + + isResume, err := hs.processServerHello() + if err != nil { + return err + } + + // No signatures of the handshake are needed in a resumption. + // Otherwise, in a full handshake, if we don't have any certificates + // configured then we will never send a CertificateVerify message and + // thus no signatures are needed in that case either. + if isResume || len(c.config.Certificates) == 0 { + hs.finishedHash.discardHandshakeBuffer() + } + + hs.finishedHash.Write(hs.hello.marshal()) + hs.finishedHash.Write(hs.serverHello.marshal()) + + if isResume { + if err := hs.establishKeys(); err != nil { + return err + } + if err := hs.readSessionTicket(); err != nil { + return err + } + if err := hs.readFinished(c.firstFinished[:]); err != nil { + return err + } + if err := hs.sendFinished(nil); err != nil { + return err + } + } else { + if err := hs.doFullHandshake(); err != nil { + return err + } + if err := hs.establishKeys(); err != nil { + return err + } + if err := hs.sendFinished(c.firstFinished[:]); err != nil { + return err + } + if err := hs.readSessionTicket(); err != nil { + return err + } + if err := hs.readFinished(nil); err != nil { + return err + } + } + + if sessionCache != nil && hs.session != nil && session != hs.session { + sessionCache.Put(cacheKey, hs.session) + } + + c.didResume = isResume + c.handshakeComplete = true + c.cipherSuite = suite.id + return nil +} + +func (hs *clientHandshakeState) doFullHandshake() error { + c := hs.c + + msg, err := c.readHandshake() + if err != nil { + return err + } + certMsg, ok := msg.(*certificateMsg) + if !ok || len(certMsg.certificates) == 0 { + c.sendAlert(alertUnexpectedMessage) + return unexpectedMessageError(certMsg, msg) + } + hs.finishedHash.Write(certMsg.marshal()) + + certs := make([]*x509.Certificate, len(certMsg.certificates)) + for i, asn1Data := range certMsg.certificates { + cert, err := x509.ParseCertificate(asn1Data) + if err != nil { + c.sendAlert(alertBadCertificate) + return errors.New("tls: failed to parse certificate from server: " + err.Error()) + } + certs[i] = cert + } + + if !c.config.InsecureSkipVerify { + opts := x509.VerifyOptions{ + Roots: c.config.RootCAs, + CurrentTime: c.config.time(), + DNSName: c.config.ServerName, + Intermediates: x509.NewCertPool(), + } + + for i, cert := range certs { + if i == 0 { + continue + } + opts.Intermediates.AddCert(cert) + } + c.verifiedChains, err = certs[0].Verify(opts) + if err != nil { + c.sendAlert(alertBadCertificate) + return err + } + } + + switch certs[0].PublicKey.(type) { + case *rsa.PublicKey, *ecdsa.PublicKey: + break + default: + c.sendAlert(alertUnsupportedCertificate) + return fmt.Errorf("tls: server's certificate contains an unsupported type of public key: %T", certs[0].PublicKey) + } + + c.peerCertificates = certs + + if hs.serverHello.ocspStapling { + msg, err = c.readHandshake() + if err != nil { + return err + } + cs, ok := msg.(*certificateStatusMsg) + if !ok { + c.sendAlert(alertUnexpectedMessage) + return unexpectedMessageError(cs, msg) + } + hs.finishedHash.Write(cs.marshal()) + + if cs.statusType == statusTypeOCSP { + c.ocspResponse = cs.response + } + } + + msg, err = c.readHandshake() + if err != nil { + return err + } + + keyAgreement := hs.suite.ka(c.vers) + + skx, ok := msg.(*serverKeyExchangeMsg) + if ok { + hs.finishedHash.Write(skx.marshal()) + err = keyAgreement.processServerKeyExchange(c.config, hs.hello, hs.serverHello, certs[0], skx) + if err != nil { + c.sendAlert(alertUnexpectedMessage) + return err + } + + msg, err = c.readHandshake() + if err != nil { + return err + } + } + + var chainToSend *Certificate + var certRequested bool + certReq, ok := msg.(*certificateRequestMsg) + if ok { + certRequested = true + + // RFC 4346 on the certificateAuthorities field: + // A list of the distinguished names of acceptable certificate + // authorities. These distinguished names may specify a desired + // distinguished name for a root CA or for a subordinate CA; + // thus, this message can be used to describe both known roots + // and a desired authorization space. If the + // certificate_authorities list is empty then the client MAY + // send any certificate of the appropriate + // ClientCertificateType, unless there is some external + // arrangement to the contrary. + + hs.finishedHash.Write(certReq.marshal()) + + var rsaAvail, ecdsaAvail bool + for _, certType := range certReq.certificateTypes { + switch certType { + case certTypeRSASign: + rsaAvail = true + case certTypeECDSASign: + ecdsaAvail = true + } + } + + // We need to search our list of client certs for one + // where SignatureAlgorithm is acceptable to the server and the + // Issuer is in certReq.certificateAuthorities + findCert: + for i, chain := range c.config.Certificates { + if !rsaAvail && !ecdsaAvail { + continue + } + + for j, cert := range chain.Certificate { + x509Cert := chain.Leaf + // parse the certificate if this isn't the leaf + // node, or if chain.Leaf was nil + if j != 0 || x509Cert == nil { + if x509Cert, err = x509.ParseCertificate(cert); err != nil { + c.sendAlert(alertInternalError) + return errors.New("tls: failed to parse client certificate #" + strconv.Itoa(i) + ": " + err.Error()) + } + } + + switch { + case rsaAvail && x509Cert.PublicKeyAlgorithm == x509.RSA: + case ecdsaAvail && x509Cert.PublicKeyAlgorithm == x509.ECDSA: + default: + continue findCert + } + + if len(certReq.certificateAuthorities) == 0 { + // they gave us an empty list, so just take the + // first cert from c.config.Certificates + chainToSend = &chain + break findCert + } + + for _, ca := range certReq.certificateAuthorities { + if bytes.Equal(x509Cert.RawIssuer, ca) { + chainToSend = &chain + break findCert + } + } + } + } + + msg, err = c.readHandshake() + if err != nil { + return err + } + } + + shd, ok := msg.(*serverHelloDoneMsg) + if !ok { + c.sendAlert(alertUnexpectedMessage) + return unexpectedMessageError(shd, msg) + } + hs.finishedHash.Write(shd.marshal()) + + // If the server requested a certificate then we have to send a + // Certificate message, even if it's empty because we don't have a + // certificate to send. + if certRequested { + certMsg = new(certificateMsg) + if chainToSend != nil { + certMsg.certificates = chainToSend.Certificate + } + hs.finishedHash.Write(certMsg.marshal()) + c.writeRecord(recordTypeHandshake, certMsg.marshal()) + } + + preMasterSecret, ckx, err := keyAgreement.generateClientKeyExchange(c.config, hs.hello, certs[0]) + if err != nil { + c.sendAlert(alertInternalError) + return err + } + if ckx != nil { + hs.finishedHash.Write(ckx.marshal()) + c.writeRecord(recordTypeHandshake, ckx.marshal()) + } + + if chainToSend != nil { + certVerify := &certificateVerifyMsg{ + hasSignatureAndHash: c.vers >= VersionTLS12, + } + + key, ok := chainToSend.PrivateKey.(crypto.Signer) + if !ok { + c.sendAlert(alertInternalError) + return fmt.Errorf("tls: client certificate private key of type %T does not implement crypto.Signer", chainToSend.PrivateKey) + } + + var signatureType uint8 + switch key.Public().(type) { + case *ecdsa.PublicKey: + signatureType = signatureECDSA + case *rsa.PublicKey: + signatureType = signatureRSA + default: + c.sendAlert(alertInternalError) + return fmt.Errorf("tls: failed to sign handshake with client certificate: unknown client certificate key type: %T", key) + } + + certVerify.signatureAndHash, err = hs.finishedHash.selectClientCertSignatureAlgorithm(certReq.signatureAndHashes, signatureType) + if err != nil { + c.sendAlert(alertInternalError) + return err + } + digest, hashFunc, err := hs.finishedHash.hashForClientCertificate(certVerify.signatureAndHash, hs.masterSecret) + if err != nil { + c.sendAlert(alertInternalError) + return err + } + certVerify.signature, err = key.Sign(c.config.rand(), digest, hashFunc) + if err != nil { + c.sendAlert(alertInternalError) + return err + } + + hs.finishedHash.Write(certVerify.marshal()) + c.writeRecord(recordTypeHandshake, certVerify.marshal()) + } + + hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.hello.random, hs.serverHello.random) + + hs.finishedHash.discardHandshakeBuffer() + + return nil +} + +func (hs *clientHandshakeState) establishKeys() error { + c := hs.c + + clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV := + keysFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.hello.random, hs.serverHello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen) + var clientCipher, serverCipher interface{} + var clientHash, serverHash macFunction + if hs.suite.cipher != nil { + clientCipher = hs.suite.cipher(clientKey, clientIV, false /* not for reading */) + clientHash = hs.suite.mac(c.vers, clientMAC) + serverCipher = hs.suite.cipher(serverKey, serverIV, true /* for reading */) + serverHash = hs.suite.mac(c.vers, serverMAC) + } else { + clientCipher = hs.suite.aead(clientKey, clientIV) + serverCipher = hs.suite.aead(serverKey, serverIV) + } + + c.in.prepareCipherSpec(c.vers, serverCipher, serverHash) + c.out.prepareCipherSpec(c.vers, clientCipher, clientHash) + return nil +} + +func (hs *clientHandshakeState) serverResumedSession() bool { + // If the server responded with the same sessionId then it means the + // sessionTicket is being used to resume a TLS session. + return hs.session != nil && hs.hello.sessionId != nil && + bytes.Equal(hs.serverHello.sessionId, hs.hello.sessionId) +} + +func (hs *clientHandshakeState) processServerHello() (bool, error) { + c := hs.c + + if hs.serverHello.compressionMethod != compressionNone { + c.sendAlert(alertUnexpectedMessage) + return false, errors.New("tls: server selected unsupported compression format") + } + + clientDidNPN := hs.hello.nextProtoNeg + clientDidALPN := len(hs.hello.alpnProtocols) > 0 + serverHasNPN := hs.serverHello.nextProtoNeg + serverHasALPN := len(hs.serverHello.alpnProtocol) > 0 + + if !clientDidNPN && serverHasNPN { + c.sendAlert(alertHandshakeFailure) + return false, errors.New("server advertised unrequested NPN extension") + } + + if !clientDidALPN && serverHasALPN { + c.sendAlert(alertHandshakeFailure) + return false, errors.New("server advertised unrequested ALPN extension") + } + + if serverHasNPN && serverHasALPN { + c.sendAlert(alertHandshakeFailure) + return false, errors.New("server advertised both NPN and ALPN extensions") + } + + if serverHasALPN { + c.clientProtocol = hs.serverHello.alpnProtocol + c.clientProtocolFallback = false + } + c.scts = hs.serverHello.scts + + if hs.serverResumedSession() { + // Restore masterSecret and peerCerts from previous state + hs.masterSecret = hs.session.masterSecret + c.peerCertificates = hs.session.serverCertificates + c.verifiedChains = hs.session.verifiedChains + return true, nil + } + return false, nil +} + +func (hs *clientHandshakeState) readFinished(out []byte) error { + c := hs.c + + c.readRecord(recordTypeChangeCipherSpec) + if err := c.in.error(); err != nil { + return err + } + + msg, err := c.readHandshake() + if err != nil { + return err + } + serverFinished, ok := msg.(*finishedMsg) + if !ok { + c.sendAlert(alertUnexpectedMessage) + return unexpectedMessageError(serverFinished, msg) + } + + verify := hs.finishedHash.serverSum(hs.masterSecret) + if len(verify) != len(serverFinished.verifyData) || + subtle.ConstantTimeCompare(verify, serverFinished.verifyData) != 1 { + c.sendAlert(alertHandshakeFailure) + return errors.New("tls: server's Finished message was incorrect") + } + hs.finishedHash.Write(serverFinished.marshal()) + copy(out, verify) + return nil +} + +func (hs *clientHandshakeState) readSessionTicket() error { + if !hs.serverHello.ticketSupported { + return nil + } + + c := hs.c + msg, err := c.readHandshake() + if err != nil { + return err + } + sessionTicketMsg, ok := msg.(*newSessionTicketMsg) + if !ok { + c.sendAlert(alertUnexpectedMessage) + return unexpectedMessageError(sessionTicketMsg, msg) + } + hs.finishedHash.Write(sessionTicketMsg.marshal()) + + hs.session = &ClientSessionState{ + sessionTicket: sessionTicketMsg.ticket, + vers: c.vers, + cipherSuite: hs.suite.id, + masterSecret: hs.masterSecret, + serverCertificates: c.peerCertificates, + verifiedChains: c.verifiedChains, + } + + return nil +} + +func (hs *clientHandshakeState) sendFinished(out []byte) error { + c := hs.c + + c.writeRecord(recordTypeChangeCipherSpec, []byte{1}) + if hs.serverHello.nextProtoNeg { + nextProto := new(nextProtoMsg) + proto, fallback := mutualProtocol(c.config.NextProtos, hs.serverHello.nextProtos) + nextProto.proto = proto + c.clientProtocol = proto + c.clientProtocolFallback = fallback + + hs.finishedHash.Write(nextProto.marshal()) + c.writeRecord(recordTypeHandshake, nextProto.marshal()) + } + + finished := new(finishedMsg) + finished.verifyData = hs.finishedHash.clientSum(hs.masterSecret) + hs.finishedHash.Write(finished.marshal()) + c.writeRecord(recordTypeHandshake, finished.marshal()) + copy(out, finished.verifyData) + return nil +} + +// clientSessionCacheKey returns a key used to cache sessionTickets that could +// be used to resume previously negotiated TLS sessions with a server. +func clientSessionCacheKey(serverAddr net.Addr, config *Config) string { + if len(config.ServerName) > 0 { + return config.ServerName + } + return serverAddr.String() +} + +// mutualProtocol finds the mutual Next Protocol Negotiation or ALPN protocol +// given list of possible protocols and a list of the preference order. The +// first list must not be empty. It returns the resulting protocol and flag +// indicating if the fallback case was reached. +func mutualProtocol(protos, preferenceProtos []string) (string, bool) { + for _, s := range preferenceProtos { + for _, c := range protos { + if s == c { + return s, false + } + } + } + + return protos[0], true +} diff --git a/vendor/github.com/cloudflare/cfssl/scan/crypto/tls/handshake_messages.go b/vendor/github.com/cloudflare/cfssl/scan/crypto/tls/handshake_messages.go new file mode 100644 index 00000000000..111ce53487a --- /dev/null +++ b/vendor/github.com/cloudflare/cfssl/scan/crypto/tls/handshake_messages.go @@ -0,0 +1,1528 @@ +// Copyright 2009 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 "bytes" + +type clientHelloMsg struct { + raw []byte + 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 + signatureAndHashes []signatureAndHash + secureRenegotiation bool + alpnProtocols []string +} + +func (m *clientHelloMsg) equal(i interface{}) bool { + m1, ok := i.(*clientHelloMsg) + if !ok { + return false + } + + return bytes.Equal(m.raw, m1.raw) && + m.vers == m1.vers && + bytes.Equal(m.random, m1.random) && + bytes.Equal(m.sessionId, m1.sessionId) && + eqUint16s(m.cipherSuites, m1.cipherSuites) && + bytes.Equal(m.compressionMethods, m1.compressionMethods) && + m.nextProtoNeg == m1.nextProtoNeg && + m.serverName == m1.serverName && + m.ocspStapling == m1.ocspStapling && + m.scts == m1.scts && + eqCurveIDs(m.supportedCurves, m1.supportedCurves) && + bytes.Equal(m.supportedPoints, m1.supportedPoints) && + m.ticketSupported == m1.ticketSupported && + bytes.Equal(m.sessionTicket, m1.sessionTicket) && + eqSignatureAndHashes(m.signatureAndHashes, m1.signatureAndHashes) && + m.secureRenegotiation == m1.secureRenegotiation && + eqStrings(m.alpnProtocols, m1.alpnProtocols) +} + +func (m *clientHelloMsg) marshal() []byte { + if m.raw != nil { + return m.raw + } + + length := 2 + 32 + 1 + len(m.sessionId) + 2 + len(m.cipherSuites)*2 + 1 + len(m.compressionMethods) + numExtensions := 0 + extensionsLength := 0 + if m.nextProtoNeg { + numExtensions++ + } + if m.ocspStapling { + extensionsLength += 1 + 2 + 2 + numExtensions++ + } + if len(m.serverName) > 0 { + extensionsLength += 5 + len(m.serverName) + numExtensions++ + } + if len(m.supportedCurves) > 0 { + extensionsLength += 2 + 2*len(m.supportedCurves) + numExtensions++ + } + if len(m.supportedPoints) > 0 { + extensionsLength += 1 + len(m.supportedPoints) + numExtensions++ + } + if m.ticketSupported { + extensionsLength += len(m.sessionTicket) + numExtensions++ + } + if len(m.signatureAndHashes) > 0 { + extensionsLength += 2 + 2*len(m.signatureAndHashes) + numExtensions++ + } + if m.secureRenegotiation { + extensionsLength += 1 + numExtensions++ + } + if len(m.alpnProtocols) > 0 { + extensionsLength += 2 + for _, s := range m.alpnProtocols { + if l := len(s); l == 0 || l > 255 { + panic("invalid ALPN protocol") + } + extensionsLength++ + extensionsLength += len(s) + } + numExtensions++ + } + if m.scts { + numExtensions++ + } + if numExtensions > 0 { + extensionsLength += 4 * numExtensions + length += 2 + extensionsLength + } + + x := make([]byte, 4+length) + x[0] = typeClientHello + x[1] = uint8(length >> 16) + x[2] = uint8(length >> 8) + x[3] = uint8(length) + x[4] = uint8(m.vers >> 8) + x[5] = uint8(m.vers) + copy(x[6:38], m.random) + x[38] = uint8(len(m.sessionId)) + copy(x[39:39+len(m.sessionId)], m.sessionId) + y := x[39+len(m.sessionId):] + y[0] = uint8(len(m.cipherSuites) >> 7) + y[1] = uint8(len(m.cipherSuites) << 1) + for i, suite := range m.cipherSuites { + y[2+i*2] = uint8(suite >> 8) + y[3+i*2] = uint8(suite) + } + z := y[2+len(m.cipherSuites)*2:] + z[0] = uint8(len(m.compressionMethods)) + copy(z[1:], m.compressionMethods) + + z = z[1+len(m.compressionMethods):] + if numExtensions > 0 { + z[0] = byte(extensionsLength >> 8) + z[1] = byte(extensionsLength) + z = z[2:] + } + if m.nextProtoNeg { + z[0] = byte(extensionNextProtoNeg >> 8) + z[1] = byte(extensionNextProtoNeg & 0xff) + // The length is always 0 + z = z[4:] + } + if len(m.serverName) > 0 { + z[0] = byte(extensionServerName >> 8) + z[1] = byte(extensionServerName & 0xff) + l := len(m.serverName) + 5 + z[2] = byte(l >> 8) + z[3] = byte(l) + z = z[4:] + + // RFC 3546, section 3.1 + // + // struct { + // NameType name_type; + // select (name_type) { + // case host_name: HostName; + // } name; + // } ServerName; + // + // enum { + // host_name(0), (255) + // } NameType; + // + // opaque HostName<1..2^16-1>; + // + // struct { + // ServerName server_name_list<1..2^16-1> + // } ServerNameList; + + z[0] = byte((len(m.serverName) + 3) >> 8) + z[1] = byte(len(m.serverName) + 3) + z[3] = byte(len(m.serverName) >> 8) + z[4] = byte(len(m.serverName)) + copy(z[5:], []byte(m.serverName)) + z = z[l:] + } + if m.ocspStapling { + // RFC 4366, section 3.6 + z[0] = byte(extensionStatusRequest >> 8) + z[1] = byte(extensionStatusRequest) + z[2] = 0 + z[3] = 5 + z[4] = 1 // OCSP type + // Two zero valued uint16s for the two lengths. + z = z[9:] + } + if len(m.supportedCurves) > 0 { + // http://tools.ietf.org/html/rfc4492#section-5.5.1 + z[0] = byte(extensionSupportedCurves >> 8) + z[1] = byte(extensionSupportedCurves) + l := 2 + 2*len(m.supportedCurves) + z[2] = byte(l >> 8) + z[3] = byte(l) + l -= 2 + z[4] = byte(l >> 8) + z[5] = byte(l) + z = z[6:] + for _, curve := range m.supportedCurves { + z[0] = byte(curve >> 8) + z[1] = byte(curve) + z = z[2:] + } + } + if len(m.supportedPoints) > 0 { + // http://tools.ietf.org/html/rfc4492#section-5.5.2 + z[0] = byte(extensionSupportedPoints >> 8) + z[1] = byte(extensionSupportedPoints) + l := 1 + len(m.supportedPoints) + z[2] = byte(l >> 8) + z[3] = byte(l) + l-- + z[4] = byte(l) + z = z[5:] + for _, pointFormat := range m.supportedPoints { + z[0] = byte(pointFormat) + z = z[1:] + } + } + if m.ticketSupported { + // http://tools.ietf.org/html/rfc5077#section-3.2 + z[0] = byte(extensionSessionTicket >> 8) + z[1] = byte(extensionSessionTicket) + l := len(m.sessionTicket) + z[2] = byte(l >> 8) + z[3] = byte(l) + z = z[4:] + copy(z, m.sessionTicket) + z = z[len(m.sessionTicket):] + } + if len(m.signatureAndHashes) > 0 { + // https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 + z[0] = byte(extensionSignatureAlgorithms >> 8) + z[1] = byte(extensionSignatureAlgorithms) + l := 2 + 2*len(m.signatureAndHashes) + 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 _, sigAndHash := range m.signatureAndHashes { + z[0] = sigAndHash.hash + z[1] = sigAndHash.signature + z = z[2:] + } + } + if m.secureRenegotiation { + z[0] = byte(extensionRenegotiationInfo >> 8) + z[1] = byte(extensionRenegotiationInfo & 0xff) + z[2] = 0 + z[3] = 1 + z = z[5:] + } + if len(m.alpnProtocols) > 0 { + z[0] = byte(extensionALPN >> 8) + z[1] = byte(extensionALPN & 0xff) + lengths := z[2:] + z = z[6:] + + stringsLength := 0 + for _, s := range m.alpnProtocols { + l := len(s) + z[0] = byte(l) + copy(z[1:], s) + z = z[1+l:] + stringsLength += 1 + l + } + + lengths[2] = byte(stringsLength >> 8) + lengths[3] = byte(stringsLength) + stringsLength += 2 + lengths[0] = byte(stringsLength >> 8) + lengths[1] = byte(stringsLength) + } + if m.scts { + // https://tools.ietf.org/html/rfc6962#section-3.3.1 + z[0] = byte(extensionSCT >> 8) + z[1] = byte(extensionSCT) + // zero uint16 for the zero-length extension_data + z = z[4:] + } + + m.raw = x + + return x +} + +func (m *clientHelloMsg) unmarshal(data []byte) bool { + if len(data) < 42 { + return false + } + m.raw = data + m.vers = uint16(data[4])<<8 | uint16(data[5]) + m.random = data[6:38] + sessionIdLen := int(data[38]) + if sessionIdLen > 32 || len(data) < 39+sessionIdLen { + return false + } + m.sessionId = data[39 : 39+sessionIdLen] + data = data[39+sessionIdLen:] + if len(data) < 2 { + return false + } + // cipherSuiteLen is the number of bytes of cipher suite numbers. Since + // they are uint16s, the number must be even. + cipherSuiteLen := int(data[0])<<8 | int(data[1]) + if cipherSuiteLen%2 == 1 || len(data) < 2+cipherSuiteLen { + return false + } + numCipherSuites := cipherSuiteLen / 2 + m.cipherSuites = make([]uint16, numCipherSuites) + for i := 0; i < numCipherSuites; i++ { + m.cipherSuites[i] = uint16(data[2+2*i])<<8 | uint16(data[3+2*i]) + if m.cipherSuites[i] == scsvRenegotiation { + m.secureRenegotiation = true + } + } + data = data[2+cipherSuiteLen:] + if len(data) < 1 { + return false + } + compressionMethodsLen := int(data[0]) + if len(data) < 1+compressionMethodsLen { + return false + } + m.compressionMethods = data[1 : 1+compressionMethodsLen] + + data = data[1+compressionMethodsLen:] + + m.nextProtoNeg = false + m.serverName = "" + m.ocspStapling = false + m.ticketSupported = false + m.sessionTicket = nil + m.signatureAndHashes = nil + m.alpnProtocols = nil + m.scts = false + + if len(data) == 0 { + // ClientHello is optionally followed by extension data + return true + } + if len(data) < 2 { + return false + } + + extensionsLength := int(data[0])<<8 | int(data[1]) + data = data[2:] + if extensionsLength != len(data) { + return false + } + + for len(data) != 0 { + if len(data) < 4 { + return false + } + extension := uint16(data[0])<<8 | uint16(data[1]) + length := int(data[2])<<8 | int(data[3]) + data = data[4:] + if len(data) < length { + return false + } + + switch extension { + case extensionServerName: + d := data[:length] + if len(d) < 2 { + return false + } + namesLen := int(d[0])<<8 | int(d[1]) + d = d[2:] + if len(d) != namesLen { + return false + } + for len(d) > 0 { + if len(d) < 3 { + return false + } + nameType := d[0] + nameLen := int(d[1])<<8 | int(d[2]) + d = d[3:] + if len(d) < nameLen { + return false + } + if nameType == 0 { + m.serverName = string(d[:nameLen]) + break + } + d = d[nameLen:] + } + case extensionNextProtoNeg: + if length > 0 { + return false + } + m.nextProtoNeg = true + case extensionStatusRequest: + m.ocspStapling = length > 0 && data[0] == statusTypeOCSP + case extensionSupportedCurves: + // http://tools.ietf.org/html/rfc4492#section-5.5.1 + if length < 2 { + return false + } + l := int(data[0])<<8 | int(data[1]) + if l%2 == 1 || length != l+2 { + return false + } + numCurves := l / 2 + m.supportedCurves = make([]CurveID, numCurves) + d := data[2:] + for i := 0; i < numCurves; i++ { + m.supportedCurves[i] = CurveID(d[0])<<8 | CurveID(d[1]) + d = d[2:] + } + case extensionSupportedPoints: + // http://tools.ietf.org/html/rfc4492#section-5.5.2 + if length < 1 { + return false + } + l := int(data[0]) + if length != l+1 { + return false + } + m.supportedPoints = make([]uint8, l) + copy(m.supportedPoints, data[1:]) + case extensionSessionTicket: + // http://tools.ietf.org/html/rfc5077#section-3.2 + m.ticketSupported = true + m.sessionTicket = data[:length] + case extensionSignatureAlgorithms: + // https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 + if length < 2 || length&1 != 0 { + return false + } + l := int(data[0])<<8 | int(data[1]) + if l != length-2 { + return false + } + n := l / 2 + d := data[2:] + m.signatureAndHashes = make([]signatureAndHash, n) + for i := range m.signatureAndHashes { + m.signatureAndHashes[i].hash = d[0] + m.signatureAndHashes[i].signature = d[1] + d = d[2:] + } + case extensionRenegotiationInfo: + if length != 1 || data[0] != 0 { + return false + } + m.secureRenegotiation = true + case extensionALPN: + if length < 2 { + return false + } + l := int(data[0])<<8 | int(data[1]) + if l != length-2 { + return false + } + d := data[2:length] + for len(d) != 0 { + stringLen := int(d[0]) + d = d[1:] + if stringLen == 0 || stringLen > len(d) { + return false + } + m.alpnProtocols = append(m.alpnProtocols, string(d[:stringLen])) + d = d[stringLen:] + } + case extensionSCT: + m.scts = true + if length != 0 { + return false + } + } + data = data[length:] + } + + return true +} + +type serverHelloMsg struct { + raw []byte + vers uint16 + random []byte + sessionId []byte + cipherSuite uint16 + compressionMethod uint8 + nextProtoNeg bool + nextProtos []string + ocspStapling bool + scts [][]byte + ticketSupported bool + secureRenegotiation bool + alpnProtocol string +} + +func (m *serverHelloMsg) equal(i interface{}) bool { + m1, ok := i.(*serverHelloMsg) + if !ok { + return false + } + + if len(m.scts) != len(m1.scts) { + return false + } + for i, sct := range m.scts { + if !bytes.Equal(sct, m1.scts[i]) { + return false + } + } + + return bytes.Equal(m.raw, m1.raw) && + m.vers == m1.vers && + bytes.Equal(m.random, m1.random) && + bytes.Equal(m.sessionId, m1.sessionId) && + m.cipherSuite == m1.cipherSuite && + m.compressionMethod == m1.compressionMethod && + m.nextProtoNeg == m1.nextProtoNeg && + eqStrings(m.nextProtos, m1.nextProtos) && + m.ocspStapling == m1.ocspStapling && + m.ticketSupported == m1.ticketSupported && + m.secureRenegotiation == m1.secureRenegotiation && + m.alpnProtocol == m1.alpnProtocol +} + +func (m *serverHelloMsg) marshal() []byte { + if m.raw != nil { + return m.raw + } + + length := 38 + len(m.sessionId) + numExtensions := 0 + extensionsLength := 0 + + nextProtoLen := 0 + if m.nextProtoNeg { + numExtensions++ + for _, v := range m.nextProtos { + nextProtoLen += len(v) + } + nextProtoLen += len(m.nextProtos) + extensionsLength += nextProtoLen + } + if m.ocspStapling { + numExtensions++ + } + if m.ticketSupported { + numExtensions++ + } + if m.secureRenegotiation { + extensionsLength += 1 + numExtensions++ + } + if alpnLen := len(m.alpnProtocol); alpnLen > 0 { + if alpnLen >= 256 { + panic("invalid ALPN protocol") + } + extensionsLength += 2 + 1 + alpnLen + numExtensions++ + } + sctLen := 0 + if len(m.scts) > 0 { + for _, sct := range m.scts { + sctLen += len(sct) + 2 + } + extensionsLength += 2 + sctLen + numExtensions++ + } + + if numExtensions > 0 { + extensionsLength += 4 * numExtensions + length += 2 + extensionsLength + } + + x := make([]byte, 4+length) + x[0] = typeServerHello + x[1] = uint8(length >> 16) + x[2] = uint8(length >> 8) + x[3] = uint8(length) + x[4] = uint8(m.vers >> 8) + x[5] = uint8(m.vers) + copy(x[6:38], m.random) + x[38] = uint8(len(m.sessionId)) + copy(x[39:39+len(m.sessionId)], m.sessionId) + z := x[39+len(m.sessionId):] + z[0] = uint8(m.cipherSuite >> 8) + z[1] = uint8(m.cipherSuite) + z[2] = uint8(m.compressionMethod) + + z = z[3:] + if numExtensions > 0 { + z[0] = byte(extensionsLength >> 8) + z[1] = byte(extensionsLength) + z = z[2:] + } + if m.nextProtoNeg { + z[0] = byte(extensionNextProtoNeg >> 8) + z[1] = byte(extensionNextProtoNeg & 0xff) + z[2] = byte(nextProtoLen >> 8) + z[3] = byte(nextProtoLen) + z = z[4:] + + for _, v := range m.nextProtos { + l := len(v) + if l > 255 { + l = 255 + } + z[0] = byte(l) + copy(z[1:], []byte(v[0:l])) + z = z[1+l:] + } + } + if m.ocspStapling { + z[0] = byte(extensionStatusRequest >> 8) + z[1] = byte(extensionStatusRequest) + z = z[4:] + } + if m.ticketSupported { + z[0] = byte(extensionSessionTicket >> 8) + z[1] = byte(extensionSessionTicket) + z = z[4:] + } + if m.secureRenegotiation { + z[0] = byte(extensionRenegotiationInfo >> 8) + z[1] = byte(extensionRenegotiationInfo & 0xff) + z[2] = 0 + z[3] = 1 + z = z[5:] + } + if alpnLen := len(m.alpnProtocol); alpnLen > 0 { + z[0] = byte(extensionALPN >> 8) + z[1] = byte(extensionALPN & 0xff) + l := 2 + 1 + alpnLen + z[2] = byte(l >> 8) + z[3] = byte(l) + l -= 2 + z[4] = byte(l >> 8) + z[5] = byte(l) + l -= 1 + z[6] = byte(l) + copy(z[7:], []byte(m.alpnProtocol)) + z = z[7+alpnLen:] + } + if sctLen > 0 { + z[0] = byte(extensionSCT >> 8) + z[1] = byte(extensionSCT) + l := sctLen + 2 + z[2] = byte(l >> 8) + z[3] = byte(l) + z[4] = byte(sctLen >> 8) + z[5] = byte(sctLen) + + z = z[6:] + for _, sct := range m.scts { + z[0] = byte(len(sct) >> 8) + z[1] = byte(len(sct)) + copy(z[2:], sct) + z = z[len(sct)+2:] + } + } + + m.raw = x + + return x +} + +func (m *serverHelloMsg) unmarshal(data []byte) bool { + if len(data) < 42 { + return false + } + m.raw = data + m.vers = uint16(data[4])<<8 | uint16(data[5]) + m.random = data[6:38] + sessionIdLen := int(data[38]) + if sessionIdLen > 32 || len(data) < 39+sessionIdLen { + return false + } + m.sessionId = data[39 : 39+sessionIdLen] + data = data[39+sessionIdLen:] + if len(data) < 3 { + return false + } + m.cipherSuite = uint16(data[0])<<8 | uint16(data[1]) + m.compressionMethod = data[2] + data = data[3:] + + m.nextProtoNeg = false + m.nextProtos = nil + m.ocspStapling = false + m.scts = nil + m.ticketSupported = false + m.alpnProtocol = "" + + if len(data) == 0 { + // ServerHello is optionally followed by extension data + return true + } + if len(data) < 2 { + return false + } + + extensionsLength := int(data[0])<<8 | int(data[1]) + data = data[2:] + if len(data) != extensionsLength { + return false + } + + for len(data) != 0 { + if len(data) < 4 { + return false + } + extension := uint16(data[0])<<8 | uint16(data[1]) + length := int(data[2])<<8 | int(data[3]) + data = data[4:] + if len(data) < length { + return false + } + + switch extension { + case extensionNextProtoNeg: + m.nextProtoNeg = true + d := data[:length] + for len(d) > 0 { + l := int(d[0]) + d = d[1:] + if l == 0 || l > len(d) { + return false + } + m.nextProtos = append(m.nextProtos, string(d[:l])) + d = d[l:] + } + case extensionStatusRequest: + if length > 0 { + return false + } + m.ocspStapling = true + case extensionSessionTicket: + if length > 0 { + return false + } + m.ticketSupported = true + case extensionRenegotiationInfo: + if length != 1 || data[0] != 0 { + return false + } + m.secureRenegotiation = true + case extensionALPN: + d := data[:length] + if len(d) < 3 { + return false + } + l := int(d[0])<<8 | int(d[1]) + if l != len(d)-2 { + return false + } + d = d[2:] + l = int(d[0]) + if l != len(d)-1 { + return false + } + d = d[1:] + if len(d) == 0 { + // ALPN protocols must not be empty. + return false + } + m.alpnProtocol = string(d) + case extensionSCT: + d := data[:length] + + if len(d) < 2 { + return false + } + l := int(d[0])<<8 | int(d[1]) + d = d[2:] + if len(d) != l { + return false + } + if l == 0 { + continue + } + + m.scts = make([][]byte, 0, 3) + for len(d) != 0 { + if len(d) < 2 { + return false + } + sctLen := int(d[0])<<8 | int(d[1]) + d = d[2:] + if len(d) < sctLen { + return false + } + m.scts = append(m.scts, d[:sctLen]) + d = d[sctLen:] + } + } + data = data[length:] + } + + return true +} + +type certificateMsg struct { + raw []byte + certificates [][]byte +} + +func (m *certificateMsg) equal(i interface{}) bool { + m1, ok := i.(*certificateMsg) + if !ok { + return false + } + + return bytes.Equal(m.raw, m1.raw) && + eqByteSlices(m.certificates, m1.certificates) +} + +func (m *certificateMsg) marshal() (x []byte) { + if m.raw != nil { + return m.raw + } + + var i int + for _, slice := range m.certificates { + i += len(slice) + } + + length := 3 + 3*len(m.certificates) + i + x = make([]byte, 4+length) + x[0] = typeCertificate + x[1] = uint8(length >> 16) + x[2] = uint8(length >> 8) + x[3] = uint8(length) + + certificateOctets := length - 3 + x[4] = uint8(certificateOctets >> 16) + x[5] = uint8(certificateOctets >> 8) + x[6] = uint8(certificateOctets) + + y := x[7:] + for _, slice := range m.certificates { + y[0] = uint8(len(slice) >> 16) + y[1] = uint8(len(slice) >> 8) + y[2] = uint8(len(slice)) + copy(y[3:], slice) + y = y[3+len(slice):] + } + + m.raw = x + return +} + +func (m *certificateMsg) unmarshal(data []byte) bool { + if len(data) < 7 { + return false + } + + m.raw = data + certsLen := uint32(data[4])<<16 | uint32(data[5])<<8 | uint32(data[6]) + if uint32(len(data)) != certsLen+7 { + return false + } + + numCerts := 0 + d := data[7:] + for certsLen > 0 { + if len(d) < 4 { + return false + } + certLen := uint32(d[0])<<16 | uint32(d[1])<<8 | uint32(d[2]) + if uint32(len(d)) < 3+certLen { + return false + } + d = d[3+certLen:] + certsLen -= 3 + certLen + numCerts++ + } + + m.certificates = make([][]byte, numCerts) + d = data[7:] + for i := 0; i < numCerts; i++ { + certLen := uint32(d[0])<<16 | uint32(d[1])<<8 | uint32(d[2]) + m.certificates[i] = d[3 : 3+certLen] + d = d[3+certLen:] + } + + return true +} + +type serverKeyExchangeMsg struct { + raw []byte + key []byte +} + +func (m *serverKeyExchangeMsg) equal(i interface{}) bool { + m1, ok := i.(*serverKeyExchangeMsg) + if !ok { + return false + } + + return bytes.Equal(m.raw, m1.raw) && + bytes.Equal(m.key, m1.key) +} + +func (m *serverKeyExchangeMsg) marshal() []byte { + if m.raw != nil { + return m.raw + } + length := len(m.key) + x := make([]byte, length+4) + x[0] = typeServerKeyExchange + x[1] = uint8(length >> 16) + x[2] = uint8(length >> 8) + x[3] = uint8(length) + copy(x[4:], m.key) + + m.raw = x + return x +} + +func (m *serverKeyExchangeMsg) unmarshal(data []byte) bool { + m.raw = data + if len(data) < 4 { + return false + } + m.key = data[4:] + return true +} + +type certificateStatusMsg struct { + raw []byte + statusType uint8 + response []byte +} + +func (m *certificateStatusMsg) equal(i interface{}) bool { + m1, ok := i.(*certificateStatusMsg) + if !ok { + return false + } + + return bytes.Equal(m.raw, m1.raw) && + m.statusType == m1.statusType && + bytes.Equal(m.response, m1.response) +} + +func (m *certificateStatusMsg) marshal() []byte { + if m.raw != nil { + return m.raw + } + + var x []byte + if m.statusType == statusTypeOCSP { + x = make([]byte, 4+4+len(m.response)) + x[0] = typeCertificateStatus + l := len(m.response) + 4 + x[1] = byte(l >> 16) + x[2] = byte(l >> 8) + x[3] = byte(l) + x[4] = statusTypeOCSP + + l -= 4 + x[5] = byte(l >> 16) + x[6] = byte(l >> 8) + x[7] = byte(l) + copy(x[8:], m.response) + } else { + x = []byte{typeCertificateStatus, 0, 0, 1, m.statusType} + } + + m.raw = x + return x +} + +func (m *certificateStatusMsg) unmarshal(data []byte) bool { + m.raw = data + if len(data) < 5 { + return false + } + m.statusType = data[4] + + m.response = nil + if m.statusType == statusTypeOCSP { + if len(data) < 8 { + return false + } + respLen := uint32(data[5])<<16 | uint32(data[6])<<8 | uint32(data[7]) + if uint32(len(data)) != 4+4+respLen { + return false + } + m.response = data[8:] + } + return true +} + +type serverHelloDoneMsg struct{} + +func (m *serverHelloDoneMsg) equal(i interface{}) bool { + _, ok := i.(*serverHelloDoneMsg) + return ok +} + +func (m *serverHelloDoneMsg) marshal() []byte { + x := make([]byte, 4) + x[0] = typeServerHelloDone + return x +} + +func (m *serverHelloDoneMsg) unmarshal(data []byte) bool { + return len(data) == 4 +} + +type clientKeyExchangeMsg struct { + raw []byte + ciphertext []byte +} + +func (m *clientKeyExchangeMsg) equal(i interface{}) bool { + m1, ok := i.(*clientKeyExchangeMsg) + if !ok { + return false + } + + return bytes.Equal(m.raw, m1.raw) && + bytes.Equal(m.ciphertext, m1.ciphertext) +} + +func (m *clientKeyExchangeMsg) marshal() []byte { + if m.raw != nil { + return m.raw + } + length := len(m.ciphertext) + x := make([]byte, length+4) + x[0] = typeClientKeyExchange + x[1] = uint8(length >> 16) + x[2] = uint8(length >> 8) + x[3] = uint8(length) + copy(x[4:], m.ciphertext) + + m.raw = x + return x +} + +func (m *clientKeyExchangeMsg) unmarshal(data []byte) bool { + m.raw = data + if len(data) < 4 { + return false + } + l := int(data[1])<<16 | int(data[2])<<8 | int(data[3]) + if l != len(data)-4 { + return false + } + m.ciphertext = data[4:] + return true +} + +type finishedMsg struct { + raw []byte + verifyData []byte +} + +func (m *finishedMsg) equal(i interface{}) bool { + m1, ok := i.(*finishedMsg) + if !ok { + return false + } + + return bytes.Equal(m.raw, m1.raw) && + bytes.Equal(m.verifyData, m1.verifyData) +} + +func (m *finishedMsg) marshal() (x []byte) { + if m.raw != nil { + return m.raw + } + + x = make([]byte, 4+len(m.verifyData)) + x[0] = typeFinished + x[3] = byte(len(m.verifyData)) + copy(x[4:], m.verifyData) + m.raw = x + return +} + +func (m *finishedMsg) unmarshal(data []byte) bool { + m.raw = data + if len(data) < 4 { + return false + } + m.verifyData = data[4:] + return true +} + +type nextProtoMsg struct { + raw []byte + proto string +} + +func (m *nextProtoMsg) equal(i interface{}) bool { + m1, ok := i.(*nextProtoMsg) + if !ok { + return false + } + + return bytes.Equal(m.raw, m1.raw) && + m.proto == m1.proto +} + +func (m *nextProtoMsg) marshal() []byte { + if m.raw != nil { + return m.raw + } + l := len(m.proto) + if l > 255 { + l = 255 + } + + padding := 32 - (l+2)%32 + length := l + padding + 2 + x := make([]byte, length+4) + x[0] = typeNextProtocol + x[1] = uint8(length >> 16) + x[2] = uint8(length >> 8) + x[3] = uint8(length) + + y := x[4:] + y[0] = byte(l) + copy(y[1:], []byte(m.proto[0:l])) + y = y[1+l:] + y[0] = byte(padding) + + m.raw = x + + return x +} + +func (m *nextProtoMsg) unmarshal(data []byte) bool { + m.raw = data + + if len(data) < 5 { + return false + } + data = data[4:] + protoLen := int(data[0]) + data = data[1:] + if len(data) < protoLen { + return false + } + m.proto = string(data[0:protoLen]) + data = data[protoLen:] + + if len(data) < 1 { + return false + } + paddingLen := int(data[0]) + data = data[1:] + if len(data) != paddingLen { + return false + } + + return true +} + +type certificateRequestMsg struct { + raw []byte + // hasSignatureAndHash indicates whether this message includes a list + // of signature and hash functions. This change was introduced with TLS + // 1.2. + hasSignatureAndHash bool + + certificateTypes []byte + signatureAndHashes []signatureAndHash + certificateAuthorities [][]byte +} + +func (m *certificateRequestMsg) equal(i interface{}) bool { + m1, ok := i.(*certificateRequestMsg) + if !ok { + return false + } + + return bytes.Equal(m.raw, m1.raw) && + bytes.Equal(m.certificateTypes, m1.certificateTypes) && + eqByteSlices(m.certificateAuthorities, m1.certificateAuthorities) && + eqSignatureAndHashes(m.signatureAndHashes, m1.signatureAndHashes) +} + +func (m *certificateRequestMsg) marshal() (x []byte) { + if m.raw != nil { + return m.raw + } + + // See http://tools.ietf.org/html/rfc4346#section-7.4.4 + length := 1 + len(m.certificateTypes) + 2 + casLength := 0 + for _, ca := range m.certificateAuthorities { + casLength += 2 + len(ca) + } + length += casLength + + if m.hasSignatureAndHash { + length += 2 + 2*len(m.signatureAndHashes) + } + + x = make([]byte, 4+length) + x[0] = typeCertificateRequest + x[1] = uint8(length >> 16) + x[2] = uint8(length >> 8) + x[3] = uint8(length) + + x[4] = uint8(len(m.certificateTypes)) + + copy(x[5:], m.certificateTypes) + y := x[5+len(m.certificateTypes):] + + if m.hasSignatureAndHash { + n := len(m.signatureAndHashes) * 2 + y[0] = uint8(n >> 8) + y[1] = uint8(n) + y = y[2:] + for _, sigAndHash := range m.signatureAndHashes { + y[0] = sigAndHash.hash + y[1] = sigAndHash.signature + y = y[2:] + } + } + + y[0] = uint8(casLength >> 8) + y[1] = uint8(casLength) + y = y[2:] + for _, ca := range m.certificateAuthorities { + y[0] = uint8(len(ca) >> 8) + y[1] = uint8(len(ca)) + y = y[2:] + copy(y, ca) + y = y[len(ca):] + } + + m.raw = x + return +} + +func (m *certificateRequestMsg) unmarshal(data []byte) bool { + m.raw = data + + if len(data) < 5 { + return false + } + + length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3]) + if uint32(len(data))-4 != length { + return false + } + + numCertTypes := int(data[4]) + data = data[5:] + if numCertTypes == 0 || len(data) <= numCertTypes { + return false + } + + m.certificateTypes = make([]byte, numCertTypes) + if copy(m.certificateTypes, data) != numCertTypes { + return false + } + + data = data[numCertTypes:] + + if m.hasSignatureAndHash { + if len(data) < 2 { + return false + } + sigAndHashLen := uint16(data[0])<<8 | uint16(data[1]) + data = data[2:] + if sigAndHashLen&1 != 0 { + return false + } + if len(data) < int(sigAndHashLen) { + return false + } + numSigAndHash := sigAndHashLen / 2 + m.signatureAndHashes = make([]signatureAndHash, numSigAndHash) + for i := range m.signatureAndHashes { + m.signatureAndHashes[i].hash = data[0] + m.signatureAndHashes[i].signature = data[1] + data = data[2:] + } + } + + if len(data) < 2 { + return false + } + casLength := uint16(data[0])<<8 | uint16(data[1]) + data = data[2:] + if len(data) < int(casLength) { + return false + } + cas := make([]byte, casLength) + copy(cas, data) + data = data[casLength:] + + m.certificateAuthorities = nil + for len(cas) > 0 { + if len(cas) < 2 { + return false + } + caLen := uint16(cas[0])<<8 | uint16(cas[1]) + cas = cas[2:] + + if len(cas) < int(caLen) { + return false + } + + m.certificateAuthorities = append(m.certificateAuthorities, cas[:caLen]) + cas = cas[caLen:] + } + if len(data) > 0 { + return false + } + + return true +} + +type certificateVerifyMsg struct { + raw []byte + hasSignatureAndHash bool + signatureAndHash signatureAndHash + signature []byte +} + +func (m *certificateVerifyMsg) equal(i interface{}) bool { + m1, ok := i.(*certificateVerifyMsg) + if !ok { + return false + } + + return bytes.Equal(m.raw, m1.raw) && + m.hasSignatureAndHash == m1.hasSignatureAndHash && + m.signatureAndHash.hash == m1.signatureAndHash.hash && + m.signatureAndHash.signature == m1.signatureAndHash.signature && + bytes.Equal(m.signature, m1.signature) +} + +func (m *certificateVerifyMsg) marshal() (x []byte) { + if m.raw != nil { + return m.raw + } + + // See http://tools.ietf.org/html/rfc4346#section-7.4.8 + siglength := len(m.signature) + length := 2 + siglength + if m.hasSignatureAndHash { + length += 2 + } + x = make([]byte, 4+length) + x[0] = typeCertificateVerify + x[1] = uint8(length >> 16) + x[2] = uint8(length >> 8) + x[3] = uint8(length) + y := x[4:] + if m.hasSignatureAndHash { + y[0] = m.signatureAndHash.hash + y[1] = m.signatureAndHash.signature + y = y[2:] + } + y[0] = uint8(siglength >> 8) + y[1] = uint8(siglength) + copy(y[2:], m.signature) + + m.raw = x + + return +} + +func (m *certificateVerifyMsg) unmarshal(data []byte) bool { + m.raw = data + + if len(data) < 6 { + return false + } + + length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3]) + if uint32(len(data))-4 != length { + return false + } + + data = data[4:] + if m.hasSignatureAndHash { + m.signatureAndHash.hash = data[0] + m.signatureAndHash.signature = data[1] + data = data[2:] + } + + if len(data) < 2 { + return false + } + siglength := int(data[0])<<8 + int(data[1]) + data = data[2:] + if len(data) != siglength { + return false + } + + m.signature = data + + return true +} + +type newSessionTicketMsg struct { + raw []byte + ticket []byte +} + +func (m *newSessionTicketMsg) equal(i interface{}) bool { + m1, ok := i.(*newSessionTicketMsg) + if !ok { + return false + } + + return bytes.Equal(m.raw, m1.raw) && + bytes.Equal(m.ticket, m1.ticket) +} + +func (m *newSessionTicketMsg) marshal() (x []byte) { + if m.raw != nil { + return m.raw + } + + // See http://tools.ietf.org/html/rfc5077#section-3.3 + ticketLen := len(m.ticket) + length := 2 + 4 + ticketLen + x = make([]byte, 4+length) + x[0] = typeNewSessionTicket + x[1] = uint8(length >> 16) + x[2] = uint8(length >> 8) + x[3] = uint8(length) + x[8] = uint8(ticketLen >> 8) + x[9] = uint8(ticketLen) + copy(x[10:], m.ticket) + + m.raw = x + + return +} + +func (m *newSessionTicketMsg) unmarshal(data []byte) bool { + m.raw = data + + if len(data) < 10 { + return false + } + + length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3]) + if uint32(len(data))-4 != length { + return false + } + + ticketLen := int(data[8])<<8 + int(data[9]) + if len(data)-10 != ticketLen { + return false + } + + m.ticket = data[10:] + + return true +} + +func eqUint16s(x, y []uint16) bool { + if len(x) != len(y) { + return false + } + for i, v := range x { + if y[i] != v { + return false + } + } + return true +} + +func eqCurveIDs(x, y []CurveID) bool { + if len(x) != len(y) { + return false + } + for i, v := range x { + if y[i] != v { + return false + } + } + return true +} + +func eqStrings(x, y []string) bool { + if len(x) != len(y) { + return false + } + for i, v := range x { + if y[i] != v { + return false + } + } + return true +} + +func eqByteSlices(x, y [][]byte) bool { + if len(x) != len(y) { + return false + } + for i, v := range x { + if !bytes.Equal(v, y[i]) { + return false + } + } + return true +} + +func eqSignatureAndHashes(x, y []signatureAndHash) bool { + if len(x) != len(y) { + return false + } + for i, v := range x { + v2 := y[i] + if v.hash != v2.hash || v.signature != v2.signature { + return false + } + } + return true +} diff --git a/vendor/github.com/cloudflare/cfssl/scan/crypto/tls/handshake_server.go b/vendor/github.com/cloudflare/cfssl/scan/crypto/tls/handshake_server.go new file mode 100644 index 00000000000..e16cddcbd81 --- /dev/null +++ b/vendor/github.com/cloudflare/cfssl/scan/crypto/tls/handshake_server.go @@ -0,0 +1,750 @@ +// Copyright 2009 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/ecdsa" + "crypto/rsa" + "crypto/subtle" + "crypto/x509" + "encoding/asn1" + "errors" + "fmt" + "io" +) + +// serverHandshakeState contains details of a server handshake in progress. +// It's discarded once the handshake has completed. +type serverHandshakeState struct { + c *Conn + clientHello *clientHelloMsg + hello *serverHelloMsg + suite *cipherSuite + ellipticOk bool + ecdsaOk bool + rsaDecryptOk bool + rsaSignOk bool + sessionState *sessionState + finishedHash finishedHash + masterSecret []byte + certsFromClient [][]byte + cert *Certificate +} + +// serverHandshake performs a TLS handshake as a server. +func (c *Conn) serverHandshake() error { + config := c.config + + // If this is the first server handshake, we generate a random key to + // encrypt the tickets with. + config.serverInitOnce.Do(config.serverInit) + + hs := serverHandshakeState{ + c: c, + } + isResume, err := hs.readClientHello() + if err != nil { + return err + } + + // For an overview of TLS handshaking, see https://tools.ietf.org/html/rfc5246#section-7.3 + if isResume { + // The client has included a session ticket and so we do an abbreviated handshake. + if err := hs.doResumeHandshake(); err != nil { + return err + } + if err := hs.establishKeys(); err != nil { + return err + } + // ticketSupported is set in a resumption handshake if the + // ticket from the client was encrypted with an old session + // ticket key and thus a refreshed ticket should be sent. + if hs.hello.ticketSupported { + if err := hs.sendSessionTicket(); err != nil { + return err + } + } + if err := hs.sendFinished(c.firstFinished[:]); err != nil { + return err + } + if err := hs.readFinished(nil); err != nil { + return err + } + c.didResume = true + } else { + // The client didn't include a session ticket, or it wasn't + // valid so we do a full handshake. + if err := hs.doFullHandshake(); err != nil { + return err + } + if err := hs.establishKeys(); err != nil { + return err + } + if err := hs.readFinished(c.firstFinished[:]); err != nil { + return err + } + if err := hs.sendSessionTicket(); err != nil { + return err + } + if err := hs.sendFinished(nil); err != nil { + return err + } + } + c.handshakeComplete = true + + return nil +} + +// readClientHello reads a ClientHello message from the client and decides +// whether we will perform session resumption. +func (hs *serverHandshakeState) readClientHello() (isResume bool, err error) { + config := hs.c.config + c := hs.c + + msg, err := c.readHandshake() + if err != nil { + return false, err + } + var ok bool + hs.clientHello, ok = msg.(*clientHelloMsg) + if !ok { + c.sendAlert(alertUnexpectedMessage) + return false, unexpectedMessageError(hs.clientHello, msg) + } + c.vers, ok = config.mutualVersion(hs.clientHello.vers) + if !ok { + c.sendAlert(alertProtocolVersion) + return false, fmt.Errorf("tls: client offered an unsupported, maximum protocol version of %x", hs.clientHello.vers) + } + c.haveVers = true + + hs.hello = new(serverHelloMsg) + + supportedCurve := false + preferredCurves := config.curvePreferences() +Curves: + for _, curve := range hs.clientHello.supportedCurves { + for _, supported := range preferredCurves { + if supported == curve { + supportedCurve = true + break Curves + } + } + } + + supportedPointFormat := false + for _, pointFormat := range hs.clientHello.supportedPoints { + if pointFormat == pointFormatUncompressed { + supportedPointFormat = true + break + } + } + hs.ellipticOk = supportedCurve && supportedPointFormat + + foundCompression := false + // We only support null compression, so check that the client offered it. + for _, compression := range hs.clientHello.compressionMethods { + if compression == compressionNone { + foundCompression = true + break + } + } + + if !foundCompression { + c.sendAlert(alertHandshakeFailure) + return false, errors.New("tls: client does not support uncompressed connections") + } + + hs.hello.vers = c.vers + hs.hello.random = make([]byte, 32) + _, err = io.ReadFull(config.rand(), hs.hello.random) + if err != nil { + c.sendAlert(alertInternalError) + return false, err + } + hs.hello.secureRenegotiation = hs.clientHello.secureRenegotiation + hs.hello.compressionMethod = compressionNone + if len(hs.clientHello.serverName) > 0 { + c.serverName = hs.clientHello.serverName + } + + if len(hs.clientHello.alpnProtocols) > 0 { + if selectedProto, fallback := mutualProtocol(hs.clientHello.alpnProtocols, c.config.NextProtos); !fallback { + hs.hello.alpnProtocol = selectedProto + c.clientProtocol = selectedProto + } + } else { + // Although sending an empty NPN extension is reasonable, Firefox has + // had a bug around this. Best to send nothing at all if + // config.NextProtos is empty. See + // https://golang.org/issue/5445. + if hs.clientHello.nextProtoNeg && len(config.NextProtos) > 0 { + hs.hello.nextProtoNeg = true + hs.hello.nextProtos = config.NextProtos + } + } + + if hs.cert, err = config.getCertificate(&ClientHelloInfo{ + CipherSuites: hs.clientHello.cipherSuites, + ServerName: hs.clientHello.serverName, + SupportedCurves: hs.clientHello.supportedCurves, + SupportedPoints: hs.clientHello.supportedPoints, + }); err != nil { + c.sendAlert(alertInternalError) + return false, err + } + if hs.clientHello.scts { + hs.hello.scts = hs.cert.SignedCertificateTimestamps + } + + if priv, ok := hs.cert.PrivateKey.(crypto.Signer); ok { + switch priv.Public().(type) { + case *ecdsa.PublicKey: + hs.ecdsaOk = true + case *rsa.PublicKey: + hs.rsaSignOk = true + default: + c.sendAlert(alertInternalError) + return false, fmt.Errorf("crypto/tls: unsupported signing key type (%T)", priv.Public()) + } + } + if priv, ok := hs.cert.PrivateKey.(crypto.Decrypter); ok { + switch priv.Public().(type) { + case *rsa.PublicKey: + hs.rsaDecryptOk = true + default: + c.sendAlert(alertInternalError) + return false, fmt.Errorf("crypto/tls: unsupported decryption key type (%T)", priv.Public()) + } + } + + if hs.checkForResumption() { + return true, nil + } + + var preferenceList, supportedList []uint16 + if c.config.PreferServerCipherSuites { + preferenceList = c.config.cipherSuites() + supportedList = hs.clientHello.cipherSuites + } else { + preferenceList = hs.clientHello.cipherSuites + supportedList = c.config.cipherSuites() + } + + for _, id := range preferenceList { + if hs.setCipherSuite(id, supportedList, c.vers) { + break + } + } + + if hs.suite == nil { + c.sendAlert(alertHandshakeFailure) + return false, errors.New("tls: no cipher suite supported by both client and server") + } + + // See https://tools.ietf.org/html/draft-ietf-tls-downgrade-scsv-00. + for _, id := range hs.clientHello.cipherSuites { + if id == TLS_FALLBACK_SCSV { + // The client is doing a fallback connection. + if hs.clientHello.vers < c.config.maxVersion() { + c.sendAlert(alertInappropriateFallback) + return false, errors.New("tls: client using inappropriate protocol fallback") + } + break + } + } + + return false, nil +} + +// checkForResumption reports whether we should perform resumption on this connection. +func (hs *serverHandshakeState) checkForResumption() bool { + c := hs.c + + if c.config.SessionTicketsDisabled { + return false + } + + var ok bool + var sessionTicket = append([]uint8{}, hs.clientHello.sessionTicket...) + if hs.sessionState, ok = c.decryptTicket(sessionTicket); !ok { + return false + } + + if hs.sessionState.vers > hs.clientHello.vers { + return false + } + if vers, ok := c.config.mutualVersion(hs.sessionState.vers); !ok || vers != hs.sessionState.vers { + return false + } + + cipherSuiteOk := false + // Check that the client is still offering the ciphersuite in the session. + for _, id := range hs.clientHello.cipherSuites { + if id == hs.sessionState.cipherSuite { + cipherSuiteOk = true + break + } + } + if !cipherSuiteOk { + return false + } + + // Check that we also support the ciphersuite from the session. + if !hs.setCipherSuite(hs.sessionState.cipherSuite, c.config.cipherSuites(), hs.sessionState.vers) { + return false + } + + sessionHasClientCerts := len(hs.sessionState.certificates) != 0 + needClientCerts := c.config.ClientAuth == RequireAnyClientCert || c.config.ClientAuth == RequireAndVerifyClientCert + if needClientCerts && !sessionHasClientCerts { + return false + } + if sessionHasClientCerts && c.config.ClientAuth == NoClientCert { + return false + } + + return true +} + +func (hs *serverHandshakeState) doResumeHandshake() error { + c := hs.c + + hs.hello.cipherSuite = hs.suite.id + // We echo the client's session ID in the ServerHello to let it know + // that we're doing a resumption. + hs.hello.sessionId = hs.clientHello.sessionId + hs.hello.ticketSupported = hs.sessionState.usedOldKey + hs.finishedHash = newFinishedHash(c.vers, hs.suite) + hs.finishedHash.discardHandshakeBuffer() + hs.finishedHash.Write(hs.clientHello.marshal()) + hs.finishedHash.Write(hs.hello.marshal()) + c.writeRecord(recordTypeHandshake, hs.hello.marshal()) + + if len(hs.sessionState.certificates) > 0 { + if _, err := hs.processCertsFromClient(hs.sessionState.certificates); err != nil { + return err + } + } + + hs.masterSecret = hs.sessionState.masterSecret + + return nil +} + +func (hs *serverHandshakeState) doFullHandshake() error { + config := hs.c.config + c := hs.c + + if hs.clientHello.ocspStapling && len(hs.cert.OCSPStaple) > 0 { + hs.hello.ocspStapling = true + } + + hs.hello.ticketSupported = hs.clientHello.ticketSupported && !config.SessionTicketsDisabled + hs.hello.cipherSuite = hs.suite.id + + hs.finishedHash = newFinishedHash(hs.c.vers, hs.suite) + if config.ClientAuth == NoClientCert { + // No need to keep a full record of the handshake if client + // certificates won't be used. + hs.finishedHash.discardHandshakeBuffer() + } + hs.finishedHash.Write(hs.clientHello.marshal()) + hs.finishedHash.Write(hs.hello.marshal()) + c.writeRecord(recordTypeHandshake, hs.hello.marshal()) + + certMsg := new(certificateMsg) + certMsg.certificates = hs.cert.Certificate + hs.finishedHash.Write(certMsg.marshal()) + c.writeRecord(recordTypeHandshake, certMsg.marshal()) + + if hs.hello.ocspStapling { + certStatus := new(certificateStatusMsg) + certStatus.statusType = statusTypeOCSP + certStatus.response = hs.cert.OCSPStaple + hs.finishedHash.Write(certStatus.marshal()) + c.writeRecord(recordTypeHandshake, certStatus.marshal()) + } + + keyAgreement := hs.suite.ka(c.vers) + skx, err := keyAgreement.generateServerKeyExchange(config, hs.cert, hs.clientHello, hs.hello) + if err != nil { + c.sendAlert(alertHandshakeFailure) + return err + } + if skx != nil { + hs.finishedHash.Write(skx.marshal()) + c.writeRecord(recordTypeHandshake, skx.marshal()) + } + + if config.ClientAuth >= RequestClientCert { + // Request a client certificate + certReq := new(certificateRequestMsg) + certReq.certificateTypes = []byte{ + byte(certTypeRSASign), + byte(certTypeECDSASign), + } + if c.vers >= VersionTLS12 { + certReq.hasSignatureAndHash = true + certReq.signatureAndHashes = supportedSignatureAlgorithms + } + + // An empty list of certificateAuthorities signals to + // the client that it may send any certificate in response + // to our request. When we know the CAs we trust, then + // we can send them down, so that the client can choose + // an appropriate certificate to give to us. + if config.ClientCAs != nil { + certReq.certificateAuthorities = config.ClientCAs.Subjects() + } + hs.finishedHash.Write(certReq.marshal()) + c.writeRecord(recordTypeHandshake, certReq.marshal()) + } + + helloDone := new(serverHelloDoneMsg) + hs.finishedHash.Write(helloDone.marshal()) + c.writeRecord(recordTypeHandshake, helloDone.marshal()) + + var pub crypto.PublicKey // public key for client auth, if any + + msg, err := c.readHandshake() + if err != nil { + return err + } + + var ok bool + // If we requested a client certificate, then the client must send a + // certificate message, even if it's empty. + if config.ClientAuth >= RequestClientCert { + if certMsg, ok = msg.(*certificateMsg); !ok { + c.sendAlert(alertUnexpectedMessage) + return unexpectedMessageError(certMsg, msg) + } + hs.finishedHash.Write(certMsg.marshal()) + + if len(certMsg.certificates) == 0 { + // The client didn't actually send a certificate + switch config.ClientAuth { + case RequireAnyClientCert, RequireAndVerifyClientCert: + c.sendAlert(alertBadCertificate) + return errors.New("tls: client didn't provide a certificate") + } + } + + pub, err = hs.processCertsFromClient(certMsg.certificates) + if err != nil { + return err + } + + msg, err = c.readHandshake() + if err != nil { + return err + } + } + + // Get client key exchange + ckx, ok := msg.(*clientKeyExchangeMsg) + if !ok { + c.sendAlert(alertUnexpectedMessage) + return unexpectedMessageError(ckx, msg) + } + hs.finishedHash.Write(ckx.marshal()) + + preMasterSecret, err := keyAgreement.processClientKeyExchange(config, hs.cert, ckx, c.vers) + if err != nil { + c.sendAlert(alertHandshakeFailure) + return err + } + hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.clientHello.random, hs.hello.random) + + // If we received a client cert in response to our certificate request message, + // the client will send us a certificateVerifyMsg immediately after the + // clientKeyExchangeMsg. This message is a digest of all preceding + // handshake-layer messages that is signed using the private key corresponding + // to the client's certificate. This allows us to verify that the client is in + // possession of the private key of the certificate. + if len(c.peerCertificates) > 0 { + msg, err = c.readHandshake() + if err != nil { + return err + } + certVerify, ok := msg.(*certificateVerifyMsg) + if !ok { + c.sendAlert(alertUnexpectedMessage) + return unexpectedMessageError(certVerify, msg) + } + + // Determine the signature type. + var signatureAndHash signatureAndHash + if certVerify.hasSignatureAndHash { + signatureAndHash = certVerify.signatureAndHash + if !isSupportedSignatureAndHash(signatureAndHash, supportedSignatureAlgorithms) { + return errors.New("tls: unsupported hash function for client certificate") + } + } else { + // Before TLS 1.2 the signature algorithm was implicit + // from the key type, and only one hash per signature + // algorithm was possible. Leave the hash as zero. + switch pub.(type) { + case *ecdsa.PublicKey: + signatureAndHash.signature = signatureECDSA + case *rsa.PublicKey: + signatureAndHash.signature = signatureRSA + } + } + + switch key := pub.(type) { + case *ecdsa.PublicKey: + if signatureAndHash.signature != signatureECDSA { + err = errors.New("bad signature type for client's ECDSA certificate") + break + } + ecdsaSig := new(ecdsaSignature) + if _, err = asn1.Unmarshal(certVerify.signature, ecdsaSig); err != nil { + break + } + if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 { + err = errors.New("ECDSA signature contained zero or negative values") + break + } + var digest []byte + if digest, _, err = hs.finishedHash.hashForClientCertificate(signatureAndHash, hs.masterSecret); err != nil { + break + } + if !ecdsa.Verify(key, digest, ecdsaSig.R, ecdsaSig.S) { + err = errors.New("ECDSA verification failure") + } + case *rsa.PublicKey: + if signatureAndHash.signature != signatureRSA { + err = errors.New("bad signature type for client's RSA certificate") + break + } + var digest []byte + var hashFunc crypto.Hash + if digest, hashFunc, err = hs.finishedHash.hashForClientCertificate(signatureAndHash, hs.masterSecret); err != nil { + break + } + err = rsa.VerifyPKCS1v15(key, hashFunc, digest, certVerify.signature) + } + if err != nil { + c.sendAlert(alertBadCertificate) + return errors.New("tls: could not validate signature of connection nonces: " + err.Error()) + } + + hs.finishedHash.Write(certVerify.marshal()) + } + + hs.finishedHash.discardHandshakeBuffer() + + return nil +} + +func (hs *serverHandshakeState) establishKeys() error { + c := hs.c + + clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV := + keysFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.clientHello.random, hs.hello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen) + + var clientCipher, serverCipher interface{} + var clientHash, serverHash macFunction + + if hs.suite.aead == nil { + clientCipher = hs.suite.cipher(clientKey, clientIV, true /* for reading */) + clientHash = hs.suite.mac(c.vers, clientMAC) + serverCipher = hs.suite.cipher(serverKey, serverIV, false /* not for reading */) + serverHash = hs.suite.mac(c.vers, serverMAC) + } else { + clientCipher = hs.suite.aead(clientKey, clientIV) + serverCipher = hs.suite.aead(serverKey, serverIV) + } + + c.in.prepareCipherSpec(c.vers, clientCipher, clientHash) + c.out.prepareCipherSpec(c.vers, serverCipher, serverHash) + + return nil +} + +func (hs *serverHandshakeState) readFinished(out []byte) error { + c := hs.c + + c.readRecord(recordTypeChangeCipherSpec) + if err := c.in.error(); err != nil { + return err + } + + if hs.hello.nextProtoNeg { + msg, err := c.readHandshake() + if err != nil { + return err + } + nextProto, ok := msg.(*nextProtoMsg) + if !ok { + c.sendAlert(alertUnexpectedMessage) + return unexpectedMessageError(nextProto, msg) + } + hs.finishedHash.Write(nextProto.marshal()) + c.clientProtocol = nextProto.proto + } + + msg, err := c.readHandshake() + if err != nil { + return err + } + clientFinished, ok := msg.(*finishedMsg) + if !ok { + c.sendAlert(alertUnexpectedMessage) + return unexpectedMessageError(clientFinished, msg) + } + + verify := hs.finishedHash.clientSum(hs.masterSecret) + if len(verify) != len(clientFinished.verifyData) || + subtle.ConstantTimeCompare(verify, clientFinished.verifyData) != 1 { + c.sendAlert(alertHandshakeFailure) + return errors.New("tls: client's Finished message is incorrect") + } + + hs.finishedHash.Write(clientFinished.marshal()) + copy(out, verify) + return nil +} + +func (hs *serverHandshakeState) sendSessionTicket() error { + if !hs.hello.ticketSupported { + return nil + } + + c := hs.c + m := new(newSessionTicketMsg) + + var err error + state := sessionState{ + vers: c.vers, + cipherSuite: hs.suite.id, + masterSecret: hs.masterSecret, + certificates: hs.certsFromClient, + } + m.ticket, err = c.encryptTicket(&state) + if err != nil { + return err + } + + hs.finishedHash.Write(m.marshal()) + c.writeRecord(recordTypeHandshake, m.marshal()) + + return nil +} + +func (hs *serverHandshakeState) sendFinished(out []byte) error { + c := hs.c + + c.writeRecord(recordTypeChangeCipherSpec, []byte{1}) + + finished := new(finishedMsg) + finished.verifyData = hs.finishedHash.serverSum(hs.masterSecret) + hs.finishedHash.Write(finished.marshal()) + c.writeRecord(recordTypeHandshake, finished.marshal()) + + c.cipherSuite = hs.suite.id + copy(out, finished.verifyData) + + return nil +} + +// processCertsFromClient takes a chain of client certificates either from a +// Certificates message or from a sessionState and verifies them. It returns +// the public key of the leaf certificate. +func (hs *serverHandshakeState) processCertsFromClient(certificates [][]byte) (crypto.PublicKey, error) { + c := hs.c + + hs.certsFromClient = certificates + certs := make([]*x509.Certificate, len(certificates)) + var err error + for i, asn1Data := range certificates { + if certs[i], err = x509.ParseCertificate(asn1Data); err != nil { + c.sendAlert(alertBadCertificate) + return nil, errors.New("tls: failed to parse client certificate: " + err.Error()) + } + } + + if c.config.ClientAuth >= VerifyClientCertIfGiven && len(certs) > 0 { + opts := x509.VerifyOptions{ + Roots: c.config.ClientCAs, + CurrentTime: c.config.time(), + Intermediates: x509.NewCertPool(), + KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}, + } + + for _, cert := range certs[1:] { + opts.Intermediates.AddCert(cert) + } + + chains, err := certs[0].Verify(opts) + if err != nil { + c.sendAlert(alertBadCertificate) + return nil, errors.New("tls: failed to verify client's certificate: " + err.Error()) + } + + c.verifiedChains = chains + } + + if len(certs) > 0 { + var pub crypto.PublicKey + switch key := certs[0].PublicKey.(type) { + case *ecdsa.PublicKey, *rsa.PublicKey: + pub = key + default: + c.sendAlert(alertUnsupportedCertificate) + return nil, fmt.Errorf("tls: client's certificate contains an unsupported public key of type %T", certs[0].PublicKey) + } + c.peerCertificates = certs + return pub, nil + } + + return nil, nil +} + +// setCipherSuite sets a cipherSuite with the given id as the serverHandshakeState +// suite if that cipher suite is acceptable to use. +// It returns a bool indicating if the suite was set. +func (hs *serverHandshakeState) setCipherSuite(id uint16, supportedCipherSuites []uint16, version uint16) bool { + for _, supported := range supportedCipherSuites { + if id == supported { + var candidate *cipherSuite + + for _, s := range cipherSuites { + if s.id == id { + candidate = s + break + } + } + if candidate == nil { + continue + } + // Don't select a ciphersuite which we can't + // support for this client. + if candidate.flags&suiteECDHE != 0 { + if !hs.ellipticOk { + continue + } + if candidate.flags&suiteECDSA != 0 { + if !hs.ecdsaOk { + continue + } + } else if !hs.rsaSignOk { + continue + } + } else if !hs.rsaDecryptOk { + continue + } + if version < VersionTLS12 && candidate.flags&suiteTLS12 != 0 { + continue + } + hs.suite = candidate + return true + } + } + return false +} diff --git a/vendor/github.com/cloudflare/cfssl/scan/crypto/tls/key_agreement.go b/vendor/github.com/cloudflare/cfssl/scan/crypto/tls/key_agreement.go new file mode 100644 index 00000000000..0e6a7c22624 --- /dev/null +++ b/vendor/github.com/cloudflare/cfssl/scan/crypto/tls/key_agreement.go @@ -0,0 +1,405 @@ +// Copyright 2010 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/ecdsa" + "crypto/elliptic" + "crypto/md5" + "crypto/rsa" + "crypto/sha1" + "crypto/x509" + "encoding/asn1" + "errors" + "io" + "math/big" +) + +var errClientKeyExchange = errors.New("tls: invalid ClientKeyExchange message") +var errServerKeyExchange = errors.New("tls: invalid ServerKeyExchange message") + +// rsaKeyAgreement implements the standard TLS key agreement where the client +// 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) { + return nil, nil +} + +func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) { + if len(ckx.ciphertext) < 2 { + return nil, errClientKeyExchange + } + + ciphertext := ckx.ciphertext + if version != VersionSSL30 { + ciphertextLen := int(ckx.ciphertext[0])<<8 | int(ckx.ciphertext[1]) + if ciphertextLen != len(ckx.ciphertext)-2 { + return nil, errClientKeyExchange + } + ciphertext = ckx.ciphertext[2:] + } + priv, ok := cert.PrivateKey.(crypto.Decrypter) + if !ok { + return nil, errors.New("tls: certificate private key does not implement crypto.Decrypter") + } + // Perform constant time RSA PKCS#1 v1.5 decryption + preMasterSecret, err := priv.Decrypt(config.rand(), ciphertext, &rsa.PKCS1v15DecryptOptions{SessionKeyLen: 48}) + if err != nil { + return nil, err + } + // We don't check the version number in the premaster secret. For one, + // by checking it, we would leak information about the validity of the + // encrypted pre-master secret. Secondly, it provides only a small + // benefit against a downgrade attack and some implementations send the + // wrong version anyway. See the discussion at the end of section + // 7.4.7.1 of RFC 4346. + return preMasterSecret, nil +} + +func (ka rsaKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error { + return errors.New("tls: unexpected ServerKeyExchange") +} + +func (ka rsaKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) { + preMasterSecret := make([]byte, 48) + preMasterSecret[0] = byte(clientHello.vers >> 8) + preMasterSecret[1] = byte(clientHello.vers) + _, err := io.ReadFull(config.rand(), preMasterSecret[2:]) + if err != nil { + return nil, nil, err + } + + encrypted, err := rsa.EncryptPKCS1v15(config.rand(), cert.PublicKey.(*rsa.PublicKey), preMasterSecret) + if err != nil { + return nil, nil, err + } + ckx := new(clientKeyExchangeMsg) + ckx.ciphertext = make([]byte, len(encrypted)+2) + ckx.ciphertext[0] = byte(len(encrypted) >> 8) + ckx.ciphertext[1] = byte(len(encrypted)) + copy(ckx.ciphertext[2:], encrypted) + return preMasterSecret, ckx, nil +} + +// sha1Hash calculates a SHA1 hash over the given byte slices. +func sha1Hash(slices [][]byte) []byte { + hsha1 := sha1.New() + for _, slice := range slices { + hsha1.Write(slice) + } + return hsha1.Sum(nil) +} + +// md5SHA1Hash implements TLS 1.0's hybrid hash function which consists of the +// concatenation of an MD5 and SHA1 hash. +func md5SHA1Hash(slices [][]byte) []byte { + md5sha1 := make([]byte, md5.Size+sha1.Size) + hmd5 := md5.New() + for _, slice := range slices { + hmd5.Write(slice) + } + copy(md5sha1, hmd5.Sum(nil)) + copy(md5sha1[md5.Size:], sha1Hash(slices)) + return md5sha1 +} + +// hashForServerKeyExchange hashes the given slices and returns their digest +// and the identifier of the hash function used. The sigAndHash argument is +// only used for >= TLS 1.2 and precisely identifies the hash function to use. +func hashForServerKeyExchange(sigAndHash signatureAndHash, version uint16, slices ...[]byte) ([]byte, crypto.Hash, error) { + if version >= VersionTLS12 { + if !isSupportedSignatureAndHash(sigAndHash, supportedSignatureAlgorithms) { + return nil, crypto.Hash(0), errors.New("tls: unsupported hash function used by peer") + } + hashFunc, err := lookupTLSHash(sigAndHash.hash) + if err != nil { + return nil, crypto.Hash(0), err + } + h := hashFunc.New() + for _, slice := range slices { + h.Write(slice) + } + digest := h.Sum(nil) + return digest, hashFunc, nil + } + if sigAndHash.signature == signatureECDSA { + return sha1Hash(slices), crypto.SHA1, nil + } + return md5SHA1Hash(slices), crypto.MD5SHA1, nil +} + +// pickTLS12HashForSignature returns a TLS 1.2 hash identifier for signing a +// ServerKeyExchange given the signature type being used and the client's +// advertised list of supported signature and hash combinations. +func pickTLS12HashForSignature(sigType uint8, clientList []signatureAndHash) (uint8, error) { + if len(clientList) == 0 { + // If the client didn't specify any signature_algorithms + // extension then we can assume that it supports SHA1. See + // http://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 + return hashSHA1, nil + } + + for _, sigAndHash := range clientList { + if sigAndHash.signature != sigType { + continue + } + if isSupportedSignatureAndHash(sigAndHash, supportedSignatureAlgorithms) { + return sigAndHash.hash, nil + } + } + + return 0, errors.New("tls: client doesn't support any common hash functions") +} + +func curveForCurveID(id CurveID) (elliptic.Curve, bool) { + switch id { + case CurveP256: + return elliptic.P256(), true + case CurveP384: + return elliptic.P384(), true + case CurveP521: + return elliptic.P521(), true + default: + return nil, false + } + +} + +// ecdheRSAKeyAgreement implements a TLS key agreement where the server +// generates a ephemeral EC public/private key pair and signs it. The +// pre-master secret is then calculated using ECDH. The signature may +// either be ECDSA or RSA. +type ecdheKeyAgreement struct { + version uint16 + sigType uint8 + privateKey []byte + curve elliptic.Curve + x, y *big.Int +} + +func (ka *ecdheKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) { + var curveid CurveID + preferredCurves := config.curvePreferences() + +NextCandidate: + for _, candidate := range preferredCurves { + for _, c := range clientHello.supportedCurves { + if candidate == c { + curveid = c + break NextCandidate + } + } + } + + if curveid == 0 { + return nil, errors.New("tls: no supported elliptic curves offered") + } + + var ok bool + if ka.curve, ok = curveForCurveID(curveid); !ok { + return nil, errors.New("tls: preferredCurves includes unsupported curve") + } + + var x, y *big.Int + var err error + ka.privateKey, x, y, err = elliptic.GenerateKey(ka.curve, config.rand()) + if err != nil { + return nil, err + } + ecdhePublic := elliptic.Marshal(ka.curve, x, y) + + // http://tools.ietf.org/html/rfc4492#section-5.4 + serverECDHParams := make([]byte, 1+2+1+len(ecdhePublic)) + serverECDHParams[0] = 3 // named curve + serverECDHParams[1] = byte(curveid >> 8) + serverECDHParams[2] = byte(curveid) + serverECDHParams[3] = byte(len(ecdhePublic)) + copy(serverECDHParams[4:], ecdhePublic) + + sigAndHash := signatureAndHash{signature: ka.sigType} + + if ka.version >= VersionTLS12 { + if sigAndHash.hash, err = pickTLS12HashForSignature(ka.sigType, clientHello.signatureAndHashes); err != nil { + return nil, err + } + } + + digest, hashFunc, err := hashForServerKeyExchange(sigAndHash, ka.version, clientHello.random, hello.random, serverECDHParams) + if err != nil { + return nil, err + } + + priv, ok := cert.PrivateKey.(crypto.Signer) + if !ok { + return nil, errors.New("tls: certificate private key does not implement crypto.Signer") + } + var sig []byte + switch ka.sigType { + case signatureECDSA: + _, ok := priv.Public().(*ecdsa.PublicKey) + if !ok { + return nil, errors.New("ECDHE ECDSA requires an ECDSA server key") + } + case signatureRSA: + _, ok := priv.Public().(*rsa.PublicKey) + if !ok { + return nil, errors.New("ECDHE RSA requires a RSA server key") + } + default: + return nil, errors.New("unknown ECDHE signature algorithm") + } + sig, err = priv.Sign(config.rand(), digest, hashFunc) + if err != nil { + return nil, errors.New("failed to sign ECDHE parameters: " + err.Error()) + } + + skx := new(serverKeyExchangeMsg) + sigAndHashLen := 0 + if ka.version >= VersionTLS12 { + sigAndHashLen = 2 + } + skx.key = make([]byte, len(serverECDHParams)+sigAndHashLen+2+len(sig)) + copy(skx.key, serverECDHParams) + k := skx.key[len(serverECDHParams):] + if ka.version >= VersionTLS12 { + k[0] = sigAndHash.hash + k[1] = sigAndHash.signature + k = k[2:] + } + k[0] = byte(len(sig) >> 8) + k[1] = byte(len(sig)) + copy(k[2:], sig) + + return skx, nil +} + +func (ka *ecdheKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) { + if len(ckx.ciphertext) == 0 || int(ckx.ciphertext[0]) != len(ckx.ciphertext)-1 { + return nil, errClientKeyExchange + } + x, y := elliptic.Unmarshal(ka.curve, ckx.ciphertext[1:]) + if x == nil { + return nil, errClientKeyExchange + } + if !ka.curve.IsOnCurve(x, y) { + return nil, errClientKeyExchange + } + x, _ = ka.curve.ScalarMult(x, y, ka.privateKey) + preMasterSecret := make([]byte, (ka.curve.Params().BitSize+7)>>3) + xBytes := x.Bytes() + copy(preMasterSecret[len(preMasterSecret)-len(xBytes):], xBytes) + + return preMasterSecret, nil +} + +func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error { + if len(skx.key) < 4 { + return errServerKeyExchange + } + if skx.key[0] != 3 { // named curve + return errors.New("tls: server selected unsupported curve") + } + curveid := CurveID(skx.key[1])<<8 | CurveID(skx.key[2]) + + var ok bool + if ka.curve, ok = curveForCurveID(curveid); !ok { + return errors.New("tls: server selected unsupported curve") + } + + publicLen := int(skx.key[3]) + if publicLen+4 > len(skx.key) { + return errServerKeyExchange + } + ka.x, ka.y = elliptic.Unmarshal(ka.curve, skx.key[4:4+publicLen]) + if ka.x == nil { + return errServerKeyExchange + } + if !ka.curve.IsOnCurve(ka.x, ka.y) { + return errServerKeyExchange + } + serverECDHParams := skx.key[:4+publicLen] + + sig := skx.key[4+publicLen:] + if len(sig) < 2 { + return errServerKeyExchange + } + + sigAndHash := signatureAndHash{signature: ka.sigType} + if ka.version >= VersionTLS12 { + // handle SignatureAndHashAlgorithm + sigAndHash = signatureAndHash{hash: sig[0], signature: sig[1]} + if sigAndHash.signature != ka.sigType { + return errServerKeyExchange + } + sig = sig[2:] + if len(sig) < 2 { + return errServerKeyExchange + } + } + sigLen := int(sig[0])<<8 | int(sig[1]) + if sigLen+2 != len(sig) { + return errServerKeyExchange + } + sig = sig[2:] + + digest, hashFunc, err := hashForServerKeyExchange(sigAndHash, ka.version, clientHello.random, serverHello.random, serverECDHParams) + if err != nil { + return err + } + switch ka.sigType { + case signatureECDSA: + pubKey, ok := cert.PublicKey.(*ecdsa.PublicKey) + if !ok { + return errors.New("ECDHE ECDSA requires a ECDSA server public key") + } + ecdsaSig := new(ecdsaSignature) + if _, err := asn1.Unmarshal(sig, ecdsaSig); err != nil { + return err + } + if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 { + return errors.New("ECDSA signature contained zero or negative values") + } + if !ecdsa.Verify(pubKey, digest, ecdsaSig.R, ecdsaSig.S) { + return errors.New("ECDSA verification failure") + } + case signatureRSA: + pubKey, ok := cert.PublicKey.(*rsa.PublicKey) + if !ok { + return errors.New("ECDHE RSA requires a RSA server public key") + } + if err := rsa.VerifyPKCS1v15(pubKey, hashFunc, digest, sig); err != nil { + return err + } + default: + return errors.New("unknown ECDHE signature algorithm") + } + + return nil +} + +func (ka *ecdheKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) { + if ka.curve == nil { + return nil, nil, errors.New("missing ServerKeyExchange message") + } + priv, mx, my, err := elliptic.GenerateKey(ka.curve, config.rand()) + if err != nil { + return nil, nil, err + } + x, _ := ka.curve.ScalarMult(ka.x, ka.y, priv) + preMasterSecret := make([]byte, (ka.curve.Params().BitSize+7)>>3) + xBytes := x.Bytes() + copy(preMasterSecret[len(preMasterSecret)-len(xBytes):], xBytes) + + serialized := elliptic.Marshal(ka.curve, mx, my) + + ckx := new(clientKeyExchangeMsg) + ckx.ciphertext = make([]byte, 1+len(serialized)) + ckx.ciphertext[0] = byte(len(serialized)) + copy(ckx.ciphertext[1:], serialized) + + return preMasterSecret, ckx, nil +} diff --git a/vendor/github.com/cloudflare/cfssl/scan/crypto/tls/prf.go b/vendor/github.com/cloudflare/cfssl/scan/crypto/tls/prf.go new file mode 100644 index 00000000000..747b817ba32 --- /dev/null +++ b/vendor/github.com/cloudflare/cfssl/scan/crypto/tls/prf.go @@ -0,0 +1,368 @@ +// Copyright 2009 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/hmac" + "crypto/md5" + "crypto/sha1" + "crypto/sha256" + "crypto/sha512" + "errors" + "hash" +) + +// Split a premaster secret in two as specified in RFC 4346, section 5. +func splitPreMasterSecret(secret []byte) (s1, s2 []byte) { + s1 = secret[0 : (len(secret)+1)/2] + s2 = secret[len(secret)/2:] + return +} + +// pHash implements the P_hash function, as defined in RFC 4346, section 5. +func pHash(result, secret, seed []byte, hash func() hash.Hash) { + h := hmac.New(hash, secret) + h.Write(seed) + a := h.Sum(nil) + + j := 0 + for j < len(result) { + h.Reset() + h.Write(a) + h.Write(seed) + b := h.Sum(nil) + todo := len(b) + if j+todo > len(result) { + todo = len(result) - j + } + copy(result[j:j+todo], b) + j += todo + + h.Reset() + h.Write(a) + a = h.Sum(nil) + } +} + +// prf10 implements the TLS 1.0 pseudo-random function, as defined in RFC 2246, section 5. +func prf10(result, secret, label, seed []byte) { + hashSHA1 := sha1.New + hashMD5 := md5.New + + labelAndSeed := make([]byte, len(label)+len(seed)) + copy(labelAndSeed, label) + copy(labelAndSeed[len(label):], seed) + + s1, s2 := splitPreMasterSecret(secret) + pHash(result, s1, labelAndSeed, hashMD5) + result2 := make([]byte, len(result)) + pHash(result2, s2, labelAndSeed, hashSHA1) + + for i, b := range result2 { + result[i] ^= b + } +} + +// prf12 implements the TLS 1.2 pseudo-random function, as defined in RFC 5246, section 5. +func prf12(hashFunc func() hash.Hash) func(result, secret, label, seed []byte) { + return func(result, secret, label, seed []byte) { + labelAndSeed := make([]byte, len(label)+len(seed)) + copy(labelAndSeed, label) + copy(labelAndSeed[len(label):], seed) + + pHash(result, secret, labelAndSeed, hashFunc) + } +} + +// prf30 implements the SSL 3.0 pseudo-random function, as defined in +// www.mozilla.org/projects/security/pki/nss/ssl/draft302.txt section 6. +func prf30(result, secret, label, seed []byte) { + hashSHA1 := sha1.New() + hashMD5 := md5.New() + + done := 0 + i := 0 + // RFC5246 section 6.3 says that the largest PRF output needed is 128 + // bytes. Since no more ciphersuites will be added to SSLv3, this will + // remain true. Each iteration gives us 16 bytes so 10 iterations will + // be sufficient. + var b [11]byte + for done < len(result) { + for j := 0; j <= i; j++ { + b[j] = 'A' + byte(i) + } + + hashSHA1.Reset() + hashSHA1.Write(b[:i+1]) + hashSHA1.Write(secret) + hashSHA1.Write(seed) + digest := hashSHA1.Sum(nil) + + hashMD5.Reset() + hashMD5.Write(secret) + hashMD5.Write(digest) + + done += copy(result[done:], hashMD5.Sum(nil)) + i++ + } +} + +const ( + tlsRandomLength = 32 // Length of a random nonce in TLS 1.1. + masterSecretLength = 48 // Length of a master secret in TLS 1.1. + finishedVerifyLength = 12 // Length of verify_data in a Finished message. +) + +var masterSecretLabel = []byte("master secret") +var keyExpansionLabel = []byte("key expansion") +var clientFinishedLabel = []byte("client finished") +var serverFinishedLabel = []byte("server finished") + +func prfAndHashForVersion(version uint16, suite *cipherSuite) (func(result, secret, label, seed []byte), crypto.Hash) { + switch version { + case VersionSSL30: + return prf30, crypto.Hash(0) + case VersionTLS10, VersionTLS11: + return prf10, crypto.Hash(0) + case VersionTLS12: + if suite.flags&suiteSHA384 != 0 { + return prf12(sha512.New384), crypto.SHA384 + } + return prf12(sha256.New), crypto.SHA256 + default: + panic("unknown version") + } +} + +func prfForVersion(version uint16, suite *cipherSuite) func(result, secret, label, seed []byte) { + prf, _ := prfAndHashForVersion(version, suite) + return prf +} + +// masterFromPreMasterSecret generates the master secret from the pre-master +// secret. See http://tools.ietf.org/html/rfc5246#section-8.1 +func masterFromPreMasterSecret(version uint16, suite *cipherSuite, preMasterSecret, clientRandom, serverRandom []byte) []byte { + seed := make([]byte, 0, len(clientRandom)+len(serverRandom)) + seed = append(seed, clientRandom...) + seed = append(seed, serverRandom...) + + masterSecret := make([]byte, masterSecretLength) + prfForVersion(version, suite)(masterSecret, preMasterSecret, masterSecretLabel, seed) + return masterSecret +} + +// keysFromMasterSecret generates the connection keys from the master +// secret, given the lengths of the MAC key, cipher key and IV, as defined in +// RFC 2246, section 6.3. +func keysFromMasterSecret(version uint16, suite *cipherSuite, masterSecret, clientRandom, serverRandom []byte, macLen, keyLen, ivLen int) (clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV []byte) { + seed := make([]byte, 0, len(serverRandom)+len(clientRandom)) + seed = append(seed, serverRandom...) + seed = append(seed, clientRandom...) + + n := 2*macLen + 2*keyLen + 2*ivLen + keyMaterial := make([]byte, n) + prfForVersion(version, suite)(keyMaterial, masterSecret, keyExpansionLabel, seed) + clientMAC = keyMaterial[:macLen] + keyMaterial = keyMaterial[macLen:] + serverMAC = keyMaterial[:macLen] + keyMaterial = keyMaterial[macLen:] + clientKey = keyMaterial[:keyLen] + keyMaterial = keyMaterial[keyLen:] + serverKey = keyMaterial[:keyLen] + keyMaterial = keyMaterial[keyLen:] + clientIV = keyMaterial[:ivLen] + keyMaterial = keyMaterial[ivLen:] + serverIV = keyMaterial[:ivLen] + return +} + +// lookupTLSHash looks up the corresponding crypto.Hash for a given +// TLS hash identifier. +func lookupTLSHash(hash uint8) (crypto.Hash, error) { + switch hash { + case hashSHA1: + return crypto.SHA1, nil + case hashSHA256: + return crypto.SHA256, nil + case hashSHA384: + return crypto.SHA384, nil + default: + return 0, errors.New("tls: unsupported hash algorithm") + } +} + +func newFinishedHash(version uint16, cipherSuite *cipherSuite) finishedHash { + var buffer []byte + if version == VersionSSL30 || version >= VersionTLS12 { + buffer = []byte{} + } + + prf, hash := prfAndHashForVersion(version, cipherSuite) + if hash != 0 { + return finishedHash{hash.New(), hash.New(), nil, nil, buffer, version, prf} + } + + return finishedHash{sha1.New(), sha1.New(), md5.New(), md5.New(), buffer, version, prf} +} + +// A finishedHash calculates the hash of a set of handshake messages suitable +// for including in a Finished message. +type finishedHash struct { + client hash.Hash + server hash.Hash + + // Prior to TLS 1.2, an additional MD5 hash is required. + clientMD5 hash.Hash + serverMD5 hash.Hash + + // In TLS 1.2, a full buffer is sadly required. + buffer []byte + + version uint16 + prf func(result, secret, label, seed []byte) +} + +func (h *finishedHash) Write(msg []byte) (n int, err error) { + h.client.Write(msg) + h.server.Write(msg) + + if h.version < VersionTLS12 { + h.clientMD5.Write(msg) + h.serverMD5.Write(msg) + } + + if h.buffer != nil { + h.buffer = append(h.buffer, msg...) + } + + return len(msg), nil +} + +func (h finishedHash) Sum() []byte { + if h.version >= VersionTLS12 { + return h.client.Sum(nil) + } + + out := make([]byte, 0, md5.Size+sha1.Size) + out = h.clientMD5.Sum(out) + return h.client.Sum(out) +} + +// finishedSum30 calculates the contents of the verify_data member of a SSLv3 +// Finished message given the MD5 and SHA1 hashes of a set of handshake +// messages. +func finishedSum30(md5, sha1 hash.Hash, masterSecret []byte, magic []byte) []byte { + md5.Write(magic) + md5.Write(masterSecret) + md5.Write(ssl30Pad1[:]) + md5Digest := md5.Sum(nil) + + md5.Reset() + md5.Write(masterSecret) + md5.Write(ssl30Pad2[:]) + md5.Write(md5Digest) + md5Digest = md5.Sum(nil) + + sha1.Write(magic) + sha1.Write(masterSecret) + sha1.Write(ssl30Pad1[:40]) + sha1Digest := sha1.Sum(nil) + + sha1.Reset() + sha1.Write(masterSecret) + sha1.Write(ssl30Pad2[:40]) + sha1.Write(sha1Digest) + sha1Digest = sha1.Sum(nil) + + ret := make([]byte, len(md5Digest)+len(sha1Digest)) + copy(ret, md5Digest) + copy(ret[len(md5Digest):], sha1Digest) + return ret +} + +var ssl3ClientFinishedMagic = [4]byte{0x43, 0x4c, 0x4e, 0x54} +var ssl3ServerFinishedMagic = [4]byte{0x53, 0x52, 0x56, 0x52} + +// clientSum returns the contents of the verify_data member of a client's +// Finished message. +func (h finishedHash) clientSum(masterSecret []byte) []byte { + if h.version == VersionSSL30 { + return finishedSum30(h.clientMD5, h.client, masterSecret, ssl3ClientFinishedMagic[:]) + } + + out := make([]byte, finishedVerifyLength) + h.prf(out, masterSecret, clientFinishedLabel, h.Sum()) + return out +} + +// serverSum returns the contents of the verify_data member of a server's +// Finished message. +func (h finishedHash) serverSum(masterSecret []byte) []byte { + if h.version == VersionSSL30 { + return finishedSum30(h.serverMD5, h.server, masterSecret, ssl3ServerFinishedMagic[:]) + } + + out := make([]byte, finishedVerifyLength) + h.prf(out, masterSecret, serverFinishedLabel, h.Sum()) + return out +} + +// selectClientCertSignatureAlgorithm returns a signatureAndHash to sign a +// client's CertificateVerify with, or an error if none can be found. +func (h finishedHash) selectClientCertSignatureAlgorithm(serverList []signatureAndHash, sigType uint8) (signatureAndHash, error) { + if h.version < VersionTLS12 { + // Nothing to negotiate before TLS 1.2. + return signatureAndHash{signature: sigType}, nil + } + + for _, v := range serverList { + if v.signature == sigType && isSupportedSignatureAndHash(v, supportedSignatureAlgorithms) { + return v, nil + } + } + return signatureAndHash{}, errors.New("tls: no supported signature algorithm found for signing client certificate") +} + +// hashForClientCertificate returns a digest, hash function, and TLS 1.2 hash +// id suitable for signing by a TLS client certificate. +func (h finishedHash) hashForClientCertificate(signatureAndHash signatureAndHash, masterSecret []byte) ([]byte, crypto.Hash, error) { + if (h.version == VersionSSL30 || h.version >= VersionTLS12) && h.buffer == nil { + panic("a handshake hash for a client-certificate was requested after discarding the handshake buffer") + } + + if h.version == VersionSSL30 { + if signatureAndHash.signature != signatureRSA { + return nil, 0, errors.New("tls: unsupported signature type for client certificate") + } + + md5Hash := md5.New() + md5Hash.Write(h.buffer) + sha1Hash := sha1.New() + sha1Hash.Write(h.buffer) + return finishedSum30(md5Hash, sha1Hash, masterSecret, nil), crypto.MD5SHA1, nil + } + if h.version >= VersionTLS12 { + hashAlg, err := lookupTLSHash(signatureAndHash.hash) + if err != nil { + return nil, 0, err + } + hash := hashAlg.New() + hash.Write(h.buffer) + return hash.Sum(nil), hashAlg, nil + } + + if signatureAndHash.signature == signatureECDSA { + return h.server.Sum(nil), crypto.SHA1, nil + } + + return h.Sum(), crypto.MD5SHA1, nil +} + +// discardHandshakeBuffer is called when there is no more need to +// buffer the entirety of the handshake messages. +func (h *finishedHash) discardHandshakeBuffer() { + h.buffer = nil +} diff --git a/vendor/github.com/cloudflare/cfssl/scan/crypto/tls/ticket.go b/vendor/github.com/cloudflare/cfssl/scan/crypto/tls/ticket.go new file mode 100644 index 00000000000..7be50ce68c9 --- /dev/null +++ b/vendor/github.com/cloudflare/cfssl/scan/crypto/tls/ticket.go @@ -0,0 +1,204 @@ +// 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. + +package tls + +import ( + "bytes" + "crypto/aes" + "crypto/cipher" + "crypto/hmac" + "crypto/sha256" + "crypto/subtle" + "errors" + "io" +) + +// sessionState contains the information that is serialized into a session +// ticket in order to later resume a connection. +type sessionState struct { + vers uint16 + cipherSuite uint16 + masterSecret []byte + certificates [][]byte + // usedOldKey is true if the ticket from which this session came from + // was encrypted with an older key and thus should be refreshed. + usedOldKey bool +} + +func (s *sessionState) equal(i interface{}) bool { + s1, ok := i.(*sessionState) + if !ok { + return false + } + + if s.vers != s1.vers || + s.cipherSuite != s1.cipherSuite || + !bytes.Equal(s.masterSecret, s1.masterSecret) { + return false + } + + if len(s.certificates) != len(s1.certificates) { + return false + } + + for i := range s.certificates { + if !bytes.Equal(s.certificates[i], s1.certificates[i]) { + return false + } + } + + return true +} + +func (s *sessionState) marshal() []byte { + length := 2 + 2 + 2 + len(s.masterSecret) + 2 + for _, cert := range s.certificates { + length += 4 + len(cert) + } + + ret := make([]byte, length) + x := ret + x[0] = byte(s.vers >> 8) + x[1] = byte(s.vers) + x[2] = byte(s.cipherSuite >> 8) + x[3] = byte(s.cipherSuite) + x[4] = byte(len(s.masterSecret) >> 8) + x[5] = byte(len(s.masterSecret)) + x = x[6:] + copy(x, s.masterSecret) + x = x[len(s.masterSecret):] + + x[0] = byte(len(s.certificates) >> 8) + x[1] = byte(len(s.certificates)) + x = x[2:] + + for _, cert := range s.certificates { + x[0] = byte(len(cert) >> 24) + x[1] = byte(len(cert) >> 16) + x[2] = byte(len(cert) >> 8) + x[3] = byte(len(cert)) + copy(x[4:], cert) + x = x[4+len(cert):] + } + + return ret +} + +func (s *sessionState) unmarshal(data []byte) bool { + if len(data) < 8 { + return false + } + + s.vers = uint16(data[0])<<8 | uint16(data[1]) + s.cipherSuite = uint16(data[2])<<8 | uint16(data[3]) + masterSecretLen := int(data[4])<<8 | int(data[5]) + data = data[6:] + if len(data) < masterSecretLen { + return false + } + + s.masterSecret = data[:masterSecretLen] + data = data[masterSecretLen:] + + if len(data) < 2 { + return false + } + + numCerts := int(data[0])<<8 | int(data[1]) + data = data[2:] + + s.certificates = make([][]byte, numCerts) + for i := range s.certificates { + if len(data) < 4 { + return false + } + certLen := int(data[0])<<24 | int(data[1])<<16 | int(data[2])<<8 | int(data[3]) + data = data[4:] + if certLen < 0 { + return false + } + if len(data) < certLen { + return false + } + s.certificates[i] = data[:certLen] + data = data[certLen:] + } + + if len(data) > 0 { + return false + } + + return true +} + +func (c *Conn) encryptTicket(state *sessionState) ([]byte, error) { + serialized := state.marshal() + encrypted := make([]byte, ticketKeyNameLen+aes.BlockSize+len(serialized)+sha256.Size) + keyName := encrypted[:ticketKeyNameLen] + iv := encrypted[ticketKeyNameLen : ticketKeyNameLen+aes.BlockSize] + macBytes := encrypted[len(encrypted)-sha256.Size:] + + if _, err := io.ReadFull(c.config.rand(), iv); err != nil { + return nil, err + } + key := c.config.ticketKeys()[0] + copy(keyName, key.keyName[:]) + block, err := aes.NewCipher(key.aesKey[:]) + if err != nil { + return nil, errors.New("tls: failed to create cipher while encrypting ticket: " + err.Error()) + } + cipher.NewCTR(block, iv).XORKeyStream(encrypted[ticketKeyNameLen+aes.BlockSize:], serialized) + + mac := hmac.New(sha256.New, key.hmacKey[:]) + mac.Write(encrypted[:len(encrypted)-sha256.Size]) + mac.Sum(macBytes[:0]) + + return encrypted, nil +} + +func (c *Conn) decryptTicket(encrypted []byte) (*sessionState, bool) { + if c.config.SessionTicketsDisabled || + len(encrypted) < ticketKeyNameLen+aes.BlockSize+sha256.Size { + return nil, false + } + + keyName := encrypted[:ticketKeyNameLen] + iv := encrypted[ticketKeyNameLen : ticketKeyNameLen+aes.BlockSize] + macBytes := encrypted[len(encrypted)-sha256.Size:] + + keys := c.config.ticketKeys() + keyIndex := -1 + for i, candidateKey := range keys { + if bytes.Equal(keyName, candidateKey.keyName[:]) { + keyIndex = i + break + } + } + + if keyIndex == -1 { + return nil, false + } + key := &keys[keyIndex] + + mac := hmac.New(sha256.New, key.hmacKey[:]) + mac.Write(encrypted[:len(encrypted)-sha256.Size]) + expected := mac.Sum(nil) + + if subtle.ConstantTimeCompare(macBytes, expected) != 1 { + return nil, false + } + + block, err := aes.NewCipher(key.aesKey[:]) + if err != nil { + return nil, false + } + ciphertext := encrypted[ticketKeyNameLen+aes.BlockSize : len(encrypted)-sha256.Size] + plaintext := ciphertext + cipher.NewCTR(block, iv).XORKeyStream(plaintext, ciphertext) + + state := &sessionState{usedOldKey: keyIndex > 0} + ok := state.unmarshal(plaintext) + return state, ok +} diff --git a/vendor/github.com/cloudflare/cfssl/scan/crypto/tls/tls.go b/vendor/github.com/cloudflare/cfssl/scan/crypto/tls/tls.go new file mode 100644 index 00000000000..4bedd7682d3 --- /dev/null +++ b/vendor/github.com/cloudflare/cfssl/scan/crypto/tls/tls.go @@ -0,0 +1,298 @@ +// Copyright 2009 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 partially implements TLS 1.2, as specified in RFC 5246. +package tls + +// BUG(agl): The crypto/tls package does not implement countermeasures +// against Lucky13 attacks on CBC-mode encryption. See +// http://www.isg.rhul.ac.uk/tls/TLStiming.pdf and +// https://www.imperialviolet.org/2013/02/04/luckythirteen.html. + +import ( + "crypto" + "crypto/ecdsa" + "crypto/rsa" + "crypto/x509" + "encoding/pem" + "errors" + "fmt" + "io/ioutil" + "net" + "strings" + "time" +) + +// Server returns a new TLS server side connection +// using conn as the underlying transport. +// The configuration config must be non-nil and must include +// at least one certificate or else set GetCertificate. +func Server(conn net.Conn, config *Config) *Conn { + return &Conn{conn: conn, config: config} +} + +// Client returns a new TLS client side connection +// using conn as the underlying transport. +// The config cannot be nil: users must set either ServerName or +// InsecureSkipVerify in the config. +func Client(conn net.Conn, config *Config) *Conn { + return &Conn{conn: conn, config: config, isClient: true} +} + +// A listener implements a network listener (net.Listener) for TLS connections. +type listener struct { + net.Listener + config *Config +} + +// Accept waits for and returns the next incoming TLS connection. +// The returned connection c is a *tls.Conn. +func (l *listener) Accept() (c net.Conn, err error) { + c, err = l.Listener.Accept() + if err != nil { + return + } + c = Server(c, l.config) + return +} + +// NewListener creates a Listener which accepts connections from an inner +// Listener and wraps each connection with Server. +// The configuration config must be non-nil and must include +// at least one certificate or else set GetCertificate. +func NewListener(inner net.Listener, config *Config) net.Listener { + l := new(listener) + l.Listener = inner + l.config = config + return l +} + +// Listen creates a TLS listener accepting connections on the +// given network address using net.Listen. +// The configuration config must be non-nil and must include +// at least one certificate or else set GetCertificate. +func Listen(network, laddr string, config *Config) (net.Listener, error) { + if config == nil || (len(config.Certificates) == 0 && config.GetCertificate == nil) { + return nil, errors.New("tls: neither Certificates nor GetCertificate set in Config") + } + l, err := net.Listen(network, laddr) + if err != nil { + return nil, err + } + return NewListener(l, config), nil +} + +type timeoutError struct{} + +func (timeoutError) Error() string { return "tls: DialWithDialer timed out" } +func (timeoutError) Timeout() bool { return true } +func (timeoutError) Temporary() bool { return true } + +// DialWithDialer connects to the given network address using dialer.Dial and +// then initiates a TLS handshake, returning the resulting TLS connection. Any +// timeout or deadline given in the dialer apply to connection and TLS +// handshake as a whole. +// +// DialWithDialer interprets a nil configuration as equivalent to the zero +// configuration; see the documentation of Config for the defaults. +func DialWithDialer(dialer *net.Dialer, network, addr string, config *Config) (*Conn, error) { + // We want the Timeout and Deadline values from dialer to cover the + // whole process: TCP connection and TLS handshake. This means that we + // also need to start our own timers now. + timeout := dialer.Timeout + + if !dialer.Deadline.IsZero() { + deadlineTimeout := dialer.Deadline.Sub(time.Now()) + if timeout == 0 || deadlineTimeout < timeout { + timeout = deadlineTimeout + } + } + + var errChannel chan error + + if timeout != 0 { + errChannel = make(chan error, 2) + time.AfterFunc(timeout, func() { + errChannel <- timeoutError{} + }) + } + + rawConn, err := dialer.Dial(network, addr) + if err != nil { + return nil, err + } + + colonPos := strings.LastIndex(addr, ":") + if colonPos == -1 { + colonPos = len(addr) + } + hostname := addr[:colonPos] + + if config == nil { + config = defaultConfig() + } + // If no ServerName is set, infer the ServerName + // from the hostname we're connecting to. + if config.ServerName == "" { + // Make a copy to avoid polluting argument or default. + c := *config + c.ServerName = hostname + config = &c + } + + conn := Client(rawConn, config) + + if timeout == 0 { + err = conn.Handshake() + } else { + go func() { + errChannel <- conn.Handshake() + }() + + err = <-errChannel + } + + if err != nil { + rawConn.Close() + return nil, err + } + + return conn, nil +} + +// Dial connects to the given network address using net.Dial +// and then initiates a TLS handshake, returning the resulting +// TLS connection. +// Dial interprets a nil configuration as equivalent to +// the zero configuration; see the documentation of Config +// for the defaults. +func Dial(network, addr string, config *Config) (*Conn, error) { + return DialWithDialer(new(net.Dialer), network, addr, config) +} + +// LoadX509KeyPair reads and parses a public/private key pair from a pair of +// files. The files must contain PEM encoded data. On successful return, +// Certificate.Leaf will be nil because the parsed form of the certificate is +// not retained. +func LoadX509KeyPair(certFile, keyFile string) (Certificate, error) { + certPEMBlock, err := ioutil.ReadFile(certFile) + if err != nil { + return Certificate{}, err + } + keyPEMBlock, err := ioutil.ReadFile(keyFile) + if err != nil { + return Certificate{}, err + } + return X509KeyPair(certPEMBlock, keyPEMBlock) +} + +// X509KeyPair parses a public/private key pair from a pair of +// PEM encoded data. On successful return, Certificate.Leaf will be nil because +// the parsed form of the certificate is not retained. +func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (Certificate, error) { + fail := func(err error) (Certificate, error) { return Certificate{}, err } + + var cert Certificate + var skippedBlockTypes []string + for { + var certDERBlock *pem.Block + certDERBlock, certPEMBlock = pem.Decode(certPEMBlock) + if certDERBlock == nil { + break + } + if certDERBlock.Type == "CERTIFICATE" { + cert.Certificate = append(cert.Certificate, certDERBlock.Bytes) + } else { + skippedBlockTypes = append(skippedBlockTypes, certDERBlock.Type) + } + } + + if len(cert.Certificate) == 0 { + if len(skippedBlockTypes) == 0 { + return fail(errors.New("crypto/tls: failed to find any PEM data in certificate input")) + } else if len(skippedBlockTypes) == 1 && strings.HasSuffix(skippedBlockTypes[0], "PRIVATE KEY") { + return fail(errors.New("crypto/tls: failed to find certificate PEM data in certificate input, but did find a private key; PEM inputs may have been switched")) + } else { + return fail(fmt.Errorf("crypto/tls: failed to find \"CERTIFICATE\" PEM block in certificate input after skipping PEM blocks of the following types: %v", skippedBlockTypes)) + } + } + + skippedBlockTypes = skippedBlockTypes[:0] + var keyDERBlock *pem.Block + for { + keyDERBlock, keyPEMBlock = pem.Decode(keyPEMBlock) + if keyDERBlock == nil { + if len(skippedBlockTypes) == 0 { + return fail(errors.New("crypto/tls: failed to find any PEM data in key input")) + } else if len(skippedBlockTypes) == 1 && skippedBlockTypes[0] == "CERTIFICATE" { + return fail(errors.New("crypto/tls: found a certificate rather than a key in the PEM for the private key")) + } else { + return fail(fmt.Errorf("crypto/tls: failed to find PEM block with type ending in \"PRIVATE KEY\" in key input after skipping PEM blocks of the following types: %v", skippedBlockTypes)) + } + } + if keyDERBlock.Type == "PRIVATE KEY" || strings.HasSuffix(keyDERBlock.Type, " PRIVATE KEY") { + break + } + skippedBlockTypes = append(skippedBlockTypes, keyDERBlock.Type) + } + + var err error + cert.PrivateKey, err = parsePrivateKey(keyDERBlock.Bytes) + if err != nil { + return fail(err) + } + + // We don't need to parse the public key for TLS, but we so do anyway + // to check that it looks sane and matches the private key. + x509Cert, err := x509.ParseCertificate(cert.Certificate[0]) + if err != nil { + return fail(err) + } + + switch pub := x509Cert.PublicKey.(type) { + case *rsa.PublicKey: + priv, ok := cert.PrivateKey.(*rsa.PrivateKey) + if !ok { + return fail(errors.New("crypto/tls: private key type does not match public key type")) + } + if pub.N.Cmp(priv.N) != 0 { + return fail(errors.New("crypto/tls: private key does not match public key")) + } + case *ecdsa.PublicKey: + priv, ok := cert.PrivateKey.(*ecdsa.PrivateKey) + if !ok { + return fail(errors.New("crypto/tls: private key type does not match public key type")) + + } + if pub.X.Cmp(priv.X) != 0 || pub.Y.Cmp(priv.Y) != 0 { + return fail(errors.New("crypto/tls: private key does not match public key")) + } + default: + return fail(errors.New("crypto/tls: unknown public key algorithm")) + } + + return cert, nil +} + +// Attempt to parse the given private key DER block. OpenSSL 0.9.8 generates +// PKCS#1 private keys by default, while OpenSSL 1.0.0 generates PKCS#8 keys. +// OpenSSL ecparam generates SEC1 EC private keys for ECDSA. We try all three. +func parsePrivateKey(der []byte) (crypto.PrivateKey, error) { + if key, err := x509.ParsePKCS1PrivateKey(der); err == nil { + return key, nil + } + if key, err := x509.ParsePKCS8PrivateKey(der); err == nil { + switch key := key.(type) { + case *rsa.PrivateKey, *ecdsa.PrivateKey: + return key, nil + default: + return nil, errors.New("crypto/tls: found unknown private key type in PKCS#8 wrapping") + } + } + if key, err := x509.ParseECPrivateKey(der); err == nil { + return key, nil + } + + return nil, errors.New("crypto/tls: failed to parse private key") +} diff --git a/vendor/github.com/cloudflare/cfssl/scan/pki.go b/vendor/github.com/cloudflare/cfssl/scan/pki.go index 205eb5b509f..2afa3dbde22 100644 --- a/vendor/github.com/cloudflare/cfssl/scan/pki.go +++ b/vendor/github.com/cloudflare/cfssl/scan/pki.go @@ -2,13 +2,13 @@ package scan import ( "bytes" - "crypto/tls" "crypto/x509" "fmt" "time" "github.com/cloudflare/cfssl/helpers" "github.com/cloudflare/cfssl/revoke" + "github.com/cloudflare/cfssl/scan/crypto/tls" ) // PKI contains scanners for the Public Key Infrastructure. diff --git a/vendor/github.com/cloudflare/cfssl/scan/scan_common.go b/vendor/github.com/cloudflare/cfssl/scan/scan_common.go index f96ed766d5f..4ebd20d87aa 100644 --- a/vendor/github.com/cloudflare/cfssl/scan/scan_common.go +++ b/vendor/github.com/cloudflare/cfssl/scan/scan_common.go @@ -1,7 +1,6 @@ package scan import ( - "crypto/tls" "crypto/x509" "net" "net/http" @@ -11,6 +10,7 @@ import ( "github.com/cloudflare/cfssl/helpers" "github.com/cloudflare/cfssl/log" + "github.com/cloudflare/cfssl/scan/crypto/tls" ) var ( diff --git a/vendor/github.com/cloudflare/cfssl/scan/tls_handshake.go b/vendor/github.com/cloudflare/cfssl/scan/tls_handshake.go index d488b0cc8f4..aba51554471 100644 --- a/vendor/github.com/cloudflare/cfssl/scan/tls_handshake.go +++ b/vendor/github.com/cloudflare/cfssl/scan/tls_handshake.go @@ -2,13 +2,13 @@ package scan import ( "bytes" - "crypto/tls" "errors" "fmt" "net" "strings" "github.com/cloudflare/cfssl/helpers" + "github.com/cloudflare/cfssl/scan/crypto/tls" ) // Sentinel for failures in sayHello. Should always be caught. @@ -19,7 +19,7 @@ var TLSHandshake = &Family{ Description: "Scans for host's SSL/TLS version and cipher suite negotiation", Scanners: map[string]*Scanner{ "CipherSuite": { - "Determines host's cipher suites accepted and prefered order", + "Determines host's cipher suites accepted and preferred order", cipherSuiteScan, }, "SigAlgs": { diff --git a/vendor/github.com/cloudflare/cfssl/scan/tls_session.go b/vendor/github.com/cloudflare/cfssl/scan/tls_session.go index dd760498f8a..6a43bd76bc6 100644 --- a/vendor/github.com/cloudflare/cfssl/scan/tls_session.go +++ b/vendor/github.com/cloudflare/cfssl/scan/tls_session.go @@ -1,6 +1,6 @@ package scan -import "crypto/tls" +import "github.com/cloudflare/cfssl/scan/crypto/tls" // TLSSession contains tests of host TLS Session Resumption via // Session Tickets and Session IDs diff --git a/vendor/github.com/cloudflare/cfssl/signer/local/local.go b/vendor/github.com/cloudflare/cfssl/signer/local/local.go index 67701af7b6e..a92b8f59171 100644 --- a/vendor/github.com/cloudflare/cfssl/signer/local/local.go +++ b/vendor/github.com/cloudflare/cfssl/signer/local/local.go @@ -337,7 +337,7 @@ func (s *Signer) Sign(req signer.SignRequest) (cert []byte, err error) { var certTBS = safeTemplate - if len(profile.CTLogServers) > 0 { + if len(profile.CTLogServers) > 0 || req.ReturnPrecert { // Add a poison extension which prevents validation var poisonExtension = pkix.Extension{Id: signer.CTPoisonOID, Critical: true, Value: []byte{0x05, 0x00}} var poisonedPreCert = certTBS @@ -347,6 +347,10 @@ func (s *Signer) Sign(req signer.SignRequest) (cert []byte, err error) { return } + if req.ReturnPrecert { + return cert, nil + } + derCert, _ := pem.Decode(cert) prechain := []ct.ASN1Cert{{Data: derCert.Bytes}, {Data: s.ca.Raw}} var sctList []ct.SignedCertificateTimestamp @@ -414,6 +418,85 @@ func (s *Signer) Sign(req signer.SignRequest) (cert []byte, err error) { return signedCert, nil } +// SignFromPrecert creates and signs a certificate from an existing precertificate +// that was previously signed by Signer.ca and inserts the provided SCTs into the +// new certificate. The resulting certificate will be a exact copy of the precert +// except for the removal of the poison extension and the addition of the SCT list +// extension. SignFromPrecert does not verify that the contents of the certificate +// still match the signing profile of the signer, it only requires that the precert +// was previously signed by the Signers CA. +func (s *Signer) SignFromPrecert(precert *x509.Certificate, scts []ct.SignedCertificateTimestamp) ([]byte, error) { + // Verify certificate was signed by s.ca + if err := precert.CheckSignatureFrom(s.ca); err != nil { + return nil, err + } + + // Verify certificate is a precert + isPrecert := false + poisonIndex := 0 + for i, ext := range precert.Extensions { + if ext.Id.Equal(signer.CTPoisonOID) { + if !ext.Critical { + return nil, cferr.New(cferr.CTError, cferr.PrecertInvalidPoison) + } + // Check extension contains ASN.1 NULL + if bytes.Compare(ext.Value, []byte{0x05, 0x00}) != 0 { + return nil, cferr.New(cferr.CTError, cferr.PrecertInvalidPoison) + } + isPrecert = true + poisonIndex = i + break + } + } + if !isPrecert { + return nil, cferr.New(cferr.CTError, cferr.PrecertMissingPoison) + } + + // Serialize SCTs into list format and create extension + serializedList, err := helpers.SerializeSCTList(scts) + if err != nil { + return nil, err + } + // Serialize again as an octet string before embedding + serializedList, err = asn1.Marshal(serializedList) + if err != nil { + return nil, cferr.Wrap(cferr.CTError, cferr.Unknown, err) + } + sctExt := pkix.Extension{Id: signer.SCTListOID, Critical: false, Value: serializedList} + + // Create the new tbsCert from precert. Do explicit copies of any slices so that we don't + // use memory that may be altered by us or the caller at a later stage. + tbsCert := x509.Certificate{ + SignatureAlgorithm: precert.SignatureAlgorithm, + PublicKeyAlgorithm: precert.PublicKeyAlgorithm, + PublicKey: precert.PublicKey, + Version: precert.Version, + SerialNumber: precert.SerialNumber, + Issuer: precert.Issuer, + Subject: precert.Subject, + NotBefore: precert.NotBefore, + NotAfter: precert.NotAfter, + KeyUsage: precert.KeyUsage, + BasicConstraintsValid: precert.BasicConstraintsValid, + IsCA: precert.IsCA, + MaxPathLen: precert.MaxPathLen, + MaxPathLenZero: precert.MaxPathLenZero, + PermittedDNSDomainsCritical: precert.PermittedDNSDomainsCritical, + } + if len(precert.Extensions) > 0 { + tbsCert.ExtraExtensions = make([]pkix.Extension, len(precert.Extensions)) + copy(tbsCert.ExtraExtensions, precert.Extensions) + } + + // Remove the poison extension from ExtraExtensions + tbsCert.ExtraExtensions = append(tbsCert.ExtraExtensions[:poisonIndex], tbsCert.ExtraExtensions[poisonIndex+1:]...) + // Insert the SCT list extension + tbsCert.ExtraExtensions = append(tbsCert.ExtraExtensions, sctExt) + + // Sign the tbsCert + return s.sign(&tbsCert) +} + // Info return a populated info.Resp struct or an error. func (s *Signer) Info(req info.Req) (resp *info.Resp, err error) { cert, err := s.Certificate(req.Label, req.Profile) diff --git a/vendor/github.com/cloudflare/cfssl/signer/signer.go b/vendor/github.com/cloudflare/cfssl/signer/signer.go index 20101f682b6..97d123673f8 100644 --- a/vendor/github.com/cloudflare/cfssl/signer/signer.go +++ b/vendor/github.com/cloudflare/cfssl/signer/signer.go @@ -64,6 +64,12 @@ type SignRequest struct { // for canonicalization) as the value of the notAfter field of the // certificate. NotAfter time.Time + // If ReturnPrecert is true a certificate with the CT poison extension + // will be returned from the Signer instead of attempting to retrieve + // SCTs and populate the tbsCert with them itself. This precert can then + // be passed to SignFromPrecert with the SCTs in order to create a + // valid certificate. + ReturnPrecert bool } // appendIf appends to a if s is not an empty string. diff --git a/vendor/github.com/cloudflare/cfssl/signer/universal/universal.go b/vendor/github.com/cloudflare/cfssl/signer/universal/universal.go index 7c8c59d1ab3..50b44a6e403 100644 --- a/vendor/github.com/cloudflare/cfssl/signer/universal/universal.go +++ b/vendor/github.com/cloudflare/cfssl/signer/universal/universal.go @@ -63,13 +63,10 @@ func newLocalSigner(root Root, policy *config.Signing) (s signer.Signer, err err // signers. var shouldProvide bool - // localSignerList is defined in the - // universal_signers*.go files. These activate - // and deactivate signers based on build - // flags; for example, - // universal_signers_pkcs11.go contains a list - // of valid signers when PKCS #11 is turned - // on. + // localSignerList is a list of signers defined + // here or in the universal_signers*.go files. + // These activate and deactivate signers based + // on build flags. for _, possibleSigner := range localSignerList { s, shouldProvide, err = possibleSigner(&root, policy) if shouldProvide { diff --git a/vendor/github.com/cloudflare/cfssl/ubiquity/ubiquity_platform.go b/vendor/github.com/cloudflare/cfssl/ubiquity/ubiquity_platform.go index d4e5dab9859..4d49aeb64a0 100644 --- a/vendor/github.com/cloudflare/cfssl/ubiquity/ubiquity_platform.go +++ b/vendor/github.com/cloudflare/cfssl/ubiquity/ubiquity_platform.go @@ -181,7 +181,7 @@ func UntrustedPlatforms(root *x509.Certificate) []string { return ret } -// CrossPlatformUbiquity returns a ubiquity score (persumably relecting the market share in percentage) +// CrossPlatformUbiquity returns a ubiquity score (presumably relecting the market share in percentage) // based on whether the given chain can be verified with the different platforms' root certificate stores. func CrossPlatformUbiquity(chain []*x509.Certificate) int { // There is no root store info, every chain is equal weighted as 0.