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  }