github.com/silveraid/fabric-ca@v1.1.0-preview.0.20180127000700-71974f53ab08/cmd/fabric-ca-client/getcacert.go (about) 1 /* 2 Copyright IBM Corp. 2017 All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package main 18 19 import ( 20 "bytes" 21 "crypto/x509" 22 "encoding/pem" 23 "fmt" 24 "net/url" 25 "os" 26 "path" 27 "path/filepath" 28 "strings" 29 30 "github.com/pkg/errors" 31 32 "github.com/cloudflare/cfssl/log" 33 "github.com/hyperledger/fabric-ca/api" 34 "github.com/hyperledger/fabric-ca/lib" 35 "github.com/hyperledger/fabric-ca/util" 36 "github.com/spf13/cobra" 37 ) 38 39 func (c *ClientCmd) newGetCACertCommand() *cobra.Command { 40 getCACertCmd := &cobra.Command{ 41 Use: "getcacert -u http://serverAddr:serverPort -M <MSP-directory>", 42 Short: "Get CA certificate chain", 43 // PreRunE block for this command will load client configuration 44 // before running the command 45 PreRunE: func(cmd *cobra.Command, args []string) error { 46 if len(args) > 0 { 47 return errors.Errorf(extraArgsError, args, cmd.UsageString()) 48 } 49 50 err := c.configInit() 51 if err != nil { 52 return err 53 } 54 55 log.Debugf("Client configuration settings: %+v", c.clientCfg) 56 57 return nil 58 }, 59 RunE: func(cmd *cobra.Command, args []string) error { 60 err := c.runGetCACert() 61 if err != nil { 62 return err 63 } 64 return nil 65 }, 66 } 67 return getCACertCmd 68 } 69 70 // The client "getcacert" main logic 71 func (c *ClientCmd) runGetCACert() error { 72 log.Debug("Entered runGetCACert") 73 74 client := &lib.Client{ 75 HomeDir: filepath.Dir(c.cfgFileName), 76 Config: c.clientCfg, 77 } 78 79 req := &api.GetCAInfoRequest{ 80 CAName: c.clientCfg.CAName, 81 } 82 83 si, err := client.GetCAInfo(req) 84 if err != nil { 85 return err 86 } 87 88 return storeCAChain(client.Config, si) 89 } 90 91 // Store the CAChain in the CACerts folder of MSP (Membership Service Provider) 92 // The root cert in the chain goes into MSP 'cacerts' directory. 93 // The others (if any) go into the MSP 'intermediatecerts' directory. 94 func storeCAChain(config *lib.ClientConfig, si *lib.GetServerInfoResponse) error { 95 mspDir := config.MSPDir 96 // Get a unique name to use for filenames 97 serverURL, err := url.Parse(config.URL) 98 if err != nil { 99 return err 100 } 101 fname := serverURL.Host 102 if config.CAName != "" { 103 fname = fmt.Sprintf("%s-%s", fname, config.CAName) 104 } 105 fname = strings.Replace(fname, ":", "-", -1) 106 fname = strings.Replace(fname, ".", "-", -1) + ".pem" 107 tlsfname := fmt.Sprintf("tls-%s", fname) 108 109 rootCACertsDir := path.Join(mspDir, "cacerts") 110 intCACertsDir := path.Join(mspDir, "intermediatecerts") 111 tlsRootCACertsDir := path.Join(mspDir, "tlscacerts") 112 tlsIntCACertsDir := path.Join(mspDir, "tlsintermediatecerts") 113 114 var rootBlks [][]byte 115 var intBlks [][]byte 116 chain := si.CAChain 117 for len(chain) > 0 { 118 var block *pem.Block 119 block, chain = pem.Decode(chain) 120 if block == nil { 121 break 122 } 123 124 cert, err := x509.ParseCertificate(block.Bytes) 125 if err != nil { 126 return errors.Wrap(err, "Failed to parse certificate in the CA chain") 127 } 128 129 if !cert.IsCA { 130 return errors.New("A certificate in the CA chain is not a CA certificate") 131 } 132 133 // If authority key id is not present or if it is present and equal to subject key id, 134 // then it is a root certificate 135 if len(cert.AuthorityKeyId) == 0 || bytes.Equal(cert.AuthorityKeyId, cert.SubjectKeyId) { 136 rootBlks = append(rootBlks, pem.EncodeToMemory(block)) 137 } else { 138 intBlks = append(intBlks, pem.EncodeToMemory(block)) 139 } 140 } 141 142 // Store the root certificates in the "cacerts" msp folder 143 certBytes := bytes.Join(rootBlks, []byte("")) 144 if config.Enrollment.Profile == "tls" { 145 err := storeCert("TLS root CA certificate", tlsRootCACertsDir, tlsfname, certBytes) 146 if err != nil { 147 return err 148 } 149 } else { 150 err = storeCert("root CA certificate", rootCACertsDir, fname, certBytes) 151 if err != nil { 152 return err 153 } 154 } 155 156 // Store the intermediate certificates in the "intermediatecerts" msp folder 157 certBytes = bytes.Join(intBlks, []byte("")) 158 if config.Enrollment.Profile == "tls" { 159 err = storeCert("TLS intermediate certificates", tlsIntCACertsDir, tlsfname, certBytes) 160 if err != nil { 161 return err 162 } 163 } else { 164 err = storeCert("intermediate CA certificates", intCACertsDir, fname, certBytes) 165 if err != nil { 166 return err 167 } 168 } 169 return nil 170 } 171 172 func storeCert(what, dir, fname string, contents []byte) error { 173 err := os.MkdirAll(dir, 0755) 174 if err != nil { 175 return errors.Wrapf(err, "Failed to create directory for %s at '%s'", what, dir) 176 } 177 fpath := path.Join(dir, fname) 178 err = util.WriteFile(fpath, contents, 0644) 179 if err != nil { 180 return errors.WithMessage(err, fmt.Sprintf("Failed to store %s at '%s'", what, fpath)) 181 } 182 log.Infof("Stored %s at %s", what, fpath) 183 return nil 184 }