Skip to content

Commit

Permalink
[FAB-9244] 2.Server changes to get Idemix credential
Browse files Browse the repository at this point in the history
This change set contains server side changes for getting
an Idemix credential. Changes include:

1. New package lib/server/idemix that contains handler for
/v1/api/idemix/credential endpoint, revocation component,
issuer credential, and db accessor for credential and revocation
component info
2. Mocks for all the new interfaces
3. Associated changes in the lib package

Change-Id: Icd7f8d7a316a184010278e1f394d78b42cad5482
Signed-off-by: Anil Ambati <[email protected]>
  • Loading branch information
Anil Ambati committed May 17, 2018
1 parent 71aac26 commit 1d632b8
Show file tree
Hide file tree
Showing 34 changed files with 3,294 additions and 203 deletions.
1 change: 1 addition & 0 deletions docs/source/servercli.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ Fabric-CA Server's CLI
--cacount int Number of non-default CA instances
--cafiles stringSlice A list of comma-separated CA configuration files
--cfg.affiliations.allowremove Enables removal of affiliations dynamically
--cfg.idemix.revocationhandlepoolsize int Specifies revocation handle pool size (default 100)
--cfg.identities.allowremove Enables removal of identities dynamically
--crl.expiry duration Expiration for the CRL generated by the gencrl request (default 24h0m0s)
--crlsizelimit int Size limit of an acceptable CRL in bytes (default 512000)
Expand Down
96 changes: 62 additions & 34 deletions lib/ca.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,26 +22,25 @@ import (
"sync"
"time"

"github.com/hyperledger/fabric/idemix"

"github.com/cloudflare/cfssl/config"
cfcsr "github.com/cloudflare/cfssl/csr"
"github.com/cloudflare/cfssl/initca"
"github.com/cloudflare/cfssl/log"
"github.com/cloudflare/cfssl/signer"
cflocalsigner "github.com/cloudflare/cfssl/signer/local"
proto "github.com/golang/protobuf/proto"
"github.com/hyperledger/fabric-amcl/amcl"
"github.com/hyperledger/fabric-ca/api"
"github.com/hyperledger/fabric-ca/lib/dbutil"
"github.com/hyperledger/fabric-ca/lib/ldap"
"github.com/hyperledger/fabric-ca/lib/metadata"
idemix "github.com/hyperledger/fabric-ca/lib/server/idemix"
"github.com/hyperledger/fabric-ca/lib/spi"
"github.com/hyperledger/fabric-ca/lib/tcert"
"github.com/hyperledger/fabric-ca/lib/tls"
"github.com/hyperledger/fabric-ca/util"
"github.com/hyperledger/fabric/bccsp"
"github.com/hyperledger/fabric/common/attrmgr"
"github.com/jmoiron/sqlx"
"github.com/pkg/errors"
)

