github.com/hxx258456/fabric-ca-gm@v0.0.3-0.20221111064038-a268ad7e3a37/lib/server/idemix/issuer_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 "crypto/rand" 11 "fmt" 12 "io/ioutil" 13 "os" 14 "path/filepath" 15 "testing" 16 17 "github.com/hxx258456/ccgo/sm2" 18 "github.com/hxx258456/fabric-ca-gm/internal/pkg/util" 19 "github.com/hxx258456/fabric-ca-gm/lib" 20 dbutil "github.com/hxx258456/fabric-ca-gm/lib/server/db/util" 21 . "github.com/hxx258456/fabric-ca-gm/lib/server/idemix" 22 "github.com/hxx258456/fabric-ca-gm/lib/server/idemix/mocks" 23 dmocks "github.com/hxx258456/fabric-ca-gm/lib/server/idemix/mocks" 24 "github.com/hxx258456/fabric-gm/bccsp" 25 "github.com/hxx258456/fabric-gm/idemix" 26 "github.com/kisielk/sqlstruct" 27 "github.com/pkg/errors" 28 "github.com/stretchr/testify/assert" 29 ) 30 31 func TestNewIssuer(t *testing.T) { 32 lib := new(mocks.Lib) 33 cfg := &Config{ 34 NonceExpiration: "15", 35 NonceSweepInterval: "15", 36 } 37 issuer := NewIssuer("ca1", ".", cfg, util.GetDefaultBCCSP(), lib) 38 assert.NotNil(t, issuer) 39 } 40 41 func TestInit(t *testing.T) { 42 testdir, err := ioutil.TempDir(".", "issuerinittest") 43 if err != nil { 44 t.Fatalf("Failed to create temp directory: %s", err.Error()) 45 } 46 defer os.RemoveAll(testdir) 47 err = os.MkdirAll(filepath.Join(testdir, "msp/keystore"), 0777) 48 if err != nil { 49 t.Fatalf("Failed to create directory: %s", err.Error()) 50 } 51 52 db, issuer := getIssuer(t, testdir, false, false) 53 assert.NotNil(t, issuer) 54 err = issuer.Init(false, nil, &dbutil.Levels{Credential: 1, RAInfo: 1, Nonce: 1}) 55 assert.NoError(t, err, "Init should not return an error if db is nil") 56 57 err = issuer.Init(false, db, &dbutil.Levels{Credential: 1, RAInfo: 1, Nonce: 1}) 58 assert.NoError(t, err) 59 60 ik, err := issuer.IssuerPublicKey() 61 assert.NoError(t, err, "IssuerPublicKey should not return an error") 62 assert.NotNil(t, ik) 63 ctx := new(mocks.ServerRequestCtx) 64 ctx.On("IsBasicAuth").Return(true) 65 ctx.On("BasicAuthentication").Return("", errors.New("Authentication error")) 66 ctx.On("TokenAuthentication").Return("", errors.New("Authentication error")) 67 _, err = issuer.IssueCredential(ctx) 68 assert.Error(t, err, "IssuerCredential should fail") 69 _, err = issuer.GetCRI(ctx) 70 assert.Error(t, err, "GetCRI should fail") 71 } 72 73 func TestInitDBNotInitialized(t *testing.T) { 74 cfg := &Config{ 75 NonceExpiration: "15s", 76 NonceSweepInterval: "15m", 77 } 78 var db *dmocks.FabricCADB 79 issuer := NewIssuer("ca1", ".", cfg, util.GetDefaultBCCSP(), NewLib()) 80 err := issuer.Init(false, db, &dbutil.Levels{Credential: 1, RAInfo: 1, Nonce: 1}) 81 assert.NoError(t, err) 82 83 db = new(dmocks.FabricCADB) 84 db.On("IsInitialized").Return(false) 85 issuer = NewIssuer("ca1", ".", cfg, util.GetDefaultBCCSP(), NewLib()) 86 err = issuer.Init(false, db, &dbutil.Levels{Credential: 1, RAInfo: 1, Nonce: 1}) 87 assert.NoError(t, err) 88 } 89 90 func TestInitExistingIssuerCredential(t *testing.T) { 91 testdir, err := ioutil.TempDir(".", "issuerinittest") 92 if err != nil { 93 t.Fatalf("Failed to create temp directory: %s", err.Error()) 94 } 95 defer os.RemoveAll(testdir) 96 err = os.MkdirAll(filepath.Join(testdir, "msp/keystore"), 0777) 97 if err != nil { 98 t.Fatalf("Failed to create directory: %s", err.Error()) 99 } 100 err = lib.CopyFile(testPublicKeyFile, filepath.Join(testdir, "IssuerPublicKey")) 101 if err != nil { 102 t.Fatalf("Failed to copy file: %s", err.Error()) 103 } 104 err = lib.CopyFile(testSecretKeyFile, filepath.Join(testdir, "msp/keystore/IssuerSecretKey")) 105 if err != nil { 106 t.Fatalf("Failed to copy file: %s", err.Error()) 107 } 108 109 db, issuer := getIssuer(t, testdir, false, false) 110 assert.NotNil(t, issuer) 111 112 secrekeyfile := filepath.Join(testdir, "msp/keystore/IssuerSecretKey") 113 secrekeyFileInfo, err := os.Stat(secrekeyfile) 114 if err != nil { 115 t.Fatalf("os.Stat failed on test dir: %s", err) 116 } 117 oldmode := secrekeyFileInfo.Mode() 118 err = os.Chmod(secrekeyfile, 0000) 119 if err != nil { 120 t.Fatalf("Chmod on %s failed: %s", secrekeyFileInfo.Name(), err) 121 } 122 err = issuer.Init(false, db, &dbutil.Levels{Credential: 1, RAInfo: 1, Nonce: 1}) 123 assert.Error(t, err, "Init should fail if it fails to load issuer credential") 124 125 err = os.Chmod(secrekeyfile, oldmode) 126 if err != nil { 127 t.Fatalf("Chmod on %s failed: %s", testdir, err) 128 } 129 err = issuer.Init(false, db, &dbutil.Levels{Credential: 1, RAInfo: 1, Nonce: 1}) 130 assert.NoError(t, err) 131 } 132 func TestInitRenewTrue(t *testing.T) { 133 testdir, err := ioutil.TempDir(".", "issuerinittest") 134 if err != nil { 135 t.Fatalf("Failed to create temp directory: %s", err.Error()) 136 } 137 defer os.RemoveAll(testdir) 138 db, issuer := getIssuer(t, testdir, true, false) 139 assert.NotNil(t, issuer) 140 141 err = issuer.Init(true, db, &dbutil.Levels{Credential: 1, RAInfo: 1, Nonce: 1}) 142 assert.Error(t, err, "Init should fail if it fails to generate random number") 143 144 db, issuer = getIssuer(t, testdir, false, true) 145 assert.NotNil(t, issuer) 146 err = issuer.Init(true, db, &dbutil.Levels{Credential: 1, RAInfo: 1, Nonce: 1}) 147 assert.Error(t, err, "Init should fail if it fails to create new issuer key") 148 149 db, issuer = getIssuer(t, testdir, false, false) 150 assert.NotNil(t, issuer) 151 152 testdataInfo, err := os.Stat(testdir) 153 if err != nil { 154 t.Fatalf("os.Stat failed on test dir: %s", err) 155 } 156 oldmode := testdataInfo.Mode() 157 err = os.Chmod(testdir, 0000) 158 if err != nil { 159 t.Fatalf("Chmod on %s failed: %s", testdataInfo.Name(), err) 160 } 161 defer func() { 162 err = os.Chmod(testdir, oldmode) 163 if err != nil { 164 t.Fatalf("Chmod on %s failed: %s", testdir, err) 165 } 166 }() 167 err = issuer.Init(true, db, &dbutil.Levels{Credential: 1, RAInfo: 1, Nonce: 1}) 168 assert.Error(t, err, "Init should fail if it fails to store issuer credential") 169 } 170 171 func TestVerifyTokenError(t *testing.T) { 172 testdir, err := ioutil.TempDir(".", "verifytokentesterror") 173 if err != nil { 174 t.Fatalf("Failed to create temp directory: %s", err.Error()) 175 } 176 defer os.RemoveAll(testdir) 177 178 err = os.MkdirAll(filepath.Join(testdir, "msp/keystore"), 0777) 179 if err != nil { 180 t.Fatalf("Failed to create directory: %s", err.Error()) 181 } 182 err = lib.CopyFile(testPublicKeyFile, filepath.Join(testdir, "IssuerPublicKey")) 183 if err != nil { 184 t.Fatalf("Failed to copy file: %s", err.Error()) 185 } 186 err = lib.CopyFile(testSecretKeyFile, filepath.Join(testdir, "msp/keystore/IssuerSecretKey")) 187 if err != nil { 188 t.Fatalf("Failed to copy file: %s", err.Error()) 189 } 190 191 db, issuer := getIssuer(t, testdir, false, false) 192 assert.NotNil(t, issuer) 193 194 _, err = issuer.VerifyToken("idemix.1.foo.blah", "", "", []byte{}) 195 assert.Error(t, err, "VerifyToken should fail as issuer is not initialized") 196 197 err = issuer.Init(false, db, &dbutil.Levels{Credential: 1, RAInfo: 1, Nonce: 1}) 198 assert.NoError(t, err) 199 200 _, err = issuer.VerifyToken("idemix.1.foo", "", "", []byte{}) 201 assert.Error(t, err, "VerifyToken should fail if the auth header does not have four parts separated by '.'") 202 203 _, err = issuer.VerifyToken("idemix.2.foo.bar", "", "", []byte{}) 204 assert.Error(t, err, "VerifyToken should fail if the auth header does not have correct version") 205 206 db.On("Rebind", SelectCredentialByIDSQL).Return(SelectCredentialByIDSQL) 207 credRecords := []CredRecord{} 208 sqlstr := fmt.Sprintf(SelectCredentialByIDSQL, sqlstruct.Columns(CredRecord{})) 209 db.On("Select", "GetCredentialsByID", &credRecords, sqlstr, "foo").Return(errors.New("db error getting creds for user")) 210 211 _, err = issuer.VerifyToken("idemix.1.foo.sig", "", "", []byte{}) 212 assert.Error(t, err, "VerifyToken should fail if there is error looking up enrollment id in the database") 213 } 214 215 func TestVerifyTokenNoCreds(t *testing.T) { 216 testdir, err := ioutil.TempDir(".", "verifytokentestnocreds") 217 if err != nil { 218 t.Fatalf("Failed to create temp directory: %s", err.Error()) 219 } 220 defer os.RemoveAll(testdir) 221 222 err = os.MkdirAll(filepath.Join(testdir, "msp/keystore"), 0777) 223 if err != nil { 224 t.Fatalf("Failed to create directory: %s", err.Error()) 225 } 226 err = lib.CopyFile(testPublicKeyFile, filepath.Join(testdir, "IssuerPublicKey")) 227 if err != nil { 228 t.Fatalf("Failed to copy file: %s", err.Error()) 229 } 230 err = lib.CopyFile(testSecretKeyFile, filepath.Join(testdir, "msp/keystore/IssuerSecretKey")) 231 if err != nil { 232 t.Fatalf("Failed to copy file: %s", err.Error()) 233 } 234 235 db, issuer := getIssuer(t, testdir, false, false) 236 assert.NotNil(t, issuer) 237 238 err = issuer.Init(false, db, &dbutil.Levels{Credential: 1, RAInfo: 1, Nonce: 1}) 239 assert.NoError(t, err) 240 241 db.On("Rebind", SelectCredentialByIDSQL).Return(SelectCredentialByIDSQL) 242 credRecords := []CredRecord{} 243 sqlstr := fmt.Sprintf(SelectCredentialByIDSQL, sqlstruct.Columns(CredRecord{})) 244 f := getCredsSelectFunc(t, &credRecords, false) 245 db.On("Select", "GetCredentialsByID", &credRecords, sqlstr, "foo").Return(f) 246 247 _, err = issuer.VerifyToken("idemix.1.foo.sig", "", "", []byte{}) 248 assert.Error(t, err, "VerifyToken should fail if the enrollment id does not have creds") 249 } 250 251 func TestVerifyTokenBadSignatureEncoding(t *testing.T) { 252 testdir, err := ioutil.TempDir(".", "verifytokentestbadsigencoding") 253 if err != nil { 254 t.Fatalf("Failed to create temp directory: %s", err.Error()) 255 } 256 defer os.RemoveAll(testdir) 257 258 err = os.MkdirAll(filepath.Join(testdir, "msp/keystore"), 0777) 259 if err != nil { 260 t.Fatalf("Failed to create directory: %s", err.Error()) 261 } 262 err = lib.CopyFile(testPublicKeyFile, filepath.Join(testdir, "IssuerPublicKey")) 263 if err != nil { 264 t.Fatalf("Failed to copy file: %s", err.Error()) 265 } 266 err = lib.CopyFile(testSecretKeyFile, filepath.Join(testdir, "msp/keystore/IssuerSecretKey")) 267 if err != nil { 268 t.Fatalf("Failed to copy file: %s", err.Error()) 269 } 270 271 db, issuer := getIssuer(t, testdir, false, false) 272 assert.NotNil(t, issuer) 273 274 err = issuer.Init(false, db, &dbutil.Levels{Credential: 1, RAInfo: 1, Nonce: 1}) 275 assert.NoError(t, err) 276 277 db.On("Rebind", SelectCredentialByIDSQL).Return(SelectCredentialByIDSQL) 278 credRecords := []CredRecord{} 279 sqlstr := fmt.Sprintf(SelectCredentialByIDSQL, sqlstruct.Columns(CredRecord{})) 280 f := getCredsSelectFunc(t, &credRecords, true) 281 db.On("Select", "GetCredentialsByID", &credRecords, sqlstr, "foo").Return(f) 282 283 _, err = issuer.VerifyToken("idemix.1.foo.sig", "", "", []byte{}) 284 assert.Error(t, err, "VerifyToken should fail if the signature is not in base64 format") 285 assert.NotEqual(t, err.Error(), "errer") 286 } 287 288 func TestVerifyTokenBadSignature(t *testing.T) { 289 testdir, err := ioutil.TempDir(".", "verifytokentestbadsig") 290 if err != nil { 291 t.Fatalf("Failed to create temp directory: %s", err.Error()) 292 } 293 defer os.RemoveAll(testdir) 294 295 err = os.MkdirAll(filepath.Join(testdir, "msp/keystore"), 0777) 296 if err != nil { 297 t.Fatalf("Failed to create directory: %s", err.Error()) 298 } 299 err = lib.CopyFile(testPublicKeyFile, filepath.Join(testdir, "IssuerPublicKey")) 300 if err != nil { 301 t.Fatalf("Failed to copy file: %s", err.Error()) 302 } 303 err = lib.CopyFile(testSecretKeyFile, filepath.Join(testdir, "msp/keystore/IssuerSecretKey")) 304 if err != nil { 305 t.Fatalf("Failed to copy file: %s", err.Error()) 306 } 307 308 db, issuer := getIssuer(t, testdir, false, false) 309 assert.NotNil(t, issuer) 310 311 err = issuer.Init(false, db, &dbutil.Levels{Credential: 1, RAInfo: 1, Nonce: 1}) 312 assert.NoError(t, err) 313 314 db.On("Rebind", SelectCredentialByIDSQL).Return(SelectCredentialByIDSQL) 315 credRecords := []CredRecord{} 316 sqlstr := fmt.Sprintf(SelectCredentialByIDSQL, sqlstruct.Columns(CredRecord{})) 317 f := getCredsSelectFunc(t, &credRecords, true) 318 db.On("Select", "GetCredentialsByID", &credRecords, sqlstr, "admin").Return(f) 319 320 sig := util.B64Encode([]byte("hello")) 321 _, err = issuer.VerifyToken("idemix.1.admin."+sig, "", "", []byte{}) 322 assert.Error(t, err, "VerifyToken should fail if the signature is not valid") 323 324 digest, err := util.GetDefaultBCCSP().Hash([]byte(sig), &bccsp.SM3Opts{}) 325 if err != nil { 326 t.Fatalf("Failed to get hash of the message: %s", err.Error()) 327 } 328 _, err = issuer.VerifyToken("idemix.1.admin.CkQKIAoanxNH9nO5ivQy94e+DH+SiwkkBhYeNbtyQhM1HD7FEiBbBcMVcCW9HoJe5KWMtyvO6a4UtB4xo2x/SV7xvxcVvBJECiBugYjF0AZ8lWvaeKCXtEbPvawQye7RK0m5SpQzEwcu/RIgioEuVacQR5DroKwgAZi3ALClpCLJFjlRwVv7w2zJcQQaRAogeAU3ZnfcA60kGIm6gHKGTRrI3O9sbkpdHt/UIF+Tz5sSIHGfTP5B7Ocb43q3sewpuqIjDyvFEzIeBpummJD4MPB5IiAewOhliKfwXta7pSCIMlfKqmuJbhAwhJl7vJdhfEW05iogGY6MfvsdO+HvQdSmlIexEBgl51KsFCO6MrAZbms/hLAyIHbqzC8f7sliJ6Hzn65JZKUyHXiAnOM3iydZ7gntoYXxOiClzG32BL3M4MyQGHz6SP8Aozxh3u0dATr0uxOOI6p94EIgO90ealPZ51ZXP+JsAWwLePpyX+lgegF0Gp002uFyv0tKIFRSBfhnRqm7Dk1VbG1hSsl7AJU8nzzYZJZKHRFrhdvGUiCWUu3nvjr5TEFtF5eOMp5XTPXmUNTq8k3SLckY1o35mlIgOeJtkxDc7NtKAiF+cz+cIsv1MIQ3qGXj0nwoMjnHvMJSIALGJWjFKVhK9B9P8BOkO03iMwzNJJdSeA8MIRGyk5WCWiCGix0AHQA29jHVOCaCrBZUVlqBRLa5Kzpftk0jp3LKXmJECiDheCgd36mEjsr1D4Sm+cbtE3XKAdRI2dLq5bFQZqN4/RIgNbxez4+fxVsRuGu8ooFkfem2C5/+1z3QDzyu8fu3fyVqID34eII73Km/SviYxAoHZ91HXIHXhGwid4DFO+xuGI7ycogBCiD+DDNQtMlsIChWD1d8KJE6zhxTmhK/hDzSJha2icCe+xIgTqZgV3OKwFTbWuHGN9gTuSTdeOKH0DWJ0mntNKN+aisaIHAgRufFQqOzdncNdRJOPlHvyyR1jWFYSOkJtIG+3Cf/IiAFVOO804jCkELupkkpfrKfi0y+gIIamLPgEoERSq0Em3pgkd4c0QZIUDeyRVBgwDj7aTk8J+xzdGZSCgIt8RpuKoxmfuDV2SlFfw/fVZqfPH02+jYeyqxbf7FD8vo5dstEpLHy86Yno6zr1bXLDLe34r2XIIH6KrYFI3gYAsQhzzd/gAEBigEA", "", "", digest) 329 assert.Error(t, err, "VerifyToken should fail signature is valid but verification fails") 330 } 331 332 func TestIsToken(t *testing.T) { 333 token := "idemixx.1.foo.blah" 334 assert.False(t, IsToken(token)) 335 token = "foo.sig" 336 assert.False(t, IsToken(token)) 337 token = "idemix.1.foo.sig" 338 assert.True(t, IsToken(token)) 339 } 340 341 func TestRevocationPublicKey(t *testing.T) { 342 testdir, err := ioutil.TempDir(".", "revocationpubkeytest") 343 if err != nil { 344 t.Fatalf("Failed to create temp directory: %s", err.Error()) 345 } 346 defer os.RemoveAll(testdir) 347 348 err = os.MkdirAll(filepath.Join(testdir, "msp/keystore"), 0777) 349 if err != nil { 350 t.Fatalf("Failed to create directory: %s", err.Error()) 351 } 352 err = lib.CopyFile(testPublicKeyFile, filepath.Join(testdir, "IssuerPublicKey")) 353 if err != nil { 354 t.Fatalf("Failed to copy file: %s", err.Error()) 355 } 356 err = lib.CopyFile(testSecretKeyFile, filepath.Join(testdir, "msp/keystore/IssuerSecretKey")) 357 if err != nil { 358 t.Fatalf("Failed to copy file: %s", err.Error()) 359 } 360 361 db, issuer := getIssuer(t, testdir, false, false) 362 assert.NotNil(t, issuer) 363 364 err = issuer.Init(false, db, &dbutil.Levels{Credential: 1, RAInfo: 1, Nonce: 1}) 365 assert.NoError(t, err, "Init should not return an error") 366 367 _, err = issuer.RevocationPublicKey() 368 assert.NoError(t, err, "RevocationPublicKey should not return an error") 369 } 370 371 func getIssuer(t *testing.T, testDir string, getranderror, newIssuerKeyerror bool) (*dmocks.FabricCADB, Issuer) { 372 err := os.MkdirAll(filepath.Join(testDir, "msp/keystore"), 0777) 373 if err != nil { 374 t.Fatalf("Failed to create directory: %s", err.Error()) 375 } 376 377 db := new(dmocks.FabricCADB) 378 379 tx := new(dmocks.FabricCATx) 380 tx.On("Commit").Return(nil) 381 tx.On("Rollback").Return(nil) 382 tx.On("Rebind", SelectRAInfo).Return(SelectRAInfo) 383 tx.On("Rebind", UpdateNextHandle).Return(UpdateNextHandle) 384 tx.On("Exec", UpdateNextHandle, 2, 1).Return(nil, nil) 385 rcInfos := []RevocationAuthorityInfo{} 386 f1 := getTxSelectFunc(t, &rcInfos, 1, false, true) 387 tx.On("Select", &rcInfos, SelectRAInfo).Return(f1) 388 389 db.On("BeginTx").Return(tx) 390 db.On("IsInitialized").Return(true) 391 392 lib := new(mocks.Lib) 393 rnd, err := idemix.GetRand() 394 if err != nil { 395 t.Fatalf("Failed to get random number: %s", err.Error()) 396 } 397 ik, err := idemix.NewIssuerKey(GetAttributeNames(), rnd) 398 if err != nil { 399 t.Fatalf("Failed to generate issuer key: %s", err.Error()) 400 } 401 if getranderror { 402 lib.On("GetRand").Return(nil, errors.New("Failed to generate random number")) 403 } else { 404 lib.On("GetRand").Return(rnd, nil) 405 } 406 407 if newIssuerKeyerror { 408 lib.On("NewIssuerKey", GetAttributeNames(), rnd).Return(nil, errors.New("Failed to generate new issuer key")) 409 } else { 410 lib.On("NewIssuerKey", GetAttributeNames(), rnd).Return(ik, nil) 411 } 412 413 key, err := sm2.GenerateKey(rand.Reader) 414 if err != nil { 415 t.Fatalf("Failed to generate key: %s", err.Error()) 416 } 417 lib.On("GenerateLongTermRevocationKey").Return(key, nil) 418 419 cfg := &Config{ 420 RHPoolSize: 100, 421 NonceExpiration: "15s", 422 NonceSweepInterval: "15m", 423 } 424 issuer := NewIssuer("ca1", testDir, cfg, util.GetDefaultBCCSP(), lib) 425 426 f := getSelectFunc(t, true, false) 427 428 rcInfosForSelect := []RevocationAuthorityInfo{} 429 db.On("Select", "GetRAInfo", &rcInfosForSelect, SelectRAInfo).Return(f) 430 rcinfo := RevocationAuthorityInfo{ 431 Epoch: 1, 432 NextRevocationHandle: 1, 433 LastHandleInPool: 100, 434 Level: 1, 435 } 436 result := new(dmocks.Result) 437 result.On("RowsAffected").Return(int64(1), nil) 438 db.On("NamedExec", "AddRAInfo", InsertRAInfo, &rcinfo).Return(result, nil) 439 440 return db, issuer 441 } 442 443 func getCredsSelectFunc(t *testing.T, creds *[]CredRecord, isAppend bool) func(string, interface{}, string, ...interface{}) error { 444 return func(funcName string, dest interface{}, query string, args ...interface{}) error { 445 credRecs := dest.(*[]CredRecord) 446 cred := CredRecord{ 447 ID: "foo", 448 Status: "active", 449 Cred: "", 450 } 451 452 if isAppend { 453 //*creds = append(*creds, cred) 454 *credRecs = append(*credRecs, cred) 455 } 456 return nil 457 } 458 }