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