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