Expand Down Expand Up @@ -78,17 +77,22 @@ type CA struct {
// The database handle used to store certificates and optionally
// the user registry information, unless LDAP it enabled for the
// user registry function.
db *sqlx.DB
db *dbutil.DB
// The crypto service provider (BCCSP)
csp bccsp.BCCSP
// The certificate DB accessor
certDBAccessor *CertDBAccessor
// The Idemix credential DB accessor
credDBAccessor idemix.CredDBAccessor
// The user registry
registry spi.UserRegistry
// The signer used for enrollment
enrollSigner signer.Signer
// idemix issuer credential for the CA
issuerCred IssuerCredential
issuerCred idemix.IssuerCredential
// A random number used in generation of Idemix nonces and credentials
idemixRand *amcl.RAND
rc idemix.RevocationComponent
// The options to use in verifying a signature in token-based authentication
verifyOptions *x509.VerifyOptions
// The attribute manager
Expand Down Expand Up @@ -278,15 +282,24 @@ func (ca *CA) initKeyMaterial(renew bool) error {
func (ca *CA) initIdemixKeyMaterial(renew bool) error {
log.Debug("Initialize Idemix key material")

rng, err := idemix.NewLib().GetRand()
if err != nil {
return errors.Wrapf(err, "Error generating random number")
}
ca.idemixRand = rng

idemixPubKey := ca.Config.CA.IdemixPublicKeyfile
idemixSecretKey := ca.Config.CA.IdemixSecretKeyfile
issuerCred := newIssuerCredential(idemixPubKey, idemixSecretKey)
issuerCred := idemix.NewCAIdemixCredential(idemixPubKey, idemixSecretKey, idemix.NewLib())

if !renew {
pubKeyFileExists := util.FileExists(idemixPubKey)
privKeyFileExists := util.FileExists(idemixSecretKey)
// If they both exist, the CA was already initialized, load the keys from the disk
if pubKeyFileExists && privKeyFileExists {
log.Info("The Idemix issuer public and secret key files already exist")
log.Infof(" secret key file location: %s", idemixSecretKey)
log.Infof(" public key file location: %s", idemixPubKey)
err := issuerCred.Load()
if err != nil {
return err
Expand All @@ -295,11 +308,11 @@ func (ca *CA) initIdemixKeyMaterial(renew bool) error {
return nil
}
}
ik, err := ca.getNewIssuerKey()
ik, err := issuerCred.NewIssuerKey()
if err != nil {
return err
}
log.Infof("The idemix public and secret keys were generated for CA %s", ca.Config.CA.Name)
log.Infof("The Idemix public and secret keys were generated for CA %s", ca.Config.CA.Name)
issuerCred.SetIssuerKey(ik)
err = issuerCred.Store()
if err != nil {
Expand All @@ -309,27 +322,6 @@ func (ca *CA) initIdemixKeyMaterial(renew bool) error {
return nil
}

func (ca *CA) getNewIssuerKey() (*idemix.IssuerKey, error) {
rng, err := idemix.GetRand()
if err != nil {
log.Errorf("Error getting rng: \"%s\"", err)
return nil, errors.Wrapf(err, "Error generating issuer key")
}
// Currently, Idemix library supports these four attributes. The supported attribute names
// must also be known when creating issuer key. In the future, Idemix library will support
// arbitary attribute names, so removing the need to hardcode attribute names in the issuer
// key.
// OU - organization unit
// id - enrollment ID of the user
// isAdmin - if the user is admin
// revocationHandle - revocation handle of a credential
ik, err := idemix.NewIssuerKey([]string{"OU", "id", "isAdmin", "revocationHandle"}, rng)
if err != nil {
return nil, err
}
return ik, nil
}

// Get the CA certificate for this CA
func (ca *CA) getCACert() (cert []byte, err error) {
if ca.Config.Intermediate.ParentServer.URL != "" {
Expand Down Expand Up @@ -547,6 +539,9 @@ func (ca *CA) initConfig() (err error) {
log.Level = log.LevelDebug
}
ca.normalizeStringSlices()
if ca.Config.Cfg.Idemix.RevocationHandlePoolSize == 0 {
ca.Config.Cfg.Idemix.RevocationHandlePoolSize = idemix.DefaultRevocationHandlePoolSize
}
return nil
}

Expand Down Expand Up @@ -688,6 +683,12 @@ func (ca *CA) initDB() error {
// Set the certificate DB accessor
ca.certDBAccessor = NewCertDBAccessor(ca.db, ca.levels.Certificate)

ca.credDBAccessor = idemix.NewCredentialAccessor(ca.db, ca.levels.Credential)
ca.rc, err = idemix.NewRevocationComponent(ca, &ca.Config.Cfg.Idemix, ca.levels.RCInfo)
if err != nil {
return err
}

// If DB initialization fails and we need to reinitialize DB, need to make sure to set the DB accessor for the signer
if ca.enrollSigner != nil {
ca.enrollSigner.SetDBAccessor(ca.certDBAccessor)
Expand Down Expand Up @@ -919,11 +920,38 @@ func (ca *CA) addAffiliation(path, parentPath string) error {
return ca.registry.InsertAffiliation(path, parentPath, ca.levels.Affiliation)
}

// GetIssuerCredential returns IssuerCredential of this CA
func (ca *CA) GetIssuerCredential() IssuerCredential {
// GetName returns name of this CA
func (ca *CA) GetName() string {
return ca.Config.CA.Name
}

// IdemixRand returns random number used by this CA in generation of nonces
// and Idemix credentials
func (ca *CA) IdemixRand() *amcl.RAND {
return ca.idemixRand
}

// IssuerCredential returns IssuerCredential of this CA
func (ca *CA) IssuerCredential() idemix.IssuerCredential {
return ca.issuerCred
}

// RevocationComponent returns revocation component of this CA
func (ca *CA) RevocationComponent() idemix.RevocationComponent {
return ca.rc
}

// DB returns the FabricCADB object (which represents database handle
// to the CA database) associated with this CA
func (ca *CA) DB() dbutil.FabricCADB {
return ca.db
}

// CredDBAccessor returns the Idemix credential DB accessor for CA
func (ca *CA) CredDBAccessor() idemix.CredDBAccessor {
return ca.credDBAccessor
}

// CertDBAccessor returns the certificate DB accessor for CA
func (ca *CA) CertDBAccessor() *CertDBAccessor {
return ca.certDBAccessor
Expand All @@ -935,7 +963,7 @@ func (ca *CA) DBAccessor() spi.UserRegistry {
}

// GetDB returns pointer to database
func (ca *CA) GetDB() *sqlx.DB {
func (ca *CA) GetDB() *dbutil.DB {
return ca.db
}

Expand Down Expand Up @@ -1048,8 +1076,8 @@ func (ca *CA) getUserAffiliation(username string) (string, error) {
return aff, nil
}

// Fill the CA info structure appropriately
func (ca *CA) fillCAInfo(info *serverInfoResponseNet) error {
// fillCAInfo fills the CA info structure appropriately
func (ca *CA) fillCAInfo(info *ServerInfoResponseNet) error {
caChain, err := ca.getCAChain()
if err != nil {
return err
Expand Down
10 changes: 5 additions & 5 deletions lib/caconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ import (
"github.com/hyperledger/fabric-ca/api"
"github.com/hyperledger/fabric-ca/lib/dbutil"
"github.com/hyperledger/fabric-ca/lib/ldap"
"github.com/hyperledger/fabric-ca/lib/server/idemix"
"github.com/hyperledger/fabric-ca/lib/tls"
"github.com/hyperledger/fabric-ca/util"
"github.com/hyperledger/fabric/bccsp/factory"
"github.com/hyperledger/fabric/idemix"
)

const (
Expand Down Expand Up @@ -90,10 +90,9 @@ csr:
// "skip" - to skip the field.
type CAConfig struct {
Version string `skip:"true"`
Cfg cfgOptions
Cfg CfgOptions
CA CAInfo
Signing *config.Signing
IssuerKey *idemix.IssuerKey
CSR api.CSRInfo
Registry CAConfigRegistry
Affiliations map[string]interface{}
Expand All @@ -107,10 +106,11 @@ type CAConfig struct {
CRL CRLConfig
}

// cfgOptions is a CA configuration that allows for setting different options
type cfgOptions struct {
// CfgOptions is a CA configuration that allows for setting different options
type CfgOptions struct {
Identities identitiesOptions
Affiliations affiliationsOptions
Idemix idemix.CfgOptions
}

// identitiesOptions are options that are related to identities
Expand Down
12 changes: 6 additions & 6 deletions lib/certdbaccessor.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,16 @@ import (
"strings"
"time"

"github.com/jmoiron/sqlx"
"github.com/pkg/errors"

"github.com/cloudflare/cfssl/certdb"
certsql "github.com/cloudflare/cfssl/certdb/sql"
"github.com/cloudflare/cfssl/log"
"github.com/hyperledger/fabric-ca/lib/dbutil"
"github.com/hyperledger/fabric-ca/lib/server"
"github.com/hyperledger/fabric-ca/util"
"github.com/kisielk/sqlstruct"

"github.com/jmoiron/sqlx"
)

const (
Expand Down Expand Up @@ -68,14 +68,14 @@ type CertRecord struct {
type CertDBAccessor struct {
level int
accessor certdb.Accessor
db *sqlx.DB
db *dbutil.DB
}

// NewCertDBAccessor returns a new Accessor.
func NewCertDBAccessor(db *sqlx.DB, level int) *CertDBAccessor {
func NewCertDBAccessor(db *dbutil.DB, level int) *CertDBAccessor {
cffslAcc := new(CertDBAccessor)
cffslAcc.db = db
cffslAcc.accessor = certsql.NewAccessor(db)
cffslAcc.accessor = certsql.NewAccessor(db.DB)
cffslAcc.level = level
return cffslAcc
}
Expand All @@ -88,7 +88,7 @@ func (d *CertDBAccessor) checkDB() error {
}

// SetDB changes the underlying sql.DB object Accessor is manipulating.
func (d *CertDBAccessor) SetDB(db *sqlx.DB) {
func (d *CertDBAccessor) SetDB(db *dbutil.DB) {
d.db = db
}

Expand Down
4 changes: 2 additions & 2 deletions lib/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ func (c *Client) GetCAInfo(req *api.GetCAInfoRequest) (*GetCAInfoResponse, error
if err != nil {
return nil, err
}
netSI := &serverInfoResponseNet{}
netSI := &ServerInfoResponseNet{}
err = c.SendReq(cainforeq, netSI)
if err != nil {
return nil, err
Expand All @@ -172,7 +172,7 @@ func (c *Client) GetCAInfo(req *api.GetCAInfoRequest) (*GetCAInfoResponse, error
}

// Convert from network to local server information
func (c *Client) net2LocalServerInfo(net *serverInfoResponseNet, local *GetCAInfoResponse) error {
func (c *Client) net2LocalServerInfo(net *ServerInfoResponseNet, local *GetCAInfoResponse) error {
caChain, err := util.B64Decode(net.CAChain)
if err != nil {
return err
Expand Down
3 changes: 2 additions & 1 deletion lib/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1313,7 +1313,8 @@ func TestRevokedIdentity(t *testing.T) {

// 'admin' revokes user 'TestUser'
revReq := &api.RevocationRequest{
Name: "TestUser",
Name: "TestUser",
GenCRL: true,
}

_, err = admin_id.Revoke(revReq)
Expand Down
10 changes: 5 additions & 5 deletions lib/dasqlite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ DELETE FROM affiliations;

type TestAccessor struct {
Accessor *Accessor
DB *sqlx.DB
DB *dbutil.DB
}

func (ta *TestAccessor) Truncate() {
Expand Down Expand Up @@ -81,7 +81,7 @@ func TestSQLite(t *testing.T) {
}

// Truncate truncates the DB
func Truncate(db *sqlx.DB) {
func Truncate(db *dbutil.DB) {
var sql []string
sql = []string{sqliteTruncateTables}

Expand Down Expand Up @@ -120,10 +120,10 @@ func TestDBCreation(t *testing.T) {
testWithExistingDb(t)
}

func createSQLiteDB(path string, t *testing.T) (*sqlx.DB, *TestAccessor) {
db, err := sqlx.Open("sqlite3", path)
func createSQLiteDB(path string, t *testing.T) (*dbutil.DB, *TestAccessor) {
sqlxdb, err := sqlx.Open("sqlite3", path)
assert.NoError(t, err, "Failed to open SQLite database")

db := &dbutil.DB{DB: sqlxdb}
accessor := NewDBAccessor(db)

ta := &TestAccessor{
Expand Down
Loading

0 comments on commit 1d632b8

Please sign in to comment.