mirror of https://github.com/k3s-io/k3s
Bump cfssl to 56268a6
parent
952fc9f6f8
commit
ed7304b30c
|
@ -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",
|
||||
|
|
|
@ -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: =
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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"],
|
||||
)
|
|
@ -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"},
|
||||
}
|
||||
}
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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)
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.",
|
||||
|
|
|
@ -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",
|
||||
],
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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.
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"],
|
||||
)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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"],
|
||||
)
|
|
@ -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()
|
||||
}
|
486
vendor/github.com/cloudflare/cfssl/scan/crypto/tls/cfsslscan_common.go
generated
vendored
Normal file
486
vendor/github.com/cloudflare/cfssl/scan/crypto/tls/cfsslscan_common.go
generated
vendored
Normal file
|
@ -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",
|
||||
}
|
109
vendor/github.com/cloudflare/cfssl/scan/crypto/tls/cfsslscan_handshake.go
generated
vendored
Normal file
109
vendor/github.com/cloudflare/cfssl/scan/crypto/tls/cfsslscan_handshake.go
generated
vendored
Normal file
|
@ -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
|
||||
}
|
289
vendor/github.com/cloudflare/cfssl/scan/crypto/tls/cipher_suites.go
generated
vendored
Normal file
289
vendor/github.com/cloudflare/cfssl/scan/crypto/tls/cipher_suites.go
generated
vendored
Normal file
|
@ -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
|
||||
)
|
|
@ -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
|
||||
}
|
File diff suppressed because it is too large
Load Diff
161
vendor/github.com/cloudflare/cfssl/scan/crypto/tls/generate_cert.go
generated
vendored
Normal file
161
vendor/github.com/cloudflare/cfssl/scan/crypto/tls/generate_cert.go
generated
vendored
Normal file
|
@ -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")
|
||||
}
|
667
vendor/github.com/cloudflare/cfssl/scan/crypto/tls/handshake_client.go
generated
vendored
Normal file
667
vendor/github.com/cloudflare/cfssl/scan/crypto/tls/handshake_client.go
generated
vendored
Normal file
|
@ -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
|
||||
}
|
1528
vendor/github.com/cloudflare/cfssl/scan/crypto/tls/handshake_messages.go
generated
vendored
Normal file
1528
vendor/github.com/cloudflare/cfssl/scan/crypto/tls/handshake_messages.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
750
vendor/github.com/cloudflare/cfssl/scan/crypto/tls/handshake_server.go
generated
vendored
Normal file
750
vendor/github.com/cloudflare/cfssl/scan/crypto/tls/handshake_server.go
generated
vendored
Normal file
|
@ -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
|
||||
}
|
405
vendor/github.com/cloudflare/cfssl/scan/crypto/tls/key_agreement.go
generated
vendored
Normal file
405
vendor/github.com/cloudflare/cfssl/scan/crypto/tls/key_agreement.go
generated
vendored
Normal file
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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")
|
||||
}
|
|
@ -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.
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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": {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue