github.com/yimialmonte/fabric@v2.1.1+incompatible/cmd/cryptogen/main.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 package main 7 8 import ( 9 "bytes" 10 "fmt" 11 "io" 12 "io/ioutil" 13 "os" 14 "path/filepath" 15 "text/template" 16 17 "github.com/hyperledger/fabric/internal/cryptogen/ca" 18 "github.com/hyperledger/fabric/internal/cryptogen/csp" 19 "github.com/hyperledger/fabric/internal/cryptogen/metadata" 20 "github.com/hyperledger/fabric/internal/cryptogen/msp" 21 22 kingpin "gopkg.in/alecthomas/kingpin.v2" 23 yaml "gopkg.in/yaml.v2" 24 ) 25 26 const ( 27 userBaseName = "User" 28 adminBaseName = "Admin" 29 defaultHostnameTemplate = "{{.Prefix}}{{.Index}}" 30 defaultCNTemplate = "{{.Hostname}}.{{.Domain}}" 31 ) 32 33 type HostnameData struct { 34 Prefix string 35 Index int 36 Domain string 37 } 38 39 type SpecData struct { 40 Hostname string 41 Domain string 42 CommonName string 43 } 44 45 type NodeTemplate struct { 46 Count int `yaml:"Count"` 47 Start int `yaml:"Start"` 48 Hostname string `yaml:"Hostname"` 49 SANS []string `yaml:"SANS"` 50 } 51 52 type NodeSpec struct { 53 isAdmin bool 54 Hostname string `yaml:"Hostname"` 55 CommonName string `yaml:"CommonName"` 56 Country string `yaml:"Country"` 57 Province string `yaml:"Province"` 58 Locality string `yaml:"Locality"` 59 OrganizationalUnit string `yaml:"OrganizationalUnit"` 60 StreetAddress string `yaml:"StreetAddress"` 61 PostalCode string `yaml:"PostalCode"` 62 SANS []string `yaml:"SANS"` 63 } 64 65 type UsersSpec struct { 66 Count int `yaml:"Count"` 67 } 68 69 type OrgSpec struct { 70 Name string `yaml:"Name"` 71 Domain string `yaml:"Domain"` 72 EnableNodeOUs bool `yaml:"EnableNodeOUs"` 73 CA NodeSpec `yaml:"CA"` 74 Template NodeTemplate `yaml:"Template"` 75 Specs []NodeSpec `yaml:"Specs"` 76 Users UsersSpec `yaml:"Users"` 77 } 78 79 type Config struct { 80 OrdererOrgs []OrgSpec `yaml:"OrdererOrgs"` 81 PeerOrgs []OrgSpec `yaml:"PeerOrgs"` 82 } 83 84 var defaultConfig = ` 85 # --------------------------------------------------------------------------- 86 # "OrdererOrgs" - Definition of organizations managing orderer nodes 87 # --------------------------------------------------------------------------- 88 OrdererOrgs: 89 # --------------------------------------------------------------------------- 90 # Orderer 91 # --------------------------------------------------------------------------- 92 - Name: Orderer 93 Domain: example.com 94 EnableNodeOUs: false 95 96 # --------------------------------------------------------------------------- 97 # "Specs" - See PeerOrgs below for complete description 98 # --------------------------------------------------------------------------- 99 Specs: 100 - Hostname: orderer 101 102 # --------------------------------------------------------------------------- 103 # "PeerOrgs" - Definition of organizations managing peer nodes 104 # --------------------------------------------------------------------------- 105 PeerOrgs: 106 # --------------------------------------------------------------------------- 107 # Org1 108 # --------------------------------------------------------------------------- 109 - Name: Org1 110 Domain: org1.example.com 111 EnableNodeOUs: false 112 113 # --------------------------------------------------------------------------- 114 # "CA" 115 # --------------------------------------------------------------------------- 116 # Uncomment this section to enable the explicit definition of the CA for this 117 # organization. This entry is a Spec. See "Specs" section below for details. 118 # --------------------------------------------------------------------------- 119 # CA: 120 # Hostname: ca # implicitly ca.org1.example.com 121 # Country: US 122 # Province: California 123 # Locality: San Francisco 124 # OrganizationalUnit: Hyperledger Fabric 125 # StreetAddress: address for org # default nil 126 # PostalCode: postalCode for org # default nil 127 128 # --------------------------------------------------------------------------- 129 # "Specs" 130 # --------------------------------------------------------------------------- 131 # Uncomment this section to enable the explicit definition of hosts in your 132 # configuration. Most users will want to use Template, below 133 # 134 # Specs is an array of Spec entries. Each Spec entry consists of two fields: 135 # - Hostname: (Required) The desired hostname, sans the domain. 136 # - CommonName: (Optional) Specifies the template or explicit override for 137 # the CN. By default, this is the template: 138 # 139 # "{{.Hostname}}.{{.Domain}}" 140 # 141 # which obtains its values from the Spec.Hostname and 142 # Org.Domain, respectively. 143 # - SANS: (Optional) Specifies one or more Subject Alternative Names 144 # to be set in the resulting x509. Accepts template 145 # variables {{.Hostname}}, {{.Domain}}, {{.CommonName}}. IP 146 # addresses provided here will be properly recognized. Other 147 # values will be taken as DNS names. 148 # NOTE: Two implicit entries are created for you: 149 # - {{ .CommonName }} 150 # - {{ .Hostname }} 151 # --------------------------------------------------------------------------- 152 # Specs: 153 # - Hostname: foo # implicitly "foo.org1.example.com" 154 # CommonName: foo27.org5.example.com # overrides Hostname-based FQDN set above 155 # SANS: 156 # - "bar.{{.Domain}}" 157 # - "altfoo.{{.Domain}}" 158 # - "{{.Hostname}}.org6.net" 159 # - 172.16.10.31 160 # - Hostname: bar 161 # - Hostname: baz 162 163 # --------------------------------------------------------------------------- 164 # "Template" 165 # --------------------------------------------------------------------------- 166 # Allows for the definition of 1 or more hosts that are created sequentially 167 # from a template. By default, this looks like "peer%d" from 0 to Count-1. 168 # You may override the number of nodes (Count), the starting index (Start) 169 # or the template used to construct the name (Hostname). 170 # 171 # Note: Template and Specs are not mutually exclusive. You may define both 172 # sections and the aggregate nodes will be created for you. Take care with 173 # name collisions 174 # --------------------------------------------------------------------------- 175 Template: 176 Count: 1 177 # Start: 5 178 # Hostname: {{.Prefix}}{{.Index}} # default 179 # SANS: 180 # - "{{.Hostname}}.alt.{{.Domain}}" 181 182 # --------------------------------------------------------------------------- 183 # "Users" 184 # --------------------------------------------------------------------------- 185 # Count: The number of user accounts _in addition_ to Admin 186 # --------------------------------------------------------------------------- 187 Users: 188 Count: 1 189 190 # --------------------------------------------------------------------------- 191 # Org2: See "Org1" for full specification 192 # --------------------------------------------------------------------------- 193 - Name: Org2 194 Domain: org2.example.com 195 EnableNodeOUs: false 196 Template: 197 Count: 1 198 Users: 199 Count: 1 200 ` 201 202 //command line flags 203 var ( 204 app = kingpin.New("cryptogen", "Utility for generating Hyperledger Fabric key material") 205 206 gen = app.Command("generate", "Generate key material") 207 outputDir = gen.Flag("output", "The output directory in which to place artifacts").Default("crypto-config").String() 208 genConfigFile = gen.Flag("config", "The configuration template to use").File() 209 210 showtemplate = app.Command("showtemplate", "Show the default configuration template") 211 212 version = app.Command("version", "Show version information") 213 ext = app.Command("extend", "Extend existing network") 214 inputDir = ext.Flag("input", "The input directory in which existing network place").Default("crypto-config").String() 215 extConfigFile = ext.Flag("config", "The configuration template to use").File() 216 ) 217 218 func main() { 219 kingpin.Version("0.0.1") 220 switch kingpin.MustParse(app.Parse(os.Args[1:])) { 221 222 // "generate" command 223 case gen.FullCommand(): 224 generate() 225 226 case ext.FullCommand(): 227 extend() 228 229 // "showtemplate" command 230 case showtemplate.FullCommand(): 231 fmt.Print(defaultConfig) 232 os.Exit(0) 233 234 // "version" command 235 case version.FullCommand(): 236 printVersion() 237 } 238 239 } 240 241 func getConfig() (*Config, error) { 242 var configData string 243 244 if *genConfigFile != nil { 245 data, err := ioutil.ReadAll(*genConfigFile) 246 if err != nil { 247 return nil, fmt.Errorf("Error reading configuration: %s", err) 248 } 249 250 configData = string(data) 251 } else if *extConfigFile != nil { 252 data, err := ioutil.ReadAll(*extConfigFile) 253 if err != nil { 254 return nil, fmt.Errorf("Error reading configuration: %s", err) 255 } 256 257 configData = string(data) 258 } else { 259 configData = defaultConfig 260 } 261 262 config := &Config{} 263 err := yaml.Unmarshal([]byte(configData), &config) 264 if err != nil { 265 return nil, fmt.Errorf("Error Unmarshaling YAML: %s", err) 266 } 267 268 return config, nil 269 } 270 271 func extend() { 272 config, err := getConfig() 273 if err != nil { 274 fmt.Printf("Error reading config: %s", err) 275 os.Exit(-1) 276 } 277 278 for _, orgSpec := range config.PeerOrgs { 279 err = renderOrgSpec(&orgSpec, "peer") 280 if err != nil { 281 fmt.Printf("Error processing peer configuration: %s", err) 282 os.Exit(-1) 283 } 284 extendPeerOrg(orgSpec) 285 } 286 287 for _, orgSpec := range config.OrdererOrgs { 288 err = renderOrgSpec(&orgSpec, "orderer") 289 if err != nil { 290 fmt.Printf("Error processing orderer configuration: %s", err) 291 os.Exit(-1) 292 } 293 extendOrdererOrg(orgSpec) 294 } 295 296 } 297 298 func extendPeerOrg(orgSpec OrgSpec) { 299 orgName := orgSpec.Domain 300 orgDir := filepath.Join(*inputDir, "peerOrganizations", orgName) 301 if _, err := os.Stat(orgDir); os.IsNotExist(err) { 302 generatePeerOrg(*inputDir, orgSpec) 303 return 304 } 305 306 peersDir := filepath.Join(orgDir, "peers") 307 usersDir := filepath.Join(orgDir, "users") 308 caDir := filepath.Join(orgDir, "ca") 309 tlscaDir := filepath.Join(orgDir, "tlsca") 310 311 signCA := getCA(caDir, orgSpec, orgSpec.CA.CommonName) 312 tlsCA := getCA(tlscaDir, orgSpec, "tls"+orgSpec.CA.CommonName) 313 314 generateNodes(peersDir, orgSpec.Specs, signCA, tlsCA, msp.PEER, orgSpec.EnableNodeOUs) 315 316 adminUser := NodeSpec{ 317 isAdmin: true, 318 CommonName: fmt.Sprintf("%s@%s", adminBaseName, orgName), 319 } 320 // copy the admin cert to each of the org's peer's MSP admincerts 321 for _, spec := range orgSpec.Specs { 322 if orgSpec.EnableNodeOUs { 323 continue 324 } 325 err := copyAdminCert(usersDir, 326 filepath.Join(peersDir, spec.CommonName, "msp", "admincerts"), adminUser.CommonName) 327 if err != nil { 328 fmt.Printf("Error copying admin cert for org %s peer %s:\n%v\n", 329 orgName, spec.CommonName, err) 330 os.Exit(1) 331 } 332 } 333 334 // TODO: add ability to specify usernames 335 users := []NodeSpec{} 336 for j := 1; j <= orgSpec.Users.Count; j++ { 337 user := NodeSpec{ 338 CommonName: fmt.Sprintf("%s%d@%s", userBaseName, j, orgName), 339 } 340 341 users = append(users, user) 342 } 343 344 generateNodes(usersDir, users, signCA, tlsCA, msp.CLIENT, orgSpec.EnableNodeOUs) 345 } 346 347 func extendOrdererOrg(orgSpec OrgSpec) { 348 orgName := orgSpec.Domain 349 350 orgDir := filepath.Join(*inputDir, "ordererOrganizations", orgName) 351 caDir := filepath.Join(orgDir, "ca") 352 usersDir := filepath.Join(orgDir, "users") 353 tlscaDir := filepath.Join(orgDir, "tlsca") 354 orderersDir := filepath.Join(orgDir, "orderers") 355 if _, err := os.Stat(orgDir); os.IsNotExist(err) { 356 generateOrdererOrg(*inputDir, orgSpec) 357 return 358 } 359 360 signCA := getCA(caDir, orgSpec, orgSpec.CA.CommonName) 361 tlsCA := getCA(tlscaDir, orgSpec, "tls"+orgSpec.CA.CommonName) 362 363 generateNodes(orderersDir, orgSpec.Specs, signCA, tlsCA, msp.ORDERER, orgSpec.EnableNodeOUs) 364 365 adminUser := NodeSpec{ 366 isAdmin: true, 367 CommonName: fmt.Sprintf("%s@%s", adminBaseName, orgName), 368 } 369 370 for _, spec := range orgSpec.Specs { 371 if orgSpec.EnableNodeOUs { 372 continue 373 } 374 err := copyAdminCert(usersDir, 375 filepath.Join(orderersDir, spec.CommonName, "msp", "admincerts"), adminUser.CommonName) 376 if err != nil { 377 fmt.Printf("Error copying admin cert for org %s orderer %s:\n%v\n", 378 orgName, spec.CommonName, err) 379 os.Exit(1) 380 } 381 } 382 } 383 384 func generate() { 385 386 config, err := getConfig() 387 if err != nil { 388 fmt.Printf("Error reading config: %s", err) 389 os.Exit(-1) 390 } 391 392 for _, orgSpec := range config.PeerOrgs { 393 err = renderOrgSpec(&orgSpec, "peer") 394 if err != nil { 395 fmt.Printf("Error processing peer configuration: %s", err) 396 os.Exit(-1) 397 } 398 generatePeerOrg(*outputDir, orgSpec) 399 } 400 401 for _, orgSpec := range config.OrdererOrgs { 402 err = renderOrgSpec(&orgSpec, "orderer") 403 if err != nil { 404 fmt.Printf("Error processing orderer configuration: %s", err) 405 os.Exit(-1) 406 } 407 generateOrdererOrg(*outputDir, orgSpec) 408 } 409 } 410 411 func parseTemplate(input string, data interface{}) (string, error) { 412 413 t, err := template.New("parse").Parse(input) 414 if err != nil { 415 return "", fmt.Errorf("Error parsing template: %s", err) 416 } 417 418 output := new(bytes.Buffer) 419 err = t.Execute(output, data) 420 if err != nil { 421 return "", fmt.Errorf("Error executing template: %s", err) 422 } 423 424 return output.String(), nil 425 } 426 427 func parseTemplateWithDefault(input, defaultInput string, data interface{}) (string, error) { 428 429 // Use the default if the input is an empty string 430 if len(input) == 0 { 431 input = defaultInput 432 } 433 434 return parseTemplate(input, data) 435 } 436 437 func renderNodeSpec(domain string, spec *NodeSpec) error { 438 data := SpecData{ 439 Hostname: spec.Hostname, 440 Domain: domain, 441 } 442 443 // Process our CommonName 444 cn, err := parseTemplateWithDefault(spec.CommonName, defaultCNTemplate, data) 445 if err != nil { 446 return err 447 } 448 449 spec.CommonName = cn 450 data.CommonName = cn 451 452 // Save off our original, unprocessed SANS entries 453 origSANS := spec.SANS 454 455 // Set our implicit SANS entries for CN/Hostname 456 spec.SANS = []string{cn, spec.Hostname} 457 458 // Finally, process any remaining SANS entries 459 for _, _san := range origSANS { 460 san, err := parseTemplate(_san, data) 461 if err != nil { 462 return err 463 } 464 465 spec.SANS = append(spec.SANS, san) 466 } 467 468 return nil 469 } 470 471 func renderOrgSpec(orgSpec *OrgSpec, prefix string) error { 472 // First process all of our templated nodes 473 for i := 0; i < orgSpec.Template.Count; i++ { 474 data := HostnameData{ 475 Prefix: prefix, 476 Index: i + orgSpec.Template.Start, 477 Domain: orgSpec.Domain, 478 } 479 480 hostname, err := parseTemplateWithDefault(orgSpec.Template.Hostname, defaultHostnameTemplate, data) 481 if err != nil { 482 return err 483 } 484 485 spec := NodeSpec{ 486 Hostname: hostname, 487 SANS: orgSpec.Template.SANS, 488 } 489 orgSpec.Specs = append(orgSpec.Specs, spec) 490 } 491 492 // Touch up all general node-specs to add the domain 493 for idx, spec := range orgSpec.Specs { 494 err := renderNodeSpec(orgSpec.Domain, &spec) 495 if err != nil { 496 return err 497 } 498 499 orgSpec.Specs[idx] = spec 500 } 501 502 // Process the CA node-spec in the same manner 503 if len(orgSpec.CA.Hostname) == 0 { 504 orgSpec.CA.Hostname = "ca" 505 } 506 err := renderNodeSpec(orgSpec.Domain, &orgSpec.CA) 507 if err != nil { 508 return err 509 } 510 511 return nil 512 } 513 514 func generatePeerOrg(baseDir string, orgSpec OrgSpec) { 515 516 orgName := orgSpec.Domain 517 518 fmt.Println(orgName) 519 // generate CAs 520 orgDir := filepath.Join(baseDir, "peerOrganizations", orgName) 521 caDir := filepath.Join(orgDir, "ca") 522 tlsCADir := filepath.Join(orgDir, "tlsca") 523 mspDir := filepath.Join(orgDir, "msp") 524 peersDir := filepath.Join(orgDir, "peers") 525 usersDir := filepath.Join(orgDir, "users") 526 adminCertsDir := filepath.Join(mspDir, "admincerts") 527 // generate signing CA 528 signCA, err := ca.NewCA(caDir, orgName, orgSpec.CA.CommonName, orgSpec.CA.Country, orgSpec.CA.Province, orgSpec.CA.Locality, orgSpec.CA.OrganizationalUnit, orgSpec.CA.StreetAddress, orgSpec.CA.PostalCode) 529 if err != nil { 530 fmt.Printf("Error generating signCA for org %s:\n%v\n", orgName, err) 531 os.Exit(1) 532 } 533 // generate TLS CA 534 tlsCA, err := ca.NewCA(tlsCADir, orgName, "tls"+orgSpec.CA.CommonName, orgSpec.CA.Country, orgSpec.CA.Province, orgSpec.CA.Locality, orgSpec.CA.OrganizationalUnit, orgSpec.CA.StreetAddress, orgSpec.CA.PostalCode) 535 if err != nil { 536 fmt.Printf("Error generating tlsCA for org %s:\n%v\n", orgName, err) 537 os.Exit(1) 538 } 539 540 err = msp.GenerateVerifyingMSP(mspDir, signCA, tlsCA, orgSpec.EnableNodeOUs) 541 if err != nil { 542 fmt.Printf("Error generating MSP for org %s:\n%v\n", orgName, err) 543 os.Exit(1) 544 } 545 546 generateNodes(peersDir, orgSpec.Specs, signCA, tlsCA, msp.PEER, orgSpec.EnableNodeOUs) 547 548 // TODO: add ability to specify usernames 549 users := []NodeSpec{} 550 for j := 1; j <= orgSpec.Users.Count; j++ { 551 user := NodeSpec{ 552 CommonName: fmt.Sprintf("%s%d@%s", userBaseName, j, orgName), 553 } 554 555 users = append(users, user) 556 } 557 // add an admin user 558 adminUser := NodeSpec{ 559 isAdmin: true, 560 CommonName: fmt.Sprintf("%s@%s", adminBaseName, orgName), 561 } 562 563 users = append(users, adminUser) 564 generateNodes(usersDir, users, signCA, tlsCA, msp.CLIENT, orgSpec.EnableNodeOUs) 565 566 // copy the admin cert to the org's MSP admincerts 567 if !orgSpec.EnableNodeOUs { 568 err = copyAdminCert(usersDir, adminCertsDir, adminUser.CommonName) 569 if err != nil { 570 fmt.Printf("Error copying admin cert for org %s:\n%v\n", 571 orgName, err) 572 os.Exit(1) 573 } 574 } 575 576 // copy the admin cert to each of the org's peer's MSP admincerts 577 for _, spec := range orgSpec.Specs { 578 if orgSpec.EnableNodeOUs { 579 continue 580 } 581 err = copyAdminCert(usersDir, 582 filepath.Join(peersDir, spec.CommonName, "msp", "admincerts"), adminUser.CommonName) 583 if err != nil { 584 fmt.Printf("Error copying admin cert for org %s peer %s:\n%v\n", 585 orgName, spec.CommonName, err) 586 os.Exit(1) 587 } 588 } 589 } 590 591 func copyAdminCert(usersDir, adminCertsDir, adminUserName string) error { 592 if _, err := os.Stat(filepath.Join(adminCertsDir, 593 adminUserName+"-cert.pem")); err == nil { 594 return nil 595 } 596 // delete the contents of admincerts 597 err := os.RemoveAll(adminCertsDir) 598 if err != nil { 599 return err 600 } 601 // recreate the admincerts directory 602 err = os.MkdirAll(adminCertsDir, 0755) 603 if err != nil { 604 return err 605 } 606 err = copyFile(filepath.Join(usersDir, adminUserName, "msp", "signcerts", 607 adminUserName+"-cert.pem"), filepath.Join(adminCertsDir, 608 adminUserName+"-cert.pem")) 609 if err != nil { 610 return err 611 } 612 return nil 613 } 614 615 func generateNodes(baseDir string, nodes []NodeSpec, signCA *ca.CA, tlsCA *ca.CA, nodeType int, nodeOUs bool) { 616 for _, node := range nodes { 617 nodeDir := filepath.Join(baseDir, node.CommonName) 618 if _, err := os.Stat(nodeDir); os.IsNotExist(err) { 619 currentNodeType := nodeType 620 if node.isAdmin && nodeOUs { 621 currentNodeType = msp.ADMIN 622 } 623 err := msp.GenerateLocalMSP(nodeDir, node.CommonName, node.SANS, signCA, tlsCA, currentNodeType, nodeOUs) 624 if err != nil { 625 fmt.Printf("Error generating local MSP for %v:\n%v\n", node, err) 626 os.Exit(1) 627 } 628 } 629 } 630 } 631 632 func generateOrdererOrg(baseDir string, orgSpec OrgSpec) { 633 634 orgName := orgSpec.Domain 635 636 // generate CAs 637 orgDir := filepath.Join(baseDir, "ordererOrganizations", orgName) 638 caDir := filepath.Join(orgDir, "ca") 639 tlsCADir := filepath.Join(orgDir, "tlsca") 640 mspDir := filepath.Join(orgDir, "msp") 641 orderersDir := filepath.Join(orgDir, "orderers") 642 usersDir := filepath.Join(orgDir, "users") 643 adminCertsDir := filepath.Join(mspDir, "admincerts") 644 // generate signing CA 645 signCA, err := ca.NewCA(caDir, orgName, orgSpec.CA.CommonName, orgSpec.CA.Country, orgSpec.CA.Province, orgSpec.CA.Locality, orgSpec.CA.OrganizationalUnit, orgSpec.CA.StreetAddress, orgSpec.CA.PostalCode) 646 if err != nil { 647 fmt.Printf("Error generating signCA for org %s:\n%v\n", orgName, err) 648 os.Exit(1) 649 } 650 // generate TLS CA 651 tlsCA, err := ca.NewCA(tlsCADir, orgName, "tls"+orgSpec.CA.CommonName, orgSpec.CA.Country, orgSpec.CA.Province, orgSpec.CA.Locality, orgSpec.CA.OrganizationalUnit, orgSpec.CA.StreetAddress, orgSpec.CA.PostalCode) 652 if err != nil { 653 fmt.Printf("Error generating tlsCA for org %s:\n%v\n", orgName, err) 654 os.Exit(1) 655 } 656 657 err = msp.GenerateVerifyingMSP(mspDir, signCA, tlsCA, orgSpec.EnableNodeOUs) 658 if err != nil { 659 fmt.Printf("Error generating MSP for org %s:\n%v\n", orgName, err) 660 os.Exit(1) 661 } 662 663 generateNodes(orderersDir, orgSpec.Specs, signCA, tlsCA, msp.ORDERER, orgSpec.EnableNodeOUs) 664 665 adminUser := NodeSpec{ 666 isAdmin: true, 667 CommonName: fmt.Sprintf("%s@%s", adminBaseName, orgName), 668 } 669 670 // generate an admin for the orderer org 671 users := []NodeSpec{} 672 // add an admin user 673 users = append(users, adminUser) 674 generateNodes(usersDir, users, signCA, tlsCA, msp.CLIENT, orgSpec.EnableNodeOUs) 675 676 // copy the admin cert to the org's MSP admincerts 677 if !orgSpec.EnableNodeOUs { 678 err = copyAdminCert(usersDir, adminCertsDir, adminUser.CommonName) 679 if err != nil { 680 fmt.Printf("Error copying admin cert for org %s:\n%v\n", 681 orgName, err) 682 os.Exit(1) 683 } 684 } 685 686 // copy the admin cert to each of the org's orderers's MSP admincerts 687 for _, spec := range orgSpec.Specs { 688 if orgSpec.EnableNodeOUs { 689 continue 690 } 691 err = copyAdminCert(usersDir, 692 filepath.Join(orderersDir, spec.CommonName, "msp", "admincerts"), adminUser.CommonName) 693 if err != nil { 694 fmt.Printf("Error copying admin cert for org %s orderer %s:\n%v\n", 695 orgName, spec.CommonName, err) 696 os.Exit(1) 697 } 698 } 699 700 } 701 702 func copyFile(src, dst string) error { 703 in, err := os.Open(src) 704 if err != nil { 705 return err 706 } 707 defer in.Close() 708 out, err := os.Create(dst) 709 if err != nil { 710 return err 711 } 712 defer out.Close() 713 _, err = io.Copy(out, in) 714 cerr := out.Close() 715 if err != nil { 716 return err 717 } 718 return cerr 719 } 720 721 func printVersion() { 722 fmt.Println(metadata.GetVersionInfo()) 723 } 724 725 func getCA(caDir string, spec OrgSpec, name string) *ca.CA { 726 priv, _ := csp.LoadPrivateKey(caDir) 727 cert, _ := ca.LoadCertificateECDSA(caDir) 728 729 return &ca.CA{ 730 Name: name, 731 Signer: priv, 732 SignCert: cert, 733 Country: spec.CA.Country, 734 Province: spec.CA.Province, 735 Locality: spec.CA.Locality, 736 OrganizationalUnit: spec.CA.OrganizationalUnit, 737 StreetAddress: spec.CA.StreetAddress, 738 PostalCode: spec.CA.PostalCode, 739 } 740 }