advancedtls: Add SNI logic to ServerOptions.GetCertificate (#3697)

* Add SNI support in the user-provided GetCertificate callback
This commit is contained in:
cindyxue
2020-07-27 23:50:43 -07:00
committed by GitHub
parent 8b7764bddb
commit dfc0c05b2d
13 changed files with 638 additions and 30 deletions

View File

@ -156,7 +156,7 @@ type ClientOptions struct {
// Certificates or GetClientCertificate indicates the certificates sent from
// the server to the client to prove server's identities. The rules for setting
// these two fields are:
// Either Certificates or GetCertificate must be set; the other will be ignored.
// Either Certificates or GetCertificates must be set; the other will be ignored.
type ServerOptions struct {
// If field Certificates is set, field GetClientCertificate will be ignored.
// The server will use Certificates every time when asked for a certificate,
@ -166,7 +166,7 @@ type ServerOptions struct {
// invoke this function every time asked to present certificates to the
// client when a new connection is established. This is known as peer
// certificate reloading.
GetCertificate func(*tls.ClientHelloInfo) (*tls.Certificate, error)
GetCertificates func(*tls.ClientHelloInfo) ([]*tls.Certificate, error)
// VerifyPeer is a custom verification check after certificate signature
// check.
// If this is set, we will perform this customized check after doing the
@ -210,8 +210,8 @@ func (o *ClientOptions) config() (*tls.Config, error) {
}
func (o *ServerOptions) config() (*tls.Config, error) {
if o.Certificates == nil && o.GetCertificate == nil {
return nil, fmt.Errorf("either Certificates or GetCertificate must be specified")
if o.Certificates == nil && o.GetCertificates == nil {
return nil, fmt.Errorf("either Certificates or GetCertificates must be specified")
}
if o.RequireClientCert && o.VType == SkipVerification && o.VerifyPeer == nil {
return nil, fmt.Errorf(
@ -236,7 +236,13 @@ func (o *ServerOptions) config() (*tls.Config, error) {
config := &tls.Config{
ClientAuth: clientAuth,
Certificates: o.Certificates,
GetCertificate: o.GetCertificate,
}
if o.GetCertificates != nil {
// GetCertificate is only able to perform SNI logic for go1.10 and above.
// It will return the first certificate in o.GetCertificates for go1.9.
config.GetCertificate = func(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {
return buildGetCertificates(clientHello, o)
}
}
if clientCAs != nil {
config.ClientCAs = clientCAs

View File

@ -197,7 +197,7 @@ func TestEnd2End(t *testing.T) {
clientVerifyFunc CustomVerificationFunc
clientVType VerificationType
serverCert []tls.Certificate
serverGetCert func(*tls.ClientHelloInfo) (*tls.Certificate, error)
serverGetCert func(*tls.ClientHelloInfo) ([]*tls.Certificate, error)
serverRoot *x509.CertPool
serverGetRoot func(params *GetRootCAsParams) (*GetRootCAsResults, error)
serverVerifyFunc CustomVerificationFunc
@ -271,12 +271,12 @@ func TestEnd2End(t *testing.T) {
return &VerificationResults{}, nil
},
clientVType: CertVerification,
serverGetCert: func(*tls.ClientHelloInfo) (*tls.Certificate, error) {
serverGetCert: func(*tls.ClientHelloInfo) ([]*tls.Certificate, error) {
switch stage.read() {
case 0:
return &cs.serverPeer1, nil
return []*tls.Certificate{&cs.serverPeer1}, nil
default:
return &cs.serverPeer2, nil
return []*tls.Certificate{&cs.serverPeer2}, nil
}
},
serverRoot: cs.serverTrust1,
@ -336,12 +336,12 @@ func TestEnd2End(t *testing.T) {
return nil, fmt.Errorf("custom authz check fails")
},
clientVType: CertVerification,
serverGetCert: func(*tls.ClientHelloInfo) (*tls.Certificate, error) {
serverGetCert: func(*tls.ClientHelloInfo) ([]*tls.Certificate, error) {
switch stage.read() {
case 0:
return &cs.serverPeer1, nil
return []*tls.Certificate{&cs.serverPeer1}, nil
default:
return &cs.serverPeer2, nil
return []*tls.Certificate{&cs.serverPeer2}, nil
}
},
serverRoot: cs.serverTrust1,
@ -389,7 +389,7 @@ func TestEnd2End(t *testing.T) {
// Start a server using ServerOptions in another goroutine.
serverOptions := &ServerOptions{
Certificates: test.serverCert,
GetCertificate: test.serverGetCert,
GetCertificates: test.serverGetCert,
RootCertificateOptions: RootCertificateOptions{
RootCACerts: test.serverRoot,
GetRootCAs: test.serverGetRoot,

View File

@ -102,7 +102,7 @@ func TestClientServerHandshake(t *testing.T) {
clientExpectHandshakeError bool
serverMutualTLS bool
serverCert []tls.Certificate
serverGetCert func(*tls.ClientHelloInfo) (*tls.Certificate, error)
serverGetCert func(*tls.ClientHelloInfo) ([]*tls.Certificate, error)
serverRoot *x509.CertPool
serverGetRoot func(params *GetRootCAsParams) (*GetRootCAsResults, error)
serverVerifyFunc CustomVerificationFunc
@ -279,8 +279,8 @@ func TestClientServerHandshake(t *testing.T) {
clientVerifyFunc: clientVerifyFuncGood,
clientVType: CertVerification,
serverMutualTLS: true,
serverGetCert: func(info *tls.ClientHelloInfo) (*tls.Certificate, error) {
return &serverPeerCert, nil
serverGetCert: func(info *tls.ClientHelloInfo) ([]*tls.Certificate, error) {
return []*tls.Certificate{&serverPeerCert}, nil
},
serverGetRoot: getRootCAsForServer,
serverVerifyFunc: serverVerifyFunc,
@ -300,8 +300,8 @@ func TestClientServerHandshake(t *testing.T) {
clientVerifyFunc: clientVerifyFuncGood,
clientVType: CertVerification,
serverMutualTLS: true,
serverGetCert: func(info *tls.ClientHelloInfo) (*tls.Certificate, error) {
return &serverPeerCert, nil
serverGetCert: func(info *tls.ClientHelloInfo) ([]*tls.Certificate, error) {
return []*tls.Certificate{&serverPeerCert}, nil
},
serverGetRoot: getRootCAsForServer,
serverVerifyFunc: serverVerifyFunc,
@ -322,8 +322,8 @@ func TestClientServerHandshake(t *testing.T) {
clientVType: CertVerification,
clientExpectHandshakeError: true,
serverMutualTLS: true,
serverGetCert: func(info *tls.ClientHelloInfo) (*tls.Certificate, error) {
return &serverPeerCert, nil
serverGetCert: func(info *tls.ClientHelloInfo) ([]*tls.Certificate, error) {
return []*tls.Certificate{&serverPeerCert}, nil
},
serverGetRoot: getRootCAsForServer,
serverVerifyFunc: serverVerifyFunc,
@ -344,8 +344,8 @@ func TestClientServerHandshake(t *testing.T) {
clientVerifyFunc: clientVerifyFuncGood,
clientVType: CertVerification,
serverMutualTLS: true,
serverGetCert: func(info *tls.ClientHelloInfo) (*tls.Certificate, error) {
return &clientPeerCert, nil
serverGetCert: func(info *tls.ClientHelloInfo) ([]*tls.Certificate, error) {
return []*tls.Certificate{&clientPeerCert}, nil
},
serverGetRoot: getRootCAsForServer,
serverVerifyFunc: serverVerifyFunc,
@ -366,8 +366,8 @@ func TestClientServerHandshake(t *testing.T) {
clientVType: CertVerification,
clientExpectHandshakeError: true,
serverMutualTLS: true,
serverGetCert: func(info *tls.ClientHelloInfo) (*tls.Certificate, error) {
return &serverPeerCert, nil
serverGetCert: func(info *tls.ClientHelloInfo) ([]*tls.Certificate, error) {
return []*tls.Certificate{&serverPeerCert}, nil
},
serverGetRoot: getRootCAsForClient,
serverVerifyFunc: serverVerifyFunc,
@ -403,7 +403,7 @@ func TestClientServerHandshake(t *testing.T) {
// Start a server using ServerOptions in another goroutine.
serverOptions := &ServerOptions{
Certificates: test.serverCert,
GetCertificate: test.serverGetCert,
GetCertificates: test.serverGetCert,
RootCertificateOptions: RootCertificateOptions{
RootCACerts: test.serverRoot,
GetRootCAs: test.serverGetRoot,

View File

@ -4,7 +4,7 @@ go 1.13
require (
github.com/golang/protobuf v1.3.5 // indirect
github.com/google/go-cmp v0.4.0 // indirect
github.com/google/go-cmp v0.4.0
golang.org/x/net v0.0.0-20200602114024-627f9648deb9 // indirect
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980 // indirect
golang.org/x/text v0.3.3 // indirect

View File

@ -0,0 +1,53 @@
// +build go1.10
/*
*
* Copyright 2020 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package advancedtls
import (
"crypto/tls"
"fmt"
)
// buildGetCertificates returns the certificate that matches the SNI field
// for the given ClientHelloInfo, defaulting to the first element of o.GetCertificates.
func buildGetCertificates(clientHello *tls.ClientHelloInfo, o *ServerOptions) (*tls.Certificate, error) {
if o.GetCertificates == nil {
return nil, fmt.Errorf("function GetCertificates must be specified")
}
certificates, err := o.GetCertificates(clientHello)
if err != nil {
return nil, err
}
if len(certificates) == 0 {
return nil, fmt.Errorf("no certificates configured")
}
// If users pass in only one certificate, return that certificate.
if len(certificates) == 1 {
return certificates[0], nil
}
// Choose the SNI certificate using SupportsCertificate.
for _, cert := range certificates {
if err := clientHello.SupportsCertificate(cert); err == nil {
return cert, nil
}
}
// If nothing matches, return the first certificate.
return certificates[0], nil
}

View File

@ -0,0 +1,41 @@
// +build !go1.10
/*
*
* Copyright 2020 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package advancedtls
import (
"crypto/tls"
"fmt"
)
// buildGetCertificates returns the first element of o.GetCertificates.
func buildGetCertificates(clientHello *tls.ClientHelloInfo, o *ServerOptions) (*tls.Certificate, error) {
if o.GetCertificates == nil {
return nil, fmt.Errorf("function GetCertificates must be specified")
}
certificates, err := o.GetCertificates(clientHello)
if err != nil {
return nil, err
}
if len(certificates) == 0 {
return nil, fmt.Errorf("no certificates configured")
}
return certificates[0], nil
}

View File

@ -0,0 +1,108 @@
// +build go1.10
/*
*
* Copyright 2019 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package advancedtls
import (
"crypto/tls"
"testing"
"github.com/google/go-cmp/cmp"
"google.golang.org/grpc/security/advancedtls/testdata"
)
// TestGetCertificatesSNI tests SNI logic for go1.10 and above.
func TestGetCertificatesSNI(t *testing.T) {
// Load server certificates for setting the serverGetCert callback function.
serverCert1, err := tls.LoadX509KeyPair(testdata.Path("server_cert_1.pem"), testdata.Path("server_key_1.pem"))
if err != nil {
t.Fatalf("tls.LoadX509KeyPair(server_cert_1.pem, server_key_1.pem) failed: %v", err)
}
serverCert2, err := tls.LoadX509KeyPair(testdata.Path("server_cert_2.pem"), testdata.Path("server_key_2.pem"))
if err != nil {
t.Fatalf("tls.LoadX509KeyPair(server_cert_2.pem, server_key_2.pem) failed: %v", err)
}
serverCert3, err := tls.LoadX509KeyPair(testdata.Path("server_cert_3.pem"), testdata.Path("server_key_3.pem"))
if err != nil {
t.Fatalf("tls.LoadX509KeyPair(server_cert_3.pem, server_key_3.pem) failed: %v", err)
}
tests := []struct {
desc string
serverGetCert func(*tls.ClientHelloInfo) ([]*tls.Certificate, error)
serverName string
wantCert tls.Certificate
}{
{
desc: "Select serverCert1",
serverGetCert: func(info *tls.ClientHelloInfo) ([]*tls.Certificate, error) {
return []*tls.Certificate{&serverCert1, &serverCert2, &serverCert3}, nil
},
// "foo.bar.com" is the common name on server certificate server_cert_1.pem.
serverName: "foo.bar.com",
wantCert: serverCert1,
},
{
desc: "Select serverCert2",
serverGetCert: func(info *tls.ClientHelloInfo) ([]*tls.Certificate, error) {
return []*tls.Certificate{&serverCert1, &serverCert2, &serverCert3}, nil
},
// "foo.bar.server2.com" is the common name on server certificate server_cert_2.pem.
serverName: "foo.bar.server2.com",
wantCert: serverCert2,
},
{
desc: "Select serverCert3",
serverGetCert: func(info *tls.ClientHelloInfo) ([]*tls.Certificate, error) {
return []*tls.Certificate{&serverCert1, &serverCert2, &serverCert3}, nil
},
// "google.com" is one of the DNS names on server certificate server_cert_3.pem.
serverName: "google.com",
wantCert: serverCert3,
},
}
for _, test := range tests {
test := test
t.Run(test.desc, func(t *testing.T) {
serverOptions := &ServerOptions{
GetCertificates: test.serverGetCert,
}
serverConfig, err := serverOptions.config()
if err != nil {
t.Fatalf("serverOptions.config() failed: %v", err)
}
pointFormatUncompressed := uint8(0)
clientHello := &tls.ClientHelloInfo{
CipherSuites: []uint16{tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA},
ServerName: test.serverName,
SupportedCurves: []tls.CurveID{tls.CurveP256},
SupportedPoints: []uint8{pointFormatUncompressed},
SupportedVersions: []uint16{tls.VersionTLS10},
}
gotCertificate, err := serverConfig.GetCertificate(clientHello)
if err != nil {
t.Fatalf("serverConfig.GetCertificate(clientHello) failed: %v", err)
}
if !cmp.Equal(gotCertificate, test.wantCert, cmp.AllowUnexported(tls.Certificate{})) {
t.Errorf("GetCertificates() = %v, want %v", gotCertificate, test.wantCert)
}
})
}
}

View File

@ -0,0 +1,108 @@
// +build !go1.10
/*
*
* Copyright 2019 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package advancedtls
import (
"crypto/tls"
"testing"
"github.com/google/go-cmp/cmp"
"google.golang.org/grpc/security/advancedtls/testdata"
)
// TestGetCertificatesSNI tests SNI logic for go1.9.
func TestGetCertificatesSNI(t *testing.T) {
// Load server certificates for setting the serverGetCert callback function.
serverCert1, err := tls.LoadX509KeyPair(testdata.Path("server_cert_1.pem"), testdata.Path("server_key_1.pem"))
if err != nil {
t.Fatalf("tls.LoadX509KeyPair(server_cert_1.pem, server_key_1.pem) failed: %v", err)
}
serverCert2, err := tls.LoadX509KeyPair(testdata.Path("server_cert_2.pem"), testdata.Path("server_key_2.pem"))
if err != nil {
t.Fatalf("tls.LoadX509KeyPair(server_cert_2.pem, server_key_2.pem) failed: %v", err)
}
serverCert3, err := tls.LoadX509KeyPair(testdata.Path("server_cert_3.pem"), testdata.Path("server_key_3.pem"))
if err != nil {
t.Fatalf("tls.LoadX509KeyPair(server_cert_3.pem, server_key_3.pem) failed: %v", err)
}
tests := []struct {
desc string
serverGetCert func(*tls.ClientHelloInfo) ([]*tls.Certificate, error)
serverName string
wantCert tls.Certificate
}{
{
desc: "Select serverCert1",
serverGetCert: func(info *tls.ClientHelloInfo) ([]*tls.Certificate, error) {
return []*tls.Certificate{&serverCert1, &serverCert2, &serverCert3}, nil
},
// "foo.bar.com" is the common name on server certificate server_cert_1.pem.
serverName: "foo.bar.com",
wantCert: serverCert1,
},
{
desc: "Select serverCert2",
serverGetCert: func(info *tls.ClientHelloInfo) ([]*tls.Certificate, error) {
return []*tls.Certificate{&serverCert1, &serverCert2, &serverCert3}, nil
},
// "foo.bar.server2.com" is the common name on server certificate server_cert_2.pem.
serverName: "foo.bar.server2.com",
wantCert: serverCert1,
},
{
desc: "Select serverCert3",
serverGetCert: func(info *tls.ClientHelloInfo) ([]*tls.Certificate, error) {
return []*tls.Certificate{&serverCert1, &serverCert2, &serverCert3}, nil
},
// "google.com" is one of the DNS names on server certificate server_cert_3.pem.
serverName: "google.com",
wantCert: serverCert1,
},
}
for _, test := range tests {
test := test
t.Run(test.desc, func(t *testing.T) {
serverOptions := &ServerOptions{
GetCertificates: test.serverGetCert,
}
serverConfig, err := serverOptions.config()
if err != nil {
t.Fatalf("serverOptions.config() failed: %v", err)
}
pointFormatUncompressed := uint8(0)
clientHello := &tls.ClientHelloInfo{
CipherSuites: []uint16{tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA},
ServerName: test.serverName,
SupportedCurves: []tls.CurveID{tls.CurveP256},
SupportedPoints: []uint8{pointFormatUncompressed},
SupportedVersions: []uint16{tls.VersionTLS10},
}
gotCertificate, err := serverConfig.GetCertificate(clientHello)
if err != nil {
t.Fatalf("serverConfig.GetCertificate(clientHello) failed: %v", err)
}
if !cmp.Equal(gotCertificate, test.wantCert, cmp.AllowUnexported(tls.Certificate{})) {
t.Errorf("GetCertificates() = %v, want %v", gotCertificate, test.wantCert)
}
})
}
}

View File

@ -0,0 +1,90 @@
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 3 (0x3)
Signature Algorithm: sha256WithRSAEncryption
Issuer: C = US, ST = CA, L = SVL, O = Internet Widgits Pty Ltd
Validity
Not Before: Nov 4 21:43:00 2019 GMT
Not After : Aug 18 21:43:00 2293 GMT
Subject: C = US, ST = CA, L = DUMMYCITY, O = Internet Widgits Pty Ltd, CN = foo.bar.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (4096 bit)
Modulus:
00:ec:3f:24:2d:91:3a:bd:c3:fc:15:72:42:b3:fb:
28:e6:04:a3:be:26:20:e6:ea:30:a8:aa:48:78:36:
0e:0b:99:29:3b:4b:f9:f1:d5:bf:bd:0c:13:7c:ea:
52:06:f4:bc:34:9e:2b:c0:b4:82:2c:87:fa:2f:e2:
cd:7c:d7:b9:e1:8f:04:71:6d:85:77:ae:18:40:e4:
b1:3a:4a:6b:e5:33:bf:3e:65:db:cf:94:64:87:1a:
20:46:c0:37:3a:9f:93:3f:d4:4f:ac:c4:e4:e0:28:
b6:0f:28:53:2a:cf:b9:fe:50:f2:ef:47:dc:7e:b6:
60:c2:47:85:b8:cb:ca:48:5b:fa:9f:8a:97:30:01:
f4:b3:51:0f:68:e1:60:ab:2f:a0:ad:fc:f0:10:4f:
60:e1:92:db:be:83:04:5c:40:87:ce:51:3e:9a:9e:
d6:1c:1b:19:cb:8c:c2:6c:57:74:6f:7b:af:94:3d:
53:ad:17:a5:99:69:7c:41:f5:3e:7a:5b:48:c7:78:
ff:d7:3b:a8:1f:f7:30:e7:83:26:78:e2:cb:a2:8f:
58:92:61:cd:ca:e9:b8:d1:80:c0:40:58:e9:d8:d3:
42:64:82:8f:e4:0c:b9:b1:36:db:9f:65:3f:3f:5b:
24:59:31:b3:60:0c:fa:41:5a:1b:b8:9d:ec:99:37:
90:fa:b5:e7:3f:cb:7c:e0:f9:ed:ea:27:ce:15:24:
c7:77:3b:45:45:2d:19:8e:2e:7f:65:0e:85:df:66:
50:69:24:2c:a4:6a:07:e5:3f:eb:28:84:53:94:4d:
5f:9c:a8:65:a6:50:4c:c0:35:06:40:6a:a5:62:b1:
93:60:e5:1c:85:28:34:9b:29:81:6f:e2:4f:cd:15:
30:b9:19:d7:4b:bb:30:0c:4b:2d:64:fe:3b:dd:0e:
a4:25:2c:4a:5c:de:d7:74:1f:5e:93:7b:1c:e8:c8:
fa:72:1f:4a:eb:8d:3f:98:e4:55:98:b8:e0:8a:29:
92:33:af:75:6b:05:84:05:d3:0c:2c:07:78:bc:0e:
b2:6d:a7:00:35:c4:53:1f:7b:e6:ba:07:72:a8:24:
c1:0a:a7:c4:46:e6:f2:6f:3a:79:23:00:0b:b8:e5:
1f:e0:e2:ee:c6:13:a3:57:d9:86:1a:95:f7:a3:04:
f1:46:d5:5f:21:d2:aa:d2:30:fb:f6:cb:e0:da:24:
c6:c3:30:2f:d2:1f:21:fe:bc:0f:99:ac:ac:9b:65:
9b:e4:83:9a:00:b8:2f:40:fc:3b:42:d3:7a:e8:b7:
52:d7:f4:67:2a:a5:f7:eb:78:f1:0a:56:8b:56:12:
d5:48:d8:48:70:ab:b8:69:5a:21:d3:71:b0:59:9d:
17:b4:4b
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
C0:82:DA:FA:69:46:30:AE:FF:6F:CD:BB:93:49:94:A6:D0:E2:17:EB
X509v3 Authority Key Identifier:
keyid:5A:A5:DA:B1:99:D4:E5:0E:E6:1E:94:EA:FF:FC:62:E2:ED:09:F1:06
X509v3 Basic Constraints:
CA:FALSE
X509v3 Key Usage:
Digital Signature, Key Encipherment
Signature Algorithm: sha256WithRSAEncryption
36:fd:cf:ec:f5:20:4b:52:dc:2e:38:f3:92:b1:e4:b6:a1:06:
86:aa:2d:c0:e6:f5:0a:58:97:a9:e3:be:13:09:61:79:ed:d4:
41:83:26:ad:ee:0b:43:83:d1:dd:19:1a:e8:7b:b2:1f:fe:d4:
c1:57:7d:6d:6b:d4:42:ea:7d:cd:34:8c:a4:1f:5b:3b:fa:de:
bb:2f:ae:56:b6:18:e5:53:a9:a3:99:58:ad:36:be:19:54:61:
0d:52:b6:a7:53:fc:60:e5:ff:f5:7f:82:3f:c1:49:06:cd:b2:
af:25:ee:de:bd:e0:e5:5e:ad:0b:dc:2e:b1:ec:7a:52:6f:9d:
e0:b9:84:18:db:49:53:ee:df:93:ee:8b:9d:9b:8e:3b:2a:82:
86:7f:45:c8:dd:d1:b0:40:17:ed:63:52:a1:5b:6e:d3:5c:a2:
72:05:fb:3a:39:71:0d:b4:2c:9d:15:23:1b:1f:8d:ac:89:dc:
c9:56:f2:19:c7:f3:2f:bb:d5:de:40:17:f1:52:ea:e8:93:ff:
56:43:f5:1d:cb:c0:51:52:25:d7:b0:81:a9:0e:4d:92:24:e7:
10:81:c7:31:26:ac:cb:66:c1:3f:f6:5f:69:7b:74:87:0d:b0:
8c:27:d4:24:29:59:e9:5b:a2:cb:0c:c0:f5:9b:1d:42:38:6b:
e3:c3:43:1e:ba:df:b1:51:0a:b7:33:55:26:39:01:2f:9f:c7:
88:ac:2f:4a:89:f3:69:de:72:43:48:49:08:59:36:86:84:09:
db:6a:82:84:3e:71:6a:9d:f9:bd:d8:b5:1e:7c:2c:29:e1:27:
45:4c:47:5b:88:b8:e6:fa:9d:9b:ff:d4:e9:8d:2d:5e:64:7f:
27:87:b2:8c:d8:7e:f5:52:3c:c4:d8:30:03:24:d7:ac:f8:53:
91:80:98:42:24:5a:6b:cb:34:48:57:e0:82:ac:96:d9:55:6c:
c2:c3:8c:19:7c:56:39:0a:a8:f1:b8:77:64:70:83:a8:04:c8:
3a:5d:0b:00:4c:e5:ba:f1:40:e5:57:cd:d9:67:48:21:e9:9c:
d3:f2:b8:01:b8:d1:c0:d1:3a:44:c0:97:db:e6:bc:8f:2e:33:
d5:e2:38:3d:d7:7b:50:13:01:36:28:61:cc:28:98:3c:f8:21:
5d:8c:fe:f5:d0:ab:e0:60:ec:36:22:8d:0b:71:30:1b:3d:56:
ae:96:e9:d2:89:c2:43:8b:ef:25:b7:d6:0d:82:e6:5a:c6:91:
8a:ad:8c:28:2a:2b:5c:4e:a1:de:cb:7d:cb:29:11:a2:66:c8:
a1:33:35:75:16:fe:28:0b:78:31:0a:1f:fa:d0:a8:f4:f1:69:
c7:97:1e:5d:fb:53:08:b5

View File

@ -0,0 +1,91 @@
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 7 (0x7)
Signature Algorithm: sha256WithRSAEncryption
Issuer: C = US, ST = CA, O = Internet Widgits Pty Ltd, CN = foo.bar.client2.trust.com
Validity
Not Before: Jan 9 22:51:54 2020 GMT
Not After : Oct 23 22:51:54 2293 GMT
Subject: C = US, ST = CA, O = Internet Widgits Pty Ltd, CN = foo.bar.server2.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (4096 bit)
Modulus:
00:b1:0b:d3:7e:5b:61:30:db:b0:5f:3f:6d:d2:e0:
3b:c6:4c:88:95:f5:7e:fd:cd:aa:20:5d:08:b9:6e:
41:db:c4:ed:0d:f8:bc:cb:b4:ee:c5:87:11:05:a0:
ac:12:3b:4e:0b:4c:e4:43:e4:17:89:c1:ae:b4:13:
58:1c:31:58:6a:f2:01:ed:df:66:e9:f9:2e:9c:c5:
85:e6:02:db:36:f4:f3:07:39:75:30:f1:b5:55:5b:
46:2f:87:b0:d4:a0:ab:57:df:30:45:ae:bd:b0:49:
9a:fc:ba:5e:bc:d0:5d:86:f4:24:45:4a:d5:4d:5b:
b6:ba:e8:b7:a1:3b:c3:2f:46:2e:b3:ad:2c:63:03:
df:cb:f4:56:62:91:bd:bc:23:00:af:a2:7a:3d:6f:
f1:33:81:60:0e:bc:20:f5:8a:49:5f:ec:58:bc:64:
d5:47:36:a0:2b:b8:1f:76:25:01:89:3e:ff:52:69:
95:03:8f:bb:14:2f:1a:38:a3:9f:c1:45:20:22:77:
70:97:5e:25:51:b8:3d:5d:89:7a:bb:15:12:cd:1d:
96:d2:9c:72:67:12:85:72:6e:27:7a:ef:25:da:af:
49:26:8d:eb:a0:34:a4:4d:64:c3:63:33:77:5d:ad:
53:c7:ee:51:32:7b:cc:43:bb:86:8d:f9:52:ba:35:
23:0e:30:5d:dc:3b:25:63:c1:e3:5f:4b:b2:02:fc:
fe:5b:18:7f:84:aa:f3:71:e4:16:b5:98:bc:73:c5:
58:13:41:38:eb:f3:a2:fa:8c:98:bd:f1:10:ee:b6:
fe:7e:a5:81:c7:5e:f2:72:54:8e:db:09:f0:35:42:
ca:b7:86:c2:48:b2:c6:18:08:ac:d1:f0:5d:de:b0:
b8:25:8b:3b:bd:61:48:0f:71:3f:ed:97:72:02:c9:
44:5d:0c:00:fc:30:ca:5d:1c:e5:13:1b:3a:d0:ce:
d9:36:a0:db:f5:c2:ad:a6:95:26:4e:7b:29:2d:fc:
c4:04:1d:47:6e:03:59:68:1e:7a:20:6d:e8:a8:e1:
3c:57:59:f8:3d:2f:16:61:7e:24:e5:13:ca:48:0a:
e6:f0:60:a3:2d:93:0b:8f:93:eb:b5:d1:06:26:52:
c0:63:1f:fc:9b:73:fe:91:c3:04:40:32:8d:09:d5:
9e:c4:f6:0b:61:3d:9f:a1:d7:94:a2:e1:3d:b6:bb:
60:26:74:89:33:25:18:0f:c3:88:db:10:5e:a0:5b:
f4:ee:d0:18:ab:36:50:c5:44:9b:6d:ba:ea:e2:6e:
52:3a:55:49:a3:72:ae:04:af:1d:f6:f2:83:27:17:
8b:9a:98:0a:f5:44:b1:c8:f2:a9:c8:ed:b0:75:ca:
52:25:f3
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
74:BD:18:0B:32:AF:D0:51:8E:4C:4C:8D:B2:F6:4E:B8:6D:AB:BD:BA
X509v3 Authority Key Identifier:
keyid:01:74:A9:44:61:3D:7A:BB:C2:32:CD:D0:ED:20:DA:3A:C4:C6:02:E8
X509v3 Basic Constraints:
CA:FALSE
X509v3 Key Usage:
Digital Signature, Key Encipherment
Signature Algorithm: sha256WithRSAEncryption
b5:63:0c:d8:ed:af:74:2d:4c:94:36:41:05:2a:f2:ef:45:e5:
6a:0c:76:0c:f3:90:25:e0:54:56:f3:26:23:95:7e:24:74:6b:
fd:02:0a:bc:33:ba:e8:e8:8f:a3:b3:85:2e:59:4c:cf:e3:85:
1a:d6:70:5c:7c:86:e2:7a:11:99:a8:fa:43:9a:bf:50:54:00:
9e:6a:7b:72:7f:c5:20:89:6e:18:6c:46:64:ce:44:44:47:4d:
87:b5:fc:cf:f3:b9:9f:45:a3:cb:b0:91:00:96:2d:29:68:8b:
ff:c7:e0:f1:b7:8d:31:c2:01:be:5b:51:1d:af:42:b1:17:22:
bc:91:e4:d9:b9:96:6d:64:40:79:6c:71:ed:f6:e5:49:16:0a:
e3:bc:18:95:2e:89:ba:c4:a5:ce:ba:ab:3a:32:eb:bc:d8:91:
cd:f2:ee:d1:fc:67:3a:51:00:92:bd:b8:68:0b:54:04:d5:07:
0b:97:11:2c:42:64:7c:47:c1:68:b4:eb:21:c4:e4:ad:17:a7:
16:b9:e0:e6:cd:04:c6:89:36:40:d4:4b:c3:f7:7e:26:6b:3a:
d7:68:b3:b2:da:00:65:13:c8:fa:d0:1c:2e:10:ba:71:3e:0f:
aa:8b:d0:ff:b7:3e:83:9c:bc:b3:d1:52:0c:9f:3f:21:4a:10:
dc:8f:ab:38:45:d4:2c:2a:15:2d:71:45:fe:91:a2:d8:d9:dd:
0c:dc:a7:d9:cd:1b:f5:35:fe:14:ba:c5:1f:ed:ee:fb:87:cc:
87:a1:08:c2:2e:ff:5d:af:b3:3d:6e:11:94:79:0b:28:e6:83:
4e:fc:28:8f:7f:00:85:79:7f:3a:d1:07:ee:6e:fa:94:c4:0b:
4b:2c:05:b1:68:00:e8:37:bc:b8:b2:03:5c:5a:ca:13:f2:68:
57:df:ac:fc:da:be:27:24:7e:6d:c4:a9:53:2d:f2:43:0e:30:
9c:82:d5:fb:f1:a2:0a:83:e0:a5:d8:9f:09:3e:99:c8:39:d6:
69:6d:d6:c2:27:70:59:05:3c:3c:7d:d6:41:6a:b4:9c:1f:70:
7e:3e:ee:6f:67:de:95:1d:eb:31:8b:11:c8:0d:a1:25:4e:08:
ef:3a:11:2d:a7:98:0d:a1:d9:30:2d:da:d2:a0:05:6b:34:38:
a6:87:b2:bd:0f:9c:51:cc:e0:2e:a2:1b:a3:a0:a6:eb:1f:0a:
22:70:59:f0:0b:c9:bd:94:4e:1d:65:3b:99:5d:8e:6c:18:82:
1d:b5:cc:6f:14:21:c4:89:07:9b:81:1d:9a:79:ff:bf:fd:ce:
e4:77:11:0f:47:21:dc:d9:79:f3:40:26:56:5c:b4:86:32:8e:
28:b9:14:e7:b3:fe:86:47

View File

@ -0,0 +1,23 @@
-----BEGIN CERTIFICATE-----
MIIDyTCCArGgAwIBAgIUeoNdEiqhXVkpcYsmHaKiVS5W/tQwDQYJKoZIhvcNAQEL
BQAwPjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMREwDwYDVQQHDAhTYW4gSm9z
ZTEPMA0GA1UECgwGR29vZ2xlMB4XDTIwMDcxNjE2NTMxOVoXDTQwMDcxMTE2NTMx
OVowgZMxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTERMA8GA1UEBwwIU2FuIEpv
c2UxEjAQBgNVBAoMCUVuZCBQb2ludDEOMAwGA1UECwwFSW5mcmExIjAgBgkqhkiG
9w0BCQEWE2NpbmR5eHVlQGdvb2dsZS5jb20xHDAaBgNVBAMME2Zvby5iYXIuc2Vy
dmVyMy5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDcIyJEt3ZA
xPn7H5f/IwXS8NcoAXWP8L6rWndcg+EWayx7W+wmUsFKGSFGzrFPPCFmKO8MrQqp
8LSAxHAVtOC6Uw+INWJJw9BRlx2nvV7hfbqu3OnPkPVkN/siUQCqnEKJQHliNT9X
Dl4/Mav75uQSWb3Vfi3KtG7mzPFNNbbe4yfHyGbC4e9RtKkGimDSJ413s3m4+scD
vtpCcCXj9XXZNdCwD1CL3kNdmOdhgfkDBP+AMLBFKZKqpCo6m0s4JJTiej13dc27
wTrnkFm1CP77SV+kQlWg5DAcVXYJkN9FqNqExqIPS/SxMk7H+3qSQACbttQK9UmC
n3qR3pGbwqzNAgMBAAGjaTBnMB8GA1UdIwQYMBaAFG4bi8k0dOd7jSpPQQ6YUDAU
ARaxMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgTwMCwGA1UdEQQlMCOCCmdvb2dsZS5j
b22CCWFwcGxlLmNvbYIKYW1hem9uLmNvbTANBgkqhkiG9w0BAQsFAAOCAQEAn5aW
HEHNTDmcgC25oEtCj+IkoAslgFze4ZqkSz0HCzx76vj3AfMmIEvqB0W74wKqeZgm
V0D7I0xHkM3ILH4RjoCotpol3nLooIPFflA6Z1ILTRZl8mE5kfBSHzKdPS0egOf6
kgrNYgJjBEtGNsmq8RKxAHVVAPgH88di0JnQDN5LcV9ZBKTQM2R7EM6a8eWD/Jsi
uujbNtdNERssSBV+Oil93MbsEcOT1RSKKxAiVvkHkR+45GRB889xBnqelcDVqcMK
Vcdp6X7aD5/Bu/4fq9AZlcHSEQDixNtjp/pQR0B5FsCGrb5OAz0B2t9jykDiIyj4
4lxhQz8ykXf7ue0/ag==
-----END CERTIFICATE-----

View File

@ -0,0 +1,60 @@
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
7a:83:5d:12:2a:a1:5d:59:29:71:8b:26:1d:a2:a2:55:2e:56:fe:d4
Signature Algorithm: sha256WithRSAEncryption
Issuer: C = US, ST = CA, L = San Jose, O = Google
Validity
Not Before: Jul 16 16:53:19 2020 GMT
Not After : Jul 11 16:53:19 2040 GMT
Subject: C = US, ST = CA, L = San Jose, O = End Point, OU = Infra, emailAddress = cindyxue@google.com, CN = foo.bar.server3.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (2048 bit)
Modulus:
00:dc:23:22:44:b7:76:40:c4:f9:fb:1f:97:ff:23:
05:d2:f0:d7:28:01:75:8f:f0:be:ab:5a:77:5c:83:
e1:16:6b:2c:7b:5b:ec:26:52:c1:4a:19:21:46:ce:
b1:4f:3c:21:66:28:ef:0c:ad:0a:a9:f0:b4:80:c4:
70:15:b4:e0:ba:53:0f:88:35:62:49:c3:d0:51:97:
1d:a7:bd:5e:e1:7d:ba:ae:dc:e9:cf:90:f5:64:37:
fb:22:51:00:aa:9c:42:89:40:79:62:35:3f:57:0e:
5e:3f:31:ab:fb:e6:e4:12:59:bd:d5:7e:2d:ca:b4:
6e:e6:cc:f1:4d:35:b6:de:e3:27:c7:c8:66:c2:e1:
ef:51:b4:a9:06:8a:60:d2:27:8d:77:b3:79:b8:fa:
c7:03:be:da:42:70:25:e3:f5:75:d9:35:d0:b0:0f:
50:8b:de:43:5d:98:e7:61:81:f9:03:04:ff:80:30:
b0:45:29:92:aa:a4:2a:3a:9b:4b:38:24:94:e2:7a:
3d:77:75:cd:bb:c1:3a:e7:90:59:b5:08:fe:fb:49:
5f:a4:42:55:a0:e4:30:1c:55:76:09:90:df:45:a8:
da:84:c6:a2:0f:4b:f4:b1:32:4e:c7:fb:7a:92:40:
00:9b:b6:d4:0a:f5:49:82:9f:7a:91:de:91:9b:c2:
ac:cd
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Authority Key Identifier:
keyid:6E:1B:8B:C9:34:74:E7:7B:8D:2A:4F:41:0E:98:50:30:14:01:16:B1
X509v3 Basic Constraints:
CA:FALSE
X509v3 Key Usage:
Digital Signature, Non Repudiation, Key Encipherment, Data Encipherment
X509v3 Subject Alternative Name:
DNS:google.com, DNS:apple.com, DNS:amazon.com
Signature Algorithm: sha256WithRSAEncryption
9f:96:96:1c:41:cd:4c:39:9c:80:2d:b9:a0:4b:42:8f:e2:24:
a0:0b:25:80:5c:de:e1:9a:a4:4b:3d:07:0b:3c:7b:ea:f8:f7:
01:f3:26:20:4b:ea:07:45:bb:e3:02:aa:79:98:26:57:40:fb:
23:4c:47:90:cd:c8:2c:7e:11:8e:80:a8:b6:9a:25:de:72:e8:
a0:83:c5:7e:50:3a:67:52:0b:4d:16:65:f2:61:39:91:f0:52:
1f:32:9d:3d:2d:1e:80:e7:fa:92:0a:cd:62:02:63:04:4b:46:
36:c9:aa:f1:12:b1:00:75:55:00:f8:07:f3:c7:62:d0:99:d0:
0c:de:4b:71:5f:59:04:a4:d0:33:64:7b:10:ce:9a:f1:e5:83:
fc:9b:22:ba:e8:db:36:d7:4d:11:1b:2c:48:15:7e:3a:29:7d:
dc:c6:ec:11:c3:93:d5:14:8a:2b:10:22:56:f9:07:91:1f:b8:
e4:64:41:f3:cf:71:06:7a:9e:95:c0:d5:a9:c3:0a:55:c7:69:
e9:7e:da:0f:9f:c1:bb:fe:1f:ab:d0:19:95:c1:d2:11:00:e2:
c4:db:63:a7:fa:50:47:40:79:16:c0:86:ad:be:4e:03:3d:01:
da:df:63:ca:40:e2:23:28:f8:e2:5c:61:43:3f:32:91:77:fb:
b9:ed:3f:6a

View File

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDcIyJEt3ZAxPn7
H5f/IwXS8NcoAXWP8L6rWndcg+EWayx7W+wmUsFKGSFGzrFPPCFmKO8MrQqp8LSA
xHAVtOC6Uw+INWJJw9BRlx2nvV7hfbqu3OnPkPVkN/siUQCqnEKJQHliNT9XDl4/
Mav75uQSWb3Vfi3KtG7mzPFNNbbe4yfHyGbC4e9RtKkGimDSJ413s3m4+scDvtpC
cCXj9XXZNdCwD1CL3kNdmOdhgfkDBP+AMLBFKZKqpCo6m0s4JJTiej13dc27wTrn
kFm1CP77SV+kQlWg5DAcVXYJkN9FqNqExqIPS/SxMk7H+3qSQACbttQK9UmCn3qR
3pGbwqzNAgMBAAECggEAU0Te84tKKdnYjUs4HYRL8ay0VienJpl0JjEEMXSZMfe8
TbVJsH1hK/wxgC0zGLuwDoqxUeQqwnmQbZzgoPVYhGJi360BztFI/XPh/c8+EqGS
eg6KSr+UcyJR1ns5e0+8Q1qmD6YAnZeLwu+xFIoT/3T+v8EI5UI3KQqgxAnrcIdc
RWqIwWLkkPm1QVRYsvRaTvmgFd2LcIT9AdIruP/VsqF3GEzvEQSr0lgmwOe0izLb
HKfZr+2JwOppwTLGhKo1wUyUUsglXCBOcFYAA03xdviQWBuCeKXamNrdB7M0T4zZ
THheNRQq2g7bTYnncCYKcrNa5VY5wmHY767mf6ahAQKBgQD+AGk21CsRgiKCGzUI
wTRynutAMkX55U1bud2+OMpzH9omvnccX5ezq5WTw/jZfz+jrUBF8YKSTtb3InUg
yXcpJ/XjRDFMZp1Avy/44rOlYg1QYMD4JK96f8bbd1yej5NVw45V9synaJHuvoDV
bkbZu00S0X8Pgvlh354MUH3CLQKBgQDd3oQdKMZgsX8gtmcQfQoEZ0VvlOYmTM5W
Kw+24iGrBkfBt+NuKx8qm1CpoFGx4G2+TgttMywjF9RG3R2uGqbJZbCOAXzjRMQJ
L9PuTiGAdYD3fA5cTmnrrNEhPydtRhF2M3p8FFeQtwsEBYreXux25rbmVOYTFMgJ
hVUW9RdZIQKBgQDwEYdgMQw70hm3iuuHSMS/iQCkfl+xH08MYRH6FkcSpIpVkDOX
96m0QXpwXQs41pJZqwhSkz9r9WQr1L+Lq58aoRBAK1XE9j+u0IUQ4YQVziTzUV9R
qarJRze2eoxpuR3yM5C2IzuvBqDXW+r8zuvcIrFoFeXXzVzTar1AulsCSQKBgQCa
UD+3QDrp2co/6F26vB0RfvpuZzPEA7undv/RBWrBVvblp46Je3iL28a4lAb+Hsh1
ijasVuEl71b3iqcwBt1mSlIIEsTYFWX7tcZDgxgODqwKdcBPN0K4ZlR2OUSk3g0b
Fybj0gotXwJMY8Z4b7Er6b/gZ8A2GUggRxotg34fwQKBgEh6a88SgTyu1KcR2yzN
Zbs8MEfZ8hqfUj+GL0+6y9KQd4uSIngyHWGNETE9dCObNz5HEdJIpUNvB3vfN0Vk
f1EEPDQLQKJjii7jZ9U9XfPVaUhqIVH3Aupmb30H3AQw7XOF23g63k9Yg1FWtDT6
4CuBsUvjXywL4yHrWK+BuSXF
-----END PRIVATE KEY-----