github.com/hxx258456/fabric-ca-gm@v0.0.3-0.20221111064038-a268ad7e3a37/lib/client.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package lib 8 9 import ( 10 "bytes" 11 "crypto" 12 "encoding/hex" 13 "encoding/json" 14 "fmt" 15 "io/ioutil" 16 "net" 17 "net/url" 18 "os" 19 "path" 20 "path/filepath" 21 "strconv" 22 "strings" 23 24 http "github.com/hxx258456/ccgo/gmhttp" 25 26 log "gitee.com/zhaochuninhefei/zcgolog/zclog" 27 proto "github.com/golang/protobuf/proto" 28 cfsslapi "github.com/hxx258456/cfssl-gm/api" 29 "github.com/hxx258456/cfssl-gm/csr" 30 "github.com/hxx258456/fabric-ca-gm/internal/pkg/api" 31 "github.com/hxx258456/fabric-ca-gm/internal/pkg/util" 32 "github.com/hxx258456/fabric-ca-gm/lib/client/credential" 33 idemixcred "github.com/hxx258456/fabric-ca-gm/lib/client/credential/idemix" 34 x509cred "github.com/hxx258456/fabric-ca-gm/lib/client/credential/x509" 35 "github.com/hxx258456/fabric-ca-gm/lib/streamer" 36 "github.com/hxx258456/fabric-ca-gm/lib/tls" 37 "github.com/hxx258456/fabric-gm/bccsp" 38 cspsigner "github.com/hxx258456/fabric-gm/bccsp/signer" 39 "github.com/hxx258456/fabric-gm/idemix" 40 fp256bn "github.com/hyperledger/fabric-amcl/amcl/FP256BN" 41 "github.com/mitchellh/mapstructure" 42 "github.com/pkg/errors" 43 ) 44 45 // Client is the fabric-ca client object 46 type Client struct { 47 // The client's home directory 48 HomeDir string `json:"homeDir,omitempty"` 49 // The client's configuration 50 Config *ClientConfig 51 // Denotes if the client object is already initialized 52 initialized bool 53 // File and directory paths 54 keyFile, certFile, idemixCredFile, idemixCredsDir, ipkFile, caCertsDir string 55 // The crypto service provider (BCCSP) 56 csp bccsp.BCCSP 57 // HTTP client associated with this Fabric CA client 58 httpClient *http.Client 59 // Public key of Idemix issuer 60 issuerPublicKey *idemix.IssuerPublicKey 61 } 62 63 // GetCAInfoResponse is the response from the GetCAInfo call 64 type GetCAInfoResponse struct { 65 // CAName is the name of the CA 66 CAName string 67 // CAChain is the PEM-encoded bytes of the fabric-ca-server's CA chain. 68 // The 1st element of the chain is the root CA cert 69 CAChain []byte 70 // Idemix issuer public key of the CA 71 IssuerPublicKey []byte 72 // Idemix issuer revocation public key of the CA 73 IssuerRevocationPublicKey []byte 74 // Version of the server 75 Version string 76 } 77 78 // EnrollmentResponse is the response from Client.Enroll and Identity.Reenroll 79 type EnrollmentResponse struct { 80 Identity *Identity 81 CAInfo GetCAInfoResponse 82 } 83 84 // Init initializes the client 85 func (c *Client) Init() error { 86 if !c.initialized { 87 cfg := c.Config 88 log.Debugf("Initializing client with config: %+v", cfg) 89 if cfg.MSPDir == "" { 90 cfg.MSPDir = "msp" 91 } 92 mspDir, err := util.MakeFileAbs(cfg.MSPDir, c.HomeDir) 93 if err != nil { 94 return err 95 } 96 cfg.MSPDir = mspDir 97 // Key directory and file 98 keyDir := path.Join(mspDir, "keystore") 99 err = os.MkdirAll(keyDir, 0700) 100 if err != nil { 101 return errors.Wrap(err, "Failed to create keystore directory") 102 } 103 c.keyFile = path.Join(keyDir, "key.pem") 104 105 // Cert directory and file 106 certDir := path.Join(mspDir, "signcerts") 107 err = os.MkdirAll(certDir, 0755) 108 if err != nil { 109 return errors.Wrap(err, "Failed to create signcerts directory") 110 } 111 c.certFile = path.Join(certDir, "cert.pem") 112 113 // CA certs directory 114 c.caCertsDir = path.Join(mspDir, "cacerts") 115 err = os.MkdirAll(c.caCertsDir, 0755) 116 if err != nil { 117 return errors.Wrap(err, "Failed to create cacerts directory") 118 } 119 120 // CA's Idemix public key 121 c.ipkFile = filepath.Join(mspDir, "IssuerPublicKey") 122 123 // Idemix credentials directory 124 c.idemixCredsDir = path.Join(mspDir, "user") 125 err = os.MkdirAll(c.idemixCredsDir, 0755) 126 if err != nil { 127 return errors.Wrap(err, "Failed to create Idemix credentials directory 'user'") 128 } 129 c.idemixCredFile = path.Join(c.idemixCredsDir, "SignerConfig") 130 131 // Initialize BCCSP (the crypto layer) 132 c.csp, err = util.InitBCCSP(&cfg.CSP, mspDir, c.HomeDir) 133 if err != nil { 134 return err 135 } 136 // Create http.Client object and associate it with this client 137 err = c.initHTTPClient() 138 if err != nil { 139 return err 140 } 141 142 // Successfully initialized the client 143 c.initialized = true 144 } 145 // 设置ProviderName 146 SetProviderName(c.Config.CSP.ProviderName) 147 return nil 148 } 149 150 func (c *Client) initHTTPClient() error { 151 tr := new(http.Transport) 152 if c.Config.TLS.Enabled { 153 log.Info("TLS Enabled") 154 155 err := tls.AbsTLSClient(&c.Config.TLS, c.HomeDir) 156 if err != nil { 157 return err 158 } 159 160 tlsConfig, err2 := tls.GetClientTLSConfig(&c.Config.TLS, c.csp) 161 if err2 != nil { 162 return errors.Errorf("Failed to get client TLS config: %s", err2) 163 } 164 // set the default ciphers 165 tlsConfig.CipherSuites = tls.DefaultCipherSuites 166 tr.TLSClientConfig = tlsConfig 167 } 168 c.httpClient = &http.Client{Transport: tr} 169 return nil 170 } 171 172 // GetCAInfo returns generic CA information 173 func (c *Client) GetCAInfo(req *api.GetCAInfoRequest) (*GetCAInfoResponse, error) { 174 err := c.Init() 175 if err != nil { 176 return nil, err 177 } 178 body, err := util.Marshal(req, "GetCAInfo") 179 if err != nil { 180 return nil, err 181 } 182 cainforeq, err := c.newPost("cainfo", body) 183 if err != nil { 184 return nil, err 185 } 186 netSI := &api.CAInfoResponseNet{} 187 err = c.SendReq(cainforeq, netSI) 188 if err != nil { 189 return nil, err 190 } 191 localSI := &GetCAInfoResponse{} 192 err = c.net2LocalCAInfo(netSI, localSI) 193 if err != nil { 194 return nil, err 195 } 196 return localSI, nil 197 } 198 199 // GenCSR generates a CSR (Certificate Signing Request) 200 func (c *Client) GenCSR(req *api.CSRInfo, id string) ([]byte, bccsp.Key, error) { 201 log.Debugf("GenCSR %+v", req) 202 203 err := c.Init() 204 if err != nil { 205 return nil, nil, err 206 } 207 208 cr := c.newCertificateRequest(req, id) 209 210 cspSigner, key, err := c.generateCSPSigner(cr, nil) 211 if err != nil { 212 return nil, nil, err 213 } 214 215 csrPEM, err := csr.Generate(cspSigner, cr) 216 if err != nil { 217 log.Debugf("failed generating CSR: %s", err) 218 return nil, nil, err 219 } 220 221 return csrPEM, key, nil 222 } 223 224 // GenCSRUsingKey generates a CSR (Certificate Signing Request) using the 225 // supplied private key. 226 func (c *Client) GenCSRUsingKey(req *api.CSRInfo, id string, k bccsp.Key) ([]byte, bccsp.Key, error) { 227 log.Debugf("GenCSRUsingKey %+v", req) 228 229 err := c.Init() 230 if err != nil { 231 return nil, nil, err 232 } 233 234 cr := c.newCertificateRequest(req, id) 235 236 cspSigner, key, err := c.generateCSPSigner(cr, k) 237 if err != nil { 238 return nil, nil, err 239 } 240 241 csrPEM, err := csr.Generate(cspSigner, cr) 242 if err != nil { 243 log.Debugf("failed generating CSR: %s", err) 244 return nil, nil, err 245 } 246 247 return csrPEM, key, nil 248 } 249 250 // generateCSPSigner generates a crypto.Signer for a given certificate request. 251 // If a key is not provided, a new one will be generated. 252 func (c *Client) generateCSPSigner(cr *csr.CertificateRequest, key bccsp.Key) (crypto.Signer, bccsp.Key, error) { 253 if key == nil { 254 // generate new key 255 key, cspSigner, err := util.BCCSPKeyRequestGenerate(cr, c.csp) 256 if err != nil { 257 log.Debugf("failed generating BCCSP key: %s", err) 258 return nil, nil, err 259 } 260 return cspSigner, key, nil 261 } 262 263 // use existing key 264 log.Debugf("generating signer with existing key: %s", hex.EncodeToString(key.SKI())) 265 cspSigner, err := cspsigner.New(c.csp, key) 266 if err != nil { 267 return nil, nil, errors.WithMessage(err, "Failed initializing CryptoSigner") 268 } 269 270 return cspSigner, key, nil 271 } 272 273 // Enroll enrolls a new identity 274 // @param req The enrollment request 275 func (c *Client) Enroll(req *api.EnrollmentRequest) (*EnrollmentResponse, error) { 276 log.Debugf("Enrolling %+v", req) 277 278 err := c.Init() 279 if err != nil { 280 return nil, err 281 } 282 283 if strings.ToLower(req.Type) == "idemix" { 284 return c.handleIdemixEnroll(req) 285 } 286 return c.handleX509Enroll(req) 287 } 288 289 // Convert from network to local CA information 290 func (c *Client) net2LocalCAInfo(net *api.CAInfoResponseNet, local *GetCAInfoResponse) error { 291 caChain, err := util.B64Decode(net.CAChain) 292 if err != nil { 293 return errors.WithMessage(err, "Failed to decode CA chain") 294 } 295 if net.IssuerPublicKey != "" { 296 ipk, err := util.B64Decode(net.IssuerPublicKey) 297 if err != nil { 298 return errors.WithMessage(err, "Failed to decode issuer public key") 299 } 300 local.IssuerPublicKey = ipk 301 } 302 if net.IssuerRevocationPublicKey != "" { 303 rpk, err := util.B64Decode(net.IssuerRevocationPublicKey) 304 if err != nil { 305 return errors.WithMessage(err, "Failed to decode issuer revocation key") 306 } 307 local.IssuerRevocationPublicKey = rpk 308 } 309 local.CAName = net.CAName 310 local.CAChain = caChain 311 local.Version = net.Version 312 return nil 313 } 314 315 func (c *Client) handleX509Enroll(req *api.EnrollmentRequest) (*EnrollmentResponse, error) { 316 // Generate the CSR 317 csrPEM, key, err := c.GenCSR(req.CSR, req.Name) 318 if err != nil { 319 return nil, errors.WithMessage(err, "Failure generating CSR") 320 } 321 322 reqNet := &api.EnrollmentRequestNet{ 323 CAName: req.CAName, 324 AttrReqs: req.AttrReqs, 325 } 326 327 if req.CSR != nil { 328 reqNet.SignRequest.Hosts = req.CSR.Hosts 329 } 330 reqNet.SignRequest.Request = string(csrPEM) 331 reqNet.SignRequest.Profile = req.Profile 332 reqNet.SignRequest.Label = req.Label 333 334 body, err := util.Marshal(reqNet, "SignRequest") 335 if err != nil { 336 return nil, err 337 } 338 339 // Send the CSR to the fabric-ca server with basic auth header 340 post, err := c.newPost("enroll", body) 341 if err != nil { 342 return nil, err 343 } 344 post.SetBasicAuth(req.Name, req.Secret) 345 var result api.EnrollmentResponseNet 346 err = c.SendReq(post, &result) 347 if err != nil { 348 return nil, err 349 } 350 351 // Create the enrollment response 352 return c.newEnrollmentResponse(&result, req.Name, key) 353 } 354 355 // Handles enrollment request for an Idemix credential 356 // 1. Sends a request with empty body to the /api/v1/idemix/credentail REST endpoint 357 // of the server to get a Nonce from the CA 358 // 2. Constructs a credential request using the nonce, CA's idemix public key 359 // 3. Sends a request with the CredentialRequest object in the body to the 360 // /api/v1/idemix/credentail REST endpoint to get a credential 361 func (c *Client) handleIdemixEnroll(req *api.EnrollmentRequest) (*EnrollmentResponse, error) { 362 log.Debugf("Getting nonce from CA %s", req.CAName) 363 reqNet := &api.IdemixEnrollmentRequestNet{ 364 CAName: req.CAName, 365 } 366 var identity *Identity 367 368 // Get nonce from the CA 369 body, err := util.Marshal(reqNet, "NonceRequest") 370 if err != nil { 371 return nil, errors.WithMessage(err, "Failed to marshal nonce request") 372 } 373 post, err := c.newPost("idemix/credential", body) 374 if err != nil { 375 return nil, errors.WithMessage(err, "Failed to create HTTP request for getting a nonce") 376 } 377 err = c.addAuthHeaderForIdemixEnroll(req, identity, body, post) 378 if err != nil { 379 return nil, errors.WithMessage(err, 380 "Either username/password or X509 enrollment certificate is required to request an Idemix credential") 381 } 382 383 // Send the request and process the response 384 var result api.IdemixEnrollmentResponseNet 385 err = c.SendReq(post, &result) 386 if err != nil { 387 return nil, err 388 } 389 nonceBytes, err := util.B64Decode(result.Nonce) 390 391 if err != nil { 392 return nil, errors.WithMessage(err, 393 fmt.Sprintf("Failed to decode nonce that was returned by CA %s", req.CAName)) 394 } 395 nonce := fp256bn.FromBytes(nonceBytes) 396 log.Infof("Successfully got nonce from CA %s", req.CAName) 397 398 ipkBytes, err := util.B64Decode(result.CAInfo.IssuerPublicKey) 399 if err != nil { 400 return nil, errors.WithMessage(err, fmt.Sprintf("Failed to decode issuer public key that was returned by CA %s", req.CAName)) 401 } 402 // Create credential request 403 credReq, sk, err := c.newIdemixCredentialRequest(nonce, ipkBytes) 404 if err != nil { 405 return nil, errors.WithMessage(err, "Failed to create an Idemix credential request") 406 } 407 reqNet.CredRequest = credReq 408 log.Info("Successfully created an Idemix credential request") 409 410 body, err = util.Marshal(reqNet, "CredentialRequest") 411 if err != nil { 412 return nil, errors.WithMessage(err, "Failed to marshal Idemix credential request") 413 } 414 415 // Send the cred request to the CA 416 post, err = c.newPost("idemix/credential", body) 417 if err != nil { 418 return nil, errors.WithMessage(err, "Failed to create HTTP request for getting Idemix credential") 419 } 420 err = c.addAuthHeaderForIdemixEnroll(req, identity, body, post) 421 if err != nil { 422 return nil, errors.WithMessage(err, 423 "Either username/password or X509 enrollment certificate is required to request idemix credential") 424 } 425 err = c.SendReq(post, &result) 426 if err != nil { 427 return nil, err 428 } 429 log.Infof("Successfully received Idemix credential from CA %s", req.CAName) 430 return c.newIdemixEnrollmentResponse(identity, &result, sk, req.Name) 431 } 432 433 // addAuthHeaderForIdemixEnroll adds authenticate header to the specified HTTP request 434 // It adds basic authentication header if userName and password are specified in the 435 // specified EnrollmentRequest object. Else, checks if a X509 credential in the client's 436 // MSP directory, if so, loads the identity, creates an oauth token based on the loaded 437 // identity's X509 credential, and adds the token to the HTTP request. The loaded 438 // identity is passed back to the caller. 439 func (c *Client) addAuthHeaderForIdemixEnroll(req *api.EnrollmentRequest, id *Identity, 440 body []byte, post *http.Request) error { 441 if req.Name != "" && req.Secret != "" { 442 post.SetBasicAuth(req.Name, req.Secret) 443 return nil 444 } 445 if id == nil { 446 err := c.checkX509Enrollment() 447 if err != nil { 448 return err 449 } 450 id, err = c.LoadMyIdentity() 451 if err != nil { 452 return err 453 } 454 } 455 err := id.addTokenAuthHdr(post, body) 456 if err != nil { 457 return err 458 } 459 return nil 460 } 461 462 // newEnrollmentResponse creates a client enrollment response from a network response 463 // @param result The result from server 464 // @param id Name of identity being enrolled or reenrolled 465 // @param key The private key which was used to sign the request 466 func (c *Client) newEnrollmentResponse(result *api.EnrollmentResponseNet, id string, key bccsp.Key) (*EnrollmentResponse, error) { 467 log.Debugf("newEnrollmentResponse %s", id) 468 certByte, err := util.B64Decode(result.Cert) 469 if err != nil { 470 return nil, errors.WithMessage(err, "Invalid response format from server") 471 } 472 signer, err := x509cred.NewSigner(key, certByte) 473 if err != nil { 474 return nil, err 475 } 476 x509Cred := x509cred.NewCredential(c.certFile, c.keyFile, c) 477 err = x509Cred.SetVal(signer) 478 if err != nil { 479 return nil, err 480 } 481 resp := &EnrollmentResponse{ 482 Identity: NewIdentity(c, id, []credential.Credential{x509Cred}), 483 } 484 err = c.net2LocalCAInfo(&result.ServerInfo, &resp.CAInfo) 485 if err != nil { 486 return nil, err 487 } 488 return resp, nil 489 } 490 491 // newIdemixEnrollmentResponse creates a client idemix enrollment response from a network response 492 func (c *Client) newIdemixEnrollmentResponse(identity *Identity, result *api.IdemixEnrollmentResponseNet, 493 sk *fp256bn.BIG, id string) (*EnrollmentResponse, error) { 494 log.Debugf("newIdemixEnrollmentResponse %s", id) 495 credBytes, err := util.B64Decode(result.Credential) 496 if err != nil { 497 return nil, errors.WithMessage(err, "Invalid response format from server") 498 } 499 500 criBytes, err := util.B64Decode(result.CRI) 501 if err != nil { 502 return nil, errors.WithMessage(err, "Invalid response format from server") 503 } 504 505 // Create SignerConfig object with credential bytes from the response 506 // and secret key 507 role, _ := result.Attrs["Role"].(int) 508 ou, _ := result.Attrs["OU"].(string) 509 enrollmentID, _ := result.Attrs["EnrollmentID"].(string) 510 signerConfig := &idemixcred.SignerConfig{ 511 Cred: credBytes, 512 Sk: idemix.BigToBytes(sk), 513 Role: role, 514 OrganizationalUnitIdentifier: ou, 515 EnrollmentID: enrollmentID, 516 CredentialRevocationInformation: criBytes, 517 } 518 519 // Create IdemixCredential object 520 cred := idemixcred.NewCredential(c.idemixCredFile, c) 521 err = cred.SetVal(signerConfig) 522 if err != nil { 523 return nil, err 524 } 525 if identity == nil { 526 identity = NewIdentity(c, id, []credential.Credential{cred}) 527 } else { 528 identity.creds = append(identity.creds, cred) 529 } 530 531 resp := &EnrollmentResponse{ 532 Identity: identity, 533 } 534 err = c.net2LocalCAInfo(&result.CAInfo, &resp.CAInfo) 535 if err != nil { 536 return nil, err 537 } 538 log.Infof("Successfully processed response from the CA") 539 return resp, nil 540 } 541 542 // newCertificateRequest creates a certificate request which is used to generate 543 // a CSR (Certificate Signing Request) 544 func (c *Client) newCertificateRequest(req *api.CSRInfo, id string) *csr.CertificateRequest { 545 cr := &csr.CertificateRequest{CN: id} 546 547 if req != nil { 548 cr.Names = req.Names 549 cr.Hosts = req.Hosts 550 cr.CA = req.CA 551 cr.SerialNumber = req.SerialNumber 552 553 keyRequest := req.KeyRequest 554 if keyRequest == nil || (keyRequest.Size == 0 && keyRequest.Algo == "") { 555 // TODO 国密改造 556 // keyRequest = api.NewKeyRequest() 557 keyRequest = api.NewGMKeyRequest() 558 } 559 cr.KeyRequest = newCfsslKeyRequest(keyRequest) 560 561 return cr 562 } 563 564 // Default requested hosts are local hostname 565 hostname, _ := os.Hostname() 566 if hostname != "" { 567 cr.Hosts = []string{hostname} 568 } 569 570 // TODO 国密改造 571 // cr.KeyRequest = newCfsslKeyRequest(api.NewKeyRequest()) 572 cr.KeyRequest = newCfsslKeyRequest(api.NewGMKeyRequest()) 573 574 return cr 575 } 576 577 // newIdemixCredentialRequest returns CredentialRequest object, a secret key, and a random number used in 578 // the creation of credential request. 579 func (c *Client) newIdemixCredentialRequest(nonce *fp256bn.BIG, ipkBytes []byte) (*idemix.CredRequest, *fp256bn.BIG, error) { 580 rng, err := idemix.GetRand() 581 if err != nil { 582 return nil, nil, err 583 } 584 sk := idemix.RandModOrder(rng) 585 586 issuerPubKey, err := c.getIssuerPubKey(ipkBytes) 587 if err != nil { 588 return nil, nil, err 589 } 590 return idemix.NewCredRequest(sk, idemix.BigToBytes(nonce), issuerPubKey, rng), sk, nil 591 } 592 593 func (c *Client) getIssuerPubKey(ipkBytes []byte) (*idemix.IssuerPublicKey, error) { 594 var err error 595 if len(ipkBytes) == 0 { 596 ipkBytes, err = ioutil.ReadFile(c.ipkFile) 597 if err != nil { 598 return nil, errors.Wrapf(err, "Error reading CA's Idemix public key at '%s'", c.ipkFile) 599 } 600 } 601 pubKey := &idemix.IssuerPublicKey{} 602 err = proto.Unmarshal(ipkBytes, pubKey) 603 if err != nil { 604 return nil, err 605 } 606 c.issuerPublicKey = pubKey 607 return c.issuerPublicKey, nil 608 } 609 610 // LoadMyIdentity loads the client's identity from disk 611 func (c *Client) LoadMyIdentity() (*Identity, error) { 612 err := c.Init() 613 if err != nil { 614 return nil, err 615 } 616 return c.LoadIdentity(c.keyFile, c.certFile, c.idemixCredFile) 617 } 618 619 // LoadIdentity loads an identity from disk 620 func (c *Client) LoadIdentity(keyFile, certFile, idemixCredFile string) (*Identity, error) { 621 log.Debugf("Loading identity: keyFile=%s, certFile=%s", keyFile, certFile) 622 err := c.Init() 623 if err != nil { 624 return nil, err 625 } 626 627 var creds []credential.Credential 628 var x509Found, idemixFound bool 629 x509Cred := x509cred.NewCredential(certFile, keyFile, c) 630 err = x509Cred.Load() 631 if err == nil { 632 x509Found = true 633 creds = append(creds, x509Cred) 634 } else { 635 log.Debugf("No X509 credential found at %s, %s", keyFile, certFile) 636 } 637 638 idemixCred := idemixcred.NewCredential(idemixCredFile, c) 639 err = idemixCred.Load() 640 if err == nil { 641 idemixFound = true 642 creds = append(creds, idemixCred) 643 } else { 644 log.Debugf("No Idemix credential found at %s", idemixCredFile) 645 } 646 647 if !x509Found && !idemixFound { 648 return nil, errors.New("Identity does not posses any enrollment credentials") 649 } 650 651 return c.NewIdentity(creds) 652 } 653 654 // NewIdentity creates a new identity 655 func (c *Client) NewIdentity(creds []credential.Credential) (*Identity, error) { 656 if len(creds) == 0 { 657 return nil, errors.New("No credentials specified. Atleast one credential must be specified") 658 } 659 name, err := creds[0].EnrollmentID() 660 if err != nil { 661 return nil, err 662 } 663 if len(creds) == 1 { 664 return NewIdentity(c, name, creds), nil 665 } 666 667 //TODO: Get the enrollment ID from the creds...they all should return same value 668 // for i := 1; i < len(creds); i++ { 669 // localid, err := creds[i].EnrollmentID() 670 // if err != nil { 671 // return nil, err 672 // } 673 // if localid != name { 674 // return nil, errors.New("Specified credentials belong to different identities, they should be long to same identity") 675 // } 676 // } 677 return NewIdentity(c, name, creds), nil 678 } 679 680 // NewX509Identity creates a new identity 681 func (c *Client) NewX509Identity(name string, creds []credential.Credential) x509cred.Identity { 682 return NewIdentity(c, name, creds) 683 } 684 685 // LoadCSRInfo reads CSR (Certificate Signing Request) from a file 686 // @parameter path The path to the file contains CSR info in JSON format 687 func (c *Client) LoadCSRInfo(path string) (*api.CSRInfo, error) { 688 csrJSON, err := ioutil.ReadFile(path) 689 if err != nil { 690 return nil, err 691 } 692 var csrInfo api.CSRInfo 693 err = util.Unmarshal(csrJSON, &csrInfo, "LoadCSRInfo") 694 if err != nil { 695 return nil, err 696 } 697 return &csrInfo, nil 698 } 699 700 // GetCertFilePath returns the path to the certificate file for this client 701 func (c *Client) GetCertFilePath() string { 702 return c.certFile 703 } 704 705 // GetCSP returns BCCSP instance associated with this client 706 func (c *Client) GetCSP() bccsp.BCCSP { 707 return c.csp 708 } 709 710 // GetIssuerPubKey returns issuer public key associated with this client 711 func (c *Client) GetIssuerPubKey() (*idemix.IssuerPublicKey, error) { 712 if c.issuerPublicKey == nil { 713 return c.getIssuerPubKey(nil) 714 } 715 return c.issuerPublicKey, nil 716 } 717 718 // newGet create a new GET request 719 func (c *Client) newGet(endpoint string) (*http.Request, error) { 720 curl, err := c.getURL(endpoint) 721 if err != nil { 722 return nil, err 723 } 724 req, err := http.NewRequest("GET", curl, bytes.NewReader([]byte{})) 725 if err != nil { 726 return nil, errors.Wrapf(err, "Failed creating GET request for %s", curl) 727 } 728 return req, nil 729 } 730 731 // newPut create a new PUT request 732 func (c *Client) newPut(endpoint string, reqBody []byte) (*http.Request, error) { 733 curl, err := c.getURL(endpoint) 734 if err != nil { 735 return nil, err 736 } 737 req, err := http.NewRequest("PUT", curl, bytes.NewReader(reqBody)) 738 if err != nil { 739 return nil, errors.Wrapf(err, "Failed creating PUT request for %s", curl) 740 } 741 return req, nil 742 } 743 744 // newDelete create a new DELETE request 745 func (c *Client) newDelete(endpoint string) (*http.Request, error) { 746 curl, err := c.getURL(endpoint) 747 if err != nil { 748 return nil, err 749 } 750 req, err := http.NewRequest("DELETE", curl, bytes.NewReader([]byte{})) 751 if err != nil { 752 return nil, errors.Wrapf(err, "Failed creating DELETE request for %s", curl) 753 } 754 return req, nil 755 } 756 757 // NewPost create a new post request 758 func (c *Client) newPost(endpoint string, reqBody []byte) (*http.Request, error) { 759 curl, err := c.getURL(endpoint) 760 if err != nil { 761 return nil, err 762 } 763 req, err := http.NewRequest("POST", curl, bytes.NewReader(reqBody)) 764 if err != nil { 765 return nil, errors.Wrapf(err, "Failed posting to %s", curl) 766 } 767 return req, nil 768 } 769 770 // SendReq sends a request to the fabric-ca-server and fills in the result 771 func (c *Client) SendReq(req *http.Request, result interface{}) (err error) { 772 773 reqStr := util.HTTPRequestToString(req) 774 log.Debugf("Sending request\n%s", reqStr) 775 776 err = c.Init() 777 if err != nil { 778 return err 779 } 780 781 resp, err := c.httpClient.Do(req) 782 if err != nil { 783 return errors.Wrapf(err, "%s failure of request: %s", req.Method, reqStr) 784 } 785 var respBody []byte 786 if resp.Body != nil { 787 respBody, err = ioutil.ReadAll(resp.Body) 788 defer func() { 789 err := resp.Body.Close() 790 if err != nil { 791 log.Debugf("Failed to close the response body: %s", err.Error()) 792 } 793 }() 794 if err != nil { 795 return errors.Wrapf(err, "Failed to read response of request: %s", reqStr) 796 } 797 log.Debugf("Received response\n%s", util.HTTPResponseToString(resp)) 798 } 799 var body *cfsslapi.Response 800 if len(respBody) > 0 { 801 body = new(cfsslapi.Response) 802 err = json.Unmarshal(respBody, body) 803 if err != nil { 804 return errors.Wrapf(err, "Failed to parse response: %s", respBody) 805 } 806 if len(body.Errors) > 0 { 807 var errorMsg string 808 for _, err := range body.Errors { 809 msg := fmt.Sprintf("Response from server: Error Code: %d - %s\n", err.Code, err.Message) 810 if errorMsg == "" { 811 errorMsg = msg 812 } else { 813 errorMsg = errorMsg + fmt.Sprintf("\n%s", msg) 814 } 815 } 816 return errors.Errorf(errorMsg) 817 } 818 } 819 scode := resp.StatusCode 820 if scode >= 400 { 821 return errors.Errorf("Failed with server status code %d for request:\n%s", scode, reqStr) 822 } 823 if body == nil { 824 return errors.Errorf("Empty response body:\n%s", reqStr) 825 } 826 if !body.Success { 827 return errors.Errorf("Server returned failure for request:\n%s", reqStr) 828 } 829 log.Debugf("Response body result: %+v", body.Result) 830 if result != nil { 831 return mapstructure.Decode(body.Result, result) 832 } 833 return nil 834 } 835 836 // StreamResponse reads the response as it comes back from the server 837 func (c *Client) StreamResponse(req *http.Request, stream string, cb func(*json.Decoder) error) (err error) { 838 839 reqStr := util.HTTPRequestToString(req) 840 log.Debugf("Sending request\n%s", reqStr) 841 842 err = c.Init() 843 if err != nil { 844 return err 845 } 846 847 resp, err := c.httpClient.Do(req) 848 if err != nil { 849 return errors.Wrapf(err, "%s failure of request: %s", req.Method, reqStr) 850 } 851 defer resp.Body.Close() 852 853 dec := json.NewDecoder(resp.Body) 854 results, err := streamer.StreamJSONArray(dec, stream, cb) 855 if err != nil { 856 return err 857 } 858 if !results { 859 fmt.Println("No results returned") 860 } 861 return nil 862 } 863 864 func (c *Client) getURL(endpoint string) (string, error) { 865 nurl, err := NormalizeURL(c.Config.URL) 866 if err != nil { 867 return "", err 868 } 869 rtn := fmt.Sprintf("%s/%s", nurl, endpoint) 870 return rtn, nil 871 } 872 873 // CheckEnrollment returns an error if this client is not enrolled 874 func (c *Client) CheckEnrollment() error { 875 err := c.Init() 876 if err != nil { 877 return err 878 } 879 var x509Enrollment, idemixEnrollment bool 880 err = c.checkX509Enrollment() 881 if err == nil { 882 x509Enrollment = true 883 } 884 err = c.checkIdemixEnrollment() 885 if err == nil { 886 idemixEnrollment = true 887 } 888 if x509Enrollment || idemixEnrollment { 889 return nil 890 } 891 log.Errorf("Enrollment check failed: %s", err.Error()) 892 return errors.New("Enrollment information does not exist. Please execute enroll command first. Example: fabric-ca-client enroll -u http://user:userpw@serverAddr:serverPort") 893 } 894 895 func (c *Client) checkX509Enrollment() error { 896 keyFileExists := util.FileExists(c.keyFile) 897 certFileExists := util.FileExists(c.certFile) 898 if keyFileExists && certFileExists { 899 return nil 900 } 901 // If key file does not exist, but certFile does, key file is probably 902 // stored by bccsp, so check to see if this is the case 903 if certFileExists { 904 _, _, _, err := util.GetSignerFromCertFile(c.certFile, c.csp) 905 if err == nil { 906 // Yes, the key is stored by BCCSP 907 return nil 908 } 909 } 910 return errors.New("X509 enrollment information does not exist") 911 } 912 913 // checkIdemixEnrollment returns an error if CA's Idemix public key and user's 914 // Idemix credential does not exist and if they exist and credential verification 915 // fails. Returns nil if the credential verification succeeds 916 func (c *Client) checkIdemixEnrollment() error { 917 log.Debugf("CheckIdemixEnrollment - ipkFile: %s, idemixCredFile: %s", c.ipkFile, c.idemixCredFile) 918 919 idemixIssuerPubKeyExists := util.FileExists(c.ipkFile) 920 idemixCredExists := util.FileExists(c.idemixCredFile) 921 if idemixIssuerPubKeyExists && idemixCredExists { 922 err := c.verifyIdemixCredential() 923 if err != nil { 924 return errors.WithMessage(err, "Idemix enrollment check failed") 925 } 926 return nil 927 } 928 return errors.New("Idemix enrollment information does not exist") 929 } 930 931 func (c *Client) verifyIdemixCredential() error { 932 ipk, err := c.getIssuerPubKey(nil) 933 if err != nil { 934 return err 935 } 936 credfileBytes, err := util.ReadFile(c.idemixCredFile) 937 if err != nil { 938 return errors.Wrapf(err, "Failed to read %s", c.idemixCredFile) 939 } 940 signerConfig := &idemixcred.SignerConfig{} 941 err = json.Unmarshal(credfileBytes, signerConfig) 942 if err != nil { 943 return errors.Wrapf(err, "Failed to unmarshal signer config from %s", c.idemixCredFile) 944 } 945 946 cred := new(idemix.Credential) 947 err = proto.Unmarshal(signerConfig.GetCred(), cred) 948 if err != nil { 949 return errors.Wrap(err, "Failed to unmarshal Idemix credential from signer config") 950 } 951 sk := fp256bn.FromBytes(signerConfig.GetSk()) 952 953 // Verify that the credential is cryptographically valid 954 err = cred.Ver(sk, ipk) 955 if err != nil { 956 return errors.Wrap(err, "Idemix credential is not cryptographically valid") 957 } 958 return nil 959 } 960 961 func newCfsslKeyRequest(bkr *api.KeyRequest) *csr.KeyRequest { 962 return &csr.KeyRequest{A: bkr.Algo, S: bkr.Size} 963 } 964 965 // NormalizeURL normalizes a URL (from cfssl) 966 func NormalizeURL(addr string) (*url.URL, error) { 967 addr = strings.TrimSpace(addr) 968 u, err := url.Parse(addr) 969 if err != nil { 970 return nil, err 971 } 972 if u.Opaque != "" { 973 u.Host = net.JoinHostPort(u.Scheme, u.Opaque) 974 u.Opaque = "" 975 } else if u.Path != "" && !strings.Contains(u.Path, ":") { 976 u.Host = net.JoinHostPort(u.Path, util.GetServerPort()) 977 u.Path = "" 978 } else if u.Scheme == "" { 979 u.Host = u.Path 980 u.Path = "" 981 } 982 if u.Scheme != "https" { 983 u.Scheme = "http" 984 } 985 _, port, err := net.SplitHostPort(u.Host) 986 if err != nil { 987 _, port, err = net.SplitHostPort(u.Host + ":" + util.GetServerPort()) 988 if err != nil { 989 return nil, err 990 } 991 } 992 if port != "" { 993 _, err = strconv.Atoi(port) 994 if err != nil { 995 return nil, err 996 } 997 } 998 return u, nil 999 }