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 }