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  }