github.com/tw-bc-group/fabric-ca-gm@v0.0.0-20201218004200-3b690512bd5a/util/util.go (about)

     1  /*
     2  Copyright IBM Corp. 2016 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 util
    18  
    19  import (
    20  	"bytes"
    21  	"crypto/ecdsa"
    22  	"crypto/rsa"
    23  	"crypto/x509"
    24  	"encoding/base64"
    25  	"encoding/json"
    26  	"encoding/pem"
    27  	"fmt"
    28  	"github.com/Hyperledger-TWGC/tjfoc-gm/sm2"
    29  	x509GM "github.com/Hyperledger-TWGC/tjfoc-gm/x509"
    30  	"io"
    31  	"io/ioutil"
    32  	"math/big"
    33  	mrand "math/rand"
    34  	"net/url"
    35  	"os"
    36  	"path"
    37  	"path/filepath"
    38  	"reflect"
    39  	"regexp"
    40  	"strings"
    41  	"testing"
    42  	"time"
    43  
    44  	"github.com/cloudflare/cfssl/log"
    45  	"github.com/pkg/errors"
    46  	"github.com/spf13/viper"
    47  	"github.com/stretchr/testify/assert"
    48  	"github.com/tw-bc-group/fabric-gm/bccsp"
    49  	"github.com/tw-bc-group/net-go-gm/http"
    50  	"golang.org/x/crypto/ocsp"
    51  )
    52  
    53  var (
    54  	rnd = mrand.NewSource(time.Now().UnixNano())
    55  	// ErrNotImplemented used to return errors for functions not implemented
    56  	ErrNotImplemented = errors.New("NOT YET IMPLEMENTED")
    57  )
    58  
    59  const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
    60  const (
    61  	letterIdxBits = 6                    // 6 bits to represent a letter index
    62  	letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
    63  	letterIdxMax  = 63 / letterIdxBits   // # of letter indices fitting in 63 bits
    64  )
    65  
    66  // RevocationReasonCodes is a map between string reason codes to integers as defined in RFC 5280
    67  var RevocationReasonCodes = map[string]int{
    68  	"unspecified":          ocsp.Unspecified,
    69  	"keycompromise":        ocsp.KeyCompromise,
    70  	"cacompromise":         ocsp.CACompromise,
    71  	"affiliationchanged":   ocsp.AffiliationChanged,
    72  	"superseded":           ocsp.Superseded,
    73  	"cessationofoperation": ocsp.CessationOfOperation,
    74  	"certificatehold":      ocsp.CertificateHold,
    75  	"removefromcrl":        ocsp.RemoveFromCRL,
    76  	"privilegewithdrawn":   ocsp.PrivilegeWithdrawn,
    77  	"aacompromise":         ocsp.AACompromise,
    78  }
    79  
    80  // SecretTag to tag a field as secret as in password, token
    81  const SecretTag = "mask"
    82  
    83  // URLRegex is the regular expression to check if a value is an URL
    84  var URLRegex = regexp.MustCompile("(ldap|http)s*://(\\S+):(\\S+)@")
    85  
    86  //ECDSASignature forms the structure for R and S value for ECDSA
    87  type ECDSASignature struct {
    88  	R, S *big.Int
    89  }
    90  
    91  // RandomString returns a random string
    92  func RandomString(n int) string {
    93  	b := make([]byte, n)
    94  
    95  	for i, cache, remain := n-1, rnd.Int63(), letterIdxMax; i >= 0; {
    96  		if remain == 0 {
    97  			cache, remain = rnd.Int63(), letterIdxMax
    98  		}
    99  		if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
   100  			b[i] = letterBytes[idx]
   101  			i--
   102  		}
   103  		cache >>= letterIdxBits
   104  		remain--
   105  	}
   106  
   107  	return string(b)
   108  }
   109  
   110  // RemoveQuotes removes outer quotes from a string if necessary
   111  func RemoveQuotes(str string) string {
   112  	if str == "" {
   113  		return str
   114  	}
   115  	if (strings.HasPrefix(str, "'") && strings.HasSuffix(str, "'")) ||
   116  		(strings.HasPrefix(str, "\"") && strings.HasSuffix(str, "\"")) {
   117  		str = str[1 : len(str)-1]
   118  	}
   119  	return str
   120  }
   121  
   122  // ReadFile reads a file
   123  func ReadFile(file string) ([]byte, error) {
   124  	return ioutil.ReadFile(file)
   125  }
   126  
   127  // WriteFile writes a file
   128  func WriteFile(file string, buf []byte, perm os.FileMode) error {
   129  	dir := path.Dir(file)
   130  	// Create the directory if it doesn't exist
   131  	if _, err := os.Stat(dir); os.IsNotExist(err) {
   132  		err = os.MkdirAll(dir, 0755)
   133  		if err != nil {
   134  			return errors.Wrapf(err, "Failed to create directory '%s' for file '%s'", dir, file)
   135  		}
   136  	}
   137  	return ioutil.WriteFile(file, buf, perm)
   138  }
   139  
   140  // FileExists checks to see if a file exists
   141  func FileExists(name string) bool {
   142  	if _, err := os.Stat(name); err != nil {
   143  		if os.IsNotExist(err) {
   144  			return false
   145  		}
   146  	}
   147  	return true
   148  }
   149  
   150  // Marshal to bytes
   151  func Marshal(from interface{}, what string) ([]byte, error) {
   152  	buf, err := json.Marshal(from)
   153  	if err != nil {
   154  		return nil, errors.Wrapf(err, "Failed to marshal %s", what)
   155  	}
   156  	return buf, nil
   157  }
   158  
   159  // Unmarshal from bytes
   160  func Unmarshal(from []byte, to interface{}, what string) error {
   161  	err := json.Unmarshal(from, to)
   162  	if err != nil {
   163  		return errors.Wrapf(err, "Failed to unmarshal %s", what)
   164  	}
   165  	return nil
   166  }
   167  
   168  // CreateToken creates a JWT-like token.
   169  // In a normal JWT token, the format of the token created is:
   170  //      <algorithm,claims,signature>
   171  // where each part is base64-encoded string separated by a period.
   172  // In this JWT-like token, there are two differences:
   173  // 1) the claims section is a certificate, so the format is:
   174  //      <certificate,signature>
   175  // 2) the signature uses the private key associated with the certificate,
   176  //    and the signature is across both the certificate and the "body" argument,
   177  //    which is the body of an HTTP request, though could be any arbitrary bytes.
   178  // @param cert The pem-encoded certificate
   179  // @param key The pem-encoded key
   180  // @param method http method of the request
   181  // @param uri URI of the request
   182  // @param body The body of an HTTP request
   183  func CreateToken(csp bccsp.BCCSP, cert []byte, key bccsp.Key, method, uri string, body []byte) (string, error) {
   184  	log.Debug("enter util.CreateToken")
   185  	x509Cert, err := GetX509CertificateFromPEM(cert)
   186  	if err != nil {
   187  		return "", err
   188  	}
   189  	publicKey := x509Cert.PublicKey
   190  
   191  	var token string
   192  
   193  	//The RSA Key Gen is commented right now as there is bccsp does
   194  	switch publicKey.(type) {
   195  	/*
   196  		case *rsa.PublicKey:
   197  			token, err = GenRSAToken(csp, cert, key, body)
   198  			if err != nil {
   199  				return "", err
   200  			}
   201  	*/
   202  	case *ecdsa.PublicKey:
   203  		log.Debug("publicKey.(type)=*ecdsa.PublicKey")
   204  		token, err = GenECDSAToken(csp, cert, key, method, uri, body)
   205  		if err != nil {
   206  			return "", err
   207  		}
   208  	case *sm2.PublicKey:
   209  		log.Debug("publicKey.(type)=*sm2.PublicKey")
   210  		token, err = GenECDSAToken(csp, cert, key, method, uri, body)
   211  		if err != nil {
   212  			return "", err
   213  		}
   214  	default:
   215  		log.Debugf("publicKey=%T", publicKey)
   216  	}
   217  	return token, nil
   218  }
   219  
   220  //GenRSAToken signs the http body and cert with RSA using RSA private key
   221  // @csp : BCCSP instance
   222  /*
   223  func GenRSAToken(csp bccsp.BCCSP, cert []byte, key []byte, body []byte) (string, error) {
   224  	privKey, err := GetRSAPrivateKey(key)
   225  	if err != nil {
   226  		return "", err
   227  	}
   228  	b64body := B64Encode(body)
   229  	b64cert := B64Encode(cert)
   230  	bodyAndcert := b64body + "." + b64cert
   231  	hash := sha512.New384()
   232  	hash.Write([]byte(bodyAndcert))
   233  	h := hash.Sum(nil)
   234  	RSAsignature, err := rsa.SignPKCS1v15(rand.Reader, privKey, crypto.SHA384, h[:])
   235  	if err != nil {
   236  		return "", errors.Wrap(err, "Failed to rsa.SignPKCS1v15")
   237  	}
   238  	b64sig := B64Encode(RSAsignature)
   239  	token := b64cert + "." + b64sig
   240  
   241  	return  token, nil
   242  }
   243  */
   244  
   245  //GenECDSAToken signs the http body and cert with ECDSA using EC private key
   246  func GenECDSAToken(csp bccsp.BCCSP, cert []byte, key bccsp.Key, method, uri string, body []byte) (string, error) {
   247  	b64body := B64Encode(body)
   248  	b64cert := B64Encode(cert)
   249  	b64uri := B64Encode([]byte(uri))
   250  	payload := method + "." + b64uri + "." + b64body + "." + b64cert
   251  
   252  	return genECDSAToken(csp, key, b64cert, payload)
   253  }
   254  
   255  func genECDSAToken(csp bccsp.BCCSP, key bccsp.Key, b64cert, payload string) (string, error) {
   256  	digest, digestError := csp.Hash([]byte(payload), &bccsp.SHAOpts{})
   257  	if digestError != nil {
   258  		return "", errors.WithMessage(digestError, fmt.Sprintf("Hash failed on '%s'", payload))
   259  	}
   260  
   261  	ecSignature, err := csp.Sign(key, digest, nil)
   262  	if err != nil {
   263  		return "", errors.WithMessage(err, "BCCSP signature generation failure")
   264  	}
   265  	if len(ecSignature) == 0 {
   266  		return "", errors.New("BCCSP signature creation failed. Signature must be different than nil")
   267  	}
   268  
   269  	b64sig := B64Encode(ecSignature)
   270  	token := b64cert + "." + b64sig
   271  
   272  	return token, nil
   273  
   274  }
   275  
   276  // VerifyToken verifies token signed by either ECDSA or RSA and
   277  // returns the associated user ID
   278  func VerifyToken(csp bccsp.BCCSP, token string, method, uri string, body []byte, compMode1_3 bool) (*x509.Certificate, error) {
   279  
   280  	if csp == nil {
   281  		return nil, errors.New("BCCSP instance is not present")
   282  	}
   283  	x509Cert, b64Cert, b64Sig, err := DecodeToken(token)
   284  	if err != nil {
   285  		return nil, err
   286  	}
   287  	sig, err := B64Decode(b64Sig)
   288  	if err != nil {
   289  		return nil, errors.WithMessage(err, "Invalid base64 encoded signature in token")
   290  	}
   291  	b64Body := B64Encode(body)
   292  	b64uri := B64Encode([]byte(uri))
   293  	sigString := method + "." + b64uri + "." + b64Body + "." + b64Cert
   294  
   295  	log.Infof("xxx before csp .KeyImport csp : %T b64Body %s", csp, sigString)
   296  	sm2cert := ParseX509Certificate2Sm2(x509Cert)
   297  	pk2, err := csp.KeyImport(sm2cert, &bccsp.X509PublicKeyImportOpts{Temporary: true})
   298  	log.Infof("xxx end csp .KeyImport pk2 : %T", pk2)
   299  	if err != nil {
   300  		return nil, errors.WithMessage(err, "Public Key import into BCCSP failed with error")
   301  	}
   302  	if pk2 == nil {
   303  		return nil, errors.New("Public Key Cannot be imported into BCCSP")
   304  	}
   305  
   306  	//bccsp.X509PublicKeyImportOpts
   307  	//Using default hash algo
   308  	digest, digestError := csp.Hash([]byte(sigString), &bccsp.SHAOpts{})
   309  	if digestError != nil {
   310  		return nil, errors.WithMessage(digestError, "Message digest failed")
   311  	}
   312  	log.Debugf("pk2 %T \n sig %T\n digest %s\n", pk2, sig, B64Encode(digest))
   313  	valid, validErr := csp.Verify(pk2, sig, digest, nil)
   314  	if compMode1_3 && !valid {
   315  		log.Debugf("Failed to verify token based on new authentication header requirements: %s", err)
   316  		sigString := b64Body + "." + b64Cert
   317  		digest, digestError := csp.Hash([]byte(sigString), &bccsp.SHAOpts{})
   318  		if digestError != nil {
   319  			return nil, errors.WithMessage(digestError, "Message digest failed")
   320  		}
   321  		valid, validErr = csp.Verify(pk2, sig, digest, nil)
   322  	}
   323  
   324  	if validErr != nil {
   325  		return nil, errors.WithMessage(validErr, "Token signature validation failure")
   326  	}
   327  	if !valid {
   328  		return nil, errors.New("Token signature validation failed")
   329  	}
   330  
   331  	return x509Cert, nil
   332  }
   333  
   334  // DecodeToken extracts an X509 certificate and base64 encoded signature from a token
   335  func DecodeToken(token string) (*x509.Certificate, string, string, error) {
   336  	if token == "" {
   337  		return nil, "", "", errors.New("Invalid token; it is empty")
   338  	}
   339  	parts := strings.Split(token, ".")
   340  	if len(parts) != 2 {
   341  		return nil, "", "", errors.New("Invalid token format; expecting 2 parts separated by '.'")
   342  	}
   343  	b64cert := parts[0]
   344  	certDecoded, err := B64Decode(b64cert)
   345  	if err != nil {
   346  		return nil, "", "", errors.WithMessage(err, "Failed to decode base64 encoded x509 cert")
   347  	}
   348  	x509Cert, err := GetX509CertificateFromPEM(certDecoded)
   349  	if err != nil {
   350  		return nil, "", "", errors.WithMessage(err, "Error in parsing x509 certificate given block bytes")
   351  	}
   352  	return x509Cert, b64cert, parts[1], nil
   353  }
   354  
   355  //GetECPrivateKey get *ecdsa.PrivateKey from key pem
   356  func GetECPrivateKey(raw []byte) (*ecdsa.PrivateKey, error) {
   357  	decoded, _ := pem.Decode(raw)
   358  	if decoded == nil {
   359  		return nil, errors.New("Failed to decode the PEM-encoded ECDSA key")
   360  	}
   361  	ECprivKey, err := x509.ParseECPrivateKey(decoded.Bytes)
   362  	if err == nil {
   363  		return ECprivKey, nil
   364  	}
   365  	key, err2 := x509.ParsePKCS8PrivateKey(decoded.Bytes)
   366  	if err2 == nil {
   367  		switch key.(type) {
   368  		case *ecdsa.PrivateKey:
   369  			return key.(*ecdsa.PrivateKey), nil
   370  		case *rsa.PrivateKey:
   371  			return nil, errors.New("Expecting EC private key but found RSA private key")
   372  		default:
   373  			return nil, errors.New("Invalid private key type in PKCS#8 wrapping")
   374  		}
   375  	}
   376  	return nil, errors.Wrap(err2, "Failed parsing EC private key")
   377  }
   378  
   379  //GetRSAPrivateKey get *rsa.PrivateKey from key pem
   380  func GetRSAPrivateKey(raw []byte) (*rsa.PrivateKey, error) {
   381  	decoded, _ := pem.Decode(raw)
   382  	if decoded == nil {
   383  		return nil, errors.New("Failed to decode the PEM-encoded RSA key")
   384  	}
   385  	RSAprivKey, err := x509.ParsePKCS1PrivateKey(decoded.Bytes)
   386  	if err == nil {
   387  		return RSAprivKey, nil
   388  	}
   389  	key, err2 := x509.ParsePKCS8PrivateKey(raw)
   390  	if err2 == nil {
   391  		switch key.(type) {
   392  		case *ecdsa.PrivateKey:
   393  			return nil, errors.New("Expecting RSA private key but found EC private key")
   394  		case *rsa.PrivateKey:
   395  			return key.(*rsa.PrivateKey), nil
   396  		default:
   397  			return nil, errors.New("Invalid private key type in PKCS#8 wrapping")
   398  		}
   399  	}
   400  	return nil, errors.Wrap(err, "Failed parsing RSA private key")
   401  }
   402  
   403  //GetSM2PrivateKey get *sm2.PrivateKey from key pem
   404  func GetSM2PrivateKey(raw []byte) (*sm2.PrivateKey, error) {
   405  	decoded, _ := pem.Decode(raw)
   406  	if decoded == nil {
   407  		return nil, errors.New("Failed to decode the PEM-encoded RSA key")
   408  	}
   409  	if key, err := x509GM.ParsePKCS8UnecryptedPrivateKey(decoded.Bytes); err == nil {
   410  		return key, nil
   411  	} else {
   412  		return nil, fmt.Errorf("tls: failed to parse private key %v", err)
   413  	}
   414  }
   415  
   416  // B64Encode base64 encodes bytes
   417  func B64Encode(buf []byte) string {
   418  	return base64.StdEncoding.EncodeToString(buf)
   419  }
   420  
   421  // B64Decode base64 decodes a string
   422  func B64Decode(str string) (buf []byte, err error) {
   423  	return base64.StdEncoding.DecodeString(str)
   424  }
   425  
   426  // StrContained returns true if 'str' is in 'strs'; otherwise return false
   427  func StrContained(str string, strs []string) bool {
   428  	for _, s := range strs {
   429  		if strings.ToLower(s) == strings.ToLower(str) {
   430  			return true
   431  		}
   432  	}
   433  	return false
   434  }
   435  
   436  // IsSubsetOf returns an error if there is something in 'small' that
   437  // is not in 'big'.  Both small and big are assumed to be comma-separated
   438  // strings.  All string comparisons are case-insensitive.
   439  // Examples:
   440  // 1) IsSubsetOf('a,B', 'A,B,C') returns nil
   441  // 2) IsSubsetOf('A,B,C', 'B,C') returns an error because A is not in the 2nd set.
   442  func IsSubsetOf(small, big string) error {
   443  	bigSet := strings.Split(big, ",")
   444  	smallSet := strings.Split(small, ",")
   445  	for _, s := range smallSet {
   446  		if s != "" && !StrContained(s, bigSet) {
   447  			return errors.Errorf("'%s' is not a member of '%s'", s, big)
   448  		}
   449  	}
   450  	return nil
   451  }
   452  
   453  // HTTPRequestToString returns a string for an HTTP request for debuggging
   454  func HTTPRequestToString(req *http.Request) string {
   455  	body, _ := ioutil.ReadAll(req.Body)
   456  	req.Body = ioutil.NopCloser(bytes.NewReader(body))
   457  	return fmt.Sprintf("%s %s\n%s",
   458  		req.Method, req.URL, string(body))
   459  }
   460  
   461  // HTTPResponseToString returns a string for an HTTP response for debuggging
   462  func HTTPResponseToString(resp *http.Response) string {
   463  	body, _ := ioutil.ReadAll(resp.Body)
   464  	resp.Body = ioutil.NopCloser(bytes.NewReader(body))
   465  	return fmt.Sprintf("statusCode=%d (%s)\n%s",
   466  		resp.StatusCode, resp.Status, string(body))
   467  }
   468  
   469  // CreateClientHome will create a home directory if it does not exist
   470  func CreateClientHome() (string, error) {
   471  	log.Debug("CreateHome")
   472  	home := filepath.Dir(GetDefaultConfigFile("fabric-ca-client"))
   473  
   474  	if _, err := os.Stat(home); err != nil {
   475  		if os.IsNotExist(err) {
   476  			err := os.MkdirAll(home, 0755)
   477  			if err != nil {
   478  				return "", err
   479  			}
   480  		}
   481  	}
   482  	return home, nil
   483  }
   484  
   485  // GetDefaultConfigFile gets the default path for the config file to display in usage message
   486  func GetDefaultConfigFile(cmdName string) string {
   487  	if cmdName == "fabric-ca-server" {
   488  		var fname = fmt.Sprintf("%s-config.yaml", cmdName)
   489  		// First check home env variables
   490  		home := "."
   491  		envs := []string{"FABRIC_CA_SERVER_HOME", "FABRIC_CA_HOME", "CA_CFG_PATH"}
   492  		for _, env := range envs {
   493  			envVal := os.Getenv(env)
   494  			if envVal != "" {
   495  				home = envVal
   496  				break
   497  			}
   498  		}
   499  		return path.Join(home, fname)
   500  	}
   501  
   502  	var fname = fmt.Sprintf("%s-config.yaml", cmdName)
   503  	// First check home env variables
   504  	var home string
   505  	envs := []string{"FABRIC_CA_CLIENT_HOME", "FABRIC_CA_HOME", "CA_CFG_PATH"}
   506  	for _, env := range envs {
   507  		envVal := os.Getenv(env)
   508  		if envVal != "" {
   509  			home = envVal
   510  			return path.Join(home, fname)
   511  		}
   512  	}
   513  
   514  	return path.Join(os.Getenv("HOME"), ".fabric-ca-client", fname)
   515  }
   516  
   517  // GetX509CertificateFromPEMFile gets an X509 certificate from a file
   518  func GetX509CertificateFromPEMFile(file string) (*x509.Certificate, error) {
   519  	pemBytes, err := ReadFile(file)
   520  	if err != nil {
   521  		return nil, err
   522  	}
   523  	x509Cert, err := GetX509CertificateFromPEM(pemBytes)
   524  	if err != nil {
   525  		return nil, errors.Wrapf(err, "Invalid certificate in '%s'", file)
   526  	}
   527  	return x509Cert, nil
   528  }
   529  
   530  // GetX509CertificateFromPEM get an X509 certificate from bytes in PEM format
   531  func GetX509CertificateFromPEM(cert []byte) (*x509.Certificate, error) {
   532  	block, _ := pem.Decode(cert)
   533  	if block == nil {
   534  		return nil, errors.New("Failed to PEM decode certificate")
   535  	}
   536  	var x509Cert *x509.Certificate
   537  	var err error
   538  	if IsGMConfig() {
   539  		log.Debugf("IsGMConfig = true")
   540  		sm2x509Cert, err := x509GM.ParseCertificate(block.Bytes)
   541  		if err == nil {
   542  			x509Cert = ParseSm2Certificate2X509(sm2x509Cert)
   543  			log.Debugf("after parse,x509Cert=%T,x509Cert.PublicKey=%T", x509Cert, x509Cert.PublicKey)
   544  		}
   545  	} else {
   546  		x509Cert, err = x509.ParseCertificate(block.Bytes)
   547  	}
   548  	if err != nil {
   549  		return nil, errors.Wrap(err, "Error parsing certificate")
   550  	}
   551  	return x509Cert, nil
   552  }
   553  
   554  // GetX509CertificatesFromPEM returns X509 certificates from bytes in PEM format
   555  func GetX509CertificatesFromPEM(pemBytes []byte) ([]*x509.Certificate, error) {
   556  	chain := pemBytes
   557  	var certs []*x509.Certificate
   558  	for len(chain) > 0 {
   559  		var block *pem.Block
   560  		block, chain = pem.Decode(chain)
   561  		if block == nil {
   562  			break
   563  		}
   564  
   565  		var x509Cert *x509.Certificate
   566  		var err error
   567  		if IsGMConfig() {
   568  			sm2x509Cert, err := x509GM.ParseCertificate(block.Bytes)
   569  			if err == nil {
   570  				x509Cert = ParseSm2Certificate2X509(sm2x509Cert)
   571  			}
   572  		} else {
   573  			x509Cert, err = x509.ParseCertificate(block.Bytes)
   574  		}
   575  		if err != nil {
   576  			return nil, errors.Wrap(err, "Error parsing certificate")
   577  		}
   578  		certs = append(certs, x509Cert)
   579  	}
   580  	return certs, nil
   581  }
   582  
   583  // GetCertificateDurationFromFile returns the validity duration for a certificate
   584  // in a file.
   585  func GetCertificateDurationFromFile(file string) (time.Duration, error) {
   586  	cert, err := GetX509CertificateFromPEMFile(file)
   587  	if err != nil {
   588  		return 0, err
   589  	}
   590  	return GetCertificateDuration(cert), nil
   591  }
   592  
   593  // GetCertificateDuration returns the validity duration for a certificate
   594  func GetCertificateDuration(cert *x509.Certificate) time.Duration {
   595  	return cert.NotAfter.Sub(cert.NotBefore)
   596  }
   597  
   598  // GetEnrollmentIDFromPEM returns the EnrollmentID from a PEM buffer
   599  func GetEnrollmentIDFromPEM(cert []byte) (string, error) {
   600  	x509Cert, err := GetX509CertificateFromPEM(cert)
   601  	if err != nil {
   602  		return "", err
   603  	}
   604  	return GetEnrollmentIDFromX509Certificate(x509Cert), nil
   605  }
   606  
   607  // GetEnrollmentIDFromX509Certificate returns the EnrollmentID from the X509 certificate
   608  func GetEnrollmentIDFromX509Certificate(cert *x509.Certificate) string {
   609  	return cert.Subject.CommonName
   610  }
   611  
   612  // MakeFileAbs makes 'file' absolute relative to 'dir' if not already absolute
   613  func MakeFileAbs(file, dir string) (string, error) {
   614  	if file == "" {
   615  		return "", nil
   616  	}
   617  	if filepath.IsAbs(file) {
   618  		return file, nil
   619  	}
   620  	path, err := filepath.Abs(filepath.Join(dir, file))
   621  	if err != nil {
   622  		return "", errors.Wrapf(err, "Failed making '%s' absolute based on '%s'", file, dir)
   623  	}
   624  	return path, nil
   625  }
   626  
   627  // MakeFileNamesAbsolute makes all file names in the list absolute, relative to home
   628  func MakeFileNamesAbsolute(files []*string, home string) error {
   629  	for _, filePtr := range files {
   630  		abs, err := MakeFileAbs(*filePtr, home)
   631  		if err != nil {
   632  			return err
   633  		}
   634  		*filePtr = abs
   635  	}
   636  	return nil
   637  }
   638  
   639  // Fatal logs a fatal message and exits
   640  func Fatal(format string, v ...interface{}) {
   641  	log.Fatalf(format, v...)
   642  	os.Exit(1)
   643  }
   644  
   645  // GetUser returns username and password from CLI input
   646  func GetUser(v *viper.Viper) (string, string, error) {
   647  	var fabricCAServerURL string
   648  	fabricCAServerURL = v.GetString("url")
   649  
   650  	URL, err := url.Parse(fabricCAServerURL)
   651  	if err != nil {
   652  		return "", "", err
   653  	}
   654  
   655  	user := URL.User
   656  	if user == nil {
   657  		return "", "", errors.New("No username and password provided as part of the Fabric CA server URL")
   658  	}
   659  
   660  	eid := user.Username()
   661  	if eid == "" {
   662  		return "", "", errors.New("No username provided as part of URL")
   663  	}
   664  
   665  	pass, _ := user.Password()
   666  	if pass == "" {
   667  		return "", "", errors.New("No password provided as part of URL")
   668  	}
   669  
   670  	return eid, pass, nil
   671  }
   672  
   673  // GetSerialAsHex returns the serial number from certificate as hex format
   674  func GetSerialAsHex(serial *big.Int) string {
   675  	hex := fmt.Sprintf("%x", serial)
   676  	return hex
   677  }
   678  
   679  // StructToString converts a struct to a string. If a field
   680  // has a 'secret' tag, it is masked in the returned string
   681  func StructToString(si interface{}) string {
   682  	rval := reflect.ValueOf(si).Elem()
   683  	tipe := rval.Type()
   684  	var buffer bytes.Buffer
   685  	buffer.WriteString("{ ")
   686  	for i := 0; i < rval.NumField(); i++ {
   687  		tf := tipe.Field(i)
   688  		if !rval.FieldByName(tf.Name).CanSet() {
   689  			continue // skip unexported fields
   690  		}
   691  		var fStr string
   692  		tagv := tf.Tag.Get(SecretTag)
   693  		if tagv == "password" || tagv == "username" {
   694  			fStr = fmt.Sprintf("%s:**** ", tf.Name)
   695  		} else if tagv == "url" {
   696  			val, ok := rval.Field(i).Interface().(string)
   697  			if ok {
   698  				val = GetMaskedURL(val)
   699  				fStr = fmt.Sprintf("%s:%v ", tf.Name, val)
   700  			} else {
   701  				fStr = fmt.Sprintf("%s:%v ", tf.Name, rval.Field(i).Interface())
   702  			}
   703  		} else {
   704  			fStr = fmt.Sprintf("%s:%v ", tf.Name, rval.Field(i).Interface())
   705  		}
   706  		buffer.WriteString(fStr)
   707  	}
   708  	buffer.WriteString(" }")
   709  	return buffer.String()
   710  }
   711  
   712  // GetMaskedURL returns masked URL. It masks username and password from the URL
   713  // if present
   714  func GetMaskedURL(url string) string {
   715  	matches := URLRegex.FindStringSubmatch(url)
   716  
   717  	// If there is a match, there should be four entries: 1 for
   718  	// the match and 3 for submatches
   719  	if len(matches) == 4 {
   720  		matchIdxs := URLRegex.FindStringSubmatchIndex(url)
   721  		matchStr := url[matchIdxs[0]:matchIdxs[1]]
   722  		for idx := 2; idx < len(matches); idx++ {
   723  			if matches[idx] != "" {
   724  				matchStr = strings.Replace(matchStr, matches[idx], "****", 1)
   725  			}
   726  		}
   727  		url = url[:matchIdxs[0]] + matchStr + url[matchIdxs[1]:len(url)]
   728  	}
   729  	return url
   730  }
   731  
   732  // NormalizeStringSlice checks for seperators
   733  func NormalizeStringSlice(slice []string) []string {
   734  	var normalizedSlice []string
   735  
   736  	for _, item := range slice {
   737  		// Remove surrounding brackets "[]" if specified
   738  		if strings.HasPrefix(item, "[") && strings.HasSuffix(item, "]") {
   739  			item = item[1 : len(item)-1]
   740  		}
   741  		// Split elements based on comma and add to normalized slice
   742  		elems := strings.Split(item, ",")
   743  		for _, elem := range elems {
   744  			normalizedSlice = append(normalizedSlice, strings.TrimSpace(elem))
   745  		}
   746  	}
   747  	return normalizedSlice
   748  }
   749  
   750  // NormalizeFileList provides absolute pathing for the list of files
   751  func NormalizeFileList(files []string, homeDir string) ([]string, error) {
   752  	var err error
   753  
   754  	files = NormalizeStringSlice(files)
   755  
   756  	for i, file := range files {
   757  		files[i], err = MakeFileAbs(file, homeDir)
   758  		if err != nil {
   759  			return nil, err
   760  		}
   761  	}
   762  
   763  	return files, nil
   764  }
   765  
   766  // CheckHostsInCert checks to see if host correctly inserted into certificate
   767  func CheckHostsInCert(certFile string, hosts ...string) error {
   768  	certBytes, err := ioutil.ReadFile(certFile)
   769  	if err != nil {
   770  		return errors.Wrapf(err, "Failed to read certificate file at '%s'", certFile)
   771  	}
   772  
   773  	cert, err := GetX509CertificateFromPEM(certBytes)
   774  	if err != nil {
   775  		return errors.Wrap(err, "Failed to get certificate")
   776  	}
   777  
   778  	// combine DNSNames and IPAddresses from cert
   779  	sans := cert.DNSNames
   780  	for _, ip := range cert.IPAddresses {
   781  		sans = append(sans, ip.String())
   782  	}
   783  	for _, host := range hosts {
   784  		if !containsString(sans, host) {
   785  			return errors.Errorf("Host '%s' was not found in the certificate in file '%s'", host, certFile)
   786  		}
   787  	}
   788  	return nil
   789  }
   790  
   791  func containsString(list []string, item string) bool {
   792  	for _, elem := range list {
   793  		if elem == item {
   794  			return true
   795  		}
   796  	}
   797  	return false
   798  }
   799  
   800  // Read reads from Reader into a byte array
   801  func Read(r io.Reader, data []byte) ([]byte, error) {
   802  	j := 0
   803  	for {
   804  		n, err := r.Read(data[j:])
   805  		j = j + n
   806  		if err != nil {
   807  			if err == io.EOF {
   808  				break
   809  			}
   810  			return nil, errors.Wrapf(err, "Read failure")
   811  		}
   812  
   813  		if (n == 0 && j == len(data)) || j > len(data) {
   814  			return nil, errors.New("Size of requested data is too large")
   815  		}
   816  	}
   817  
   818  	return data[:j], nil
   819  }
   820  
   821  // Hostname name returns the hostname of the machine
   822  func Hostname() string {
   823  	hostname, _ := os.Hostname()
   824  	if hostname == "" {
   825  		hostname = "localhost"
   826  	}
   827  	return hostname
   828  }
   829  
   830  // ValidateAndReturnAbsConf checks to see that there are no conflicts between the
   831  // configuration file path and home directory. If no conflicts, returns back the absolute
   832  // path for the configuration file and home directory.
   833  func ValidateAndReturnAbsConf(configFilePath, homeDir, cmdName string) (string, string, error) {
   834  	var err error
   835  	var homeDirSet bool
   836  	var configFileSet bool
   837  
   838  	defaultConfig := GetDefaultConfigFile(cmdName) // Get the default configuration
   839  
   840  	if configFilePath == "" {
   841  		configFilePath = defaultConfig // If no config file path specified, use the default configuration file
   842  	} else {
   843  		configFileSet = true
   844  	}
   845  
   846  	if homeDir == "" {
   847  		homeDir = filepath.Dir(defaultConfig) // If no home directory specified, use the default directory
   848  	} else {
   849  		homeDirSet = true
   850  	}
   851  
   852  	// Make the home directory absolute
   853  	homeDir, err = filepath.Abs(homeDir)
   854  	if err != nil {
   855  		return "", "", errors.Wrap(err, "Failed to get full path of config file")
   856  	}
   857  	homeDir = strings.TrimRight(homeDir, "/")
   858  
   859  	if configFileSet && homeDirSet {
   860  		log.Warning("Using both --config and --home CLI flags; --config will take precedence")
   861  	}
   862  
   863  	if configFileSet {
   864  		configFilePath, err = filepath.Abs(configFilePath)
   865  		if err != nil {
   866  			return "", "", errors.Wrap(err, "Failed to get full path of configuration file")
   867  		}
   868  		return configFilePath, filepath.Dir(configFilePath), nil
   869  	}
   870  
   871  	configFile := filepath.Join(homeDir, filepath.Base(defaultConfig)) // Join specified home directory with default config file name
   872  	return configFile, homeDir, nil
   873  }
   874  
   875  // GetSliceFromList will return a slice from a list
   876  func GetSliceFromList(split string, delim string) []string {
   877  	return strings.Split(strings.Replace(split, " ", "", -1), delim)
   878  }
   879  
   880  // ListContains looks through a comma separated list to see if a string exists
   881  func ListContains(list, find string) bool {
   882  	items := strings.Split(list, ",")
   883  	for _, item := range items {
   884  		item = strings.TrimPrefix(item, " ")
   885  		if item == find {
   886  			return true
   887  		}
   888  	}
   889  	return false
   890  }
   891  
   892  //TODO:  move these out of production code
   893  
   894  // FatalError will check to see if an error occured if so it will cause the test cases exit
   895  func FatalError(t *testing.T, err error, msg string, args ...interface{}) {
   896  	if len(args) > 0 {
   897  		msg = fmt.Sprintf(msg, args)
   898  	}
   899  	if !assert.NoError(t, err, msg) {
   900  		t.Fatal(msg)
   901  	}
   902  }
   903  
   904  // ErrorContains will check to see if an error occurred, if so it will check that it contains
   905  // the appropriate error message
   906  func ErrorContains(t *testing.T, err error, contains, msg string, args ...interface{}) {
   907  	if len(args) > 0 {
   908  		msg = fmt.Sprintf(msg, args)
   909  	}
   910  	if assert.Error(t, err, msg) {
   911  		assert.Contains(t, err.Error(), contains)
   912  	}
   913  }
   914  
   915  //sm2 证书转换 x509 证书
   916  func ParseSm2Certificate2X509(sm2Cert *x509GM.Certificate) *x509.Certificate {
   917  	x509cert := &x509.Certificate{
   918  		Raw:                     sm2Cert.Raw,
   919  		RawTBSCertificate:       sm2Cert.RawTBSCertificate,
   920  		RawSubjectPublicKeyInfo: sm2Cert.RawSubjectPublicKeyInfo,
   921  		RawSubject:              sm2Cert.RawSubject,
   922  		RawIssuer:               sm2Cert.RawIssuer,
   923  
   924  		Signature:          sm2Cert.Signature,
   925  		SignatureAlgorithm: x509.SignatureAlgorithm(sm2Cert.SignatureAlgorithm),
   926  
   927  		PublicKeyAlgorithm: x509.PublicKeyAlgorithm(sm2Cert.PublicKeyAlgorithm),
   928  		PublicKey:          sm2Cert.PublicKey,
   929  
   930  		Version:      sm2Cert.Version,
   931  		SerialNumber: sm2Cert.SerialNumber,
   932  		Issuer:       sm2Cert.Issuer,
   933  		Subject:      sm2Cert.Subject,
   934  		NotBefore:    sm2Cert.NotBefore,
   935  		NotAfter:     sm2Cert.NotAfter,
   936  		KeyUsage:     x509.KeyUsage(sm2Cert.KeyUsage),
   937  
   938  		Extensions: sm2Cert.Extensions,
   939  
   940  		ExtraExtensions: sm2Cert.ExtraExtensions,
   941  
   942  		UnhandledCriticalExtensions: sm2Cert.UnhandledCriticalExtensions,
   943  
   944  		//ExtKeyUsage:	[]x509.ExtKeyUsage(sm2Cert.ExtKeyUsage) ,
   945  		UnknownExtKeyUsage: sm2Cert.UnknownExtKeyUsage,
   946  
   947  		BasicConstraintsValid: sm2Cert.BasicConstraintsValid,
   948  		IsCA:                  sm2Cert.IsCA,
   949  		MaxPathLen:            sm2Cert.MaxPathLen,
   950  		// MaxPathLenZero indicates that BasicConstraintsValid==true and
   951  		// MaxPathLen==0 should be interpreted as an actual maximum path length
   952  		// of zero. Otherwise, that combination is interpreted as MaxPathLen
   953  		// not being set.
   954  		MaxPathLenZero: sm2Cert.MaxPathLenZero,
   955  
   956  		SubjectKeyId:   sm2Cert.SubjectKeyId,
   957  		AuthorityKeyId: sm2Cert.AuthorityKeyId,
   958  
   959  		// RFC 5280, 4.2.2.1 (Authority Information Access)
   960  		OCSPServer:            sm2Cert.OCSPServer,
   961  		IssuingCertificateURL: sm2Cert.IssuingCertificateURL,
   962  
   963  		// Subject Alternate Name values
   964  		DNSNames:       sm2Cert.DNSNames,
   965  		EmailAddresses: sm2Cert.EmailAddresses,
   966  		IPAddresses:    sm2Cert.IPAddresses,
   967  
   968  		// Name constraints
   969  		PermittedDNSDomainsCritical: sm2Cert.PermittedDNSDomainsCritical,
   970  		PermittedDNSDomains:         sm2Cert.PermittedDNSDomains,
   971  
   972  		// CRL Distribution Points
   973  		CRLDistributionPoints: sm2Cert.CRLDistributionPoints,
   974  
   975  		PolicyIdentifiers: sm2Cert.PolicyIdentifiers,
   976  	}
   977  	for _, val := range sm2Cert.ExtKeyUsage {
   978  		x509cert.ExtKeyUsage = append(x509cert.ExtKeyUsage, x509.ExtKeyUsage(val))
   979  	}
   980  
   981  	return x509cert
   982  }
   983  
   984  // X509证书格式转换为 SM2证书格式
   985  func ParseX509Certificate2Sm2(x509Cert *x509.Certificate) *x509GM.Certificate {
   986  	sm2cert := &x509GM.Certificate{
   987  		Raw:                     x509Cert.Raw,
   988  		RawTBSCertificate:       x509Cert.RawTBSCertificate,
   989  		RawSubjectPublicKeyInfo: x509Cert.RawSubjectPublicKeyInfo,
   990  		RawSubject:              x509Cert.RawSubject,
   991  		RawIssuer:               x509Cert.RawIssuer,
   992  
   993  		Signature:          x509Cert.Signature,
   994  		SignatureAlgorithm: x509GM.SignatureAlgorithm(x509Cert.SignatureAlgorithm),
   995  
   996  		PublicKeyAlgorithm: x509GM.PublicKeyAlgorithm(x509Cert.PublicKeyAlgorithm),
   997  		PublicKey:          x509Cert.PublicKey,
   998  
   999  		Version:      x509Cert.Version,
  1000  		SerialNumber: x509Cert.SerialNumber,
  1001  		Issuer:       x509Cert.Issuer,
  1002  		Subject:      x509Cert.Subject,
  1003  		NotBefore:    x509Cert.NotBefore,
  1004  		NotAfter:     x509Cert.NotAfter,
  1005  		KeyUsage:     x509GM.KeyUsage(x509Cert.KeyUsage),
  1006  
  1007  		Extensions: x509Cert.Extensions,
  1008  
  1009  		ExtraExtensions: x509Cert.ExtraExtensions,
  1010  
  1011  		UnhandledCriticalExtensions: x509Cert.UnhandledCriticalExtensions,
  1012  
  1013  		//ExtKeyUsage:	[]x509.ExtKeyUsage(x509Cert.ExtKeyUsage) ,
  1014  		UnknownExtKeyUsage: x509Cert.UnknownExtKeyUsage,
  1015  
  1016  		BasicConstraintsValid: x509Cert.BasicConstraintsValid,
  1017  		IsCA:                  x509Cert.IsCA,
  1018  		MaxPathLen:            x509Cert.MaxPathLen,
  1019  		// MaxPathLenZero indicates that BasicConstraintsValid==true and
  1020  		// MaxPathLen==0 should be interpreted as an actual maximum path length
  1021  		// of zero. Otherwise, that combination is interpreted as MaxPathLen
  1022  		// not being set.
  1023  		MaxPathLenZero: x509Cert.MaxPathLenZero,
  1024  
  1025  		SubjectKeyId:   x509Cert.SubjectKeyId,
  1026  		AuthorityKeyId: x509Cert.AuthorityKeyId,
  1027  
  1028  		// RFC 5280, 4.2.2.1 (Authority Information Access)
  1029  		OCSPServer:            x509Cert.OCSPServer,
  1030  		IssuingCertificateURL: x509Cert.IssuingCertificateURL,
  1031  
  1032  		// Subject Alternate Name values
  1033  		DNSNames:       x509Cert.DNSNames,
  1034  		EmailAddresses: x509Cert.EmailAddresses,
  1035  		IPAddresses:    x509Cert.IPAddresses,
  1036  
  1037  		// Name constraints
  1038  		PermittedDNSDomainsCritical: x509Cert.PermittedDNSDomainsCritical,
  1039  		PermittedDNSDomains:         x509Cert.PermittedDNSDomains,
  1040  
  1041  		// CRL Distribution Points
  1042  		CRLDistributionPoints: x509Cert.CRLDistributionPoints,
  1043  
  1044  		PolicyIdentifiers: x509Cert.PolicyIdentifiers,
  1045  	}
  1046  	for _, val := range x509Cert.ExtKeyUsage {
  1047  		sm2cert.ExtKeyUsage = append(sm2cert.ExtKeyUsage, x509GM.ExtKeyUsage(val))
  1048  	}
  1049  
  1050  	return sm2cert
  1051  }
  1052  
  1053  var providerName string
  1054  
  1055  func IsGMConfig() bool {
  1056  	if providerName == "" {
  1057  		return false
  1058  	}
  1059  	if strings.ToUpper(providerName) == "GM" {
  1060  		return true
  1061  	}
  1062  	return false
  1063  }
  1064  
  1065  func SetProviderName(name string) {
  1066  	providerName = name
  1067  }