Skip to content

Commit c971c77

Browse files
committed
[FAB-1558] - Revocation support in MSP
This change-set adds revocation support for the default MSP. Revocation is implemented by supplying zero or more 'complete CRLs' (as described in rfc 5280) in the RevocationList field of the FabricMSPConfig struct. The CRL can only apply to certificates and not to CAs or intermediate CAs. If a CA or an intermediate CA is to be revoked, it can just be removed from the respective fields in the config. Change-Id: I7a4d290aed264952b329fc981c17f87b94b10899 Signed-off-by: Alessandro Sorniotti <[email protected]>
1 parent a5714ce commit c971c77

File tree

2 files changed

+311
-24
lines changed

2 files changed

+311
-24
lines changed

msp/mspimpl.go

+203-24
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,11 @@ import (
2424

2525
"bytes"
2626

27+
"crypto/x509/pkix"
28+
"encoding/asn1"
2729
"errors"
30+
"math/big"
31+
"reflect"
2832

2933
"github.com/golang/protobuf/proto"
3034
"github.com/hyperledger/fabric/bccsp"
@@ -57,6 +61,9 @@ type bccspmsp struct {
5761

5862
// verification options for MSP members
5963
opts *x509.VerifyOptions
64+
65+
// list of certificate revocation lists
66+
CRL []*pkix.CertificateList
6067
}
6168

6269
// NewBccspMsp returns an MSP instance backed up by a BCCSP
@@ -140,6 +147,86 @@ func (msp *bccspmsp) getSigningIdentityFromConf(sidInfo *m.SigningIdentityInfo)
140147
idPub.(*identity).cert, idPub.(*identity).pk, peerSigner, msp), nil
141148
}
142149

