github.com/anjalikarhana/fabric@v2.1.1+incompatible/msp/configbuilder.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package msp 8 9 import ( 10 "encoding/pem" 11 "io/ioutil" 12 "os" 13 "path/filepath" 14 15 "github.com/golang/protobuf/proto" 16 "github.com/hyperledger/fabric-protos-go/msp" 17 "github.com/hyperledger/fabric/bccsp" 18 "github.com/hyperledger/fabric/bccsp/factory" 19 "github.com/pkg/errors" 20 "gopkg.in/yaml.v2" 21 ) 22 23 // OrganizationalUnitIdentifiersConfiguration is used to represent an OU 24 // and an associated trusted certificate 25 type OrganizationalUnitIdentifiersConfiguration struct { 26 // Certificate is the path to a root or intermediate certificate 27 Certificate string `yaml:"Certificate,omitempty"` 28 // OrganizationalUnitIdentifier is the name of the OU 29 OrganizationalUnitIdentifier string `yaml:"OrganizationalUnitIdentifier,omitempty"` 30 } 31 32 // NodeOUs contains information on how to tell apart clients, peers and orderers 33 // based on OUs. If the check is enforced, by setting Enabled to true, 34 // the MSP will consider an identity valid if it is an identity of a client, a peer or 35 // an orderer. An identity should have only one of these special OUs. 36 type NodeOUs struct { 37 // Enable activates the OU enforcement 38 Enable bool `yaml:"Enable,omitempty"` 39 // ClientOUIdentifier specifies how to recognize clients by OU 40 ClientOUIdentifier *OrganizationalUnitIdentifiersConfiguration `yaml:"ClientOUIdentifier,omitempty"` 41 // PeerOUIdentifier specifies how to recognize peers by OU 42 PeerOUIdentifier *OrganizationalUnitIdentifiersConfiguration `yaml:"PeerOUIdentifier,omitempty"` 43 // AdminOUIdentifier specifies how to recognize admins by OU 44 AdminOUIdentifier *OrganizationalUnitIdentifiersConfiguration `yaml:"AdminOUIdentifier,omitempty"` 45 // OrdererOUIdentifier specifies how to recognize admins by OU 46 OrdererOUIdentifier *OrganizationalUnitIdentifiersConfiguration `yaml:"OrdererOUIdentifier,omitempty"` 47 } 48 49 // Configuration represents the accessory configuration an MSP can be equipped with. 50 // By default, this configuration is stored in a yaml file 51 type Configuration struct { 52 // OrganizationalUnitIdentifiers is a list of OUs. If this is set, the MSP 53 // will consider an identity valid only it contains at least one of these OUs 54 OrganizationalUnitIdentifiers []*OrganizationalUnitIdentifiersConfiguration `yaml:"OrganizationalUnitIdentifiers,omitempty"` 55 // NodeOUs enables the MSP to tell apart clients, peers and orderers based 56 // on the identity's OU. 57 NodeOUs *NodeOUs `yaml:"NodeOUs,omitempty"` 58 } 59 60 func readFile(file string) ([]byte, error) { 61 fileCont, err := ioutil.ReadFile(file) 62 if err != nil { 63 return nil, errors.Wrapf(err, "could not read file %s", file) 64 } 65 66 return fileCont, nil 67 } 68 69 func readPemFile(file string) ([]byte, error) { 70 bytes, err := readFile(file) 71 if err != nil { 72 return nil, errors.Wrapf(err, "reading from file %s failed", file) 73 } 74 75 b, _ := pem.Decode(bytes) 76 if b == nil { // TODO: also check that the type is what we expect (cert vs key..) 77 return nil, errors.Errorf("no pem content for file %s", file) 78 } 79 80 return bytes, nil 81 } 82 83 func getPemMaterialFromDir(dir string) ([][]byte, error) { 84 mspLogger.Debugf("Reading directory %s", dir) 85 86 _, err := os.Stat(dir) 87 if os.IsNotExist(err) { 88 return nil, err 89 } 90 91 content := make([][]byte, 0) 92 files, err := ioutil.ReadDir(dir) 93 if err != nil { 94 return nil, errors.Wrapf(err, "could not read directory %s", dir) 95 } 96 97 for _, f := range files { 98 fullName := filepath.Join(dir, f.Name()) 99 100 f, err := os.Stat(fullName) 101 if err != nil { 102 mspLogger.Warningf("Failed to stat %s: %s", fullName, err) 103 continue 104 } 105 if f.IsDir() { 106 continue 107 } 108 109 mspLogger.Debugf("Inspecting file %s", fullName) 110 111 item, err := readPemFile(fullName) 112 if err != nil { 113 mspLogger.Warningf("Failed reading file %s: %s", fullName, err) 114 continue 115 } 116 117 content = append(content, item) 118 } 119 120 return content, nil 121 } 122 123 const ( 124 cacerts = "cacerts" 125 admincerts = "admincerts" 126 signcerts = "signcerts" 127 keystore = "keystore" 128 intermediatecerts = "intermediatecerts" 129 crlsfolder = "crls" 130 configfilename = "config.yaml" 131 tlscacerts = "tlscacerts" 132 tlsintermediatecerts = "tlsintermediatecerts" 133 ) 134 135 func SetupBCCSPKeystoreConfig(bccspConfig *factory.FactoryOpts, keystoreDir string) *factory.FactoryOpts { 136 if bccspConfig == nil { 137 bccspConfig = factory.GetDefaultOpts() 138 } 139 140 if bccspConfig.ProviderName == "SW" || bccspConfig.SwOpts != nil { 141 if bccspConfig.SwOpts == nil { 142 bccspConfig.SwOpts = factory.GetDefaultOpts().SwOpts 143 } 144 145 // Only override the KeyStorePath if it was left empty 146 if bccspConfig.SwOpts.FileKeystore == nil || 147 bccspConfig.SwOpts.FileKeystore.KeyStorePath == "" { 148 bccspConfig.SwOpts.Ephemeral = false 149 bccspConfig.SwOpts.FileKeystore = &factory.FileKeystoreOpts{KeyStorePath: keystoreDir} 150 } 151 } 152 153 return bccspConfig 154 } 155 156 // GetLocalMspConfigWithType returns a local MSP 157 // configuration for the MSP in the specified 158 // directory, with the specified ID and type 159 func GetLocalMspConfigWithType(dir string, bccspConfig *factory.FactoryOpts, ID, mspType string) (*msp.MSPConfig, error) { 160 switch mspType { 161 case ProviderTypeToString(FABRIC): 162 return GetLocalMspConfig(dir, bccspConfig, ID) 163 case ProviderTypeToString(IDEMIX): 164 return GetIdemixMspConfig(dir, ID) 165 default: 166 return nil, errors.Errorf("unknown MSP type '%s'", mspType) 167 } 168 } 169 170 func GetLocalMspConfig(dir string, bccspConfig *factory.FactoryOpts, ID string) (*msp.MSPConfig, error) { 171 signcertDir := filepath.Join(dir, signcerts) 172 keystoreDir := filepath.Join(dir, keystore) 173 bccspConfig = SetupBCCSPKeystoreConfig(bccspConfig, keystoreDir) 174 175 err := factory.InitFactories(bccspConfig) 176 if err != nil { 177 return nil, errors.WithMessage(err, "could not initialize BCCSP Factories") 178 } 179 180 signcert, err := getPemMaterialFromDir(signcertDir) 181 if err != nil || len(signcert) == 0 { 182 return nil, errors.Wrapf(err, "could not load a valid signer certificate from directory %s", signcertDir) 183 } 184 185 /* FIXME: for now we're making the following assumptions 186 1) there is exactly one signing cert 187 2) BCCSP's KeyStore has the private key that matches SKI of 188 signing cert 189 */ 190 191 sigid := &msp.SigningIdentityInfo{PublicSigner: signcert[0], PrivateSigner: nil} 192 193 return getMspConfig(dir, ID, sigid) 194 } 195 196 // GetVerifyingMspConfig returns an MSP config given directory, ID and type 197 func GetVerifyingMspConfig(dir, ID, mspType string) (*msp.MSPConfig, error) { 198 switch mspType { 199 case ProviderTypeToString(FABRIC): 200 return getMspConfig(dir, ID, nil) 201 case ProviderTypeToString(IDEMIX): 202 return GetIdemixMspConfig(dir, ID) 203 default: 204 return nil, errors.Errorf("unknown MSP type '%s'", mspType) 205 } 206 } 207 208 func getMspConfig(dir string, ID string, sigid *msp.SigningIdentityInfo) (*msp.MSPConfig, error) { 209 cacertDir := filepath.Join(dir, cacerts) 210 admincertDir := filepath.Join(dir, admincerts) 211 intermediatecertsDir := filepath.Join(dir, intermediatecerts) 212 crlsDir := filepath.Join(dir, crlsfolder) 213 configFile := filepath.Join(dir, configfilename) 214 tlscacertDir := filepath.Join(dir, tlscacerts) 215 tlsintermediatecertsDir := filepath.Join(dir, tlsintermediatecerts) 216 217 cacerts, err := getPemMaterialFromDir(cacertDir) 218 if err != nil || len(cacerts) == 0 { 219 return nil, errors.WithMessagef(err, "could not load a valid ca certificate from directory %s", cacertDir) 220 } 221 222 admincert, err := getPemMaterialFromDir(admincertDir) 223 if err != nil && !os.IsNotExist(err) { 224 return nil, errors.WithMessagef(err, "could not load a valid admin certificate from directory %s", admincertDir) 225 } 226 227 intermediatecerts, err := getPemMaterialFromDir(intermediatecertsDir) 228 if os.IsNotExist(err) { 229 mspLogger.Debugf("Intermediate certs folder not found at [%s]. Skipping. [%s]", intermediatecertsDir, err) 230 } else if err != nil { 231 return nil, errors.WithMessagef(err, "failed loading intermediate ca certs at [%s]", intermediatecertsDir) 232 } 233 234 tlsCACerts, err := getPemMaterialFromDir(tlscacertDir) 235 tlsIntermediateCerts := [][]byte{} 236 if os.IsNotExist(err) { 237 mspLogger.Debugf("TLS CA certs folder not found at [%s]. Skipping and ignoring TLS intermediate CA folder. [%s]", tlsintermediatecertsDir, err) 238 } else if err != nil { 239 return nil, errors.WithMessagef(err, "failed loading TLS ca certs at [%s]", tlsintermediatecertsDir) 240 } else if len(tlsCACerts) != 0 { 241 tlsIntermediateCerts, err = getPemMaterialFromDir(tlsintermediatecertsDir) 242 if os.IsNotExist(err) { 243 mspLogger.Debugf("TLS intermediate certs folder not found at [%s]. Skipping. [%s]", tlsintermediatecertsDir, err) 244 } else if err != nil { 245 return nil, errors.WithMessagef(err, "failed loading TLS intermediate ca certs at [%s]", tlsintermediatecertsDir) 246 } 247 } else { 248 mspLogger.Debugf("TLS CA certs folder at [%s] is empty. Skipping.", tlsintermediatecertsDir) 249 } 250 251 crls, err := getPemMaterialFromDir(crlsDir) 252 if os.IsNotExist(err) { 253 mspLogger.Debugf("crls folder not found at [%s]. Skipping. [%s]", crlsDir, err) 254 } else if err != nil { 255 return nil, errors.WithMessagef(err, "failed loading crls at [%s]", crlsDir) 256 } 257 258 // Load configuration file 259 // if the configuration file is there then load it 260 // otherwise skip it 261 var ouis []*msp.FabricOUIdentifier 262 var nodeOUs *msp.FabricNodeOUs 263 _, err = os.Stat(configFile) 264 if err == nil { 265 // load the file, if there is a failure in loading it then 266 // return an error 267 raw, err := ioutil.ReadFile(configFile) 268 if err != nil { 269 return nil, errors.Wrapf(err, "failed loading configuration file at [%s]", configFile) 270 } 271 272 configuration := Configuration{} 273 err = yaml.Unmarshal(raw, &configuration) 274 if err != nil { 275 return nil, errors.Wrapf(err, "failed unmarshalling configuration file at [%s]", configFile) 276 } 277 278 // Prepare OrganizationalUnitIdentifiers 279 if len(configuration.OrganizationalUnitIdentifiers) > 0 { 280 for _, ouID := range configuration.OrganizationalUnitIdentifiers { 281 f := filepath.Join(dir, ouID.Certificate) 282 raw, err = readFile(f) 283 if err != nil { 284 return nil, errors.Wrapf(err, "failed loading OrganizationalUnit certificate at [%s]", f) 285 } 286 287 oui := &msp.FabricOUIdentifier{ 288 Certificate: raw, 289 OrganizationalUnitIdentifier: ouID.OrganizationalUnitIdentifier, 290 } 291 ouis = append(ouis, oui) 292 } 293 } 294 295 // Prepare NodeOUs 296 if configuration.NodeOUs != nil && configuration.NodeOUs.Enable { 297 mspLogger.Debug("Loading NodeOUs") 298 nodeOUs = &msp.FabricNodeOUs{ 299 Enable: true, 300 } 301 if configuration.NodeOUs.ClientOUIdentifier != nil && len(configuration.NodeOUs.ClientOUIdentifier.OrganizationalUnitIdentifier) != 0 { 302 nodeOUs.ClientOuIdentifier = &msp.FabricOUIdentifier{OrganizationalUnitIdentifier: configuration.NodeOUs.ClientOUIdentifier.OrganizationalUnitIdentifier} 303 } 304 if configuration.NodeOUs.PeerOUIdentifier != nil && len(configuration.NodeOUs.PeerOUIdentifier.OrganizationalUnitIdentifier) != 0 { 305 nodeOUs.PeerOuIdentifier = &msp.FabricOUIdentifier{OrganizationalUnitIdentifier: configuration.NodeOUs.PeerOUIdentifier.OrganizationalUnitIdentifier} 306 } 307 if configuration.NodeOUs.AdminOUIdentifier != nil && len(configuration.NodeOUs.AdminOUIdentifier.OrganizationalUnitIdentifier) != 0 { 308 nodeOUs.AdminOuIdentifier = &msp.FabricOUIdentifier{OrganizationalUnitIdentifier: configuration.NodeOUs.AdminOUIdentifier.OrganizationalUnitIdentifier} 309 } 310 if configuration.NodeOUs.OrdererOUIdentifier != nil && len(configuration.NodeOUs.OrdererOUIdentifier.OrganizationalUnitIdentifier) != 0 { 311 nodeOUs.OrdererOuIdentifier = &msp.FabricOUIdentifier{OrganizationalUnitIdentifier: configuration.NodeOUs.OrdererOUIdentifier.OrganizationalUnitIdentifier} 312 } 313 314 // Read certificates, if defined 315 316 // ClientOU 317 if nodeOUs.ClientOuIdentifier != nil { 318 nodeOUs.ClientOuIdentifier.Certificate = loadCertificateAt(dir, configuration.NodeOUs.ClientOUIdentifier.Certificate, "ClientOU") 319 } 320 // PeerOU 321 if nodeOUs.PeerOuIdentifier != nil { 322 nodeOUs.PeerOuIdentifier.Certificate = loadCertificateAt(dir, configuration.NodeOUs.PeerOUIdentifier.Certificate, "PeerOU") 323 } 324 // AdminOU 325 if nodeOUs.AdminOuIdentifier != nil { 326 nodeOUs.AdminOuIdentifier.Certificate = loadCertificateAt(dir, configuration.NodeOUs.AdminOUIdentifier.Certificate, "AdminOU") 327 } 328 // OrdererOU 329 if nodeOUs.OrdererOuIdentifier != nil { 330 nodeOUs.OrdererOuIdentifier.Certificate = loadCertificateAt(dir, configuration.NodeOUs.OrdererOUIdentifier.Certificate, "OrdererOU") 331 } 332 } 333 } else { 334 mspLogger.Debugf("MSP configuration file not found at [%s]: [%s]", configFile, err) 335 } 336 337 // Set FabricCryptoConfig 338 cryptoConfig := &msp.FabricCryptoConfig{ 339 SignatureHashFamily: bccsp.SHA2, 340 IdentityIdentifierHashFunction: bccsp.SHA256, 341 } 342 343 // Compose FabricMSPConfig 344 fmspconf := &msp.FabricMSPConfig{ 345 Admins: admincert, 346 RootCerts: cacerts, 347 IntermediateCerts: intermediatecerts, 348 SigningIdentity: sigid, 349 Name: ID, 350 OrganizationalUnitIdentifiers: ouis, 351 RevocationList: crls, 352 CryptoConfig: cryptoConfig, 353 TlsRootCerts: tlsCACerts, 354 TlsIntermediateCerts: tlsIntermediateCerts, 355 FabricNodeOus: nodeOUs, 356 } 357 358 fmpsjs, _ := proto.Marshal(fmspconf) 359 360 mspconf := &msp.MSPConfig{Config: fmpsjs, Type: int32(FABRIC)} 361 362 return mspconf, nil 363 } 364 365 func loadCertificateAt(dir, certificatePath string, ouType string) []byte { 366 f := filepath.Join(dir, certificatePath) 367 raw, err := readFile(f) 368 if err != nil { 369 mspLogger.Warnf("Failed loading %s certificate at [%s]: [%s]", ouType, f, err) 370 } else { 371 return raw 372 } 373 374 return nil 375 } 376 377 const ( 378 IdemixConfigDirMsp = "msp" 379 IdemixConfigDirUser = "user" 380 IdemixConfigFileIssuerPublicKey = "IssuerPublicKey" 381 IdemixConfigFileRevocationPublicKey = "RevocationPublicKey" 382 IdemixConfigFileSigner = "SignerConfig" 383 ) 384 385 // GetIdemixMspConfig returns the configuration for the Idemix MSP 386 func GetIdemixMspConfig(dir string, ID string) (*msp.MSPConfig, error) { 387 ipkBytes, err := readFile(filepath.Join(dir, IdemixConfigDirMsp, IdemixConfigFileIssuerPublicKey)) 388 if err != nil { 389 return nil, errors.Wrapf(err, "failed to read issuer public key file") 390 } 391 392 revocationPkBytes, err := readFile(filepath.Join(dir, IdemixConfigDirMsp, IdemixConfigFileRevocationPublicKey)) 393 if err != nil { 394 return nil, errors.Wrapf(err, "failed to read revocation public key file") 395 } 396 397 idemixConfig := &msp.IdemixMSPConfig{ 398 Name: ID, 399 Ipk: ipkBytes, 400 RevocationPk: revocationPkBytes, 401 } 402 403 signerBytes, err := readFile(filepath.Join(dir, IdemixConfigDirUser, IdemixConfigFileSigner)) 404 if err == nil { 405 signerConfig := &msp.IdemixMSPSignerConfig{} 406 err = proto.Unmarshal(signerBytes, signerConfig) 407 if err != nil { 408 return nil, err 409 } 410 idemixConfig.Signer = signerConfig 411 } 412 413 confBytes, err := proto.Marshal(idemixConfig) 414 if err != nil { 415 return nil, err 416 } 417 418 return &msp.MSPConfig{Config: confBytes, Type: int32(IDEMIX)}, nil 419 }