Skip to content

Commit 2f02dc3

Browse files
committed
[FAB-3677] Identity validation
This change-set addressed FAB-3677 in the following way: At MSP setup time, a certification tree T is constructed based on the root CA and Intermediate CA certificates (after their sanitization). The MSP instance then stores the number of children each node in T has. An identity is valid only if its corresponding certificates had been signed by a leaf of T. Specific tests haves been added. Change-Id: Ie7d07c2faadc76890eec151267172ed92db0af34 Signed-off-by: Angelo De Caro <[email protected]>
1 parent b2cce35 commit 2f02dc3

File tree

8 files changed

+145
-8
lines changed

8 files changed

+145
-8
lines changed

msp/mspimpl.go

+41-8
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@ type bccspmsp struct {
4444
// list of intermediate certs we trust
4545
intermediateCerts []Identity
4646

47+
// certificationTreeInternalNodesMap whose keys correspond to the raw material
48+
// (DER representation) of a certificate casted to a string, and whose values
49+
// are boolean. True means that the certificate is an internal node of the certification tree.
50+
// False means that the certificate corresponds to a leaf of the certification tree.
51+
certificationTreeInternalNodesMap map[string]bool
52+
4753
// list of signing identities
4854
signer SigningIdentity
4955

@@ -311,26 +317,24 @@ func (msp *bccspmsp) Setup(conf1 *m.MSPConfig) error {
311317
return errors.New("Expected at least one CA certificate")
312318
}
313319

314-
// pre-create the verify options with roots and intermediates
315-
// this is needed to make certificate sanitation working.
316-
msp.opts = &x509.VerifyOptions{
317-
Roots: x509.NewCertPool(),
318-
Intermediates: x509.NewCertPool(),
319-
}
320+
// pre-create the verify options with roots and intermediates.
321+
// This is needed to make certificate sanitation working.
322+
// Recall that sanitization is applied also to root CA and intermediate
323+
// CA certificates. After their sanitization is done, the opts
324+
// will be recreated using the sanitized certs.
325+
msp.opts = &x509.VerifyOptions{Roots: x509.NewCertPool(), Intermediates: x509.NewCertPool()}
320326
for _, v := range conf.RootCerts {
321327
cert, err := msp.getCertFromPem(v)
322328
if err != nil {
323329
return err
324330
}
325-
326331
msp.opts.Roots.AddCert(cert)
327332
}
328333
for _, v := range conf.IntermediateCerts {
329334
cert, err := msp.getCertFromPem(v)
330335
if err != nil {
331336
return err
332337
}
333-
334338
msp.opts.Intermediates.AddCert(cert)
335339
}
336340

@@ -357,6 +361,15 @@ func (msp *bccspmsp) Setup(conf1 *m.MSPConfig) error {
357361
msp.intermediateCerts[i] = id
358362
}
359363

364+
// root CA and intermediate CA certificates are sanitized, they can be reimported
365+
msp.opts = &x509.VerifyOptions{Roots: x509.NewCertPool(), Intermediates: x509.NewCertPool()}
366+
for _, id := range msp.rootCerts {
367+
msp.opts.Roots.AddCert(id.(*identity).cert)
368+
}
369+
for _, id := range msp.intermediateCerts {
370+
msp.opts.Intermediates.AddCert(id.(*identity).cert)
371+
}
372+
360373
// make and fill the set of admin certs (if present)
361374
msp.admins = make([]Identity, len(conf.Admins))
362375
for i, admCert := range conf.Admins {
@@ -395,6 +408,21 @@ func (msp *bccspmsp) Setup(conf1 *m.MSPConfig) error {
395408
}
396409
}
397410

411+
// populate certificationTreeInternalNodesMap to mark the internal nodes of the
412+
// certification tree
413+
msp.certificationTreeInternalNodesMap = make(map[string]bool)
414+
for _, cert := range append([]Identity{}, msp.intermediateCerts...) {
415+
chain, err := msp.getUniqueValidationChain(cert.(*identity).cert)
416+
if err != nil {
417+
return fmt.Errorf("Failed getting validation chain, (SN: %s)", cert.(*identity).cert.SerialNumber)
418+
}
419+
420+
// Recall chain[0] is cert.(*identity).cert so it does not count as a parent
421+
for i := 1; i < len(chain); i++ {
422+
msp.certificationTreeInternalNodesMap[string(chain[i].Raw)] = true
423+
}
424+
}
425+
398426
// setup the signer (if present)
399427
if conf.SigningIdentity != nil {
400428
sid, err := msp.getSigningIdentityFromConf(conf.SigningIdentity)
@@ -683,6 +711,11 @@ func (msp *bccspmsp) getValidationChain(cert *x509.Certificate) ([]*x509.Certifi
683711
return nil, fmt.Errorf("Expected a chain of length at least 2, got %d", len(validationChain))
684712
}
685713

714+
// check that the parent is a leaf of the certification tree
715+
if msp.certificationTreeInternalNodesMap[string(validationChain[1].Raw)] {
716+
return nil, fmt.Errorf("Invalid validation chain. Parent certificate should be a leaf of the certification tree [%v].", cert.Raw)
717+
}
718+
686719
return validationChain, nil
687720
}
688721

msp/mspwithintermediatecas_test.go

+28
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package msp
1818

1919
import (
20+
"path/filepath"
2021
"testing"
2122

2223
"github.com/stretchr/testify/assert"
@@ -63,3 +64,30 @@ func TestIntermediateCAIdentityValidity(t *testing.T) {
6364
id := thisMSP.(*bccspmsp).intermediateCerts[0]
6465
assert.Error(t, id.Validate())
6566
}
67+
68+
func TestMSPWithIntermediateCAs2(t *testing.T) {
69+
// testdata/intermediate2 contains the credentials for a test MSP setup that has
70+
// 1) a key and a signcert (used to populate the default signing identity);
71+
// signcert is not signed by a CA directly but by an intermediate CA
72+
// 2) intermediatecert is an intermediate CA, signed by the CA
73+
// 3) cacert is the CA that signed the intermediate
74+
// 4) user2-cert is the certificate of an identity signed directly by the CA
75+
// therefore validation should fail.
76+
thisMSP := getLocalMSP(t, filepath.Join("testdata", "intermediate2"))
77+
78+
// the default signing identity is signed by the intermediate CA,
79+
// the validation should return no error
80+
id, err := thisMSP.GetDefaultSigningIdentity()
81+
assert.NoError(t, err)
82+
err = thisMSP.Validate(id.GetPublicVersion())
83+
assert.NoError(t, err)
84+
85+
// user2-cert has been signed by the root CA, validation must fail
86+
pem, err := readPemFile(filepath.Join("testdata", "intermediate2", "users", "user2-cert.pem"))
87+
assert.NoError(t, err)
88+
id2, _, err := thisMSP.(*bccspmsp).getIdentityFromConf(pem)
89+
assert.NoError(t, err)
90+
err = thisMSP.Validate(id2)
91+
assert.Error(t, err)
92+
assert.Contains(t, err.Error(), "Invalid validation chain. Parent certificate should be a leaf of the certification tree ")
93+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIICLzCCAdagAwIBAgIQLcb0TM7r3ga3Z+o4nBRSFjAKBggqhkjOPQQDAjBJMQsw
3+
CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy
4+
YW5jaXNjbzENMAsGA1UEAxMEaWNhMTAeFw0xNzA1MTAxNjIxNDhaFw0yNzA1MDgx
5+
NjIxNDhaMEoxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYD
6+
VQQHEw1TYW4gRnJhbmNpc2NvMQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEG
7+
CCqGSM49AwEHA0IABPdaoTrPLuSB0Ns3gRy/7UhMSMWc6knnaiLmWsF9eEW34XXa
8+
oupK5izQSokvRW9u0pkyR1cCSBAHbqJ8AC+q1OejgZ4wgZswDgYDVR0PAQH/BAQD
9+
AgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwZgYDVR0jBF8w
10+
XYBbMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEB2id4RLBxhAE+TrhgE/cd/yk
11+
5fe8TKgeJUKHDoKbcRUeYSz1lR1uYR2+ucGvRPP1qmYOKA0HdPKbVLBE0fAhOTAK
12+
BggqhkjOPQQDAgNHADBEAiAdeTm6jnLCVEKfNCnrYcOLkB2lUFaNr8hLtQXCOlnD
13+
swIgMdTefeOqQvpKY1VrCR3VUE3zOMKF5k2kruyr7gGdU3E=
14+
-----END CERTIFICATE-----
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIICEDCCAbegAwIBAgIQKy5yRZcslB/rn4imlQYAkzAKBggqhkjOPQQDAjBVMQsw
3+
CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy
4+
YW5jaXNjbzEMMAoGA1UEChMDb3JnMQswCQYDVQQDEwJjYTAeFw0xNzA1MTAxNjIx
5+
NDhaFw0yNzA1MDgxNjIxNDhaMFUxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxp
6+
Zm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMQwwCgYDVQQKEwNvcmcxCzAJ
7+
BgNVBAMTAmNhMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEdYa6mGu7DbwLl9ax
8+
kfDWe5irUfO/NF/ISxBBZuN2QaxV0IWsL66Bbr1hGWDbrQjrsrfWHO/73d1xrlbT
9+
wmcOQ6NpMGcwDgYDVR0PAQH/BAQDAgGmMBkGA1UdJQQSMBAGBFUdJQAGCCsGAQUF
10+
BwMBMA8GA1UdEwEB/wQFMAMBAf8wKQYDVR0OBCIEIF7PPyL7Fc9WILdySDYZIJ+u
11+
JR7wDRyZN5OKrEQVECAHMAoGCCqGSM49BAMCA0cAMEQCIGKJRDsVIHMioqTUevBp
12+
dRnXZnKUFiPJb2t00NGh6oKuAiAs5vlQ+6izRviSO7ujTNdsqjfs5WlCcesy5reV
13+
8F7esg==
14+
-----END CERTIFICATE-----
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIICbzCCAhWgAwIBAgIQKA9DhIj8YDJpbP7wFsmuSDAKBggqhkjOPQQDAjBVMQsw
3+
CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy
4+
YW5jaXNjbzEMMAoGA1UEChMDb3JnMQswCQYDVQQDEwJjYTAeFw0xNzA1MTAxNjIx
5+
NDhaFw0yNzA1MDgxNjIxNDhaMEkxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxp
6+
Zm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMQ0wCwYDVQQDEwRpY2ExMFkw
7+
EwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEB2id4RLBxhAE+TrhgE/cd/yk5fe8TKge
8+
JUKHDoKbcRUeYSz1lR1uYR2+ucGvRPP1qmYOKA0HdPKbVLBE0fAhOaOB0jCBzzAO
9+
BgNVHQ8BAf8EBAMCAaYwGQYDVR0lBBIwEAYEVR0lAAYIKwYBBQUHAwEwDwYDVR0T
10+
AQH/BAUwAwEB/zBkBgNVHQ4EXQRbMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE
11+
B2id4RLBxhAE+TrhgE/cd/yk5fe8TKgeJUKHDoKbcRUeYSz1lR1uYR2+ucGvRPP1
12+
qmYOKA0HdPKbVLBE0fAhOTArBgNVHSMEJDAigCBezz8i+xXPViC3ckg2GSCfriUe
13+
8A0cmTeTiqxEFRAgBzAKBggqhkjOPQQDAgNIADBFAiEAjt/IU7E9fBIXG8WzKxIz
14+
Jmbfjm/qCOmLvt53HPa/B0ICIB2q1TE21KK68fxO6C92AhNuTmGHmumLB8yTBG7j
15+
QsQL
16+
-----END CERTIFICATE-----
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
-----BEGIN PRIVATE KEY-----
2+
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgTNlF7jY6jBKQGLqs
3+
AgllL7utSIRxZdxy4fexQaNX7JKhRANCAAT3WqE6zy7kgdDbN4Ecv+1ITEjFnOpJ
4+
52oi5lrBfXhFt+F12qLqSuYs0EqJL0VvbtKZMkdXAkgQB26ifAAvqtTn
5+
-----END PRIVATE KEY-----
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIICLzCCAdagAwIBAgIQLcb0TM7r3ga3Z+o4nBRSFjAKBggqhkjOPQQDAjBJMQsw
3+
CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy
4+
YW5jaXNjbzENMAsGA1UEAxMEaWNhMTAeFw0xNzA1MTAxNjIxNDhaFw0yNzA1MDgx
5+
NjIxNDhaMEoxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYD
6+
VQQHEw1TYW4gRnJhbmNpc2NvMQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEG
7+
CCqGSM49AwEHA0IABPdaoTrPLuSB0Ns3gRy/7UhMSMWc6knnaiLmWsF9eEW34XXa
8+
oupK5izQSokvRW9u0pkyR1cCSBAHbqJ8AC+q1OejgZ4wgZswDgYDVR0PAQH/BAQD
9+
AgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwZgYDVR0jBF8w
10+
XYBbMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEB2id4RLBxhAE+TrhgE/cd/yk
11+
5fe8TKgeJUKHDoKbcRUeYSz1lR1uYR2+ucGvRPP1qmYOKA0HdPKbVLBE0fAhOTAK
12+
BggqhkjOPQQDAgNHADBEAiAdeTm6jnLCVEKfNCnrYcOLkB2lUFaNr8hLtQXCOlnD
13+
swIgMdTefeOqQvpKY1VrCR3VUE3zOMKF5k2kruyr7gGdU3E=
14+
-----END CERTIFICATE-----
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIB/zCCAaagAwIBAgIRAO7SLOYTMXE76j8HsQvesuswCgYIKoZIzj0EAwIwVTEL
3+
MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG
4+
cmFuY2lzY28xDDAKBgNVBAoTA29yZzELMAkGA1UEAxMCY2EwHhcNMTcwNTEwMTYy
5+
MTQ4WhcNMjcwNTA4MTYyMTQ4WjBKMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2Fs
6+
aWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEOMAwGA1UEAxMFdXNlcjIw
7+
WTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAT+6mBEtOvply3HopfMlDN1CrpY3lNj
8+
A/Kfyh+5HUhcFY+shi7NP1qCAvQ3rId57Zm2ii7GhQip6g9pJzbHoRWbo2IwYDAO
9+
BgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIw
10+
ADArBgNVHSMEJDAigCBezz8i+xXPViC3ckg2GSCfriUe8A0cmTeTiqxEFRAgBzAK
11+
BggqhkjOPQQDAgNHADBEAiApy6JAi5mEkaRknmvuRFQykqsJ1WJ3YxhEP2GrX95x
12+
9gIgH5lA0xykOrvVyARyCO1u+6NebJsv2aUMdXJ7eJMjREE=
13+
-----END CERTIFICATE-----

0 commit comments

Comments
 (0)