Skip to content

Commit ca29f9b

Browse files
committed
Organizational Unit Certification Path Support
This change-set does the following: 1. It changes the msp identity's GetOrganizationalUnit method to return an array of FabricOUIdentifiers. A FabricOUIdentifier carries information about an organization unit and its corresponding certification chain identifier. 2. It updates the msp principal ORGANIZATION_UNIT check to take in account also the certification chain identifier. This comes in the context of the following FAB: 1. https://jira.hyperledger.org/browse/FAB-2400 Change-Id: I007ff7f5a588a99103751e8454157b0b95eb2bcc Signed-off-by: Angelo De Caro <[email protected]>
1 parent 3172f83 commit ca29f9b

File tree

8 files changed

+161
-52
lines changed

8 files changed

+161
-52
lines changed

common/cauthdsl/cauthdsl_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ func (id *mockIdentity) Validate() error {
5454
return nil
5555
}
5656

57-
func (id *mockIdentity) GetOrganizationalUnits() []string {
58-
return []string{"dunno"}
57+
func (id *mockIdentity) GetOrganizationalUnits() []mb.FabricOUIdentifier {
58+
return nil
5959
}
6060

6161
func (id *mockIdentity) Verify(msg []byte, sig []byte) error {

core/policy/mocks.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,8 @@ func (id *MockIdentity) Validate() error {
111111
return nil
112112
}
113113

114-
func (id *MockIdentity) GetOrganizationalUnits() []string {
115-
return []string{"dunno"}
114+
func (id *MockIdentity) GetOrganizationalUnits() []mspproto.FabricOUIdentifier {
115+
return nil
116116
}
117117

118118
func (id *MockIdentity) Verify(msg []byte, sig []byte) error {

msp/identities.go

+17-2
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,27 @@ func (id *identity) Validate() error {
7171
}
7272

7373
// GetOrganizationalUnits returns the OU for this instance
74-
func (id *identity) GetOrganizationalUnits() []string {
74+
func (id *identity) GetOrganizationalUnits() []msp.FabricOUIdentifier {
7575
if id.cert == nil {
7676
return nil
7777
}
7878

79-
return id.cert.Subject.OrganizationalUnit
79+
cid, err := id.msp.getCertificationChainIdentifier(id)
80+
if err != nil {
81+
mspLogger.Errorf("Failed getting certification chain identifier for [%v]: [%s]", id, err)
82+
83+
return nil
84+
}
85+
86+
res := []msp.FabricOUIdentifier{}
87+
for _, unit := range id.cert.Subject.OrganizationalUnit {
88+
res = append(res, msp.FabricOUIdentifier{
89+
OrganizationalUnitIdentifier: unit,
90+
CertifiersIdentifier: cid,
91+
})
92+
}
93+
94+
return res
8095
}
8196

8297
// NewSerializedIdentity returns a serialized identity

msp/msp.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ type Identity interface {
137137
// TODO: For X.509 based identities, check if we need a dedicated type
138138
// for OU where the Certificate OU is properly namespaced by the
139139
// signer's identity
140-
GetOrganizationalUnits() []string
140+
GetOrganizationalUnits() []msp.FabricOUIdentifier
141141

142142
// Verify a signature over some message using this identity as reference
143143
Verify(msg []byte, sig []byte) error

msp/msp_test.go

+46-2
Original file line numberDiff line numberDiff line change
@@ -256,14 +256,21 @@ func TestGetOU(t *testing.T) {
256256
return
257257
}
258258

259-
assert.Equal(t, "COP", id.GetOrganizationalUnits()[0])
259+
assert.Equal(t, "COP", id.GetOrganizationalUnits()[0].OrganizationalUnitIdentifier)
260260
}
261261

262262
func TestOUPolicyPrincipal(t *testing.T) {
263263
id, err := localMsp.GetDefaultSigningIdentity()
264264
assert.NoError(t, err)
265265

266-
ou := &msp.OrganizationUnit{OrganizationalUnitIdentifier: "COP", MspIdentifier: "DEFAULT"}
266+
cid, err := localMsp.(*bccspmsp).getCertificationChainIdentifier(id.GetPublicVersion())
267+
assert.NoError(t, err)
268+
269+
ou := &msp.OrganizationUnit{
270+
OrganizationalUnitIdentifier: "COP",
271+
MspIdentifier: "DEFAULT",
272+
CertifiersIdentifier: cid,
273+
}
267274
bytes, err := proto.Marshal(ou)
268275
assert.NoError(t, err)
269276

@@ -276,6 +283,43 @@ func TestOUPolicyPrincipal(t *testing.T) {
276283
assert.NoError(t, err)
277284
}
278285

286+
func TestOUPolicyPrincipalBadPath(t *testing.T) {
287+
id, err := localMsp.GetDefaultSigningIdentity()
288+
assert.NoError(t, err)
289+
290+
ou := &msp.OrganizationUnit{
291+
OrganizationalUnitIdentifier: "COP",
292+
MspIdentifier: "DEFAULT",
293+
CertifiersIdentifier: nil,
294+
}
295+
bytes, err := proto.Marshal(ou)
296+
assert.NoError(t, err)
297+
298+
principal := &msp.MSPPrincipal{
299+
PrincipalClassification: msp.MSPPrincipal_ORGANIZATION_UNIT,
300+
Principal: bytes,
301+
}
302+
303+
err = id.SatisfiesPrincipal(principal)
304+
assert.Error(t, err)
305+
306+
ou = &msp.OrganizationUnit{
307+
OrganizationalUnitIdentifier: "COP",
308+
MspIdentifier: "DEFAULT",
309+
CertifiersIdentifier: []byte{0, 1, 2, 3, 4},
310+
}
311+
bytes, err = proto.Marshal(ou)
312+
assert.NoError(t, err)
313+
314+
principal = &msp.MSPPrincipal{
315+
PrincipalClassification: msp.MSPPrincipal_ORGANIZATION_UNIT,
316+
Principal: bytes,
317+
}
318+
319+
err = id.SatisfiesPrincipal(principal)
320+
assert.Error(t, err)
321+
}
322+
279323
func TestAdminPolicyPrincipal(t *testing.T) {
280324
id, err := localMsp.GetDefaultSigningIdentity()
281325
assert.NoError(t, err)

msp/mspimpl.go

+89-39
Original file line numberDiff line numberDiff line change
@@ -382,49 +382,15 @@ func (msp *bccspmsp) Validate(id Identity) error {
382382
// this is how I can validate it given the
383383
// root of trust this MSP has
384384
case *identity:
385-
// we expect to have a valid VerifyOptions instance
386-
if msp.opts == nil {
387-
return errors.New("Invalid msp instance")
388-
}
389-
390-
// CAs cannot be directly used as identities..
391-
if id.cert.IsCA {
392-
return errors.New("A CA certificate cannot be used directly by this MSP")
393-
}
394-
395-
// at this point we might want to perform some
396-
// more elaborate validation. We do not do this
397-
// yet because we do not want to impose any
398-
// constraints without knowing the exact requirements,
399-
// but we at least list the kind of extra validation that we might perform:
400-
// 1) we might only allow a single verification chain (e.g. we expect the
401-
// cert to be signed exactly only by the CA or only by the intermediate)
402-
// 2) we might want to let golang find any path, and then have a blacklist
403-
// of paths (e.g. it can be signed by CA -> iCA1 -> iCA2 and it can be
404-
// signed by CA but not by CA -> iCA1)
405-
406-
// ask golang to validate the cert for us based on the options that we've built at setup time
407-
validationChain, err := id.cert.Verify(*(msp.opts))
385+
validationChain, err := msp.getCertificationChainForBCCSPIdentity(id)
408386
if err != nil {
409-
return fmt.Errorf("The supplied identity is not valid, Verify() returned %s", err)
410-
}
411-
412-
// we only support a single validation chain;
413-
// if there's more than one then there might
414-
// be unclarity about who owns the identity
415-
if len(validationChain) != 1 {
416-
return fmt.Errorf("This MSP only supports a single validation chain, got %d", len(validationChain))
417-
}
418-
419-
// we expect a chain of length at least 2
420-
if len(validationChain[0]) < 2 {
421-
return fmt.Errorf("Expected a chain of length at least 2, got %d", len(validationChain))
387+
return fmt.Errorf("Could not obtain certification chain, err %s", err)
422388
}
423389

424390
// here we know that the identity is valid; now we have to check whether it has been revoked
425391

426392
// identify the SKI of the CA that signed this cert
427-
SKI, err := getSubjectKeyIdentifierFromCert(validationChain[0][1])
393+
SKI, err := getSubjectKeyIdentifierFromCert(validationChain[1])
428394
if err != nil {
429395
return fmt.Errorf("Could not obtain Subject Key Identifier for signer cert, err %s", err)
430396
}
@@ -447,7 +413,7 @@ func (msp *bccspmsp) Validate(id Identity) error {
447413
// certificate that is under validation. As a
448414
// precaution, we verify that said CA is also the
449415
// signer of this CRL.
450-
err = validationChain[0][1].CheckCRLSignature(crl)
416+
err = validationChain[1].CheckCRLSignature(crl)
451417
if err != nil {
452418
// the CA cert that signed the certificate
453419
// that is under validation did not sign the
@@ -609,7 +575,8 @@ func (msp *bccspmsp) SatisfiesPrincipal(id Identity, principal *m.MSPPrincipal)
609575

610576
// now we check whether any of this identity's OUs match the requested one
611577
for _, ou := range id.GetOrganizationalUnits() {
612-
if ou == OU.OrganizationalUnitIdentifier {
578+
if ou.OrganizationalUnitIdentifier == OU.OrganizationalUnitIdentifier &&
579+
bytes.Equal(ou.CertifiersIdentifier, OU.CertifiersIdentifier) {
613580
return nil
614581
}
615582
}
@@ -620,3 +587,86 @@ func (msp *bccspmsp) SatisfiesPrincipal(id Identity, principal *m.MSPPrincipal)
620587
return fmt.Errorf("Invalid principal type %d", int32(principal.PrincipalClassification))
621588
}
622589
}
590+
591+
// getCertificationChain returns the certification chain of the passed identity within this msp
592+
func (msp *bccspmsp) getCertificationChain(id Identity) ([]*x509.Certificate, error) {
593+
mspLogger.Debugf("MSP %s getting certification chain", msp.name)
594+
595+
switch id := id.(type) {
596+
// If this identity is of this specific type,
597+
// this is how I can validate it given the
598+
// root of trust this MSP has
599+
case *identity:
600+
return msp.getCertificationChainForBCCSPIdentity(id)
601+
default:
602+
return nil, fmt.Errorf("Identity type not recognized")
603+
}
604+
}
605+
606+
// getCertificationChainForBCCSPIdentity returns the certification chain of the passed bccsp identity within this msp
607+
func (msp *bccspmsp) getCertificationChainForBCCSPIdentity(id *identity) ([]*x509.Certificate, error) {
608+
if id == nil {
609+
return nil, errors.New("Invalid bccsp identity. Must be different from nil.")
610+
}
611+
612+
// we expect to have a valid VerifyOptions instance
613+
if msp.opts == nil {
614+
return nil, errors.New("Invalid msp instance")
615+
}
616+
617+
// CAs cannot be directly used as identities..
618+
if id.cert.IsCA {
619+
return nil, errors.New("A CA certificate cannot be used directly by this MSP")
620+
}
621+
622+
// at this point we might want to perform some
623+
// more elaborate validation. We do not do this
624+
// yet because we do not want to impose any
625+
// constraints without knowing the exact requirements,
626+
// but we at least list the kind of extra validation that we might perform:
627+
// 1) we might only allow a single verification chain (e.g. we expect the
628+
// cert to be signed exactly only by the CA or only by the intermediate)
629+
// 2) we might want to let golang find any path, and then have a blacklist
630+
// of paths (e.g. it can be signed by CA -> iCA1 -> iCA2 and it can be
631+
// signed by CA but not by CA -> iCA1)
632+
633+
// ask golang to validate the cert for us based on the options that we've built at setup time
634+
validationChain, err := id.cert.Verify(*(msp.opts))
635+
if err != nil {
636+
return nil, fmt.Errorf("The supplied identity is not valid, Verify() returned %s", err)
637+
}
638+
639+
// we only support a single validation chain;
640+
// if there's more than one then there might
641+
// be unclarity about who owns the identity
642+
if len(validationChain) != 1 {
643+
return nil, fmt.Errorf("This MSP only supports a single validation chain, got %d", len(validationChain))
644+
}
645+
646+
// we expect a chain of length at least 2
647+
if len(validationChain[0]) < 2 {
648+
return nil, fmt.Errorf("Expected a chain of length at least 2, got %d", len(validationChain))
649+
}
650+
651+
return validationChain[0], nil
652+
}
653+
654+
// getCertificationChainIdentifier returns the certification chain identifier of the passed identity within this msp.
655+
// The identifier is computes as the SHA256 of the concatenation of the certificates in the chain.
656+
func (msp *bccspmsp) getCertificationChainIdentifier(id Identity) ([]byte, error) {
657+
chain, err := msp.getCertificationChain(id)
658+
if err != nil {
659+
return nil, fmt.Errorf("Failed getting certification chain for [%v]: [%s]", id, err)
660+
}
661+
662+
// Hash the chain
663+
hf, err := msp.bccsp.GetHash(&bccsp.SHA256Opts{})
664+
if err != nil {
665+
return nil, fmt.Errorf("Failed getting hash function when computing certification chain identifier for [%v]: [%s]", id, err)
666+
}
667+
668+
for i := 0; i < len(chain); i++ {
669+
hf.Write(chain[i].Raw)
670+
}
671+
return hf.Sum(nil), nil
672+
}

msp/noopmsp.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,8 @@ func (id *noopidentity) Validate() error {
101101
return nil
102102
}
103103

104-
func (id *noopidentity) GetOrganizationalUnits() []string {
105-
return []string{"dunno"}
104+
func (id *noopidentity) GetOrganizationalUnits() []msp.FabricOUIdentifier {
105+
return nil
106106
}
107107

108108
func (id *noopidentity) Verify(msg []byte, sig []byte) error {

peer/gossip/mcs/mocks.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -131,8 +131,8 @@ func (id *mockIdentity) Validate() error {
131131
return nil
132132
}
133133

134-
func (id *mockIdentity) GetOrganizationalUnits() []string {
135-
return []string{"dunno"}
134+
func (id *mockIdentity) GetOrganizationalUnits() []mspproto.FabricOUIdentifier {
135+
return nil
136136
}
137137

138138
func (id *mockIdentity) Verify(msg []byte, sig []byte) error {

0 commit comments

Comments
 (0)