github.com/hxx258456/fabric-ca-gm@v0.0.3-0.20221111064038-a268ad7e3a37/internal/pkg/util/util.go (about)

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