Skip to content

Commit 589efc6

Browse files
committed
[FAB-1558] - Revocation support in MSP
This change-set verifies the signature over the CRL upon every certificate validation. The way the code previously handled validation was not secure for the following unlikely (but not impossible) reason: a malicious CA sets its SKI to match that of another CA under the same MSP. Under this scenario (and with the previous code), the malicious CA may revoke another CA's certificates. This is true because the code previously established the link between CA and CRL at setup time (by verifying the CA's certificate) and between CA and CRL at validation time (but, crucially, only by matching SKI and AKI). A possible optimization would be to pre-verify signatures of CAs over CRLs and to keep a mapping of verified pairs. However, it's important that the lookup key of this mapping is not SKI (as it was before). Change-Id: I25a5a92b319c6565a092d5de7fc96a0548d1a37d Signed-off-by: Alessandro Sorniotti <[email protected]>
1 parent 0a6570f commit 589efc6

File tree

1 file changed

+18
-34
lines changed

1 file changed

+18
-34
lines changed

msp/mspimpl.go

+18-34
Original file line numberDiff line numberDiff line change
@@ -314,45 +314,15 @@ func (msp *bccspmsp) Setup(conf1 *m.MSPConfig) error {
314314
// setup the CRL (if present)
315315
msp.CRL = make([]*pkix.CertificateList, len(conf.RevocationList))
316316
for i, crlbytes := range conf.RevocationList {
317-
valid := false
318-
319-
// at first we parse it
320317
crl, err := x509.ParseCRL(crlbytes)
321318
if err != nil {
322319
return fmt.Errorf("Could not parse RevocationList, err %s", err)
323320
}
324321

325-
// we extract the AKI - this is needed so that we know which CA should have signed us
326-
aki, err := getAuthorityKeyIdentifierFromCrl(crl)
327-
if err != nil {
328-
return fmt.Errorf("Could not get AuthorityKeyIdentifier from RevocationList, err %s", err)
329-
}
330-
331-
// now check the signature over the CRL - it has to be signed
332-
// by one of our CAs (either root or intermediate)
333-
for _, ca := range append(append([]Identity{}, msp.rootCerts...), msp.intermediateCerts...) {
334-
// get the SKI for the CA
335-
ski, err := getSubjectKeyIdentifierFromCert(ca.(*identity).cert)
336-
if err != nil {
337-
return fmt.Errorf("Could not get SubjectKeyIdentifier from CA cert, err %s", err)
338-
}
339-
340-
// this is the CA that should have signed
341-
// this CRL, check its signature over it
342-
if bytes.Equal(aki, ski) {
343-
err := ca.(*identity).cert.CheckCRLSignature(crl)
344-
if err != nil {
345-
return fmt.Errorf("Invalid signature on the CRL, err %s", err)
346-
}
347-
valid = true
348-
break
349-
}
350-
}
351-
352-
// valid may not be set in case none of the CAs signed the CRL
353-
if !valid {
354-
return errors.New("Could not verify signature over the CRL")
355-
}
322+
// TODO: pre-verify the signature on the CRL and create a map
323+
// of CA certs to respective CRLs so that later upon
324+
// validation we can already look up the CRL given the
325+
// chain of the certificate to be validated
356326

357327
msp.CRL[i] = crl
358328
}
@@ -462,6 +432,20 @@ func (msp *bccspmsp) Validate(id Identity) error {
462432
// we have a CRL, check whether the serial number is revoked
463433
for _, rc := range crl.TBSCertList.RevokedCertificates {
464434
if rc.SerialNumber.Cmp(id.cert.SerialNumber) == 0 {
435+
// We have found a CRL whose AKI matches the SKI of
436+
// the CA (root or intermediate) that signed the
437+
// certificate that is under validation. As a
438+
// precaution, we verify that said CA is also the
439+
// signer of this CRL.
440+
err = validationChain[0][1].CheckCRLSignature(crl)
441+
if err != nil {
442+
// the CA cert that signed the certificate
443+
// that is under validation did not sign the
444+
// candidate CRL - skip
445+
mspLogger.Warningf("Invalid signature over the identified CRL, error %s", err)
446+
continue
447+
}
448+
465449
// A CRL also includes a time of revocation so that
466450
// the CA can say "this cert is to be revoked starting
467451
// from this time"; however here we just assume that

0 commit comments

Comments
 (0)