github.com/blockchain-gm/fabric-ca@v0.0.0-20200423072702-b2c40c7ac69c/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 log.Debug("chain----------------", string(chain)) 143 cert, err := sm2.ParseCertificate(block.Bytes) 144 if err != nil { 145 return errors.Wrap(err, "Failed to parse certificate in the CA chain") 146 } 147 148 if !cert.IsCA { 149 return errors.New("A certificate in the CA chain is not a CA certificate") 150 } 151 152 // If authority key id is not present or if it is present and equal to subject key id, 153 // then it is a root certificate 154 if len(cert.AuthorityKeyId) == 0 || bytes.Equal(cert.AuthorityKeyId, cert.SubjectKeyId) { 155 rootBlks = append(rootBlks, pem.EncodeToMemory(block)) 156 } else { 157 intBlks = append(intBlks, pem.EncodeToMemory(block)) 158 } 159 } 160 161 // Store the root certificates in the "cacerts" msp folder 162 certBytes := bytes.Join(rootBlks, []byte("")) 163 if len(certBytes) > 0 { 164 if config.Enrollment.Profile == "tls" { 165 err := storeToFile("TLS root CA certificate", tlsRootCACertsDir, tlsfname, certBytes) 166 if err != nil { 167 return err 168 } 169 } else { 170 err = storeToFile("root CA certificate", rootCACertsDir, fname, certBytes) 171 if err != nil { 172 return err 173 } 174 } 175 } 176 177 // Store the intermediate certificates in the "intermediatecerts" msp folder 178 certBytes = bytes.Join(intBlks, []byte("")) 179 if len(certBytes) > 0 { 180 if config.Enrollment.Profile == "tls" { 181 err = storeToFile("TLS intermediate certificates", tlsIntCACertsDir, tlsfname, certBytes) 182 if err != nil { 183 return err 184 } 185 } else { 186 err = storeToFile("intermediate CA certificates", intCACertsDir, fname, certBytes) 187 if err != nil { 188 return err 189 } 190 } 191 } 192 return nil 193 } 194 195 func storeIssuerPublicKey(config *lib.ClientConfig, si *lib.GetCAInfoResponse) error { 196 if len(si.IssuerPublicKey) > 0 { 197 err := storeToFile("Issuer public key", config.MSPDir, "IssuerPublicKey", si.IssuerPublicKey) 198 if err != nil { 199 return err 200 } 201 } 202 return nil 203 } 204 205 func storeIssuerRevocationPublicKey(config *lib.ClientConfig, si *lib.GetCAInfoResponse) error { 206 if len(si.IssuerRevocationPublicKey) > 0 { 207 err := storeToFile("Issuer revocation public key", config.MSPDir, "IssuerRevocationPublicKey", si.IssuerRevocationPublicKey) 208 if err != nil { 209 return err 210 } 211 } 212 return nil 213 } 214 215 func storeToFile(what, dir, fname string, contents []byte) error { 216 err := os.MkdirAll(dir, 0755) 217 if err != nil { 218 return errors.Wrapf(err, "Failed to create directory for %s at '%s'", what, dir) 219 } 220 fpath := path.Join(dir, fname) 221 err = util.WriteFile(fpath, contents, 0644) 222 if err != nil { 223 return errors.WithMessage(err, fmt.Sprintf("Failed to store %s at '%s'", what, fpath)) 224 } 225 log.Infof("Stored %s at %s", what, fpath) 226 return nil 227 }