Skip to content

Commit

Permalink
add SPIFFE ID in the verification func parameters
Browse files Browse the repository at this point in the history
  • Loading branch information
ZhenLian committed Oct 6, 2020
1 parent b2c5f4a commit 06b8ef0
Show file tree
Hide file tree
Showing 8 changed files with 479 additions and 12 deletions.
47 changes: 46 additions & 1 deletion internal/credentials/spiffe.go
Expand Up @@ -25,7 +25,9 @@ package credentials

import (
"crypto/tls"
"crypto/x509"
"net/url"
"fmt"

"google.golang.org/grpc/grpclog"
)
Expand All @@ -35,6 +37,7 @@ var logger = grpclog.Component("credentials")
// SPIFFEIDFromState parses the SPIFFE ID from State. If the SPIFFE ID format
// is invalid, return nil with warning.
func SPIFFEIDFromState(state tls.ConnectionState) *url.URL {
fmt.Println("-------------debugging SPIFFEIDFromState is called------------")
if len(state.PeerCertificates) == 0 || len(state.PeerCertificates[0].URIs) == 0 {
return nil
}
Expand All @@ -44,11 +47,15 @@ func SPIFFEIDFromState(state tls.ConnectionState) *url.URL {
continue
}
// From this point, we assume the uri is intended for a SPIFFE ID.
fmt.Println(uri)
fmt.Println(uri.RawPath)
fmt.Println(uri.Host)
fmt.Println(uri.Path)
if len(uri.String()) > 2048 {
logger.Warning("invalid SPIFFE ID: total ID length larger than 2048 bytes")
return nil
}
if len(uri.Host) == 0 || len(uri.RawPath) == 0 || len(uri.Path) == 0 {
if len(uri.Host) == 0 || len(uri.Path) == 0 {
logger.Warning("invalid SPIFFE ID: domain or workload ID is empty")
return nil
}
Expand All @@ -65,3 +72,41 @@ func SPIFFEIDFromState(state tls.ConnectionState) *url.URL {
}
return spiffeID
}

// SPIFFEIDFromState parses the SPIFFE ID from x509.Certificate. If the SPIFFE
// ID format is invalid, return nil with warning.
func SPIFFEIDFromCert(cert *x509.Certificate) *url.URL {
if cert == nil {
return nil
}
var spiffeID *url.URL
for _, uri := range cert.URIs {
if uri == nil || uri.Scheme != "spiffe" || uri.Opaque != "" || (uri.User != nil && uri.User.Username() != "") {
continue
}
// From this point, we assume the uri is intended for a SPIFFE ID.
//fmt.Println(uri)
//fmt.Println(uri.RawPath)
//fmt.Println(uri.Host)
//fmt.Println(uri.Path)
if len(uri.String()) > 2048 {
logger.Warning("invalid SPIFFE ID: total ID length larger than 2048 bytes")
return nil
}
if len(uri.Host) == 0 || len(uri.Path) == 0 {
logger.Warning("invalid SPIFFE ID: domain or workload ID is empty")
return nil
}
if len(uri.Host) > 255 {
logger.Warning("invalid SPIFFE ID: domain length larger than 255 characters")
return nil
}
// A valid SPIFFE certificate can only have exactly one URI SAN field.
if len(cert.URIs) > 1 {
logger.Warning("invalid SPIFFE ID: multiple URI SANs")
return nil
}
spiffeID = uri
}
return spiffeID
}
8 changes: 7 additions & 1 deletion security/advancedtls/advancedtls.go
Expand Up @@ -27,6 +27,7 @@ import (
"crypto/x509"
"fmt"
"net"
"net/url"
"reflect"
"syscall"
"time"
Expand All @@ -53,6 +54,10 @@ type VerificationFuncParams struct {
// certificate(s) and that verification passed. This field would be nil if
// either user chose not to verify or the verification failed.
Leaf *x509.Certificate
// The connection information stored during the verification.
RawConn net.Conn
// The SPIFFE ID stored in |State|.
SPIFFEID *url.URL
}

// VerificationResults contains the information about results of
Expand Down Expand Up @@ -502,13 +507,14 @@ func buildVerifyFunc(c *advancedTLSCreds,
}
leafCert = certs[0]
}
// Perform custom verification check if specified.
if c.verifyFunc != nil {
_, err := c.verifyFunc(&VerificationFuncParams{
ServerName: serverName,
RawCerts: rawCerts,
VerifiedChains: chains,
Leaf: leafCert,
RawConn: rawConn,
SPIFFEID: credinternal.SPIFFEIDFromCert(leafCert),
})
return err
}
Expand Down
74 changes: 69 additions & 5 deletions security/advancedtls/advancedtls_integration_test.go
Expand Up @@ -80,11 +80,19 @@ type certStore struct {
serverPeer1 tls.Certificate
// serverPeer2 is the certificate sent by server to prove its identity.
// It is trusted by clientTrust2.
serverPeer2 tls.Certificate
clientTrust1 *x509.CertPool
clientTrust2 *x509.CertPool
serverTrust1 *x509.CertPool
serverTrust2 *x509.CertPool
serverPeer2 tls.Certificate
// clientPeerSPIFFE1 is the certificate with the SPIFFE ID
// "spiffe://foo.bar.com/client/workload/1" sent by client to prove identity.
// It is trusted by serverTrust1.
clientPeerSPIFFE1 tls.Certificate
// serverPeerSPIFFE1 is the certificate with the SPIFFE ID
// "spiffe://foo.bar.com/client/workload/1" sent by client to prove identity.
// It is trusted by serverTrust1.
serverPeerSPIFFE1 tls.Certificate
clientTrust1 *x509.CertPool
clientTrust2 *x509.CertPool
serverTrust1 *x509.CertPool
serverTrust2 *x509.CertPool
}

// loadCerts function is used to load test certificates at the beginning of
Expand All @@ -111,6 +119,16 @@ func (cs *certStore) loadCerts() error {
if err != nil {
return err
}
cs.clientPeerSPIFFE1, err = tls.LoadX509KeyPair(testdata.Path("client_cert_spiffe_1.pem"),
testdata.Path("client_key_spiffe_1.pem"))
if err != nil {
return err
}
cs.serverPeerSPIFFE1, err = tls.LoadX509KeyPair(testdata.Path("server_cert_spiffe_1.pem"),
testdata.Path("server_key_spiffe_1.pem"))
if err != nil {
return err
}
cs.clientTrust1, err = readTrustCert(testdata.Path("client_trust_cert_1.pem"))
if err != nil {
return err
Expand Down Expand Up @@ -384,6 +402,52 @@ func (s) TestEnd2End(t *testing.T) {
},
serverVType: CertVerification,
},
// Test if the SPIFFE ID is plumbed to VerificationFuncParams while
// performing the custom authorization.
// At initialization(stage = 0), client will be initialized with cert
// clientPeerSPIFFE1 and clientTrust1, server with serverPeerSPIFFE1 and
// serverTrust1.
// The mutual authentication works at the beginning, since clientPeerSPIFFE1
// trusted by serverTrust1, serverPeerSPIFFE1 trusted by clientTrust1.
// Besides, the client custom verification check allows the SPIFFE
// ID shown on serverPeerSPIFFE1, and server verification allows SPIFFE ID
// on clientPeerSPIFFE1.
// At stage 1, server disallows the the connections by setting custom
// verification check. The following calls should fail. Previous
// connections should not be affected.
// At stage 2, server allows the SPIFFE ID shown on the clientPeerSPIFFE1.
// Authentications should go back to normal.
{
desc: "TestSPIFFEIDIsPlumbed",
clientCert: []tls.Certificate{cs.clientPeerSPIFFE1},
clientRoot: cs.clientTrust1,
clientVerifyFunc: func(params *VerificationFuncParams) (*VerificationResults, error) {
if params.SPIFFEID == nil || params.SPIFFEID.Scheme != "spiffe" ||
params.SPIFFEID.Host != "foo.bar.com" || params.SPIFFEID.Path != "/server/workload/1" {
return nil, fmt.Errorf("custom authz check fails")
}
return &VerificationResults{}, nil

},
clientVType: CertVerification,
serverCert: []tls.Certificate{cs.serverPeerSPIFFE1},
serverRoot: cs.serverTrust1,
serverVerifyFunc: func(params *VerificationFuncParams) (*VerificationResults, error) {
switch stage.read() {
case 0, 2:
if params.SPIFFEID == nil || params.SPIFFEID.Scheme != "spiffe" ||
params.SPIFFEID.Host != "foo.bar.com" || params.SPIFFEID.Path != "/client/workload/1" {
return nil, fmt.Errorf("custom authz check fails")
}
return &VerificationResults{}, nil
case 1:
return nil, fmt.Errorf("custom authz check fails")
default:
return nil, fmt.Errorf("custom authz check fails")
}
},
serverVType: CertVerification,
},
} {
test := test
t.Run(test.desc, func(t *testing.T) {
Expand Down
10 changes: 5 additions & 5 deletions security/advancedtls/testdata/README.md
Expand Up @@ -14,16 +14,16 @@ commands we run:
$ openssl req -x509 -newkey rsa:4096 -keyout ca_key.pem -out ca_cert.pem -nodes -days $DURATION_DAYS
```

2. Generate a CSR `csr.pem` using `subject_key.pem`:

2. Generate a private key `subject_key.pem` for the subject:
```
$ openssl req -new -key subject_key.pem -out csr.pem
$ openssl genrsa -out subject_key.pem 4096
```

3. Generate a private key `subject_key.pem` for the subject:
3. Generate a CSR `csr.pem` using `subject_key.pem`:

```
$ openssl genrsa -out subject_key.pem 4096
$ openssl req -new -key subject_key.pem -out csr.pem
```

4. Use `ca_key.pem` and `ca_cert.pem` to sign `csr.pem`, and get a certificate, `subject_cert.pem`, for the subject:
Expand Down
125 changes: 125 additions & 0 deletions security/advancedtls/testdata/client_cert_spiffe_1.pem
@@ -0,0 +1,125 @@
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 2 (0x2)
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=US, ST=VA, O=Internet Widgits Pty Ltd, CN=foo.bar.hoo.ca.com
Validity
Not Before: Oct 5 20:11:06 2020 GMT
Not After : May 27 20:11:06 2045 GMT
Subject: C=US, ST=CA, L=Sunnyvale, O=XX, OU=XXX, CN=foo.bar.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (4096 bit)
Modulus:
00:bb:ee:3e:6d:79:0b:3c:33:b5:cb:ef:56:f7:a4:
15:42:d4:94:05:c8:59:37:d1:d8:7c:44:40:dd:cd:
9f:64:e1:c6:6d:c8:8d:a1:3a:85:df:34:3e:5b:23:
1d:16:d1:c3:67:94:c9:35:21:cd:8f:80:46:a6:a2:
78:c1:f6:c7:45:c3:f2:0a:9d:ad:2c:64:72:f6:5b:
7b:79:dd:33:d7:5c:c0:9f:97:9e:45:8e:c9:30:33:
6d:0e:24:b4:62:85:ab:ce:43:b3:25:98:31:39:f4:
d2:fe:ce:10:bf:53:e7:92:a5:b7:8d:a4:5b:e3:37:
ec:c5:06:8e:94:ee:10:d0:6e:dc:6b:90:08:c9:06:
6d:01:79:ba:94:df:0b:20:3d:ae:a2:cc:7f:30:53:
07:cb:8a:ca:77:80:d5:94:12:1a:2a:36:b3:f3:5e:
d7:51:02:00:2a:1e:f1:bd:89:0b:37:4f:dc:58:af:
0f:74:14:01:21:20:8e:69:b6:e9:0d:da:52:21:ea:
71:2b:64:69:a9:c9:fb:f8:7e:55:d7:8f:a0:c7:98:
cb:a7:e5:16:44:2f:39:d2:9b:ad:e7:4a:de:f8:3b:
1b:65:a0:c9:50:ce:0a:6c:32:29:38:78:4a:f5:11:
28:53:a9:c6:c1:85:2b:10:09:79:5a:54:9c:9f:1b:
b7:f7:16:66:3e:be:cb:2f:3b:e6:27:3e:d2:d1:c6:
f5:2b:d7:46:e7:22:6a:42:17:0c:cc:46:1d:12:e0:
81:f8:6d:cc:58:2c:1c:0a:21:8d:0d:af:d5:a9:31:
35:1f:99:14:3b:2c:32:c2:b2:8b:9d:39:cd:ee:40:
22:7b:4e:a8:4a:f1:15:b2:51:4d:82:3c:0e:35:e7:
d1:79:d7:b9:0e:f9:9d:ba:d0:bf:17:fb:e2:df:55:
ac:f8:8e:e5:dc:f2:dc:50:1b:cc:a5:a2:2a:84:8a:
75:16:a8:95:b2:6c:bc:21:d9:89:6f:c9:83:6d:f8:
0f:26:26:de:f1:1a:ad:4e:8b:54:dd:43:e9:ef:04:
92:71:75:bb:7f:3c:82:e9:1f:4e:c2:04:73:fd:c1:
73:df:0a:ae:2d:c5:9a:5d:08:cf:28:ea:2e:1f:ee:
d7:8e:21:01:55:a1:8e:90:79:43:86:ac:6f:ec:58:
ca:e5:04:b2:a0:75:35:89:0e:09:d0:7c:03:b3:25:
e1:ff:42:ec:8e:b7:43:1f:9e:b3:71:51:a7:b5:42:
c8:27:f1:6d:9f:ae:4e:2c:d2:8b:0c:f9:90:7a:5c:
93:ed:4a:8d:14:06:06:36:f0:a5:1b:6c:8e:85:46:
9b:14:3f:b7:23:69:a1:d2:48:32:27:67:20:49:c8:
ce:a6:c1
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
FD:25:82:CC:12:B6:0D:19:F6:94:A5:00:A7:E2:20:A0:C8:1B:05:FA
X509v3 Authority Key Identifier:
keyid:B4:19:08:1C:FC:10:23:C5:30:86:22:BC:CB:B1:5F:AD:EA:7A:5D:F1

X509v3 Basic Constraints:
CA:FALSE
X509v3 Key Usage:
Digital Signature, Key Encipherment
X509v3 Subject Alternative Name:
URI:spiffe://foo.bar.com/client/workload/1
Signature Algorithm: sha256WithRSAEncryption
4f:21:c8:46:e0:f7:04:a0:98:a5:02:b9:c1:6b:9b:29:26:26:
9e:29:c1:42:8f:5c:71:4a:cc:5c:ff:d0:0c:02:6e:13:9f:89:
8e:24:f9:92:6c:4f:97:25:fd:d3:03:6f:aa:8d:69:fa:b0:df:
84:da:f6:47:af:3f:f3:17:5a:96:08:20:2d:df:78:a7:99:4f:
5a:9b:5c:06:7c:e9:89:f0:04:47:75:b0:da:20:d2:3f:88:9e:
a2:79:59:23:54:8e:13:05:be:26:d4:b6:e2:70:78:3f:41:56:
53:dc:ff:b7:22:04:12:38:75:c2:ec:da:b6:b3:3e:d0:1f:bc:
80:78:b8:b4:4d:de:b8:34:b3:a9:30:9b:1d:af:2a:53:df:2c:
7d:fe:c8:4c:93:a6:ad:3f:1b:73:31:56:4d:3b:3c:4f:b3:be:
40:78:08:b7:65:fd:08:37:62:6e:bb:bc:22:7e:dd:d5:3a:ad:
07:e1:31:24:c0:20:bf:0c:cc:85:60:b5:2c:34:e1:5f:f4:26:
f4:b2:8d:76:ae:de:0c:ca:17:2d:cb:ec:1d:66:b4:9b:9f:0b:
2e:1a:64:ea:fa:52:4b:bb:bd:33:73:8d:bc:9f:8b:a6:24:ea:
12:62:6b:60:23:f3:cb:e8:b9:f2:b3:ca:d2:0b:ea:76:3f:4c:
cf:cc:eb:4f:0e:5a:a6:66:96:7f:46:6f:15:e4:28:a3:dd:ea:
93:24:c3:b3:99:3f:bc:b7:71:dc:24:28:5c:4c:21:b3:ca:6a:
67:b0:a8:f4:00:c5:75:5e:6e:65:07:95:39:c2:2c:a6:bd:dc:
78:61:19:29:9d:dd:1e:54:5e:3e:6f:fb:79:37:ff:06:8c:f5:
50:cc:f2:4a:3b:03:e3:6e:7c:65:ad:c3:80:0e:79:d3:28:fd:
bf:4b:6a:b6:56:a6:2f:d0:a0:19:96:85:7e:69:46:b1:8c:4c:
c3:eb:43:86:15:06:e9:9e:90:d4:3d:85:28:3a:cf:6f:c4:e7:
d7:7d:61:29:ae:7a:99:2a:c7:26:48:84:01:43:98:97:b4:69:
5a:47:eb:f5:33:bb:f8:a5:8d:6f:56:9e:01:58:f7:0d:8c:1b:
e3:8b:a9:e2:58:20:bf:27:f2:7b:7d:e4:a5:35:61:8e:12:57:
4e:b7:31:09:73:13:0b:f9:b7:26:f9:d5:bb:c5:5d:f3:e4:d5:
b6:17:14:e5:99:39:36:e8:a9:a8:88:ca:da:79:45:cd:c8:66:
5e:ad:78:b2:52:52:fb:06:b7:a3:4d:50:16:7e:af:d8:0e:6f:
8f:48:40:57:97:6e:c3:19:cf:fb:bc:e4:3f:33:61:80:af:15:
1b:d7:b3:20:3f:ed:ff:7d
-----BEGIN CERTIFICATE-----
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
-----END CERTIFICATE-----

0 comments on commit 06b8ef0

Please sign in to comment.