github.com/hxx258456/fabric-ca-gm@v0.0.3-0.20221111064038-a268ad7e3a37/test/integration/default/default_test.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package defserver 8 9 import ( 10 "bytes" 11 "crypto/rand" 12 "crypto/x509/pkix" 13 "encoding/pem" 14 "fmt" 15 "io" 16 "math/big" 17 "os" 18 "path/filepath" 19 "testing" 20 "time" 21 22 log "gitee.com/zhaochuninhefei/zcgolog/zclog" 23 "github.com/hxx258456/ccgo/sm2" 24 "github.com/hxx258456/ccgo/x509" 25 "github.com/hxx258456/cfssl-gm/certdb" 26 "github.com/hxx258456/cfssl-gm/config" 27 "github.com/hxx258456/fabric-ca-gm/cmd/fabric-ca-client/command" 28 "github.com/hxx258456/fabric-ca-gm/internal/pkg/util" 29 "github.com/hxx258456/fabric-ca-gm/lib" 30 "github.com/hxx258456/fabric-ca-gm/lib/metadata" 31 "github.com/hxx258456/fabric-ca-gm/lib/server/db" 32 "github.com/pkg/errors" 33 "github.com/stretchr/testify/assert" 34 ) 35 36 const ( 37 cmdName = "fabric-ca-client" 38 ) 39 40 var ( 41 defaultServer *lib.Server 42 defaultServerPort = 7054 43 defaultServerEnrollURL = fmt.Sprintf("http://admin:adminpw@localhost:%d", defaultServerPort) 44 defaultServerHomeDir = "defaultServerDir" 45 storeCertsDir = "/tmp/testCerts" 46 ) 47 48 func TestMain(m *testing.M) { 49 var err error 50 51 metadata.Version = "1.1.0" 52 53 os.RemoveAll(defaultServerHomeDir) 54 defaultServer, err = getDefaultServer() 55 if err != nil { 56 log.Errorf("Failed to get instance of server: %s", err) 57 os.Exit(1) 58 } 59 60 err = defaultServer.Start() 61 if err != nil { 62 log.Errorf("Failed to start server: %s", err) 63 os.Exit(1) 64 } 65 66 rc := m.Run() 67 68 err = defaultServer.Stop() 69 if err != nil { 70 log.Errorf("Failed to stop server: %s, integration test results: %d", err, rc) 71 os.Exit(1) 72 } 73 74 os.RemoveAll(defaultServerHomeDir) 75 os.RemoveAll(storeCertsDir) 76 os.Exit(rc) 77 } 78 79 func TestListCertificateCmdNegative(t *testing.T) { 80 var err error 81 // Remove default client home location to remove any existing enrollment information 82 os.RemoveAll(filepath.Dir(util.GetDefaultConfigFile("fabric-ca-client"))) 83 84 // Command should fail if caller has not yet enrolled 85 err = command.RunMain([]string{cmdName, "certificate", "list", "-d"}) 86 util.ErrorContains(t, err, "Enrollment information does not exist", "Should have failed to call command, if caller has not yet enrolled") 87 88 // Enroll a user that will be used for subsequent certificate commands 89 err = command.RunMain([]string{cmdName, "enroll", "-u", defaultServerEnrollURL, "-d"}) 90 util.FatalError(t, err, "Failed to enroll user") 91 92 // Test with --revocation flag 93 err = command.RunMain([]string{cmdName, "certificate", "list", "-d", "--id", "admin", "--revocation", "-30d:-15d"}) 94 t.Log("Error: ", err) 95 assert.Error(t, err, "Should fail, only one ':' specified need to specify two '::'") 96 97 err = command.RunMain([]string{cmdName, "certificate", "list", "-d", "--id", "admin", "--revocation", "30d::-15d"}) 98 t.Log("Error: ", err) 99 assert.Error(t, err, "Should fail, missing +/- on starting duration") 100 101 err = command.RunMain([]string{cmdName, "certificate", "list", "-d", "--id", "admin", "--revocation", "+30d::15d"}) 102 t.Log("Error: ", err) 103 assert.Error(t, err, "Should fail, missing +/- on ending duration") 104 105 err = command.RunMain([]string{cmdName, "certificate", "list", "-d", "--id", "admin", "--revocation", "+30d::+15y"}) 106 t.Log("Error: ", err) 107 assert.Error(t, err, "Should fail, invalid duration type (y)") 108 109 // Test with --expiration flag 110 err = command.RunMain([]string{cmdName, "certificate", "list", "-d", "--id", "admin", "--expiration", "-30d:-15d"}) 111 t.Log("Error: ", err) 112 assert.Error(t, err, "Should fail, only one ':' specified need to specify two '::'") 113 114 err = command.RunMain([]string{cmdName, "certificate", "list", "-d", "--id", "admin", "--expiration", "30d::-15d"}) 115 t.Log("Error: ", err) 116 assert.Error(t, err, "Should fail, missing +/- on starting duration") 117 118 err = command.RunMain([]string{cmdName, "certificate", "list", "-d", "--id", "admin", "--expiration", "+30d::15d"}) 119 t.Log("Error: ", err) 120 assert.Error(t, err, "Should fail, missing +/- on ending duration") 121 122 err = command.RunMain([]string{cmdName, "certificate", "list", "-d", "--id", "admin", "--expiration", "1/30/18::2/14/2018"}) 123 t.Log("Error: ", err) 124 assert.Error(t, err, "Should fail, using slashes instead of dashes in time format") 125 } 126 127 func TestListCertificateCmdPositive(t *testing.T) { 128 populateCertificatesTable(t, defaultServer) 129 130 var err error 131 err = command.RunMain([]string{cmdName, "certificate", "list", "-d", "--id", "admin", "--expiration", "+30d::+15d", "--notexpired"}) 132 t.Log("Error: ", err) 133 assert.Error(t, err, "Should fail, --expiration and --notexpired together") 134 135 err = command.RunMain([]string{cmdName, "certificate", "list", "-d", "--id", "admin", "--revocation", "-30d::-10d", "--notrevoked"}) 136 t.Log("Error: ", err) 137 assert.Error(t, err, "Should fail, --revocation and --notrevoked together") 138 139 // Enroll a user that will be used for subsequent certificate commands 140 err = command.RunMain([]string{cmdName, "enroll", "-u", defaultServerEnrollURL, "-d"}) 141 util.FatalError(t, err, "Failed to enroll user") 142 143 err = command.RunMain([]string{cmdName, "certificate", "list", "-d"}) 144 assert.NoError(t, err, "Failed to get certificates") 145 146 result, err := captureCLICertificatesOutput(command.RunMain, []string{cmdName, "certificate", "list", "-d", "--id", "expire1"}) 147 assert.NoError(t, err, "Failed to get certificate for an id") 148 assert.Contains(t, result, "expire1") 149 150 result, err = captureCLICertificatesOutput(command.RunMain, []string{cmdName, "certificate", "list", "-d", "--serial", "1111"}) 151 assert.NoError(t, err, "Failed to parse a correctly formatted revocation duration") 152 assert.Contains(t, result, "Serial Number: 1111") 153 154 result, err = captureCLICertificatesOutput(command.RunMain, []string{cmdName, "certificate", "list", "-d", "--aki", "9876"}) 155 assert.NoError(t, err, "Failed to parse a correctly formatted revocation duration") 156 assert.Contains(t, result, "Serial Number: 1111") 157 assert.Contains(t, result, "Serial Number: 1112") 158 159 result, err = captureCLICertificatesOutput(command.RunMain, []string{cmdName, "certificate", "list", "-d", "--serial", "1112", "--aki", "9876"}) 160 assert.NoError(t, err, "Failed to parse a correctly formatted revocation duration") 161 assert.Contains(t, result, "Serial Number: 1112") 162 assert.NotContains(t, result, "Serial Number: 1111") 163 164 result, err = captureCLICertificatesOutput(command.RunMain, []string{cmdName, "certificate", "list", "-d", "--id", "testCertificate3", "--aki", "9876AB"}) 165 assert.NoError(t, err, "Failed to parse a correctly formatted revocation duration") 166 assert.Contains(t, result, "1113") 167 assert.Contains(t, result, "testCertificate3") 168 assert.NotContains(t, result, "testCertificate1") 169 170 result, err = captureCLICertificatesOutput(command.RunMain, []string{cmdName, "certificate", "list", "-d", "--id", "expire1", "--expiration", "2018-01-01::2018-03-05"}) 171 assert.NoError(t, err, "Failed to parse a correctly formatted expiration date range") 172 assert.Contains(t, result, "expire1") 173 assert.NotContains(t, result, "expire3") 174 175 result, err = captureCLICertificatesOutput(command.RunMain, []string{cmdName, "certificate", "list", "-d", "--id", "revoked2", "--revocation", "2017-01-01::2017-12-31"}) 176 assert.NoError(t, err, "Failed to parse a correctly formatted revocation date range") 177 assert.Contains(t, result, "revoked2") 178 assert.NotContains(t, result, "revoked3") 179 180 result, err = captureCLICertificatesOutput(command.RunMain, []string{cmdName, "certificate", "list", "-d", "--expiration", "2018-03-01T00:00:00Z::2018-03-03T23:00:00Z"}) 181 assert.NoError(t, err, "Failed to parse a correctly formatted expiration date range") 182 assert.Contains(t, result, "Serial Number: 1121") 183 assert.NotContains(t, result, "Serial Number: 1123") 184 185 result, err = captureCLICertificatesOutput(command.RunMain, []string{cmdName, "certificate", "list", "-d", "--revocation", "2017-02-01T01:00:00Z::2017-02-20T23:00:00Z"}) 186 assert.NoError(t, err, "Failed to parse a correctly formatted revocation date range") 187 assert.Contains(t, result, "Serial Number: 1132") 188 assert.NotContains(t, result, "Serial Number: 1131") 189 190 result, err = captureCLICertificatesOutput(command.RunMain, []string{cmdName, "certificate", "list", "-d", "--expiration", "now::+101h"}) 191 assert.NoError(t, err, "Failed to parse a expiration date range using 'now'") 192 assert.Contains(t, result, "Serial Number: 1123") 193 assert.NotContains(t, result, "Serial Number: 1121") 194 195 result, err = captureCLICertificatesOutput(command.RunMain, []string{cmdName, "certificate", "list", "-d", "--revocation", "-15d::now"}) 196 assert.NoError(t, err, "Failed to parse a revocation date range using 'now'") 197 assert.Contains(t, result, "Serial Number: 1131") 198 assert.NotContains(t, result, "Serial Number: 1111") 199 200 result, err = captureCLICertificatesOutput(command.RunMain, []string{cmdName, "certificate", "list", "-d", "--expiration", "now::"}) 201 assert.NoError(t, err, "Failed to parse a expiration date range using 'now' and empty end date") 202 assert.NotContains(t, result, "Serial Number: 1121") 203 204 result, err = captureCLICertificatesOutput(command.RunMain, []string{cmdName, "certificate", "list", "-d", "--expiration", "::now"}) 205 assert.NoError(t, err, "Failed to parse a expiration date range using 'now' and empty start date") 206 assert.Contains(t, result, "Serial Number: 1121") 207 assert.Contains(t, result, "Serial Number: 1122") 208 assert.Contains(t, result, "Serial Number: 1124") 209 210 result, err = captureCLICertificatesOutput(command.RunMain, []string{cmdName, "certificate", "list", "-d", "--expiration", "::now", "--notrevoked"}) 211 assert.NoError(t, err, "Failed to parse a expiration date range using 'now' and empty start date") 212 assert.Contains(t, result, "Serial Number: 1121") 213 assert.Contains(t, result, "Serial Number: 1122") 214 assert.NotContains(t, result, "Serial Number: 1124") 215 216 result, err = captureCLICertificatesOutput(command.RunMain, []string{cmdName, "certificate", "list", "-d", "--revocation", "2018-02-01T01:00:00Z::"}) 217 assert.NoError(t, err, "Failed to parse a revocation date range using 'now' and empty end date") 218 assert.Contains(t, result, "1131") 219 220 result, err = captureCLICertificatesOutput(command.RunMain, []string{cmdName, "certificate", "list", "-d", "--revocation", "::now"}) 221 assert.NoError(t, err, "Failed to parse a revocation date range using 'now' and empty start date") 222 assert.Contains(t, result, "Serial Number: 1131") 223 assert.Contains(t, result, "Serial Number: 1132") 224 assert.Contains(t, result, "Serial Number: 1124") 225 226 result, err = captureCLICertificatesOutput(command.RunMain, []string{cmdName, "certificate", "list", "-d", "--revocation", "::now", "--notexpired"}) 227 assert.NoError(t, err, "Failed to parse a revocation date range using 'now' and empty start date") 228 assert.Contains(t, result, "Serial Number: 1131") 229 assert.Contains(t, result, "Serial Number: 1132") 230 assert.NotContains(t, result, "Serial Number: 1124") 231 232 result, err = captureCLICertificatesOutput(command.RunMain, []string{cmdName, "certificate", "list", "-d", "--notrevoked", "--notexpired"}) 233 assert.NoError(t, err, "Failed to parse a revocation date range using 'now' and empty start date") 234 assert.Contains(t, result, "Serial Number: 1111") 235 assert.Contains(t, result, "Serial Number: 1112") 236 assert.Contains(t, result, "Serial Number: 1113") 237 assert.Contains(t, result, "Serial Number: 1123") 238 assert.NotContains(t, result, "Serial Number: 1121") 239 assert.NotContains(t, result, "Serial Number: 1122") 240 assert.NotContains(t, result, "Serial Number: 1124") 241 assert.NotContains(t, result, "Serial Number: 1131") 242 assert.NotContains(t, result, "Serial Number: 1132") 243 assert.NotContains(t, result, "Serial Number: 1133") 244 245 result, err = captureCLICertificatesOutput(command.RunMain, []string{cmdName, "certificate", "list", "-d", "--id", "fakeID"}) 246 assert.NoError(t, err, "Should not error if the ID does not exist") 247 assert.Contains(t, result, "No results returned") 248 249 result, err = captureCLICertificatesOutput(command.RunMain, []string{cmdName, "certificate", "list", "--id", "expire1", "--store", storeCertsDir}) 250 assert.NoError(t, err, "Should not error if the ID does not exist") 251 assert.Equal(t, true, util.FileExists(filepath.Join(storeCertsDir, "expire1-1.pem"))) 252 assert.Equal(t, true, util.FileExists(filepath.Join(storeCertsDir, "expire1-2.pem"))) 253 assert.Contains(t, result, "Serial Number: 1121") 254 assert.Contains(t, result, "Serial Number: 1124") 255 } 256 257 func populateCertificatesTable(t *testing.T, srv *lib.Server) { 258 var err error 259 260 dur, err := time.ParseDuration("+100h") 261 util.FatalError(t, err, "Failed to parse duration '+100h'") 262 futureTime := time.Now().Add(dur).UTC() 263 264 dur, err = time.ParseDuration("-72h") 265 util.FatalError(t, err, "Failed to parse duration '-72h'") 266 pastTime := time.Now().Add(dur).UTC() 267 268 // Active Certs 269 err = testInsertCertificate(&certdb.CertificateRecord{ 270 Serial: "1111", 271 AKI: "9876", 272 Expiry: futureTime, 273 }, "testCertificate1", srv) 274 util.FatalError(t, err, "Failed to insert certificate with serial/AKI") 275 276 err = testInsertCertificate(&certdb.CertificateRecord{ 277 Serial: "1112", 278 AKI: "9876", 279 Expiry: futureTime, 280 }, "testCertificate2", srv) 281 util.FatalError(t, err, "Failed to insert certificate with serial/AKI") 282 283 err = testInsertCertificate(&certdb.CertificateRecord{ 284 Serial: "1113", 285 AKI: "9876ab", 286 Expiry: futureTime, 287 }, "testCertificate3", srv) 288 util.FatalError(t, err, "Failed to insert certificate with serial/AKI") 289 290 // Expired 291 err = testInsertCertificate(&certdb.CertificateRecord{ 292 Serial: "1121", 293 AKI: "98765", 294 Expiry: time.Date(2018, time.March, 1, 0, 0, 0, 0, time.UTC), 295 }, "expire1", srv) 296 util.FatalError(t, err, "Failed to insert certificate with expiration date") 297 298 err = testInsertCertificate(&certdb.CertificateRecord{ 299 Serial: "1122", 300 AKI: "98765", 301 Expiry: time.Date(2018, time.March, 1, 0, 0, 0, 0, time.UTC), 302 }, "expire3", srv) 303 util.FatalError(t, err, "Failed to insert certificate with expiration date") 304 305 // Not Expired 306 err = testInsertCertificate(&certdb.CertificateRecord{ 307 Serial: "1123", 308 AKI: "98765", 309 Expiry: futureTime, 310 }, "expire2", srv) 311 util.FatalError(t, err, "Failed to insert certificate with expiration date") 312 313 // Expired and Revoked 314 err = testInsertCertificate(&certdb.CertificateRecord{ 315 Serial: "1124", 316 AKI: "98765", 317 Expiry: time.Date(2018, time.March, 1, 0, 0, 0, 0, time.UTC), 318 RevokedAt: pastTime, 319 }, "expire1", srv) 320 util.FatalError(t, err, "Failed to insert certificate with expiration date") 321 322 // Revoked 323 err = testInsertCertificate(&certdb.CertificateRecord{ 324 Serial: "1131", 325 AKI: "98765", 326 Expiry: futureTime, 327 RevokedAt: pastTime, 328 }, "revoked1", srv) 329 util.FatalError(t, err, "Failed to insert certificate with revocation date") 330 331 err = testInsertCertificate(&certdb.CertificateRecord{ 332 Serial: "1132", 333 AKI: "98765", 334 Expiry: futureTime, 335 RevokedAt: time.Date(2017, time.February, 15, 0, 0, 0, 0, time.UTC), 336 }, "revoked2", srv) 337 util.FatalError(t, err, "Failed to insert certificate with revocation date") 338 339 err = testInsertCertificate(&certdb.CertificateRecord{ 340 Serial: "1133", 341 AKI: "98765", 342 Expiry: futureTime, 343 RevokedAt: time.Date(2017, time.February, 15, 0, 0, 0, 0, time.UTC), 344 }, "revoked3", srv) 345 util.FatalError(t, err, "Failed to insert certificate with revocation date") 346 } 347 348 func captureCLICertificatesOutput(f func(args []string) error, args []string) (string, error) { 349 old := os.Stdout 350 r, w, err := os.Pipe() 351 if err != nil { 352 panic(err) 353 } 354 os.Stdout = w 355 err = f(args) 356 if err != nil { 357 return "", err 358 } 359 w.Close() 360 os.Stdout = old 361 var buf bytes.Buffer 362 io.Copy(&buf, r) 363 return buf.String(), nil 364 } 365 366 func TestRevokeWithColons(t *testing.T) { 367 var err error 368 369 err = testInsertCertificate(&certdb.CertificateRecord{ 370 Serial: "11aa22bb", 371 AKI: "33cc44dd", 372 }, "testingRevoke", defaultServer) 373 util.FatalError(t, err, "Failed to insert certificate with serial/AKI") 374 375 // Enroll a user that will be used for subsequent revoke commands 376 err = command.RunMain([]string{cmdName, "enroll", "-u", defaultServerEnrollURL, "-d"}) 377 util.FatalError(t, err, "Failed to enroll user") 378 379 err = command.RunMain([]string{cmdName, "register", "-u", defaultServerEnrollURL, "--id.name", "testingRevoke", "-d"}) 380 util.FatalError(t, err, "Failed to enroll user") 381 382 err = command.RunMain([]string{cmdName, "revoke", "-s", "11:AA:22:bb", "-a", "33:Cc:44:DD", "-d"}) 383 assert.NoError(t, err, "Failed to revoke certificate, when serial number and AKI contained colons") 384 } 385 386 func getDefaultServer() (*lib.Server, error) { 387 affiliations := map[string]interface{}{ 388 "hyperledger": map[string]interface{}{ 389 "fabric": []string{"ledger", "orderer", "security"}, 390 "fabric-ca": nil, 391 "sdk": nil, 392 }, 393 "org2": []string{"dept1"}, 394 "org1": nil, 395 "org2dept1": nil, 396 } 397 profiles := map[string]*config.SigningProfile{ 398 "tls": &config.SigningProfile{ 399 Usage: []string{"signing", "key encipherment", "server auth", "client auth", "key agreement"}, 400 ExpiryString: "8760h", 401 }, 402 "ca": &config.SigningProfile{ 403 Usage: []string{"cert sign", "crl sign"}, 404 ExpiryString: "8760h", 405 CAConstraint: config.CAConstraint{ 406 IsCA: true, 407 MaxPathLen: 0, 408 }, 409 }, 410 } 411 defaultProfile := &config.SigningProfile{ 412 Usage: []string{"cert sign"}, 413 ExpiryString: "8760h", 414 } 415 srv := &lib.Server{ 416 Config: &lib.ServerConfig{ 417 Port: defaultServerPort, 418 Debug: true, 419 }, 420 CA: lib.CA{ 421 Config: &lib.CAConfig{ 422 Intermediate: lib.IntermediateCA{ 423 ParentServer: lib.ParentServer{ 424 URL: "", 425 }, 426 }, 427 Affiliations: affiliations, 428 Registry: lib.CAConfigRegistry{ 429 MaxEnrollments: -1, 430 }, 431 Signing: &config.Signing{ 432 Profiles: profiles, 433 Default: defaultProfile, 434 }, 435 Version: "1.1.0", // The default test server/ca should use the latest version 436 }, 437 }, 438 HomeDir: defaultServerHomeDir, 439 } 440 // The bootstrap user's affiliation is the empty string, which 441 // means the user is at the affiliation root 442 err := srv.RegisterBootstrapUser("admin", "adminpw", "") 443 if err != nil { 444 return nil, err 445 } 446 return srv, nil 447 } 448 449 func testInsertCertificate(req *certdb.CertificateRecord, id string, srv *lib.Server) error { 450 priv, err := sm2.GenerateKey(rand.Reader) 451 if err != nil { 452 return errors.Errorf("Failed to generate private key: %s", err) 453 } 454 455 serial := new(big.Int) 456 serial.SetString(req.Serial, 10) //base 10 457 template := x509.Certificate{ 458 Subject: pkix.Name{ 459 CommonName: id, 460 }, 461 SerialNumber: serial, 462 AuthorityKeyId: []byte(req.AKI), 463 KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, 464 } 465 466 derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv) 467 if err != nil { 468 return err 469 } 470 471 cert := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes}) 472 record := &db.CertRecord{ 473 ID: id, 474 CertificateRecord: certdb.CertificateRecord{ 475 Serial: req.Serial, 476 AKI: req.AKI, 477 CALabel: req.CALabel, 478 Status: req.Status, 479 Reason: req.Reason, 480 Expiry: req.Expiry.UTC(), 481 RevokedAt: req.RevokedAt.UTC(), 482 PEM: string(cert), 483 }, 484 } 485 486 db := srv.CA.GetDB() 487 res, err := db.NamedExec("", `INSERT INTO certificates (id, serial_number, authority_key_identifier, ca_label, status, reason, expiry, revoked_at, pem, level) 488 VALUES (:id, :serial_number, :authority_key_identifier, :ca_label, :status, :reason, :expiry, :revoked_at, :pem, :level);`, record) 489 490 if err != nil { 491 return errors.Wrap(err, "Failed to insert record into database") 492 } 493 494 numRowsAffected, err := res.RowsAffected() 495 496 if numRowsAffected == 0 { 497 return errors.New("Failed to insert the certificate record; no rows affected") 498 } 499 500 if numRowsAffected != 1 { 501 return errors.Errorf("Expected to affect 1 entry in certificate database but affected %d", 502 numRowsAffected) 503 } 504 505 return err 506 }