Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
133 changes: 99 additions & 34 deletions lib/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,19 @@ func (c *Client) Init() error {
return nil
}

// SetHTTPClient sets a custom HTTP client for this Fabric CA client.
// Call this before Init() to prevent default HTTP client creation, or after
// Init() to override the default HTTP client.
func (c *Client) SetHTTPClient(client *http.Client) {
c.httpClient = client
}

func (c *Client) initHTTPClient() error {
// Skip initialization if HTTP client was already set
if c.httpClient != nil {
return nil
}

tr := new(http.Transport)
if c.Config.TLS.Enabled {
log.Info("TLS Enabled")
Expand Down Expand Up @@ -206,6 +218,31 @@ func (c *Client) GetCAInfo(req *api.GetCAInfoRequest) (*GetCAInfoResponse, error
return localSI, nil
}

// GenerateKey generates a new key using the BCCSP provider.
// It performs only the cryptographic operation and does not write to disk.
func (c *Client) GenerateKey(cr *csr.CertificateRequest) (bccsp.Key, error) {
key, _, err := util.BCCSPKeyRequestGenerate(cr, c.csp)
if err != nil {
log.Debugf("failed generating BCCSP key: %s", err)
return nil, err
}
return key, nil
}

// GenerateCSR generates a CSR using the provided key and certificate request.
// It performs only the cryptographic operation and does not write to disk.
func (c *Client) GenerateCSR(cr *csr.CertificateRequest, key bccsp.Key) ([]byte, error) {
cspSigner, err := cspsigner.New(c.csp, key)
if err != nil {
return nil, errors.WithMessage(err, "Failed initializing CryptoSigner")
}
csrPEM, err := csr.Generate(cspSigner, cr)
if err != nil {
return nil, errors.WithMessage(err, "Failed generating CSR")
}
return csrPEM, nil
}

// GenCSR generates a CSR (Certificate Signing Request)
func (c *Client) GenCSR(req *api.CSRInfo, id string) ([]byte, bccsp.Key, error) {
log.Debugf("GenCSR %+v", req)
Expand All @@ -217,14 +254,13 @@ func (c *Client) GenCSR(req *api.CSRInfo, id string) ([]byte, bccsp.Key, error)

cr := c.newCertificateRequest(req, id)

cspSigner, key, err := c.generateCSPSigner(cr, nil)
key, err := c.GenerateKey(cr)
if err != nil {
return nil, nil, err
}

csrPEM, err := csr.Generate(cspSigner, cr)
csrPEM, err := c.GenerateCSR(cr, key)
if err != nil {
log.Debugf("failed generating CSR: %s", err)
return nil, nil, err
}

Expand All @@ -243,18 +279,12 @@ func (c *Client) GenCSRUsingKey(req *api.CSRInfo, id string, k bccsp.Key) ([]byt

cr := c.newCertificateRequest(req, id)

cspSigner, key, err := c.generateCSPSigner(cr, k)
csrPEM, err := c.GenerateCSR(cr, k)
if err != nil {
return nil, nil, err
}

csrPEM, err := csr.Generate(cspSigner, cr)
if err != nil {
log.Debugf("failed generating CSR: %s", err)
return nil, nil, err
}

return csrPEM, key, nil
return csrPEM, k, nil
}

// generateCSPSigner generates a crypto.Signer for a given certificate request.
Expand Down Expand Up @@ -617,6 +647,26 @@ func (c *Client) getIssuerPubKey(ipkBytes []byte) (*idemix.IssuerPublicKey, erro
return c.issuerPublicKey, nil
}

// loadX509Credential loads an X509 credential from the given cert and key files
func (c *Client) loadX509Credential(certFile, keyFile string) (credential.Credential, error) {
x509Cred := x509cred.NewCredential(certFile, keyFile, c)
err := x509Cred.Load()
if err != nil {
return nil, err
}
return x509Cred, nil
}

// loadIdemixCredential loads an Idemix credential from the given file
func (c *Client) loadIdemixCredential(idemixCredFile string) (credential.Credential, error) {
idemixCred := idemixcred.NewCredential(idemixCredFile, c, c.curveID)
err := idemixCred.Load()
if err != nil {
return nil, err
}
return idemixCred, nil
}

// LoadMyIdentity loads the client's identity from disk
func (c *Client) LoadMyIdentity() (*Identity, error) {
log.Debugf("LoadMyIdentity ")
Expand All @@ -637,17 +687,16 @@ func (c *Client) LoadIdentity(keyFile, certFile, idemixCredFile string) (*Identi

var creds []credential.Credential
var x509Found, idemixFound bool
x509Cred := x509cred.NewCredential(certFile, keyFile, c)
err = x509Cred.Load()

x509Cred, err := c.loadX509Credential(certFile, keyFile)
if err == nil {
x509Found = true
creds = append(creds, x509Cred)
} else {
log.Debugf("No X509 credential found at %s, %s", keyFile, certFile)
}

idemixCred := idemixcred.NewCredential(idemixCredFile, c, c.curveID)
err = idemixCred.Load()
idemixCred, err := c.loadIdemixCredential(idemixCredFile)
if err == nil {
idemixFound = true
creds = append(creds, idemixCred)
Expand Down Expand Up @@ -901,33 +950,54 @@ func (c *Client) CheckEnrollment() error {
return errors.New("Enrollment information does not exist. Please execute enroll command first. Example: fabric-ca-client enroll -u http://user:userpw@serverAddr:serverPort")
}

func (c *Client) checkX509Enrollment() error {
// x509EnrollmentFilesExist checks if the X509 key and cert files exist or if the key is stored by BCCSP
func (c *Client) x509EnrollmentFilesExist() bool {
keyFileExists := util.FileExists(c.keyFile)
certFileExists := util.FileExists(c.certFile)
if keyFileExists && certFileExists {
return nil
return true
}
// If key file does not exist, but certFile does, key file is probably
// stored by bccsp, so check to see if this is the case
if certFileExists {
_, _, _, err := util.GetSignerFromCertFile(c.certFile, c.csp)
if err == nil {
// Yes, the key is stored by BCCSP
return nil
return true
}
}
return false
}

// idemixEnrollmentFilesExist checks if the Idemix public key and credential files exist
func (c *Client) idemixEnrollmentFilesExist() bool {
idemixIssuerPubKeyExists := util.FileExists(c.ipkFile)
idemixCredExists := util.FileExists(c.idemixCredFile)
return idemixIssuerPubKeyExists && idemixCredExists
}

// loadIdemixSignerConfig loads the Idemix signer config from file
func (c *Client) loadIdemixSignerConfig() (*idemixcred.SignerConfig, error) {
credfileBytes, err := util.ReadFile(c.idemixCredFile)
if err != nil {
return nil, errors.Wrapf(err, "Failed to read %s", c.idemixCredFile)
}
signerConfig := &idemixcred.SignerConfig{}
err = json.Unmarshal(credfileBytes, signerConfig)
if err != nil {
return nil, errors.Wrapf(err, "Failed to unmarshal signer config from %s", c.idemixCredFile)
}
return signerConfig, nil
}

func (c *Client) checkX509Enrollment() error {
if c.x509EnrollmentFilesExist() {
return nil
}
return fmt.Errorf("x509 enrollment information does not exist - certFile: %s keyFile: %s", c.certFile, c.keyFile)
}

// checkIdemixEnrollment returns an error if CA's Idemix public key and user's
// Idemix credential does not exist and if they exist and credential verification
// fails. Returns nil if the credential verification succeeds
func (c *Client) checkIdemixEnrollment() error {
log.Debugf("CheckIdemixEnrollment - ipkFile: %s, idemixCredFile: %s", c.ipkFile, c.idemixCredFile)

idemixIssuerPubKeyExists := util.FileExists(c.ipkFile)
idemixCredExists := util.FileExists(c.idemixCredFile)
if idemixIssuerPubKeyExists && idemixCredExists {
if c.idemixEnrollmentFilesExist() {
err := c.verifyIdemixCredential()
if err != nil {
return errors.WithMessage(err, "Idemix enrollment check failed")
Expand All @@ -942,14 +1012,9 @@ func (c *Client) verifyIdemixCredential() error {
if err != nil {
return err
}
credfileBytes, err := util.ReadFile(c.idemixCredFile)
if err != nil {
return errors.Wrapf(err, "Failed to read %s", c.idemixCredFile)
}
signerConfig := &idemixcred.SignerConfig{}
err = json.Unmarshal(credfileBytes, signerConfig)
signerConfig, err := c.loadIdemixSignerConfig()
if err != nil {
return errors.Wrapf(err, "Failed to unmarshal signer config from %s", c.idemixCredFile)
return err
}

cred := new(idemix.Credential)
Expand Down
50 changes: 35 additions & 15 deletions lib/client/credential/idemix/credential.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,33 @@ func (cred *Credential) SetVal(val interface{}) error {
return nil
}

// Store stores this Idemix credential to the location specified by the
// signerConfigFile attribute
func (cred *Credential) Store() error {
// SetSignerConfig sets the credential value from a SignerConfig.
// This is a cryptographic operation and does not perform file I/O.
func (cred *Credential) SetSignerConfig(val *SignerConfig) error {
cred.val = val
return nil
}

// loadSignerConfigFromFile loads the SignerConfig from the specified file
func (cred *Credential) loadSignerConfigFromFile() (*SignerConfig, error) {
signerConfigBytes, err := util.ReadFile(cred.signerConfigFile)
if err != nil {
log.Debugf("No credential found at %s: %s", cred.signerConfigFile, err.Error())
return nil, err
}
val := SignerConfig{}
err = json.Unmarshal(signerConfigBytes, &val)
if err != nil {
return nil, errors.Wrapf(err, fmt.Sprintf("Failed to unmarshal SignerConfig bytes from %s", cred.signerConfigFile))
}
if val.CurveID == "" {
val.CurveID = idemix4.DefaultIdemixCurve
}
return &val, nil
}

// storeSignerConfigToFile writes the SignerConfig to the specified file
func (cred *Credential) storeSignerConfigToFile() error {
val, err := cred.Val()
if err != nil {
return err
Expand All @@ -108,24 +132,20 @@ func (cred *Credential) Store() error {
return nil
}

// Store stores this Idemix credential to the location specified by the
// signerConfigFile attribute
func (cred *Credential) Store() error {
return cred.storeSignerConfigToFile()
}

// Load loads the Idemix credential from the location specified by the
// signerConfigFile attribute
func (cred *Credential) Load() error {
signerConfigBytes, err := util.ReadFile(cred.signerConfigFile)
val, err := cred.loadSignerConfigFromFile()
if err != nil {
log.Debugf("No credential found at %s: %s", cred.signerConfigFile, err.Error())
return err
}
val := SignerConfig{}
err = json.Unmarshal(signerConfigBytes, &val)
if err != nil {
return errors.Wrapf(err, fmt.Sprintf("Failed to unmarshal SignerConfig bytes from %s", cred.signerConfigFile))
}
if val.CurveID == "" {
val.CurveID = idemix4.DefaultIdemixCurve
}
cred.val = &val
return nil
return cred.SetSignerConfig(val)
}

// CreateToken creates authorization token based on this Idemix credential
Expand Down
52 changes: 34 additions & 18 deletions lib/client/credential/x509/credential.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,25 +71,28 @@ func (cred *Credential) EnrollmentID() (string, error) {
return cred.val.GetName(), nil
}

// SetVal sets *Signer for this X509 credential
// SetCredentialFromSigner sets the credential value from a Signer.
// This is a cryptographic operation and does not perform file I/O.
func (cred *Credential) SetCredentialFromSigner(signer *Signer) error {
cred.val = signer
return nil
}

// SetVal sets *Signer for this X509 credential (implements credential.Credential interface)
func (cred *Credential) SetVal(val interface{}) error {
s, ok := val.(*Signer)
if !ok {
return errors.New("The X509 credential value must be of type *Signer for X509 credential")
}
cred.val = s
return nil
return cred.SetCredentialFromSigner(s)
}

// Load loads the certificate and key from the location specified by
// certFile attribute using the BCCSP of the client. The private key is
// loaded from the location specified by the keyFile attribute, if the
// private key is not found in the keystore managed by BCCSP
func (cred *Credential) Load() error {
// loadCredentialFromFiles loads the certificate and key from the specified files and returns a Signer
func (cred *Credential) loadCredentialFromFiles() (*Signer, error) {
cert, err := util.ReadFile(cred.certFile)
if err != nil {
log.Debugf("No certificate found at %s", cred.certFile)
return err
return nil, err
}
csp := cred.getCSP()
key, _, _, err := util.GetSignerFromCertFile(cred.certFile, csp)
Expand All @@ -98,19 +101,14 @@ func (cred *Credential) Load() error {
log.Debugf("No key found in the BCCSP keystore, attempting fallback")
key, err = util.ImportBCCSPKeyFromPEM(cred.keyFile, csp, true)
if err != nil {
return errors.WithMessage(err, fmt.Sprintf("Could not find the private key in the BCCSP keystore nor in the keyfile %s", cred.keyFile))
return nil, errors.WithMessage(err, fmt.Sprintf("Could not find the private key in the BCCSP keystore nor in the keyfile %s", cred.keyFile))
}
}
cred.val, err = NewSigner(key, cert)
if err != nil {
return err
}
return nil
return NewSigner(key, cert)
}

// Store stores the certificate associated with this X509 credential to the location
// specified by certFile attribute
func (cred *Credential) Store() error {
// storeCredentialToFile writes the certificate to the specified file
func (cred *Credential) storeCredentialToFile() error {
if cred.val == nil {
return errors.New("X509 Credential value is not set")
}
Expand All @@ -122,6 +120,24 @@ func (cred *Credential) Store() error {
return nil
}

// Load loads the certificate and key from the location specified by
// certFile attribute using the BCCSP of the client. The private key is
// loaded from the location specified by the keyFile attribute, if the
// private key is not found in the keystore managed by BCCSP
func (cred *Credential) Load() error {
signer, err := cred.loadCredentialFromFiles()
if err != nil {
return err
}
return cred.SetCredentialFromSigner(signer)
}

// Store stores the certificate associated with this X509 credential to the location
// specified by certFile attribute
func (cred *Credential) Store() error {
return cred.storeCredentialToFile()
}

// CreateToken creates token based on this X509 credential
func (cred *Credential) CreateToken(req *http.Request, reqBody []byte) (string, error) {
return util.CreateToken(cred.getCSP(), cred.val.certBytes, cred.val.key, req.Method, req.URL.RequestURI(), reqBody)
Expand Down
Loading