948 lines
27 KiB
Go
948 lines
27 KiB
Go
/*
|
|
Copyright IBM Corp. All Rights Reserved.
|
|
|
|
SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
package configtx
|
|
|
|
import (
|
|
"crypto"
|
|
"crypto/rand"
|
|
"crypto/x509"
|
|
"crypto/x509/pkix"
|
|
"encoding/asn1"
|
|
"encoding/pem"
|
|
"fmt"
|
|
"reflect"
|
|
"time"
|
|
|
|
"github.com/golang/protobuf/proto"
|
|
"github.com/hyperledger/fabric-config/configtx/membership"
|
|
cb "github.com/hyperledger/fabric-protos-go/common"
|
|
mb "github.com/hyperledger/fabric-protos-go/msp"
|
|
)
|
|
|
|
// MSP is the configuration information for a Fabric MSP.
|
|
// Here we assume a default certificate validation policy, where
|
|
// any certificate signed by any of the listed rootCA certs would
|
|
// be considered as valid under this MSP.
|
|
// This MSP may or may not come with a signing identity. If it does,
|
|
// it can also issue signing identities. If it does not, it can only
|
|
// be used to validate and verify certificates.
|
|
type MSP struct {
|
|
// Name holds the identifier of the MSP; MSP identifier
|
|
// is chosen by the application that governs this MSP.
|
|
// For example, and assuming the default implementation of MSP,
|
|
// that is X.509-based and considers a single Issuer,
|
|
// this can refer to the Subject OU field or the Issuer OU field.
|
|
Name string
|
|
// List of root certificates trusted by this MSP
|
|
// they are used upon certificate validation (see
|
|
// comment for IntermediateCerts below).
|
|
RootCerts []*x509.Certificate
|
|
// List of intermediate certificates trusted by this MSP;
|
|
// they are used upon certificate validation as follows:
|
|
// validation attempts to build a path from the certificate
|
|
// to be validated (which is at one end of the path) and
|
|
// one of the certs in the RootCerts field (which is at
|
|
// the other end of the path). If the path is longer than
|
|
// 2, certificates in the middle are searched within the
|
|
// IntermediateCerts pool.
|
|
IntermediateCerts []*x509.Certificate
|
|
// Identity denoting the administrator of this MSP.
|
|
Admins []*x509.Certificate
|
|
// Identity revocation list.
|
|
RevocationList []*pkix.CertificateList
|
|
// OrganizationalUnitIdentifiers holds one or more
|
|
// fabric organizational unit identifiers that belong to
|
|
// this MSP configuration.
|
|
OrganizationalUnitIdentifiers []membership.OUIdentifier
|
|
// CryptoConfig contains the configuration parameters
|
|
// for the cryptographic algorithms used by this MSP.
|
|
CryptoConfig membership.CryptoConfig
|
|
// List of TLS root certificates trusted by this MSP.
|
|
// They are returned by GetTLSRootCerts.
|
|
TLSRootCerts []*x509.Certificate
|
|
// List of TLS intermediate certificates trusted by this MSP;
|
|
// They are returned by GetTLSIntermediateCerts.
|
|
TLSIntermediateCerts []*x509.Certificate
|
|
// Contains the configuration to distinguish clients
|
|
// from peers from orderers based on the OUs.
|
|
NodeOUs membership.NodeOUs
|
|
}
|
|
|
|
// YEAR is a time duration for a standard 365 day year.
|
|
const YEAR = 365 * 24 * time.Hour
|
|
|
|
// OrganizationMSP encapsulates the configuration functions used to modify an organization MSP.
|
|
type OrganizationMSP struct {
|
|
configGroup *cb.ConfigGroup
|
|
}
|
|
|
|
// Configuration returns the MSP value for a organization in the updated config.
|
|
func (m *OrganizationMSP) Configuration() (MSP, error) {
|
|
return getMSPConfig(m.configGroup)
|
|
}
|
|
|
|
// AddAdminCert adds an administator identity to the organization MSP.
|
|
func (m *OrganizationMSP) AddAdminCert(cert *x509.Certificate) error {
|
|
msp, err := getMSPConfig(m.configGroup)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, c := range msp.Admins {
|
|
if c.Equal(cert) {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
msp.Admins = append(msp.Admins, cert)
|
|
|
|
return msp.setConfig(m.configGroup)
|
|
}
|
|
|
|
// RemoveAdminCert removes an administator identity from the organization MSP.
|
|
func (m *OrganizationMSP) RemoveAdminCert(cert *x509.Certificate) error {
|
|
msp, err := getMSPConfig(m.configGroup)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
certs := msp.Admins[:]
|
|
for i, c := range msp.Admins {
|
|
if c.Equal(cert) {
|
|
certs = append(certs[:i], certs[i+1:]...)
|
|
break
|
|
}
|
|
}
|
|
|
|
msp.Admins = certs
|
|
|
|
return msp.setConfig(m.configGroup)
|
|
}
|
|
|
|
// AddRootCert adds a root certificate trusted by the organization MSP.
|
|
func (m *OrganizationMSP) AddRootCert(cert *x509.Certificate) error {
|
|
msp, err := getMSPConfig(m.configGroup)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, c := range msp.RootCerts {
|
|
if c.Equal(cert) {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
msp.RootCerts = append(msp.RootCerts, cert)
|
|
|
|
err = msp.validateCACerts()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return msp.setConfig(m.configGroup)
|
|
}
|
|
|
|
// RemoveRootCert removes a trusted root certificate from the organization MSP.
|
|
func (m *OrganizationMSP) RemoveRootCert(cert *x509.Certificate) error {
|
|
msp, err := getMSPConfig(m.configGroup)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
certs := msp.RootCerts[:]
|
|
for i, c := range msp.RootCerts {
|
|
if c.Equal(cert) {
|
|
certs = append(certs[:i], certs[i+1:]...)
|
|
break
|
|
}
|
|
}
|
|
|
|
msp.RootCerts = certs
|
|
|
|
err = msp.validateCACerts()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return msp.setConfig(m.configGroup)
|
|
}
|
|
|
|
// AddIntermediateCert adds an intermediate certificate trusted by the organization MSP.
|
|
func (m *OrganizationMSP) AddIntermediateCert(cert *x509.Certificate) error {
|
|
msp, err := getMSPConfig(m.configGroup)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, c := range msp.IntermediateCerts {
|
|
if c.Equal(cert) {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
msp.IntermediateCerts = append(msp.IntermediateCerts, cert)
|
|
|
|
err = msp.validateCACerts()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return msp.setConfig(m.configGroup)
|
|
}
|
|
|
|
// RemoveIntermediateCert removes a trusted intermediate certificate from the organization MSP.
|
|
func (m *OrganizationMSP) RemoveIntermediateCert(cert *x509.Certificate) error {
|
|
msp, err := getMSPConfig(m.configGroup)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
certs := msp.IntermediateCerts[:]
|
|
for i, c := range msp.IntermediateCerts {
|
|
if c.Equal(cert) {
|
|
certs = append(certs[:i], certs[i+1:]...)
|
|
break
|
|
}
|
|
}
|
|
|
|
msp.IntermediateCerts = certs
|
|
|
|
err = msp.validateCACerts()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return msp.setConfig(m.configGroup)
|
|
}
|
|
|
|
// AddOUIdentifier adds a custom organizational unit identifier to the organization MSP.
|
|
func (m *OrganizationMSP) AddOUIdentifier(ou membership.OUIdentifier) error {
|
|
msp, err := getMSPConfig(m.configGroup)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, o := range msp.OrganizationalUnitIdentifiers {
|
|
if reflect.DeepEqual(o, ou) {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
msp.OrganizationalUnitIdentifiers = append(msp.OrganizationalUnitIdentifiers, ou)
|
|
|
|
return msp.setConfig(m.configGroup)
|
|
}
|
|
|
|
// RemoveOUIdentifier removes an existing organizational unit identifier from the organization MSP.
|
|
func (m *OrganizationMSP) RemoveOUIdentifier(ou membership.OUIdentifier) error {
|
|
msp, err := getMSPConfig(m.configGroup)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
ous := msp.OrganizationalUnitIdentifiers[:]
|
|
for i, o := range msp.OrganizationalUnitIdentifiers {
|
|
if reflect.DeepEqual(o, ou) {
|
|
ous = append(ous[:i], ous[i+1:]...)
|
|
break
|
|
}
|
|
}
|
|
|
|
msp.OrganizationalUnitIdentifiers = ous
|
|
|
|
return msp.setConfig(m.configGroup)
|
|
}
|
|
|
|
// SetCryptoConfig sets the configuration for the cryptographic algorithms for the organization MSP.
|
|
func (m *OrganizationMSP) SetCryptoConfig(cryptoConfig membership.CryptoConfig) error {
|
|
msp, err := getMSPConfig(m.configGroup)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
msp.CryptoConfig = cryptoConfig
|
|
|
|
return msp.setConfig(m.configGroup)
|
|
}
|
|
|
|
// AddTLSRootCert adds a TLS root certificate trusted by the organization MSP.
|
|
func (m *OrganizationMSP) AddTLSRootCert(cert *x509.Certificate) error {
|
|
msp, err := getMSPConfig(m.configGroup)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, c := range msp.TLSRootCerts {
|
|
if c.Equal(cert) {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
msp.TLSRootCerts = append(msp.TLSRootCerts, cert)
|
|
|
|
err = msp.validateCACerts()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return msp.setConfig(m.configGroup)
|
|
}
|
|
|
|
// RemoveTLSRootCert removes a trusted TLS root certificate from the organization MSP.
|
|
func (m *OrganizationMSP) RemoveTLSRootCert(cert *x509.Certificate) error {
|
|
msp, err := getMSPConfig(m.configGroup)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
certs := msp.TLSRootCerts[:]
|
|
for i, c := range msp.TLSRootCerts {
|
|
if c.Equal(cert) {
|
|
certs = append(certs[:i], certs[i+1:]...)
|
|
break
|
|
}
|
|
}
|
|
|
|
msp.TLSRootCerts = certs
|
|
|
|
err = msp.validateCACerts()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return msp.setConfig(m.configGroup)
|
|
}
|
|
|
|
// AddTLSIntermediateCert adds a TLS intermediate cert trusted by the organization MSP.
|
|
func (m *OrganizationMSP) AddTLSIntermediateCert(cert *x509.Certificate) error {
|
|
msp, err := getMSPConfig(m.configGroup)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, c := range msp.TLSIntermediateCerts {
|
|
if c.Equal(cert) {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
msp.TLSIntermediateCerts = append(msp.TLSIntermediateCerts, cert)
|
|
|
|
err = msp.validateCACerts()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return msp.setConfig(m.configGroup)
|
|
}
|
|
|
|
// RemoveTLSIntermediateCert removes a trusted TLS intermediate cert from the organization MSP.
|
|
func (m *OrganizationMSP) RemoveTLSIntermediateCert(cert *x509.Certificate) error {
|
|
msp, err := getMSPConfig(m.configGroup)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
certs := msp.TLSIntermediateCerts[:]
|
|
for i, c := range msp.TLSIntermediateCerts {
|
|
if c.Equal(cert) {
|
|
certs = append(certs[:i], certs[i+1:]...)
|
|
break
|
|
}
|
|
}
|
|
|
|
msp.TLSIntermediateCerts = certs
|
|
|
|
err = msp.validateCACerts()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return msp.setConfig(m.configGroup)
|
|
}
|
|
|
|
// SetClientOUIdentifier sets the NodeOUs client ou identifier for the organization MSP.
|
|
func (m *OrganizationMSP) SetClientOUIdentifier(clientOU membership.OUIdentifier) error {
|
|
msp, err := getMSPConfig(m.configGroup)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
msp.NodeOUs.ClientOUIdentifier = clientOU
|
|
|
|
return msp.setConfig(m.configGroup)
|
|
}
|
|
|
|
// SetPeerOUIdentifier sets the NodeOUs peer ou identifier for the organization MSP.
|
|
func (m *OrganizationMSP) SetPeerOUIdentifier(peerOU membership.OUIdentifier) error {
|
|
msp, err := getMSPConfig(m.configGroup)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
msp.NodeOUs.PeerOUIdentifier = peerOU
|
|
|
|
return msp.setConfig(m.configGroup)
|
|
}
|
|
|
|
// SetAdminOUIdentifier sets the NodeOUs admin ou identifier for the organization MSP.
|
|
func (m *OrganizationMSP) SetAdminOUIdentifier(adminOU membership.OUIdentifier) error {
|
|
msp, err := getMSPConfig(m.configGroup)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
msp.NodeOUs.AdminOUIdentifier = adminOU
|
|
|
|
return msp.setConfig(m.configGroup)
|
|
}
|
|
|
|
// SetOrdererOUIdentifier sets the NodeOUs orderer ou identifier for the organization MSP.
|
|
func (m *OrganizationMSP) SetOrdererOUIdentifier(ordererOU membership.OUIdentifier) error {
|
|
msp, err := getMSPConfig(m.configGroup)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
msp.NodeOUs.OrdererOUIdentifier = ordererOU
|
|
|
|
return msp.setConfig(m.configGroup)
|
|
}
|
|
|
|
// SetEnableNodeOUs sets the NodeOUs recognition, if NodeOUs recognition is enabled then an msp identity
|
|
// that does not contain exactly one of the fabric Node OU Identifiers will be considered invalid.
|
|
func (m *OrganizationMSP) SetEnableNodeOUs(isEnabled bool) error {
|
|
msp, err := getMSPConfig(m.configGroup)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
msp.NodeOUs.Enable = isEnabled
|
|
|
|
return msp.setConfig(m.configGroup)
|
|
}
|
|
|
|
// AddCRL adds a CRL to the identity revocation list for the organization MSP.
|
|
func (m *OrganizationMSP) AddCRL(crl *pkix.CertificateList) error {
|
|
msp, err := getMSPConfig(m.configGroup)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
msp.RevocationList = append(msp.RevocationList, crl)
|
|
|
|
return msp.setConfig(m.configGroup)
|
|
}
|
|
|
|
// AddCRLFromSigningIdentity creates a CRL from the provided signing identity and associated certs and then adds the CRL to
|
|
// the identity revocation list for the organization MSP.
|
|
func (m *OrganizationMSP) AddCRLFromSigningIdentity(signingIdentity *SigningIdentity, certs ...*x509.Certificate) error {
|
|
msp, err := getMSPConfig(m.configGroup)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
crl, err := msp.CreateMSPCRL(signingIdentity, certs...)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
msp.RevocationList = append(msp.RevocationList, crl)
|
|
|
|
return msp.setConfig(m.configGroup)
|
|
}
|
|
|
|
// CreateMSPCRL creates a CRL that revokes the provided certificates
|
|
// for the specified organization's msp signed by the provided SigningIdentity.
|
|
func (m *MSP) CreateMSPCRL(signingIdentity *SigningIdentity, certs ...*x509.Certificate) (*pkix.CertificateList, error) {
|
|
return m.newMSPCRL(signingIdentity, certs...)
|
|
}
|
|
|
|
// newMSPCRL creates a CRL that revokes the provided certificates for the specified org
|
|
// signed by the provided SigningIdentity. If any of the provided certs were
|
|
// not signed by any of the root/intermediate CA cets in the MSP configuration,
|
|
// it will return an error.
|
|
func (m *MSP) newMSPCRL(signingIdentity *SigningIdentity, certs ...*x509.Certificate) (*pkix.CertificateList, error) {
|
|
if err := m.validateCertificates(signingIdentity.Certificate, certs...); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
revokeTime := time.Now().UTC()
|
|
|
|
revokedCertificates := make([]pkix.RevokedCertificate, len(certs))
|
|
for i, cert := range certs {
|
|
revokedCertificates[i] = pkix.RevokedCertificate{
|
|
SerialNumber: cert.SerialNumber,
|
|
RevocationTime: revokeTime,
|
|
}
|
|
}
|
|
|
|
crlBytes, err := signingIdentity.Certificate.CreateCRL(rand.Reader, signingIdentity.PrivateKey, revokedCertificates, revokeTime, revokeTime.Add(YEAR))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
crl, err := x509.ParseCRL(crlBytes)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return crl, nil
|
|
}
|
|
|
|
// validateCertificates first validates that the signing certificate is either
|
|
// a root or intermediate CA certificate for the specified application org. It
|
|
// then validates that the certificates to add to the CRL were signed by that
|
|
// signing certificate.
|
|
func (m *MSP) validateCertificates(signingCert *x509.Certificate, certs ...*x509.Certificate) error {
|
|
err := m.isCACert(signingCert)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, cert := range certs {
|
|
if err := cert.CheckSignatureFrom(signingCert); err != nil {
|
|
return fmt.Errorf("certificate not issued by this MSP. serial number: %d", cert.SerialNumber)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (m *MSP) isCACert(signingCert *x509.Certificate) error {
|
|
for _, rootCert := range m.RootCerts {
|
|
if signingCert.Equal(rootCert) {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
for _, intermediateCert := range m.IntermediateCerts {
|
|
if signingCert.Equal(intermediateCert) {
|
|
return nil
|
|
}
|
|
}
|
|
return fmt.Errorf("signing cert is not a root/intermediate cert for this MSP: %s", m.Name)
|
|
}
|
|
|
|
func (m *MSP) setConfig(configGroup *cb.ConfigGroup) error {
|
|
mspConfig, err := newMSPConfig(*m)
|
|
if err != nil {
|
|
return fmt.Errorf("new msp config: %v", err)
|
|
}
|
|
|
|
err = setValue(configGroup, mspValue(mspConfig), AdminsPolicyKey)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// getMSPConfig parses the MSP value in a config group returns
|
|
// the configuration as an MSP type.
|
|
func getMSPConfig(configGroup *cb.ConfigGroup) (MSP, error) {
|
|
mspValueProto := &mb.MSPConfig{}
|
|
|
|
err := unmarshalConfigValueAtKey(configGroup, MSPKey, mspValueProto)
|
|
if err != nil {
|
|
return MSP{}, err
|
|
}
|
|
|
|
fabricMSPConfig := &mb.FabricMSPConfig{}
|
|
|
|
err = proto.Unmarshal(mspValueProto.Config, fabricMSPConfig)
|
|
if err != nil {
|
|
return MSP{}, fmt.Errorf("unmarshaling fabric msp config: %v", err)
|
|
}
|
|
|
|
// ROOT CERTS
|
|
rootCerts, err := parseCertificateListFromBytes(fabricMSPConfig.RootCerts)
|
|
if err != nil {
|
|
return MSP{}, fmt.Errorf("parsing root certs: %v", err)
|
|
}
|
|
|
|
// INTERMEDIATE CERTS
|
|
intermediateCerts, err := parseCertificateListFromBytes(fabricMSPConfig.IntermediateCerts)
|
|
if err != nil {
|
|
return MSP{}, fmt.Errorf("parsing intermediate certs: %v", err)
|
|
}
|
|
|
|
// ADMIN CERTS
|
|
adminCerts, err := parseCertificateListFromBytes(fabricMSPConfig.Admins)
|
|
if err != nil {
|
|
return MSP{}, fmt.Errorf("parsing admin certs: %v", err)
|
|
}
|
|
|
|
// REVOCATION LIST
|
|
revocationList, err := parseCRL(fabricMSPConfig.RevocationList)
|
|
if err != nil {
|
|
return MSP{}, err
|
|
}
|
|
|
|
// OU IDENTIFIERS
|
|
ouIdentifiers, err := parseOUIdentifiers(fabricMSPConfig.OrganizationalUnitIdentifiers)
|
|
if err != nil {
|
|
return MSP{}, fmt.Errorf("parsing ou identifiers: %v", err)
|
|
}
|
|
|
|
// TLS ROOT CERTS
|
|
tlsRootCerts, err := parseCertificateListFromBytes(fabricMSPConfig.TlsRootCerts)
|
|
if err != nil {
|
|
return MSP{}, fmt.Errorf("parsing tls root certs: %v", err)
|
|
}
|
|
|
|
// TLS INTERMEDIATE CERTS
|
|
tlsIntermediateCerts, err := parseCertificateListFromBytes(fabricMSPConfig.TlsIntermediateCerts)
|
|
if err != nil {
|
|
return MSP{}, fmt.Errorf("parsing tls intermediate certs: %v", err)
|
|
}
|
|
|
|
// NODE OUS
|
|
nodeOUs := membership.NodeOUs{}
|
|
if fabricMSPConfig.FabricNodeOus != nil {
|
|
clientOUIdentifierCert, err := parseCertificateFromBytes(fabricMSPConfig.FabricNodeOus.ClientOuIdentifier.Certificate)
|
|
if err != nil {
|
|
return MSP{}, fmt.Errorf("parsing client ou identifier cert: %v", err)
|
|
}
|
|
|
|
peerOUIdentifierCert, err := parseCertificateFromBytes(fabricMSPConfig.FabricNodeOus.PeerOuIdentifier.Certificate)
|
|
if err != nil {
|
|
return MSP{}, fmt.Errorf("parsing peer ou identifier cert: %v", err)
|
|
}
|
|
|
|
adminOUIdentifierCert, err := parseCertificateFromBytes(fabricMSPConfig.FabricNodeOus.AdminOuIdentifier.Certificate)
|
|
if err != nil {
|
|
return MSP{}, fmt.Errorf("parsing admin ou identifier cert: %v", err)
|
|
}
|
|
|
|
ordererOUIdentifierCert, err := parseCertificateFromBytes(fabricMSPConfig.FabricNodeOus.OrdererOuIdentifier.Certificate)
|
|
if err != nil {
|
|
return MSP{}, fmt.Errorf("parsing orderer ou identifier cert: %v", err)
|
|
}
|
|
|
|
nodeOUs = membership.NodeOUs{
|
|
Enable: fabricMSPConfig.FabricNodeOus.Enable,
|
|
ClientOUIdentifier: membership.OUIdentifier{
|
|
Certificate: clientOUIdentifierCert,
|
|
OrganizationalUnitIdentifier: fabricMSPConfig.FabricNodeOus.ClientOuIdentifier.OrganizationalUnitIdentifier,
|
|
},
|
|
PeerOUIdentifier: membership.OUIdentifier{
|
|
Certificate: peerOUIdentifierCert,
|
|
OrganizationalUnitIdentifier: fabricMSPConfig.FabricNodeOus.PeerOuIdentifier.OrganizationalUnitIdentifier,
|
|
},
|
|
AdminOUIdentifier: membership.OUIdentifier{
|
|
Certificate: adminOUIdentifierCert,
|
|
OrganizationalUnitIdentifier: fabricMSPConfig.FabricNodeOus.AdminOuIdentifier.OrganizationalUnitIdentifier,
|
|
},
|
|
OrdererOUIdentifier: membership.OUIdentifier{
|
|
Certificate: ordererOUIdentifierCert,
|
|
OrganizationalUnitIdentifier: fabricMSPConfig.FabricNodeOus.OrdererOuIdentifier.OrganizationalUnitIdentifier,
|
|
},
|
|
}
|
|
}
|
|
|
|
return MSP{
|
|
Name: fabricMSPConfig.Name,
|
|
RootCerts: rootCerts,
|
|
IntermediateCerts: intermediateCerts,
|
|
Admins: adminCerts,
|
|
RevocationList: revocationList,
|
|
OrganizationalUnitIdentifiers: ouIdentifiers,
|
|
CryptoConfig: membership.CryptoConfig{
|
|
SignatureHashFamily: fabricMSPConfig.CryptoConfig.SignatureHashFamily,
|
|
IdentityIdentifierHashFunction: fabricMSPConfig.CryptoConfig.IdentityIdentifierHashFunction,
|
|
},
|
|
TLSRootCerts: tlsRootCerts,
|
|
TLSIntermediateCerts: tlsIntermediateCerts,
|
|
NodeOUs: nodeOUs,
|
|
}, nil
|
|
}
|
|
|
|
func parseCertificateListFromBytes(certs [][]byte) ([]*x509.Certificate, error) {
|
|
certificateList := []*x509.Certificate{}
|
|
|
|
for _, cert := range certs {
|
|
certificate, err := parseCertificateFromBytes(cert)
|
|
if err != nil {
|
|
return certificateList, err
|
|
}
|
|
|
|
certificateList = append(certificateList, certificate)
|
|
}
|
|
|
|
return certificateList, nil
|
|
}
|
|
|
|
func parseCertificateFromBytes(cert []byte) (*x509.Certificate, error) {
|
|
pemBlock, _ := pem.Decode(cert)
|
|
if pemBlock == nil {
|
|
return &x509.Certificate{}, fmt.Errorf("no PEM data found in cert[% x]", cert)
|
|
}
|
|
|
|
certificate, err := x509.ParseCertificate(pemBlock.Bytes)
|
|
if err != nil {
|
|
return &x509.Certificate{}, err
|
|
}
|
|
|
|
return certificate, nil
|
|
}
|
|
|
|
func parseCRL(crls [][]byte) ([]*pkix.CertificateList, error) {
|
|
certificateLists := []*pkix.CertificateList{}
|
|
|
|
for _, crl := range crls {
|
|
pemBlock, _ := pem.Decode(crl)
|
|
if pemBlock == nil {
|
|
return certificateLists, fmt.Errorf("no PEM data found in CRL[% x]", crl)
|
|
}
|
|
|
|
certificateList, err := x509.ParseCRL(pemBlock.Bytes)
|
|
if err != nil {
|
|
return certificateLists, fmt.Errorf("parsing crl: %v", err)
|
|
}
|
|
|
|
certificateLists = append(certificateLists, certificateList)
|
|
}
|
|
|
|
return certificateLists, nil
|
|
}
|
|
|
|
func parsePrivateKeyFromBytes(priv []byte) (crypto.PrivateKey, error) {
|
|
if len(priv) == 0 {
|
|
return nil, nil
|
|
}
|
|
|
|
pemBlock, _ := pem.Decode(priv)
|
|
if pemBlock == nil {
|
|
return nil, fmt.Errorf("no PEM data found in private key[% x]", priv)
|
|
}
|
|
|
|
privateKey, err := x509.ParsePKCS8PrivateKey(pemBlock.Bytes)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed parsing PKCS#8 private key: %v", err)
|
|
}
|
|
|
|
return privateKey, nil
|
|
}
|
|
|
|
func parseOUIdentifiers(identifiers []*mb.FabricOUIdentifier) ([]membership.OUIdentifier, error) {
|
|
fabricIdentifiers := []membership.OUIdentifier{}
|
|
|
|
for _, identifier := range identifiers {
|
|
cert, err := parseCertificateFromBytes(identifier.Certificate)
|
|
if err != nil {
|
|
return fabricIdentifiers, err
|
|
}
|
|
|
|
fabricOUIdentifier := membership.OUIdentifier{
|
|
Certificate: cert,
|
|
OrganizationalUnitIdentifier: identifier.OrganizationalUnitIdentifier,
|
|
}
|
|
|
|
fabricIdentifiers = append(fabricIdentifiers, fabricOUIdentifier)
|
|
}
|
|
|
|
return fabricIdentifiers, nil
|
|
}
|
|
|
|
// toProto converts an MSP configuration to an mb.FabricMSPConfig proto.
|
|
// It pem encodes x509 certificates and ECDSA private keys to byte slices.
|
|
func (m *MSP) toProto() (*mb.FabricMSPConfig, error) {
|
|
revocationList, err := buildPemEncodedRevocationList(m.RevocationList)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("building pem encoded revocation list: %v", err)
|
|
}
|
|
|
|
ouIdentifiers := buildOUIdentifiers(m.OrganizationalUnitIdentifiers)
|
|
|
|
var fabricNodeOUs *mb.FabricNodeOUs
|
|
if m.NodeOUs != (membership.NodeOUs{}) {
|
|
fabricNodeOUs = &mb.FabricNodeOUs{
|
|
Enable: m.NodeOUs.Enable,
|
|
ClientOuIdentifier: &mb.FabricOUIdentifier{
|
|
Certificate: pemEncodeX509Certificate(m.NodeOUs.ClientOUIdentifier.Certificate),
|
|
OrganizationalUnitIdentifier: m.NodeOUs.ClientOUIdentifier.OrganizationalUnitIdentifier,
|
|
},
|
|
PeerOuIdentifier: &mb.FabricOUIdentifier{
|
|
Certificate: pemEncodeX509Certificate(m.NodeOUs.PeerOUIdentifier.Certificate),
|
|
OrganizationalUnitIdentifier: m.NodeOUs.PeerOUIdentifier.OrganizationalUnitIdentifier,
|
|
},
|
|
AdminOuIdentifier: &mb.FabricOUIdentifier{
|
|
Certificate: pemEncodeX509Certificate(m.NodeOUs.AdminOUIdentifier.Certificate),
|
|
OrganizationalUnitIdentifier: m.NodeOUs.AdminOUIdentifier.OrganizationalUnitIdentifier,
|
|
},
|
|
OrdererOuIdentifier: &mb.FabricOUIdentifier{
|
|
Certificate: pemEncodeX509Certificate(m.NodeOUs.OrdererOUIdentifier.Certificate),
|
|
OrganizationalUnitIdentifier: m.NodeOUs.OrdererOUIdentifier.OrganizationalUnitIdentifier,
|
|
},
|
|
}
|
|
}
|
|
|
|
return &mb.FabricMSPConfig{
|
|
Name: m.Name,
|
|
RootCerts: buildPemEncodedCertListFromX509(m.RootCerts),
|
|
IntermediateCerts: buildPemEncodedCertListFromX509(m.IntermediateCerts),
|
|
Admins: buildPemEncodedCertListFromX509(m.Admins),
|
|
RevocationList: revocationList,
|
|
OrganizationalUnitIdentifiers: ouIdentifiers,
|
|
CryptoConfig: &mb.FabricCryptoConfig{
|
|
SignatureHashFamily: m.CryptoConfig.SignatureHashFamily,
|
|
IdentityIdentifierHashFunction: m.CryptoConfig.IdentityIdentifierHashFunction,
|
|
},
|
|
TlsRootCerts: buildPemEncodedCertListFromX509(m.TLSRootCerts),
|
|
TlsIntermediateCerts: buildPemEncodedCertListFromX509(m.TLSIntermediateCerts),
|
|
FabricNodeOus: fabricNodeOUs,
|
|
}, nil
|
|
}
|
|
|
|
func buildOUIdentifiers(identifiers []membership.OUIdentifier) []*mb.FabricOUIdentifier {
|
|
fabricIdentifiers := []*mb.FabricOUIdentifier{}
|
|
|
|
for _, identifier := range identifiers {
|
|
fabricOUIdentifier := &mb.FabricOUIdentifier{
|
|
Certificate: pemEncodeX509Certificate(identifier.Certificate),
|
|
OrganizationalUnitIdentifier: identifier.OrganizationalUnitIdentifier,
|
|
}
|
|
|
|
fabricIdentifiers = append(fabricIdentifiers, fabricOUIdentifier)
|
|
}
|
|
|
|
return fabricIdentifiers
|
|
}
|
|
|
|
// buildPemEncodedRevocationList returns a byte slice of the pem-encoded
|
|
// CRLs for a revocation list.
|
|
func buildPemEncodedRevocationList(crls []*pkix.CertificateList) ([][]byte, error) {
|
|
pemEncodedRevocationList := [][]byte{}
|
|
|
|
for _, crl := range crls {
|
|
// asn1MarshalledBytes, err := asn1.Marshal(*crl)
|
|
pemCRL, err := pemEncodeCRL(crl)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
pemEncodedRevocationList = append(pemEncodedRevocationList, pemCRL)
|
|
}
|
|
|
|
return pemEncodedRevocationList, nil
|
|
}
|
|
|
|
func pemEncodeCRL(crl *pkix.CertificateList) ([]byte, error) {
|
|
asn1MarshalledBytes, err := asn1.Marshal(*crl)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return pem.EncodeToMemory(&pem.Block{Type: "X509 CRL", Bytes: asn1MarshalledBytes}), nil
|
|
}
|
|
|
|
func buildPemEncodedCertListFromX509(certList []*x509.Certificate) [][]byte {
|
|
certs := [][]byte{}
|
|
for _, cert := range certList {
|
|
certs = append(certs, pemEncodeX509Certificate(cert))
|
|
}
|
|
|
|
return certs
|
|
}
|
|
|
|
func pemEncodeX509Certificate(cert *x509.Certificate) []byte {
|
|
return pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw})
|
|
}
|
|
|
|
func pemEncodePKCS8PrivateKey(priv crypto.PrivateKey) ([]byte, error) {
|
|
privBytes, err := x509.MarshalPKCS8PrivateKey(priv)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("marshaling PKCS#8 private key: %v", err)
|
|
}
|
|
|
|
return pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: privBytes}), nil
|
|
}
|
|
|
|
// newMSPConfig returns an config for a msp.
|
|
func newMSPConfig(updatedMSP MSP) (*mb.MSPConfig, error) {
|
|
fabricMSPConfig, err := updatedMSP.toProto()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
conf, err := proto.Marshal(fabricMSPConfig)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("marshaling msp config: %v", err)
|
|
}
|
|
|
|
mspConfig := &mb.MSPConfig{
|
|
Config: conf,
|
|
}
|
|
|
|
return mspConfig, nil
|
|
}
|
|
|
|
func (m *MSP) validateCACerts() error {
|
|
err := validateCACerts(m.RootCerts)
|
|
if err != nil {
|
|
return fmt.Errorf("invalid root cert: %v", err)
|
|
}
|
|
|
|
err = validateCACerts(m.IntermediateCerts)
|
|
if err != nil {
|
|
return fmt.Errorf("invalid intermediate cert: %v", err)
|
|
}
|
|
|
|
// TODO: follow the workaround that msp code use to incorporate cert.Verify()
|
|
for _, ic := range m.IntermediateCerts {
|
|
validIntermediateCert := false
|
|
for _, rc := range m.RootCerts {
|
|
err := ic.CheckSignatureFrom(rc)
|
|
if err == nil {
|
|
validIntermediateCert = true
|
|
break
|
|
}
|
|
}
|
|
if !validIntermediateCert {
|
|
return fmt.Errorf("intermediate cert not signed by any root certs of this MSP. serial number: %d", ic.SerialNumber)
|
|
}
|
|
}
|
|
|
|
err = validateCACerts(m.TLSRootCerts)
|
|
if err != nil {
|
|
return fmt.Errorf("invalid tls root cert: %v", err)
|
|
}
|
|
|
|
err = validateCACerts(m.TLSIntermediateCerts)
|
|
if err != nil {
|
|
return fmt.Errorf("invalid tls intermediate cert: %v", err)
|
|
}
|
|
|
|
tlsRootPool := x509.NewCertPool()
|
|
for _, rootCert := range m.TLSRootCerts {
|
|
tlsRootPool.AddCert(rootCert)
|
|
}
|
|
|
|
for _, ic := range m.TLSIntermediateCerts {
|
|
_, err := ic.Verify(x509.VerifyOptions{
|
|
Roots: tlsRootPool,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func validateCACerts(caCerts []*x509.Certificate) error {
|
|
for _, caCert := range caCerts {
|
|
if (caCert.KeyUsage & x509.KeyUsageCertSign) == 0 {
|
|
return fmt.Errorf("KeyUsage must be x509.KeyUsageCertSign. serial number: %d", caCert.SerialNumber)
|
|
}
|
|
|
|
if !caCert.IsCA {
|
|
return fmt.Errorf("must be a CA certificate. serial number: %d", caCert.SerialNumber)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|