github.com/adecaro/fabric-ca@v2.0.0-alpha+incompatible/lib/server/idemix/revocationauthority_test.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package idemix_test
     8  
     9  import (
    10  	"bytes"
    11  	"crypto/ecdsa"
    12  	"io/ioutil"
    13  	"os"
    14  	"path"
    15  	"testing"
    16  
    17  	fp256bn "github.com/hyperledger/fabric-amcl/amcl/FP256BN"
    18  	. "github.com/hyperledger/fabric-ca/lib/server/idemix"
    19  	"github.com/hyperledger/fabric-ca/lib/server/idemix/mocks"
    20  	dmocks "github.com/hyperledger/fabric-ca/lib/server/idemix/mocks"
    21  	"github.com/hyperledger/fabric-ca/util"
    22  	"github.com/hyperledger/fabric/idemix"
    23  	"github.com/pkg/errors"
    24  	"github.com/stretchr/testify/assert"
    25  )
    26  
    27  func TestLongTermKeyError(t *testing.T) {
    28  	issuer := new(mocks.MyIssuer)
    29  	issuer.On("Name").Return("")
    30  	issuer.On("HomeDir").Return(".")
    31  	opts := &Config{RHPoolSize: 100, RevocationPublicKeyfile: path.Join(".", DefaultRevocationPublicKeyFile),
    32  		RevocationPrivateKeyfile: path.Join("./msp/keystore", DefaultRevocationPrivateKeyFile)}
    33  	issuer.On("Config").Return(opts)
    34  	lib := new(mocks.Lib)
    35  	lib.On("GenerateLongTermRevocationKey").Return(nil, errors.New("Failed to create revocation key"))
    36  	issuer.On("IdemixLib").Return(lib)
    37  	db := new(dmocks.FabricCADB)
    38  	issuer.On("DB").Return(db)
    39  	_, err := NewRevocationAuthority(issuer, 1)
    40  	assert.Error(t, err)
    41  	if err != nil {
    42  		assert.Contains(t, err.Error(), "Failed to generate revocation key for issuer")
    43  	}
    44  }
    45  func TestRevocationKeyLoadError(t *testing.T) {
    46  	homeDir, err := ioutil.TempDir(".", "revokekeyloaderrortest")
    47  	if err != nil {
    48  		t.Fatalf("Failed to create temp directory: %s", err.Error())
    49  	}
    50  	defer os.RemoveAll(homeDir)
    51  	err = os.MkdirAll(path.Join(homeDir, "msp/keystore"), 0777)
    52  	if err != nil {
    53  		t.Fatalf("Failed to create directory: %s", err.Error())
    54  	}
    55  	revocationpubkeyfile := path.Join(homeDir, DefaultRevocationPublicKeyFile)
    56  	revocationprivkeyfile := path.Join(homeDir, "msp/keystore", DefaultRevocationPrivateKeyFile)
    57  	err = util.WriteFile(revocationprivkeyfile, []byte(""), 0666)
    58  	if err != nil {
    59  		t.Fatalf("Failed to write to file: %s", err.Error())
    60  	}
    61  	err = util.WriteFile(revocationpubkeyfile, []byte(""), 0666)
    62  	if err != nil {
    63  		t.Fatalf("Failed to write to file: %s", err.Error())
    64  	}
    65  	issuer := new(mocks.MyIssuer)
    66  	issuer.On("Name").Return("")
    67  	issuer.On("HomeDir").Return(homeDir)
    68  	opts := &Config{RHPoolSize: 100, RevocationPublicKeyfile: revocationpubkeyfile,
    69  		RevocationPrivateKeyfile: revocationprivkeyfile}
    70  	issuer.On("Config").Return(opts)
    71  	lib := new(mocks.Lib)
    72  	issuer.On("IdemixLib").Return(lib)
    73  	db := new(dmocks.FabricCADB)
    74  	issuer.On("DB").Return(db)
    75  	_, err = NewRevocationAuthority(issuer, 1)
    76  	assert.Error(t, err)
    77  	if err != nil {
    78  		assert.Contains(t, err.Error(), "Failed to load revocation key for issuer")
    79  	}
    80  }
    81  
    82  func TestGetRAInfoFromDBError(t *testing.T) {
    83  	homeDir, err := ioutil.TempDir(".", "rainfodberrortest")
    84  	if err != nil {
    85  		t.Fatalf("Failed to create temp directory: %s", err.Error())
    86  	}
    87  	defer os.RemoveAll(homeDir)
    88  	err = os.MkdirAll(path.Join(homeDir, "msp/keystore"), 0777)
    89  	if err != nil {
    90  		t.Fatalf("Failed to create directory: %s", err.Error())
    91  	}
    92  	issuer := new(mocks.MyIssuer)
    93  	issuer.On("Name").Return("ca1")
    94  	lib := new(mocks.Lib)
    95  	revocationKey, err := idemix.GenerateLongTermRevocationKey()
    96  	if err != nil {
    97  		t.Fatalf("Failed to generate test revocation key: %s", err.Error())
    98  	}
    99  	lib.On("GenerateLongTermRevocationKey").Return(revocationKey, nil)
   100  	issuer.On("IdemixLib").Return(lib)
   101  	rainfos := []RevocationAuthorityInfo{}
   102  	db := new(dmocks.FabricCADB)
   103  	db.On("Select", "GetRAInfo", &rainfos, "SELECT * FROM revocation_authority_info").
   104  		Return(errors.New("Failed to execute select query"))
   105  	issuer.On("DB").Return(db)
   106  	opts := &Config{RHPoolSize: 100, RevocationPublicKeyfile: path.Join(homeDir, DefaultRevocationPublicKeyFile),
   107  		RevocationPrivateKeyfile: path.Join(homeDir, "msp/keystore", DefaultRevocationPrivateKeyFile)}
   108  	issuer.On("Config").Return(opts)
   109  	_, err = NewRevocationAuthority(issuer, 1)
   110  	assert.Error(t, err)
   111  }
   112  
   113  func TestGetRAInfoFromNewDBSelectError(t *testing.T) {
   114  	homeDir, err := ioutil.TempDir(".", "rainfodberrortest")
   115  	if err != nil {
   116  		t.Fatalf("Failed to create temp directory: %s", err.Error())
   117  	}
   118  	defer os.RemoveAll(homeDir)
   119  	err = os.MkdirAll(path.Join(homeDir, "msp/keystore"), 0777)
   120  	if err != nil {
   121  		t.Fatalf("Failed to create directory: %s", err.Error())
   122  	}
   123  	issuer := new(mocks.MyIssuer)
   124  	issuer.On("Name").Return("")
   125  	issuer.On("HomeDir").Return(homeDir)
   126  	lib := new(mocks.Lib)
   127  	revocationKey, err := idemix.GenerateLongTermRevocationKey()
   128  	if err != nil {
   129  		t.Fatalf("Failed to generate test revocation key: %s", err.Error())
   130  	}
   131  	lib.On("GenerateLongTermRevocationKey").Return(revocationKey, nil)
   132  	issuer.On("IdemixLib").Return(lib)
   133  	db := new(dmocks.FabricCADB)
   134  	raInfos := []RevocationAuthorityInfo{}
   135  	f := getSelectFunc(t, true, true)
   136  	db.On("Select", "GetRAInfo", &raInfos, SelectRAInfo).Return(f)
   137  	issuer.On("DB").Return(db)
   138  	opts := &Config{RHPoolSize: 100, RevocationPublicKeyfile: path.Join(homeDir, DefaultRevocationPublicKeyFile),
   139  		RevocationPrivateKeyfile: path.Join(homeDir, "msp/keystore", DefaultRevocationPrivateKeyFile)}
   140  	issuer.On("Config").Return(opts)
   141  	_, err = NewRevocationAuthority(issuer, 1)
   142  	assert.Error(t, err)
   143  }
   144  
   145  func TestGetRAInfoFromExistingDB(t *testing.T) {
   146  	homeDir, err := ioutil.TempDir(".", "newraexistingdbtest")
   147  	if err != nil {
   148  		t.Fatalf("Failed to create temp directory: %s", err.Error())
   149  	}
   150  	defer os.RemoveAll(homeDir)
   151  	err = os.MkdirAll(path.Join(homeDir, "msp/keystore"), 0777)
   152  	if err != nil {
   153  		t.Fatalf("Failed to create directory: %s", err.Error())
   154  	}
   155  	issuer := new(mocks.MyIssuer)
   156  	issuer.On("Name").Return("")
   157  	issuer.On("HomeDir").Return(homeDir)
   158  	lib := new(mocks.Lib)
   159  	revocationKey, err := idemix.GenerateLongTermRevocationKey()
   160  	if err != nil {
   161  		t.Fatalf("Failed to generate test revocation key: %s", err.Error())
   162  	}
   163  	issuer.On("IdemixLib").Return(lib)
   164  	rk := NewRevocationKey(path.Join(homeDir, DefaultRevocationPublicKeyFile),
   165  		path.Join(homeDir, "msp/keystore/", DefaultRevocationPrivateKeyFile), lib)
   166  	rk.SetKey(revocationKey)
   167  	err = rk.Store()
   168  	if err != nil {
   169  		t.Fatalf("Failed to store test revocation key: %s", err.Error())
   170  	}
   171  	db := new(dmocks.FabricCADB)
   172  	raInfos := []RevocationAuthorityInfo{}
   173  	f := getSelectFunc(t, false, false)
   174  	db.On("Select", "GetRAInfo", &raInfos, SelectRAInfo).Return(f)
   175  	issuer.On("DB").Return(db)
   176  	opts := &Config{RHPoolSize: 100,
   177  		RevocationPublicKeyfile:  path.Join(homeDir, DefaultRevocationPublicKeyFile),
   178  		RevocationPrivateKeyfile: path.Join(homeDir, "msp/keystore", DefaultRevocationPrivateKeyFile)}
   179  	issuer.On("Config").Return(opts)
   180  	_, err = NewRevocationAuthority(issuer, 1)
   181  	assert.NoError(t, err)
   182  }
   183  
   184  func TestRevocationKeyStoreFailure(t *testing.T) {
   185  	homeDir, err := ioutil.TempDir(".", "rkstoretesthome")
   186  	if err != nil {
   187  		t.Fatalf("Failed to create temp directory: %s", err.Error())
   188  	}
   189  	defer os.RemoveAll(homeDir)
   190  	issuer, db, _ := setupForInsertTests(t, homeDir)
   191  	os.RemoveAll(path.Join(homeDir, "msp/keystore"))
   192  	rainfo := RevocationAuthorityInfo{
   193  		Epoch:                1,
   194  		NextRevocationHandle: 1,
   195  		LastHandleInPool:     100,
   196  		Level:                1,
   197  	}
   198  	result := new(dmocks.Result)
   199  	result.On("RowsAffected").Return(int64(1), nil)
   200  	db.On("NamedExec", InsertRAInfo, &rainfo).Return(result, nil)
   201  	issuer.On("DB").Return(db)
   202  	keystoreDir := path.Join(homeDir, "msp/keystore")
   203  	err = os.MkdirAll(keystoreDir, 4444)
   204  	if err != nil {
   205  		t.Fatalf("Failed to create read only directory: %s", err.Error())
   206  	}
   207  	opts := &Config{RHPoolSize: 100, RevocationPublicKeyfile: path.Join(homeDir, DefaultRevocationPublicKeyFile),
   208  		RevocationPrivateKeyfile: path.Join(keystoreDir, DefaultRevocationPrivateKeyFile)}
   209  	issuer.On("Config").Return(opts)
   210  	_, err = NewRevocationAuthority(issuer, 1)
   211  	assert.Error(t, err)
   212  	if err != nil {
   213  		assert.Contains(t, err.Error(), "Failed to store revocation key of issuer")
   214  	}
   215  }
   216  
   217  func TestGetRAInfoFromNewDBInsertFailure(t *testing.T) {
   218  	homeDir, err := ioutil.TempDir(".", "rainfoinserttest")
   219  	if err != nil {
   220  		t.Fatalf("Failed to create temp directory: %s", err.Error())
   221  	}
   222  	defer os.RemoveAll(homeDir)
   223  	issuer, db, _ := setupForInsertTests(t, homeDir)
   224  	rainfo := RevocationAuthorityInfo{
   225  		Epoch:                1,
   226  		NextRevocationHandle: 1,
   227  		LastHandleInPool:     100,
   228  		Level:                1,
   229  	}
   230  	result := new(dmocks.Result)
   231  	result.On("RowsAffected").Return(int64(0), nil)
   232  	db.On("NamedExec", "AddRAInfo", InsertRAInfo, &rainfo).Return(result, nil)
   233  	issuer.On("DB").Return(db)
   234  	opts := &Config{RHPoolSize: 100, RevocationPublicKeyfile: path.Join(homeDir, DefaultRevocationPublicKeyFile),
   235  		RevocationPrivateKeyfile: path.Join(homeDir, "msp/keystore", DefaultRevocationPrivateKeyFile)}
   236  	issuer.On("Config").Return(opts)
   237  	_, err = NewRevocationAuthority(issuer, 1)
   238  	assert.Error(t, err)
   239  	if err != nil {
   240  		assert.Contains(t, err.Error(), "Failed to insert the revocation authority info record; no rows affected")
   241  	}
   242  }
   243  
   244  func TestGetRAInfoFromNewDBInsertFailure1(t *testing.T) {
   245  	homeDir, err := ioutil.TempDir(".", "rainfoinserttest")
   246  	if err != nil {
   247  		t.Fatalf("Failed to create temp directory: %s", err.Error())
   248  	}
   249  	err = os.MkdirAll(path.Join(homeDir, "msp/keystore"), 0777)
   250  	if err != nil {
   251  		t.Fatalf("Failed to create directory: %s", err.Error())
   252  	}
   253  	defer os.RemoveAll(homeDir)
   254  	issuer, db, _ := setupForInsertTests(t, homeDir)
   255  	rainfo := RevocationAuthorityInfo{
   256  		Epoch:                1,
   257  		NextRevocationHandle: 1,
   258  		LastHandleInPool:     100,
   259  		Level:                1,
   260  	}
   261  	result := new(dmocks.Result)
   262  	result.On("RowsAffected").Return(int64(2), nil)
   263  	db.On("NamedExec", "AddRAInfo", InsertRAInfo, &rainfo).Return(result, nil)
   264  	issuer.On("DB").Return(db)
   265  	opts := &Config{RHPoolSize: 100, RevocationPublicKeyfile: path.Join(homeDir, DefaultRevocationPublicKeyFile),
   266  		RevocationPrivateKeyfile: path.Join(homeDir, "msp/keystore", DefaultRevocationPrivateKeyFile)}
   267  	issuer.On("Config").Return(opts)
   268  	_, err = NewRevocationAuthority(issuer, 1)
   269  	assert.Error(t, err)
   270  	if err != nil {
   271  		assert.Contains(t, err.Error(), "Expected to affect 1 entry in revocation authority info table but affected")
   272  	}
   273  }
   274  
   275  func TestGetRAInfoFromNewDBInsertError(t *testing.T) {
   276  	homeDir, err := ioutil.TempDir(".", "rainfoinserttest")
   277  	if err != nil {
   278  		t.Fatalf("Failed to create temp directory: %s", err.Error())
   279  	}
   280  	defer os.RemoveAll(homeDir)
   281  	issuer, db, _ := setupForInsertTests(t, homeDir)
   282  	rainfo := RevocationAuthorityInfo{
   283  		Epoch:                1,
   284  		NextRevocationHandle: 1,
   285  		LastHandleInPool:     100,
   286  		Level:                1,
   287  	}
   288  	db.On("NamedExec", "AddRAInfo", InsertRAInfo, &rainfo).Return(nil,
   289  		errors.New("Inserting revocation authority info into DB failed"))
   290  	issuer.On("DB").Return(db)
   291  	opts := &Config{RHPoolSize: 100, RevocationPublicKeyfile: path.Join(homeDir, DefaultRevocationPublicKeyFile),
   292  		RevocationPrivateKeyfile: path.Join(homeDir, "msp/keystore", DefaultRevocationPrivateKeyFile)}
   293  	issuer.On("Config").Return(opts)
   294  	_, err = NewRevocationAuthority(issuer, 1)
   295  	assert.Error(t, err)
   296  	if err != nil {
   297  		assert.Contains(t, err.Error(), "Failed to insert revocation authority info into database")
   298  	}
   299  }
   300  
   301  func TestGetNewRevocationHandleSelectError(t *testing.T) {
   302  	homeDir, err := ioutil.TempDir(".", "selecterrortest")
   303  	if err != nil {
   304  		t.Fatalf("Failed to create temp directory: %s", err.Error())
   305  	}
   306  	defer os.RemoveAll(homeDir)
   307  	db := new(dmocks.FabricCADB)
   308  	selectFnc := getSelectFunc(t, true, false)
   309  	ra := getRevocationAuthority(t, "GetNextRevocationHandle", homeDir, db, nil, 0, false, false, selectFnc)
   310  
   311  	tx := new(dmocks.FabricCATx)
   312  	tx.On("Commit", "GetNextRevocationHandle").Return(nil)
   313  	tx.On("Rollback", "GetNextRevocationHandle").Return(nil)
   314  	tx.On("Rebind", SelectRAInfo).Return(SelectRAInfo)
   315  	tx.On("Rebind", UpdateNextHandle).Return(UpdateNextHandle)
   316  	tx.On("Exec", "GetNextRevocationHandle", UpdateNextHandle, 2, 1).Return(nil, nil)
   317  	rcInfos := []RevocationAuthorityInfo{}
   318  	fnc := getTxSelectFunc(t, &rcInfos, 1, true, true)
   319  	tx.On("Select", "GetRAInfo", &rcInfos, SelectRAInfo).Return(fnc)
   320  	tx.On("Select", "GetNextRevocationHandle", &rcInfos, SelectRAInfo).Return(fnc)
   321  
   322  	db.On("BeginTx").Return(tx)
   323  	_, err = ra.GetNewRevocationHandle()
   324  	assert.Error(t, err)
   325  	if err != nil {
   326  		assert.Contains(t, err.Error(), "Failed to get revocation authority info from database")
   327  	}
   328  }
   329  
   330  func TestGetNewRevocationHandleNoData(t *testing.T) {
   331  	homeDir, err := ioutil.TempDir(".", "rhnodatatest")
   332  	if err != nil {
   333  		t.Fatalf("Failed to create temp directory: %s", err.Error())
   334  	}
   335  	defer os.RemoveAll(homeDir)
   336  	db := new(dmocks.FabricCADB)
   337  	selectFnc := getSelectFunc(t, true, false)
   338  	ra := getRevocationAuthority(t, "GetRAInfo", homeDir, db, nil, 0, false, false, selectFnc)
   339  
   340  	tx := new(dmocks.FabricCATx)
   341  	tx.On("Commit", "GetNextRevocationHandle").Return(nil)
   342  	tx.On("Rollback", "GetNextRevocationHandle").Return(nil)
   343  	tx.On("Rebind", SelectRAInfo).Return(SelectRAInfo)
   344  	tx.On("Rebind", UpdateNextHandle).Return(UpdateNextHandle)
   345  	tx.On("Exec", "GetNextRevocationHandle", UpdateNextHandle, 2, 1).Return(nil, nil)
   346  	rcInfos := []RevocationAuthorityInfo{}
   347  	fnc := getTxSelectFunc(t, &rcInfos, 1, false, false)
   348  	tx.On("Select", "GetRAInfo", &rcInfos, SelectRAInfo).Return(fnc)
   349  
   350  	db.On("BeginTx").Return(tx)
   351  	_, err = ra.GetNewRevocationHandle()
   352  	assert.Error(t, err)
   353  	if err != nil {
   354  		assert.Contains(t, err.Error(), "No revocation authority info found in database")
   355  	}
   356  }
   357  
   358  func TestGetNewRevocationHandleExecError(t *testing.T) {
   359  	homeDir, err := ioutil.TempDir(".", "nextrhexecerrortest")
   360  	if err != nil {
   361  		t.Fatalf("Failed to create temp directory: %s", err.Error())
   362  	}
   363  	defer os.RemoveAll(homeDir)
   364  	db := new(dmocks.FabricCADB)
   365  	selectFnc := getSelectFunc(t, true, false)
   366  	ra := getRevocationAuthority(t, "GetRAInfo", homeDir, db, nil, 0, false, false, selectFnc)
   367  
   368  	tx := new(dmocks.FabricCATx)
   369  	rcInfos := []RevocationAuthorityInfo{}
   370  	fnc := getTxSelectFunc(t, &rcInfos, 1, false, true)
   371  	tx.On("Select", "GetRAInfo", &rcInfos, SelectRAInfo).Return(fnc)
   372  	tx.On("Rebind", SelectRAInfo).Return(SelectRAInfo)
   373  	tx.On("Rebind", UpdateNextHandle).Return(UpdateNextHandle)
   374  	tx.On("Exec", "GetNextRevocationHandle", UpdateNextHandle, 2, 1).Return(nil, errors.New("Exec error"))
   375  	tx.On("Commit", "GetNextRevocationHandle").Return(nil)
   376  	tx.On("Rollback", "GetNextRevocationHandle").Return(nil)
   377  
   378  	db.On("BeginTx").Return(tx)
   379  	_, err = ra.GetNewRevocationHandle()
   380  	assert.Error(t, err)
   381  	if err != nil {
   382  		assert.Contains(t, err.Error(), "Failed to update revocation authority info")
   383  	}
   384  }
   385  
   386  func TestGetNewRevocationHandleRollbackError(t *testing.T) {
   387  	homeDir, err := ioutil.TempDir(".", "nextrhrollbackerrortest")
   388  	if err != nil {
   389  		t.Fatalf("Failed to create temp directory: %s", err.Error())
   390  	}
   391  	defer os.RemoveAll(homeDir)
   392  	db := new(dmocks.FabricCADB)
   393  	selectFnc := getSelectFunc(t, true, false)
   394  	ra := getRevocationAuthority(t, "GetRAInfo", homeDir, db, nil, 0, false, false, selectFnc)
   395  
   396  	tx := new(dmocks.FabricCATx)
   397  	rcInfos := []RevocationAuthorityInfo{}
   398  	fnc := getTxSelectFunc(t, &rcInfos, 1, false, true)
   399  	tx.On("Select", "GetRAInfo", &rcInfos, SelectRAInfo).Return(fnc)
   400  	tx.On("Rebind", SelectRAInfo).Return(SelectRAInfo)
   401  	tx.On("Rebind", UpdateNextHandle).Return(UpdateNextHandle)
   402  	tx.On("Exec", "GetNextRevocationHandle", UpdateNextHandle, 2, 1).Return(nil, errors.New("Exec error"))
   403  	tx.On("Commit", "GetNextRevocationHandle").Return(nil)
   404  	tx.On("Rollback", "GetNextRevocationHandle").Return(errors.New("Rollback error"))
   405  
   406  	db.On("BeginTx").Return(tx)
   407  	_, err = ra.GetNewRevocationHandle()
   408  	assert.Error(t, err)
   409  	if err != nil {
   410  		assert.Contains(t, err.Error(), "Error encountered while rolling back transaction")
   411  	}
   412  }
   413  
   414  func TestGetNewRevocationHandleCommitError(t *testing.T) {
   415  	homeDir, err := ioutil.TempDir(".", "nextrhcommiterrortest")
   416  	if err != nil {
   417  		t.Fatalf("Failed to create temp directory: %s", err.Error())
   418  	}
   419  	defer os.RemoveAll(homeDir)
   420  	db := new(dmocks.FabricCADB)
   421  	selectFnc := getSelectFunc(t, true, false)
   422  	ra := getRevocationAuthority(t, "GetRAInfo", homeDir, db, nil, 0, false, false, selectFnc)
   423  
   424  	tx := new(dmocks.FabricCATx)
   425  	tx.On("Commit", "GetNextRevocationHandle").Return(errors.New("Error commiting"))
   426  	tx.On("Rollback").Return(nil)
   427  	tx.On("Rebind", SelectRAInfo).Return(SelectRAInfo)
   428  	tx.On("Rebind", UpdateNextHandle).Return(UpdateNextHandle)
   429  	tx.On("Exec", "GetNextRevocationHandle", UpdateNextHandle, 2, 1).Return(nil, nil)
   430  	rcInfos := []RevocationAuthorityInfo{}
   431  	f1 := getTxSelectFunc(t, &rcInfos, 1, false, true)
   432  	tx.On("Select", "GetRAInfo", &rcInfos, SelectRAInfo).Return(f1)
   433  
   434  	db.On("BeginTx").Return(tx)
   435  	_, err = ra.GetNewRevocationHandle()
   436  	assert.Error(t, err)
   437  	assert.Contains(t, err.Error(), "Error encountered while committing transaction")
   438  }
   439  
   440  func TestGetNewRevocationHandle(t *testing.T) {
   441  	homeDir, err := ioutil.TempDir(".", "nextrhtest")
   442  	if err != nil {
   443  		t.Fatalf("Failed to create temp directory: %s", err.Error())
   444  	}
   445  	defer os.RemoveAll(homeDir)
   446  	db := new(dmocks.FabricCADB)
   447  	selectFnc := getSelectFunc(t, true, false)
   448  	rc := getRevocationAuthority(t, "GetRAInfo", homeDir, db, nil, 0, false, false, selectFnc)
   449  
   450  	tx := new(dmocks.FabricCATx)
   451  	tx.On("Commit", "GetNextRevocationHandle").Return(nil)
   452  	tx.On("Rollback", "GetNextRevocationHandle").Return(nil)
   453  	tx.On("Rebind", SelectRAInfo).Return(SelectRAInfo)
   454  	tx.On("Rebind", UpdateNextHandle).Return(UpdateNextHandle)
   455  	tx.On("Exec", "GetNextRevocationHandle", UpdateNextHandle, 2, 1).Return(nil, nil)
   456  	rcInfos := []RevocationAuthorityInfo{}
   457  	f1 := getTxSelectFunc(t, &rcInfos, 1, false, true)
   458  	tx.On("Select", "GetRAInfo", &rcInfos, SelectRAInfo).Return(f1)
   459  
   460  	db.On("BeginTx").Return(tx)
   461  	rh, err := rc.GetNewRevocationHandle()
   462  	assert.NoError(t, err)
   463  	assert.Equal(t, 0, bytes.Compare(idemix.BigToBytes(fp256bn.NewBIGint(1)), idemix.BigToBytes(rh)), "Expected next revocation handle to be 1")
   464  }
   465  
   466  func TestGetNewRevocationHandleLastHandle(t *testing.T) {
   467  	homeDir, err := ioutil.TempDir(".", "nextlastrhtest")
   468  	if err != nil {
   469  		t.Fatalf("Failed to create temp directory: %s", err.Error())
   470  	}
   471  	defer os.RemoveAll(homeDir)
   472  	db := new(dmocks.FabricCADB)
   473  	selectFnc := getSelectFunc(t, true, false)
   474  	ra := getRevocationAuthority(t, "GetRAInfo", homeDir, db, nil, 0, false, false, selectFnc)
   475  
   476  	tx := new(dmocks.FabricCATx)
   477  	tx.On("Commit", "GetNextRevocationHandle").Return(nil)
   478  	tx.On("Rollback", "GetNextRevocationHandle").Return(nil)
   479  	tx.On("Rebind", SelectRAInfo).Return(SelectRAInfo)
   480  	tx.On("Rebind", UpdateNextAndLastHandle).Return(UpdateNextAndLastHandle)
   481  	tx.On("Exec", "GetNextRevocationHandle", UpdateNextAndLastHandle, 101, 200, 2, 1).Return(nil, nil)
   482  	rcInfos := []RevocationAuthorityInfo{}
   483  	f1 := getTxSelectFunc(t, &rcInfos, 100, false, true)
   484  	tx.On("Select", "GetRAInfo", &rcInfos, SelectRAInfo).Return(f1)
   485  
   486  	db.On("BeginTx").Return(tx)
   487  	rh, err := ra.GetNewRevocationHandle()
   488  	assert.NoError(t, err)
   489  	assert.Equal(t, 0, bytes.Compare(idemix.BigToBytes(fp256bn.NewBIGint(100)), idemix.BigToBytes(rh)),
   490  		"Expected next revocation handle to be 100")
   491  	assert.Equal(t, util.B64Encode(idemix.BigToBytes(fp256bn.NewBIGint(100))), util.B64Encode(idemix.BigToBytes(rh)),
   492  		"Expected next revocation handle to be 100")
   493  }
   494  
   495  func TestGetEpoch(t *testing.T) {
   496  	homeDir, err := ioutil.TempDir(".", "getepochtest")
   497  	if err != nil {
   498  		t.Fatalf("Failed to create temp directory: %s", err.Error())
   499  	}
   500  	defer os.RemoveAll(homeDir)
   501  	db := new(dmocks.FabricCADB)
   502  	selectFnc := getSelectFunc(t, true, false)
   503  	ra := getRevocationAuthority(t, "GetRAInfo", homeDir, db, nil, 0, false, false, selectFnc)
   504  
   505  	rcInfos := []RevocationAuthorityInfo{}
   506  	db.On("Select", "GetRAInfo", &rcInfos, SelectRAInfo).Return(selectFnc)
   507  	epoch, err := ra.Epoch()
   508  	assert.NoError(t, err)
   509  	assert.Equal(t, 1, epoch)
   510  	key := ra.PublicKey()
   511  	assert.NotNil(t, key, "Public key should not be nil")
   512  }
   513  
   514  func TestGetEpochRAInfoError(t *testing.T) {
   515  	homeDir, err := ioutil.TempDir(".", "createcritest")
   516  	if err != nil {
   517  		t.Fatalf("Failed to create temp directory: %s", err.Error())
   518  	}
   519  	defer os.RemoveAll(homeDir)
   520  	db := new(dmocks.FabricCADB)
   521  
   522  	revocationKey, err := idemix.GenerateLongTermRevocationKey()
   523  	if err != nil {
   524  		t.Fatalf("Failed to generate ECDSA key for revocation authority")
   525  	}
   526  	selectFnc := getSelectFuncForCreateCRI(t, true, true)
   527  	ra := getRevocationAuthority(t, "GetRAInfo", homeDir, db, revocationKey, 0, false, false, selectFnc)
   528  	_, err = ra.Epoch()
   529  	assert.Error(t, err, "Epoch should fail if there is an error getting revocation info from DB")
   530  }
   531  
   532  func TestCreateCRIGetRAInfoError(t *testing.T) {
   533  	homeDir, err := ioutil.TempDir(".", "createcritest")
   534  	if err != nil {
   535  		t.Fatalf("Failed to create temp directory: %s", err.Error())
   536  	}
   537  	defer os.RemoveAll(homeDir)
   538  	db := new(dmocks.FabricCADB)
   539  
   540  	revocationKey, err := idemix.GenerateLongTermRevocationKey()
   541  	if err != nil {
   542  		t.Fatalf("Failed to generate ECDSA key for revocation authority")
   543  	}
   544  	selectFnc := getSelectFuncForCreateCRI(t, true, true)
   545  	ra := getRevocationAuthority(t, "GetRAInfo", homeDir, db, revocationKey, 0, false, false, selectFnc)
   546  	_, err = ra.CreateCRI()
   547  	assert.Error(t, err, "CreateCRI should fail if there is an error getting revocation info from DB")
   548  }
   549  
   550  func TestCreateCRIGetRevokeCredsError(t *testing.T) {
   551  	homeDir, err := ioutil.TempDir(".", "createcritest")
   552  	if err != nil {
   553  		t.Fatalf("Failed to create temp directory: %s", err.Error())
   554  	}
   555  	defer os.RemoveAll(homeDir)
   556  	db := new(dmocks.FabricCADB)
   557  
   558  	revocationKey, err := idemix.GenerateLongTermRevocationKey()
   559  	if err != nil {
   560  		t.Fatalf("Failed to generate ECDSA key for revocation authority")
   561  	}
   562  
   563  	selectFnc := getSelectFuncForCreateCRI(t, true, false)
   564  	ra := getRevocationAuthority(t, "GetRAInfo", homeDir, db, revocationKey, 0, true, false, selectFnc)
   565  	_, err = ra.CreateCRI()
   566  	assert.Error(t, err, "CreateCRI should fail if there is an error getting revoked credentials")
   567  }
   568  
   569  func TestIdemixCreateCRIError(t *testing.T) {
   570  	homeDir, err := ioutil.TempDir(".", "createcritest")
   571  	if err != nil {
   572  		t.Fatalf("Failed to create temp directory: %s", err.Error())
   573  	}
   574  	defer os.RemoveAll(homeDir)
   575  	db := new(dmocks.FabricCADB)
   576  
   577  	revocationKey, err := idemix.GenerateLongTermRevocationKey()
   578  	if err != nil {
   579  		t.Fatalf("Failed to generate ECDSA key for revocation authority")
   580  	}
   581  
   582  	db = new(dmocks.FabricCADB)
   583  	selectFnc := getSelectFuncForCreateCRI(t, true, false)
   584  	ra := getRevocationAuthority(t, "GetRAInfo", homeDir, db, revocationKey, 0, false, true, selectFnc)
   585  	_, err = ra.CreateCRI()
   586  	assert.Error(t, err, "CreateCRI should fail if idemix.CreateCRI returns an error")
   587  }
   588  
   589  func TestEpochValuesInCRI(t *testing.T) {
   590  	homeDir, err := ioutil.TempDir(".", "createcritest")
   591  	if err != nil {
   592  		t.Fatalf("Failed to create temp directory: %s", err.Error())
   593  	}
   594  	defer os.RemoveAll(homeDir)
   595  	revocationKey, err := idemix.GenerateLongTermRevocationKey()
   596  	if err != nil {
   597  		t.Fatalf("Failed to generate ECDSA key for revocation authority")
   598  	}
   599  	selectFnc := getSelectFuncForCreateCRI(t, true, false)
   600  	db := new(dmocks.FabricCADB)
   601  	ra := getRevocationAuthority(t, "GetRAInfo", homeDir, db, revocationKey, 0, false, false, selectFnc)
   602  	cri, err := ra.CreateCRI()
   603  	assert.NoError(t, err)
   604  
   605  	db = new(dmocks.FabricCADB)
   606  	cri1, err := ra.CreateCRI()
   607  	assert.NoError(t, err)
   608  	if err == nil {
   609  		assert.Equal(t, cri.Epoch, cri1.Epoch)
   610  	}
   611  }
   612  
   613  func setupForInsertTests(t *testing.T, homeDir string) (*mocks.MyIssuer, *dmocks.FabricCADB, *ecdsa.PrivateKey) {
   614  	issuer := new(mocks.MyIssuer)
   615  	issuer.On("Name").Return("")
   616  	issuer.On("HomeDir").Return(homeDir)
   617  	keystore := path.Join(homeDir, "msp/keystore")
   618  	err := os.MkdirAll(keystore, 0777)
   619  	if err != nil {
   620  		t.Fatalf("Failed to create directory %s: %s", keystore, err.Error())
   621  	}
   622  	lib := new(mocks.Lib)
   623  	privateKey, err := idemix.GenerateLongTermRevocationKey()
   624  	if err != nil {
   625  		t.Fatalf("Failed to generate ECDSA key for revocation authority")
   626  	}
   627  	lib.On("GenerateLongTermRevocationKey").Return(privateKey, nil)
   628  	issuer.On("IdemixLib").Return(lib)
   629  	db := new(dmocks.FabricCADB)
   630  	rcInfos := []RevocationAuthorityInfo{}
   631  	f := getSelectFunc(t, true, false)
   632  	db.On("Select", "GetRAInfo", &rcInfos, SelectRAInfo).Return(f)
   633  	return issuer, db, privateKey
   634  }
   635  
   636  func getRevocationAuthority(t *testing.T, funcName, homeDir string, db *dmocks.FabricCADB, revocationKey *ecdsa.PrivateKey, revokedCred int,
   637  	getRevokedCredsError bool, idemixCreateCRIError bool, selectFnc func(string, interface{}, string, ...interface{}) error) RevocationAuthority {
   638  	issuer := new(mocks.MyIssuer)
   639  	issuer.On("Name").Return("ca1")
   640  	issuer.On("HomeDir").Return(homeDir)
   641  	keystore := path.Join(homeDir, "msp/keystore")
   642  	err := os.MkdirAll(keystore, 0777)
   643  	if err != nil {
   644  		t.Fatalf("Failed to create directory %s: %s", keystore, err.Error())
   645  	}
   646  
   647  	if revocationKey == nil {
   648  		var err error
   649  		revocationKey, err = idemix.GenerateLongTermRevocationKey()
   650  		if err != nil {
   651  			t.Fatalf("Failed to generate ECDSA key for revocation authority")
   652  		}
   653  	}
   654  	lib := new(mocks.Lib)
   655  	lib.On("GenerateLongTermRevocationKey").Return(revocationKey, nil)
   656  	issuer.On("IdemixLib").Return(lib)
   657  
   658  	rcInfosForSelect := []RevocationAuthorityInfo{}
   659  	db.On("Select", "GetRAInfo", &rcInfosForSelect, SelectRAInfo).Return(selectFnc)
   660  	rcinfo := RevocationAuthorityInfo{
   661  		Epoch:                1,
   662  		NextRevocationHandle: 1,
   663  		LastHandleInPool:     100,
   664  		Level:                1,
   665  	}
   666  	result := new(dmocks.Result)
   667  	result.On("RowsAffected").Return(int64(1), nil)
   668  	db.On("NamedExec", "AddRAInfo", InsertRAInfo, &rcinfo).Return(result, nil)
   669  	issuer.On("DB").Return(db)
   670  	cfg := &Config{RHPoolSize: 100, RevocationPublicKeyfile: path.Join(homeDir, DefaultRevocationPublicKeyFile),
   671  		RevocationPrivateKeyfile: path.Join(homeDir, "msp/keystore", DefaultRevocationPrivateKeyFile)}
   672  	issuer.On("Config").Return(cfg)
   673  
   674  	rnd, err := idemix.GetRand()
   675  	if err != nil {
   676  		t.Fatalf("Failed generate random number: %s", err.Error())
   677  	}
   678  	issuer.On("IdemixRand").Return(rnd)
   679  
   680  	credDBAccessor := new(mocks.CredDBAccessor)
   681  	if getRevokedCredsError {
   682  		credDBAccessor.On("GetRevokedCredentials").Return(nil, errors.New("Failed to get revoked credentials"))
   683  	} else {
   684  		revokedCreds := []CredRecord{}
   685  		if revokedCred > 0 {
   686  			rh := util.B64Encode(idemix.BigToBytes(fp256bn.NewBIGint(revokedCred)))
   687  			cr := CredRecord{
   688  				RevocationHandle: rh,
   689  				Cred:             "",
   690  				ID:               "",
   691  				Status:           "revoked",
   692  			}
   693  			revokedCreds = append(revokedCreds, cr)
   694  		}
   695  		credDBAccessor.On("GetRevokedCredentials").Return(revokedCreds, nil)
   696  	}
   697  
   698  	issuer.On("CredDBAccessor").Return(credDBAccessor)
   699  
   700  	validHandles := []*fp256bn.BIG{}
   701  	for i := 1; i <= 100; i = i + 1 {
   702  		validHandles = append(validHandles, fp256bn.NewBIGint(i))
   703  	}
   704  	alg := idemix.ALG_NO_REVOCATION
   705  	if idemixCreateCRIError {
   706  		lib.On("CreateCRI", revocationKey, validHandles, 1, alg, rnd).Return(nil, errors.New("Idemix lib create CRI error"))
   707  	} else {
   708  		cri, err := idemix.CreateCRI(revocationKey, validHandles, 1, alg, rnd)
   709  		if err != nil {
   710  			t.Fatalf("Failed to create CRI: %s", err.Error())
   711  		}
   712  		lib.On("CreateCRI", revocationKey, validHandles, 1, alg, rnd).Return(cri, nil)
   713  	}
   714  
   715  	ra, err := NewRevocationAuthority(issuer, 1)
   716  	if err != nil {
   717  		t.Fatalf("Failed to get revocation authority instance: %s", err.Error())
   718  	}
   719  	return ra
   720  }
   721  
   722  func getSelectFunc(t *testing.T, newDB bool, isError bool) func(string, interface{}, string, ...interface{}) error {
   723  	numTimesCalled := 0
   724  	return func(funcName string, dest interface{}, query string, args ...interface{}) error {
   725  		rcInfos, _ := dest.(*[]RevocationAuthorityInfo)
   726  		rcInfo := RevocationAuthorityInfo{
   727  			Epoch:                1,
   728  			NextRevocationHandle: 1,
   729  			LastHandleInPool:     100,
   730  			Level:                1,
   731  		}
   732  		if !newDB || numTimesCalled > 0 {
   733  			*rcInfos = append(*rcInfos, rcInfo)
   734  		}
   735  		if isError {
   736  			return errors.New("Failed to get RevocationComponentInfo from DB")
   737  		}
   738  		numTimesCalled = numTimesCalled + 1
   739  		return nil
   740  	}
   741  }
   742  
   743  func getSelectFuncForCreateCRI(t *testing.T, newDB bool, isError bool) func(string, interface{}, string, ...interface{}) error {
   744  	numTimesCalled := 0
   745  	return func(funcName string, dest interface{}, query string, args ...interface{}) error {
   746  		rcInfos, _ := dest.(*[]RevocationAuthorityInfo)
   747  		rcInfo := RevocationAuthorityInfo{
   748  			Epoch:                1,
   749  			NextRevocationHandle: 1,
   750  			LastHandleInPool:     100,
   751  			Level:                1,
   752  		}
   753  		if !newDB || numTimesCalled > 0 {
   754  			*rcInfos = append(*rcInfos, rcInfo)
   755  		}
   756  
   757  		var err error
   758  		if isError && numTimesCalled%2 == 1 {
   759  			err = errors.New("Failed to get RevocationComponentInfo from DB")
   760  		}
   761  		numTimesCalled = numTimesCalled + 1
   762  		return err
   763  	}
   764  }
   765  
   766  func getTxSelectFunc(t *testing.T, rcs *[]RevocationAuthorityInfo, nextRH int, isError bool, isAppend bool) func(string, interface{}, string, ...interface{}) error {
   767  	return func(funcName string, dest interface{}, query string, args ...interface{}) error {
   768  		rcInfos := dest.(*[]RevocationAuthorityInfo)
   769  		rcInfo := RevocationAuthorityInfo{
   770  			Epoch:                1,
   771  			NextRevocationHandle: nextRH,
   772  			LastHandleInPool:     100,
   773  			Level:                1,
   774  		}
   775  		if isAppend {
   776  			*rcInfos = append(*rcInfos, rcInfo)
   777  			*rcs = append(*rcs, rcInfo)
   778  		}
   779  
   780  		if isError {
   781  			return errors.New("Failed to get RevocationComponentInfo from DB")
   782  		}
   783  		return nil
   784  	}
   785  }