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  }