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