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 }