150+
/*
151+
This is the definition of the ASN.1 marshalling of AuthorityKeyIdentifier
152+
from https://www.ietf.org/rfc/rfc5280.txt
153+
154+
AuthorityKeyIdentifier ::= SEQUENCE {
155+
keyIdentifier [0] KeyIdentifier OPTIONAL,
156+
authorityCertIssuer [1] GeneralNames OPTIONAL,
157+
authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL }
158+
159+
KeyIdentifier ::= OCTET STRING
160+
161+
CertificateSerialNumber ::= INTEGER
162+
163+
*/
164+
165+
type authorityKeyIdentifier struct {
166+
KeyIdentifier []byte `asn1:"optional,tag:0"`
167+
AuthorityCertIssuer []byte `asn1:"optional,tag:1"`
168+
AuthorityCertSerialNumber big.Int `asn1:"optional,tag:2"`
169+
}
170+
171+
// getAuthorityKeyIdentifierFromCrl returns the Authority Key Identifier
172+
// for the supplied CRL. The authority key identifier can be used to identify
173+
// the public key corresponding to the private key which was used to sign the CRL.
174+
func getAuthorityKeyIdentifierFromCrl(crl *pkix.CertificateList) ([]byte, error) {
175+
aki := authorityKeyIdentifier{}
176+
177+
for _, ext := range crl.TBSCertList.Extensions {
178+
// Authority Key Identifier is identified by the following ASN.1 tag
179+
// authorityKeyIdentifier (2 5 29 35) (see https://tools.ietf.org/html/rfc3280.html)
180+
if reflect.DeepEqual(ext.Id, asn1.ObjectIdentifier{2, 5, 29, 35}) {
181+
_, err := asn1.Unmarshal(ext.Value, &aki)
182+
if err != nil {
183+
return nil, fmt.Errorf("Failed to unmarshal AKI, error %s", err)
184+
}
185+
186+
return aki.KeyIdentifier, nil
187+
}
188+
}
189+
190+
return nil, errors.New("authorityKeyIdentifier not found in certificate")
191+
}
192+
193+
// getSubjectKeyIdentifierFromCert returns the Subject Key Identifier for the supplied certificate
194+
// Subject Key Identifier is an identifier of the public key of this certificate
195+
func getSubjectKeyIdentifierFromCert(cert *x509.Certificate) ([]byte, error) {
196+
var SKI []byte
197+
198+
for _, ext := range cert.Extensions {
199+
// Subject Key Identifier is identified by the following ASN.1 tag
200+
// subjectKeyIdentifier (2 5 29 14) (see https://tools.ietf.org/html/rfc3280.html)
201+
if reflect.DeepEqual(ext.Id, asn1.ObjectIdentifier{2, 5, 29, 14}) {
202+
_, err := asn1.Unmarshal(ext.Value, &SKI)
203+
if err != nil {
204+
return nil, fmt.Errorf("Failed to unmarshal Subject Key Identifier, err %s", err)
205+
}
206+
207+
return SKI, nil
208+
}
209+
}
210+
211+
return nil, errors.New("subjectKeyIdentifier not found in certificate")
212+
}
213+
214+
// isCAProperlyFormed does a few checks on the certificate,
215+
// assuming it's a CA; it returns true if all looks good
216+
// and false otherwise
217+
func isCAProperlyFormed(cert *x509.Certificate) bool {
218+
_, err := getSubjectKeyIdentifierFromCert(cert)
219+
if err != nil {
220+
return false
221+
}
222+
223+
if !cert.IsCA {
224+
return false
225+
}
226+
227+
return true
228+
}
229+
143230
// Setup sets up the internal data structures
144231
// for this MSP, given an MSPConfig ref; it
145232
// returns nil in case of success or an error otherwise
@@ -160,16 +247,14 @@ func (msp *bccspmsp) Setup(conf1 *m.MSPConfig) error {
160247
mspLogger.Debugf("Setting up MSP instance %s", msp.name)
161248

162249
// make and fill the set of admin certs (if present)
163-
if conf.Admins != nil {
164-
msp.admins = make([]Identity, len(conf.Admins))
165-
for i, admCert := range conf.Admins {
166-
id, err := msp.getIdentityFromConf(admCert)
167-
if err != nil {
168-
return err
169-
}
170-
171-
msp.admins[i] = id
250+
msp.admins = make([]Identity, len(conf.Admins))
251+
for i, admCert := range conf.Admins {
252+
id, err := msp.getIdentityFromConf(admCert)
253+
if err != nil {
254+
return err
172255
}
256+
257+
msp.admins[i] = id
173258
}
174259

175260
// make and fill the set of CA certs - we expect them to be there
@@ -187,18 +272,21 @@ func (msp *bccspmsp) Setup(conf1 *m.MSPConfig) error {
187272
}
188273

189274
// make and fill the set of intermediate certs (if present)
190-
if conf.IntermediateCerts != nil {
191-
msp.intermediateCerts = make([]Identity, len(conf.IntermediateCerts))
192-
for i, trustedCert := range conf.IntermediateCerts {
193-
id, err := msp.getIdentityFromConf(trustedCert)
194-
if err != nil {
195-
return err
196-
}
275+
msp.intermediateCerts = make([]Identity, len(conf.IntermediateCerts))
276+
for i, trustedCert := range conf.IntermediateCerts {
277+
id, err := msp.getIdentityFromConf(trustedCert)
278+
if err != nil {
279+
return err
280+
}
197281

198-
msp.intermediateCerts[i] = id
282+
msp.intermediateCerts[i] = id
283+
}
284+
285+
// ensure that our CAs are properly formed
286+
for _, cert := range append(append([]Identity{}, msp.rootCerts...), msp.intermediateCerts...) {
287+
if !isCAProperlyFormed(cert.(*identity).cert) {
288+
return fmt.Errorf("CA Certificate did not have the Subject Key Identifier extension, (SN: %s)", cert.(*identity).cert.SerialNumber)
199289
}
200-
} else {
201-
msp.intermediateCerts = make([]Identity, 0)
202290
}
203291

204292
// setup the signer (if present)
@@ -223,6 +311,52 @@ func (msp *bccspmsp) Setup(conf1 *m.MSPConfig) error {
223311
msp.opts.Intermediates.AddCert(v.(*identity).cert)
224312
}
225313

314+
// setup the CRL (if present)
315+
msp.CRL = make([]*pkix.CertificateList, len(conf.RevocationList))
316+
for i, crlbytes := range conf.RevocationList {
317+
valid := false
318+
319+
// at first we parse it
320+
crl, err := x509.ParseCRL(crlbytes)
321+
if err != nil {
322+
return fmt.Errorf("Could not parse RevocationList, err %s", err)
323+
}
324+
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+
}
356+
357+
msp.CRL[i] = crl
358+
}
359+
226360
return nil
227361
}
228362

@@ -263,7 +397,7 @@ func (msp *bccspmsp) GetSigningIdentity(identifier *IdentityIdentifier) (Signing
263397
func (msp *bccspmsp) Validate(id Identity) error {
264398
mspLogger.Infof("MSP %s validating identity", msp.name)
265399

266-
switch id.(type) {
400+
switch id := id.(type) {
267401
// If this identity is of this specific type,
268402
// this is how I can validate it given the
269403
// root of trust this MSP has
@@ -274,7 +408,7 @@ func (msp *bccspmsp) Validate(id Identity) error {
274408
}
275409

276410
// CAs cannot be directly used as identities..
277-
if id.(*identity).cert.IsCA {
411+
if id.cert.IsCA {
278412
return errors.New("A CA certificate cannot be used directly by this MSP")
279413
}
280414

@@ -290,12 +424,57 @@ func (msp *bccspmsp) Validate(id Identity) error {
290424
// signed by CA but not by CA -> iCA1)
291425

292426
// ask golang to validate the cert for us based on the options that we've built at setup time
293-
_, err := id.(*identity).cert.Verify(*(msp.opts))
427+
validationChain, err := id.cert.Verify(*(msp.opts))
294428
if err != nil {
295429
return fmt.Errorf("The supplied identity is not valid, Verify() returned %s", err)
296-
} else {
297-
return nil
298430
}
431+
432+
// we only support a single validation chain;
433+
// if there's more than one then there might
434+
// be unclarity about who owns the identity
435+
if len(validationChain) != 1 {
436+
return fmt.Errorf("This MSP only supports a single validation chain, got %d", len(validationChain))
437+
}
438+
439+
// we expect a chain of length at least 2
440+
if len(validationChain[0]) < 2 {
441+
return fmt.Errorf("Expected a chain of length at least 2, got %d", len(validationChain))
442+
}
443+
444+
// here we know that the identity is valid; now we have to check whether it has been revoked
445+
446+
// identify the SKI of the CA that signed this cert
447+
SKI, err := getSubjectKeyIdentifierFromCert(validationChain[0][1])
448+
if err != nil {
449+
return fmt.Errorf("Could not obtain Subject Key Identifier for signer cert, err %s", err)
450+
}
451+
452+
// check whether one of the CRLs we have has this cert's
453+
// SKI as its AuthorityKeyIdentifier
454+
for _, crl := range msp.CRL {
455+
aki, err := getAuthorityKeyIdentifierFromCrl(crl)
456+
if err != nil {
457+
return fmt.Errorf("Could not obtain Authority Key Identifier for crl, err %s", err)
458+
}
459+
460+
// check if the SKI of the cert that signed us matches the AKI of any of the CRLs
461+
if bytes.Equal(aki, SKI) {
462+
// we have a CRL, check whether the serial number is revoked
463+
for _, rc := range crl.TBSCertList.RevokedCertificates {
464+
if rc.SerialNumber.Cmp(id.cert.SerialNumber) == 0 {
465+
// A CRL also includes a time of revocation so that
466+
// the CA can say "this cert is to be revoked starting
467+
// from this time"; however here we just assume that
468+
// revocation applies instantaneously from the time
469+
// the MSP config is committed and used so we will not
470+
// make use of that field
471+
return errors.New("The certificate has been revoked")
472+
}
473+
}
474+
}
475+
}
476+
477+
return nil
299478
default:
300479
return fmt.Errorf("Identity type not recognized")
301480
}

0 commit comments

Comments
 (0)