github.com/dddengyunjie/fabric-ca@v0.0.0-20190606043049-92df60ae2f0f/cmd/fabric-ca-client/command/getcainfo.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 command 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/cloudflare/cfssl/log" 31 "github.com/hyperledger/fabric-ca/api" 32 "github.com/hyperledger/fabric-ca/lib" 33 "github.com/hyperledger/fabric-ca/util" 34 "github.com/pkg/errors" 35 "github.com/spf13/cobra" 36 "github.com/tjfoc/gmsm/sm2" 37 ) 38 39 const ( 40 // GetCAInfoCmdUsage is the usage text for getCACert command 41 GetCAInfoCmdUsage = "getcainfo -u http://serverAddr:serverPort -M <MSP-directory>" 42 // GetCAInfoCmdShortDesc is the short description for getCACert command 43 GetCAInfoCmdShortDesc = "Get CA certificate chain and Idemix public key" 44 ) 45 46 type getCAInfoCmd struct { 47 Command 48 } 49 50 func newGetCAInfoCmd(c Command) *getCAInfoCmd { 51 getcacertcmd := &getCAInfoCmd{c} 52 return getcacertcmd 53 } 54 55 func (c *getCAInfoCmd) getCommand() *cobra.Command { 56 cmd := &cobra.Command{ 57 Use: GetCAInfoCmdUsage, 58 Short: GetCAInfoCmdShortDesc, 59 Aliases: []string{"getcacert"}, 60 PreRunE: c.preRunGetCACert, 61 RunE: c.runGetCACert, 62 } 63 return cmd 64 } 65 66 func (c *getCAInfoCmd) preRunGetCACert(cmd *cobra.Command, args []string) error { 67 if len(args) > 0 { 68 return errors.Errorf(extraArgsError, args, cmd.UsageString()) 69 } 70 71 err := c.ConfigInit() 72 if err != nil { 73 return err 74 } 75 76 log.Debugf("Client configuration settings: %+v", c.GetClientCfg()) 77 78 return nil 79 } 80 81 func (c *getCAInfoCmd) runGetCACert(cmd *cobra.Command, args []string) error { 82 log.Debug("Entered runGetCACert") 83 84 client := &lib.Client{ 85 HomeDir: filepath.Dir(c.GetCfgFileName()), 86 Config: c.GetClientCfg(), 87 } 88 89 req := &api.GetCAInfoRequest{ 90 CAName: c.GetClientCfg().CAName, 91 } 92 93 si, err := client.GetCAInfo(req) 94 if err != nil { 95 return err 96 } 97 98 err = storeCAChain(client.Config, si) 99 if err != nil { 100 return err 101 } 102 err = storeIssuerPublicKey(client.Config, si) 103 if err != nil { 104 return err 105 } 106 return storeIssuerRevocationPublicKey(client.Config, si) 107 } 108 109 // Store the CAChain in the CACerts folder of MSP (Membership Service Provider) 110 // The root cert in the chain goes into MSP 'cacerts' directory. 111 // The others (if any) go into the MSP 'intermediatecerts' directory. 112 func storeCAChain(config *lib.ClientConfig, si *lib.GetCAInfoResponse) error { 113 mspDir := config.MSPDir 114 // Get a unique name to use for filenames 115 serverURL, err := url.Parse(config.URL) 116 if err != nil { 117 return err 118 } 119 fname := serverURL.Host 120 if config.CAName != "" { 121 fname = fmt.Sprintf("%s-%s", fname, config.CAName) 122 } 123 fname = strings.Replace(fname, ":", "-", -1) 124 fname = strings.Replace(fname, ".", "-", -1) + ".pem" 125 tlsfname := fmt.Sprintf("tls-%s", fname) 126 127 rootCACertsDir := path.Join(mspDir, "cacerts") 128 intCACertsDir := path.Join(mspDir, "intermediatecerts") 129 tlsRootCACertsDir := path.Join(mspDir, "tlscacerts") 130 tlsIntCACertsDir := path.Join(mspDir, "tlsintermediatecerts") 131 132 var rootBlks [][]byte 133 var intBlks [][]byte 134 chain := si.CAChain 135 for len(chain) > 0 { 136 var block *pem.Block 137 block, chain = pem.Decode(chain) 138 if block == nil { 139 break 140 } 141 142 cert, err := sm2.ParseCertificate(block.Bytes) 143 if err != nil { 144 return errors.Wrap(err, "Failed to parse certificate in the CA chain") 145 } 146 147 if !cert.IsCA { 148 return errors.New("A certificate in the CA chain is not a CA certificate") 149 } 150 151 // If authority key id is not present or if it is present and equal to subject key id, 152 // then it is a root certificate 153 if len(cert.AuthorityKeyId) == 0 || bytes.Equal(cert.AuthorityKeyId, cert.SubjectKeyId) { 154 rootBlks = append(rootBlks, pem.EncodeToMemory(block)) 155 } else { 156 intBlks = append(intBlks, pem.EncodeToMemory(block)) 157 } 158 } 159 160 // Store the root certificates in the "cacerts" msp folder 161 certBytes := bytes.Join(rootBlks, []byte("")) 162 if len(certBytes) > 0 { 163 if config.Enrollment.Profile == "tls" { 164 err := storeToFile("TLS root CA certificate", tlsRootCACertsDir, tlsfname, certBytes) 165 if err != nil { 166 return err 167 } 168 } else { 169 err = storeToFile("root CA certificate", rootCACertsDir, fname, certBytes) 170 if err != nil { 171 return err 172 } 173 } 174 } 175 176 // Store the intermediate certificates in the "intermediatecerts" msp folder 177 certBytes = bytes.Join(intBlks, []byte("")) 178 if len(certBytes) > 0 { 179 if config.Enrollment.Profile == "tls" { 180 err = storeToFile("TLS intermediate certificates", tlsIntCACertsDir, tlsfname, certBytes) 181 if err != nil { 182 return err 183 } 184 } else { 185 err = storeToFile("intermediate CA certificates", intCACertsDir, fname, certBytes) 186 if err != nil { 187 return err 188 } 189 } 190 } 191 return nil 192 } 193 194 func storeIssuerPublicKey(config *lib.ClientConfig, si *lib.GetCAInfoResponse) error { 195 if len(si.IssuerPublicKey) > 0 { 196 err := storeToFile("Issuer public key", config.MSPDir, "IssuerPublicKey", si.IssuerPublicKey) 197 if err != nil { 198 return err 199 } 200 } 201 return nil 202 } 203 204 func storeIssuerRevocationPublicKey(config *lib.ClientConfig, si *lib.GetCAInfoResponse) error { 205 if len(si.IssuerRevocationPublicKey) > 0 { 206 err := storeToFile("Issuer revocation public key", config.MSPDir, "IssuerRevocationPublicKey", si.IssuerRevocationPublicKey) 207 if err != nil { 208 return err 209 } 210 } 211 return nil 212 } 213 214 func storeToFile(what, dir, fname string, contents []byte) error { 215 err := os.MkdirAll(dir, 0755) 216 if err != nil { 217 return errors.Wrapf(err, "Failed to create directory for %s at '%s'", what, dir) 218 } 219 fpath := path.Join(dir, fname) 220 err = util.WriteFile(fpath, contents, 0644) 221 if err != nil { 222 return errors.WithMessage(err, fmt.Sprintf("Failed to store %s at '%s'", what, fpath)) 223 } 224 log.Infof("Stored %s at %s", what, fpath) 225 return nil 226 }