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