github.com/tw-bc-group/fabric-ca-gm@v0.0.0-20201218004200-3b690512bd5a/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 22 //"crypto/x509" 23 "encoding/pem" 24 "fmt" 25 "net/url" 26 "os" 27 "path" 28 "path/filepath" 29 "strings" 30 31 x509GM "github.com/Hyperledger-TWGC/tjfoc-gm/x509" 32 "github.com/cloudflare/cfssl/log" 33 "github.com/pkg/errors" 34 "github.com/spf13/cobra" 35 "github.com/tw-bc-group/fabric-ca-gm/api" 36 "github.com/tw-bc-group/fabric-ca-gm/lib" 37 "github.com/tw-bc-group/fabric-ca-gm/util" 38 ) 39 40 const ( 41 // GetCAInfoCmdUsage is the usage text for getCACert command 42 GetCAInfoCmdUsage = "getcainfo -u http://serverAddr:serverPort -M <MSP-directory>" 43 // GetCAInfoCmdShortDesc is the short description for getCACert command 44 GetCAInfoCmdShortDesc = "Get CA certificate chain and Idemix public key" 45 ) 46 47 type getCAInfoCmd struct { 48 Command 49 } 50 51 func newGetCAInfoCmd(c Command) *getCAInfoCmd { 52 getcacertcmd := &getCAInfoCmd{c} 53 return getcacertcmd 54 } 55 56 func (c *getCAInfoCmd) getCommand() *cobra.Command { 57 cmd := &cobra.Command{ 58 Use: GetCAInfoCmdUsage, 59 Short: GetCAInfoCmdShortDesc, 60 Aliases: []string{"getcacert"}, 61 PreRunE: c.preRunGetCACert, 62 RunE: c.runGetCACert, 63 } 64 return cmd 65 } 66 67 func (c *getCAInfoCmd) preRunGetCACert(cmd *cobra.Command, args []string) error { 68 if len(args) > 0 { 69 return errors.Errorf(extraArgsError, args, cmd.UsageString()) 70 } 71 72 err := c.ConfigInit() 73 if err != nil { 74 return err 75 } 76 77 log.Debugf("Client configuration settings: %+v", c.GetClientCfg()) 78 79 return nil 80 } 81 82 func (c *getCAInfoCmd) runGetCACert(cmd *cobra.Command, args []string) error { 83 log.Debug("Entered runGetCACert") 84 85 client := &lib.Client{ 86 HomeDir: filepath.Dir(c.GetCfgFileName()), 87 Config: c.GetClientCfg(), 88 } 89 90 req := &api.GetCAInfoRequest{ 91 CAName: c.GetClientCfg().CAName, 92 } 93 94 si, err := client.GetCAInfo(req) 95 if err != nil { 96 return err 97 } 98 99 err = storeCAChain(client.Config, si) 100 if err != nil { 101 return err 102 } 103 err = storeIssuerPublicKey(client.Config, si) 104 if err != nil { 105 return err 106 } 107 return storeIssuerRevocationPublicKey(client.Config, si) 108 } 109 110 // Store the CAChain in the CACerts folder of MSP (Membership Service Provider) 111 // The root cert in the chain goes into MSP 'cacerts' directory. 112 // The others (if any) go into the MSP 'intermediatecerts' directory. 113 func storeCAChain(config *lib.ClientConfig, si *lib.GetCAInfoResponse) error { 114 mspDir := config.MSPDir 115 // Get a unique name to use for filenames 116 serverURL, err := url.Parse(config.URL) 117 if err != nil { 118 return err 119 } 120 fname := serverURL.Host 121 if config.CAName != "" { 122 fname = fmt.Sprintf("%s-%s", fname, config.CAName) 123 } 124 fname = strings.Replace(fname, ":", "-", -1) 125 fname = strings.Replace(fname, ".", "-", -1) + ".pem" 126 tlsfname := fmt.Sprintf("tls-%s", fname) 127 128 rootCACertsDir := path.Join(mspDir, "cacerts") 129 intCACertsDir := path.Join(mspDir, "intermediatecerts") 130 tlsRootCACertsDir := path.Join(mspDir, "tlscacerts") 131 tlsIntCACertsDir := path.Join(mspDir, "tlsintermediatecerts") 132 133 var rootBlks [][]byte 134 var intBlks [][]byte 135 chain := si.CAChain 136 for len(chain) > 0 { 137 var block *pem.Block 138 block, chain = pem.Decode(chain) 139 if block == nil { 140 break 141 } 142 143 cert, err := x509GM.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 }