gitee.com/zhaochuninhefei/fabric-ca-gm@v0.0.2/lib/certdbaccessor_test.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package lib
     8  
     9  import (
    10  	"crypto/rand"
    11  	"crypto/x509/pkix"
    12  	"encoding/pem"
    13  	"math/big"
    14  	"os"
    15  	"testing"
    16  	"time"
    17  
    18  	"gitee.com/zhaochuninhefei/gmgo/sm2"
    19  	"gitee.com/zhaochuninhefei/gmgo/x509"
    20  
    21  	"gitee.com/zhaochuninhefei/cfssl-gm/certdb"
    22  	"gitee.com/zhaochuninhefei/fabric-ca-gm/internal/pkg/util"
    23  	"gitee.com/zhaochuninhefei/fabric-ca-gm/lib/mocks"
    24  	"gitee.com/zhaochuninhefei/fabric-ca-gm/lib/server/certificaterequest"
    25  	"gitee.com/zhaochuninhefei/fabric-ca-gm/lib/server/db"
    26  	dbutil "gitee.com/zhaochuninhefei/fabric-ca-gm/lib/server/db/util"
    27  	cadbuser "gitee.com/zhaochuninhefei/fabric-ca-gm/lib/server/user"
    28  	"gitee.com/zhaochuninhefei/fabric-gm/common/metrics/metricsfakes"
    29  	log "gitee.com/zhaochuninhefei/zcgolog/zclog"
    30  	"github.com/jmoiron/sqlx"
    31  	"github.com/pkg/errors"
    32  	"github.com/stretchr/testify/assert"
    33  )
    34  
    35  func TestGetCertificatesDB(t *testing.T) {
    36  	os.RemoveAll("getCertDBTest")
    37  	defer os.RemoveAll("getCertDBTest")
    38  	log.Level = log.LOG_LEVEL_DEBUG
    39  
    40  	level := &dbutil.Levels{
    41  		Affiliation: 1,
    42  		Identity:    1,
    43  		Certificate: 1,
    44  	}
    45  	mockOperationsServer := &mocks.OperationsServer{}
    46  	fakeCounter := &metricsfakes.Counter{}
    47  	fakeCounter.WithReturns(fakeCounter)
    48  	mockOperationsServer.NewCounterReturns(fakeCounter)
    49  	fakeHistogram := &metricsfakes.Histogram{}
    50  	fakeHistogram.WithReturns(fakeHistogram)
    51  	mockOperationsServer.NewHistogramReturns(fakeHistogram)
    52  	srv := &Server{
    53  		Operations: mockOperationsServer,
    54  		levels:     level,
    55  	}
    56  	ca, err := newCA("getCertDBTest/config.yaml", &CAConfig{}, srv, false)
    57  	util.FatalError(t, err, "Failed to get CA")
    58  
    59  	populateCertificatesTable(t, ca)
    60  
    61  	certReq := getCertReq("testCertificate1", "", "", false, false, nil, nil, nil, nil)
    62  	rows, err := ca.certDBAccessor.GetCertificates(certReq, "")
    63  	assert.NoError(t, err, "Failed to get certificates from database")
    64  	certs, err := readRows(rows)
    65  	assert.NoError(t, err)
    66  	assert.Equal(t, "testCertificate1", certs[0].Subject.CommonName)
    67  
    68  	certReq = getCertReq("", "1111", "", false, false, nil, nil, nil, nil)
    69  	rows, err = ca.certDBAccessor.GetCertificates(certReq, "")
    70  	assert.NoError(t, err, "Failed to get certificates from database")
    71  	certs, err = readRows(rows)
    72  	assert.NoError(t, err)
    73  	assert.Equal(t, big.NewInt(1111), certs[0].SerialNumber)
    74  
    75  	certReq = getCertReq("", "", "9876", false, false, nil, nil, nil, nil)
    76  	rows, err = ca.certDBAccessor.GetCertificates(certReq, "")
    77  	assert.NoError(t, err, "Failed to get certificates from database")
    78  	certs, err = readRows(rows)
    79  	assert.NoError(t, err)
    80  	assert.Equal(t, 2, len(certs))
    81  	assert.Equal(t, []byte("9876"), certs[0].AuthorityKeyId)
    82  
    83  	certReq = getCertReq("", "", "", true, false, nil, nil, nil, nil)
    84  	rows, err = ca.certDBAccessor.GetCertificates(certReq, "")
    85  	assert.NoError(t, err, "Failed to get certificates from database")
    86  	certs, err = readRows(rows)
    87  	assert.NoError(t, err)
    88  	assert.Equal(t, 5, len(certs))
    89  
    90  	certReq = getCertReq("", "", "", false, true, nil, nil, nil, nil)
    91  	rows, err = ca.certDBAccessor.GetCertificates(certReq, "")
    92  	assert.NoError(t, err, "Failed to get certificates from database")
    93  	certs, err = readRows(rows)
    94  	assert.NoError(t, err)
    95  	assert.Equal(t, 6, len(certs))
    96  
    97  	certReq = getCertReq("", "1111", "", false, false, nil, nil, nil, nil)
    98  	rows, err = ca.certDBAccessor.GetCertificates(certReq, "dept1")
    99  	assert.NoError(t, err, "Failed to get certificates from database")
   100  	certs, err = readRows(rows)
   101  	assert.NoError(t, err)
   102  	assert.Equal(t, 1, len(certs))
   103  	assert.Equal(t, "testCertificate1", certs[0].Subject.CommonName)
   104  
   105  	certReq = getCertReq("", "", "9876AB", false, false, nil, nil, nil, nil)
   106  	rows, err = ca.certDBAccessor.GetCertificates(certReq, "")
   107  	assert.NoError(t, err, "Failed to get certificates from database")
   108  	certs, err = readRows(rows)
   109  	assert.NoError(t, err)
   110  	assert.Equal(t, 1, len(certs))
   111  	assert.Equal(t, "testCertificate3", certs[0].Subject.CommonName)
   112  
   113  	revokedStart := time.Date(2018, time.January, 1, 0, 0, 0, 0, time.UTC)
   114  	certReq = getCertReq("", "", "", false, false, &revokedStart, nil, nil, nil)
   115  	rows, err = ca.certDBAccessor.GetCertificates(certReq, "")
   116  	assert.NoError(t, err, "Failed to get certificates from database")
   117  	certs, err = readRows(rows)
   118  	assert.NoError(t, err)
   119  	assert.Equal(t, 1, len(certs))
   120  	assert.Equal(t, "revoked1", certs[0].Subject.CommonName)
   121  
   122  	revokedEnd := time.Date(2018, time.March, 1, 0, 0, 0, 0, time.UTC)
   123  	certReq = getCertReq("", "", "", false, false, nil, &revokedEnd, nil, nil)
   124  	rows, err = ca.certDBAccessor.GetCertificates(certReq, "")
   125  	assert.NoError(t, err, "Failed to get certificates from database")
   126  	certs, err = readRows(rows)
   127  	assert.NoError(t, err)
   128  	assert.Equal(t, 2, len(certs))
   129  
   130  	revokedStart = time.Date(2017, time.January, 1, 0, 0, 0, 0, time.UTC)
   131  	revokedEnd = time.Date(2017, time.August, 1, 0, 0, 0, 0, time.UTC)
   132  	certReq = getCertReq("", "", "", false, false, &revokedStart, &revokedEnd, nil, nil)
   133  	rows, err = ca.certDBAccessor.GetCertificates(certReq, "")
   134  	assert.NoError(t, err, "Failed to get certificates from database")
   135  	certs, err = readRows(rows)
   136  	assert.NoError(t, err)
   137  	assert.Equal(t, 1, len(certs))
   138  	assert.Equal(t, "revoked2", certs[0].Subject.CommonName)
   139  
   140  	expiredStart := time.Date(2018, time.March, 2, 0, 0, 0, 0, time.UTC)
   141  	certReq = getCertReq("", "", "", false, false, nil, nil, &expiredStart, nil)
   142  	rows, err = ca.certDBAccessor.GetCertificates(certReq, "")
   143  	assert.NoError(t, err, "Failed to get certificates from database")
   144  	certs, err = readRows(rows)
   145  	assert.NoError(t, err)
   146  	assert.Equal(t, 6, len(certs))
   147  
   148  	dur, err := time.ParseDuration("+100h")
   149  	assert.NoError(t, err)
   150  	expiredEnd := time.Now().Add(dur).UTC()
   151  	certReq = getCertReq("", "", "", false, false, nil, nil, nil, &expiredEnd)
   152  	rows, err = ca.certDBAccessor.GetCertificates(certReq, "")
   153  	assert.NoError(t, err, "Failed to get certificates from database")
   154  	certs, err = readRows(rows)
   155  	assert.NoError(t, err)
   156  	assert.Equal(t, 7, len(certs))
   157  
   158  	expiredStart = time.Date(2017, time.January, 1, 0, 0, 0, 0, time.UTC)
   159  	expiredEnd = time.Date(2018, time.March, 1, 0, 0, 0, 0, time.UTC)
   160  	certReq = getCertReq("", "", "", false, false, nil, nil, &expiredStart, &expiredEnd)
   161  	rows, err = ca.certDBAccessor.GetCertificates(certReq, "")
   162  	assert.NoError(t, err, "Failed to get certificates from database")
   163  	certs, err = readRows(rows)
   164  	assert.NoError(t, err)
   165  	assert.Equal(t, 1, len(certs))
   166  	assert.Equal(t, "expire1", certs[0].Subject.CommonName)
   167  }
   168  
   169  func readRows(rows *sqlx.Rows) ([]*x509.Certificate, error) {
   170  	var certs []*x509.Certificate
   171  
   172  	for rows.Next() {
   173  		var cert certPEM
   174  		err := rows.StructScan(&cert)
   175  		if err != nil {
   176  			return nil, errors.Errorf("Failed to get read row: %s", err)
   177  		}
   178  
   179  		block, rest := pem.Decode([]byte(cert.PEM))
   180  		if block == nil || len(rest) > 0 {
   181  			return nil, errors.New("Certificate decoding error")
   182  		}
   183  		certificate, err := x509.ParseCertificate(block.Bytes)
   184  		if err != nil {
   185  			return nil, err
   186  		}
   187  
   188  		certs = append(certs, certificate)
   189  	}
   190  
   191  	return certs, nil
   192  }
   193  
   194  func populateCertificatesTable(t *testing.T, ca *CA) {
   195  	var err error
   196  
   197  	dur, err := time.ParseDuration("+100h")
   198  	util.FatalError(t, err, "Failed to parse duration '+100h'")
   199  	futureTime := time.Now().Add(dur).UTC()
   200  
   201  	ca.registry.InsertUser(&cadbuser.Info{
   202  		Name:        "testCertificate1",
   203  		Affiliation: "dept1",
   204  	})
   205  	// Active Certs
   206  	err = testInsertCertificate(&certdb.CertificateRecord{
   207  		Serial: "1111",
   208  		AKI:    "9876",
   209  		Expiry: futureTime,
   210  	}, "testCertificate1", ca)
   211  	util.FatalError(t, err, "Failed to insert certificate with serial/AKI")
   212  
   213  	ca.registry.InsertUser(&cadbuser.Info{
   214  		Name:        "testCertificate2",
   215  		Affiliation: "dept1",
   216  	})
   217  	err = testInsertCertificate(&certdb.CertificateRecord{
   218  		Serial: "1112",
   219  		AKI:    "9876",
   220  		Expiry: futureTime,
   221  	}, "testCertificate2", ca)
   222  	util.FatalError(t, err, "Failed to insert certificate with serial/AKI")
   223  
   224  	err = testInsertCertificate(&certdb.CertificateRecord{
   225  		Serial: "1132",
   226  		AKI:    "9876ab",
   227  		Expiry: futureTime,
   228  	}, "testCertificate3", ca)
   229  	util.FatalError(t, err, "Failed to insert certificate with revocation date")
   230  
   231  	// Expired
   232  	err = testInsertCertificate(&certdb.CertificateRecord{
   233  		Serial: "1121",
   234  		AKI:    "98765",
   235  		Expiry: time.Date(2018, time.March, 1, 0, 0, 0, 0, time.UTC),
   236  	}, "expire1", ca)
   237  	util.FatalError(t, err, "Failed to insert certificate with expiration date")
   238  
   239  	// Not Expired
   240  	err = testInsertCertificate(&certdb.CertificateRecord{
   241  		Serial: "1122",
   242  		AKI:    "98765",
   243  		Expiry: futureTime,
   244  	}, "expire2", ca)
   245  	util.FatalError(t, err, "Failed to insert certificate with expiration date")
   246  
   247  	// Revoked
   248  	err = testInsertCertificate(&certdb.CertificateRecord{
   249  		Serial:    "1131",
   250  		AKI:       "98765",
   251  		Expiry:    futureTime,
   252  		RevokedAt: time.Date(2018, time.February, 15, 0, 0, 0, 0, time.UTC),
   253  	}, "revoked1", ca)
   254  	util.FatalError(t, err, "Failed to insert certificate with revocation date")
   255  
   256  	err = testInsertCertificate(&certdb.CertificateRecord{
   257  		Serial:    "1132",
   258  		AKI:       "98765",
   259  		Expiry:    futureTime,
   260  		RevokedAt: time.Date(2017, time.February, 15, 0, 0, 0, 0, time.UTC),
   261  	}, "revoked2", ca)
   262  	util.FatalError(t, err, "Failed to insert certificate with revocation date")
   263  }
   264  
   265  func testInsertCertificate(req *certdb.CertificateRecord, id string, ca *CA) error {
   266  	priv, err := sm2.GenerateKey(rand.Reader)
   267  	if err != nil {
   268  		return errors.Errorf("Failed to generate private key: %s", err)
   269  	}
   270  
   271  	serial := new(big.Int)
   272  	serial.SetString(req.Serial, 10) //base 10
   273  
   274  	template := x509.Certificate{
   275  		Subject: pkix.Name{
   276  			CommonName: id,
   277  		},
   278  		SerialNumber:   serial,
   279  		AuthorityKeyId: []byte(req.AKI),
   280  		KeyUsage:       x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
   281  	}
   282  
   283  	derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
   284  	if err != nil {
   285  		log.Fatalf("Failed to create certificate: %s", err)
   286  	}
   287  
   288  	cert := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
   289  
   290  	var record = &db.CertRecord{
   291  		ID: id,
   292  		CertificateRecord: certdb.CertificateRecord{
   293  			Serial:    req.Serial,
   294  			AKI:       req.AKI,
   295  			CALabel:   req.CALabel,
   296  			Status:    req.Status,
   297  			Reason:    req.Reason,
   298  			Expiry:    req.Expiry.UTC(),
   299  			RevokedAt: req.RevokedAt.UTC(),
   300  			PEM:       string(cert),
   301  		},
   302  	}
   303  
   304  	db := ca.GetDB()
   305  	res, err := db.NamedExec("", insertSQL, record)
   306  	if err != nil {
   307  		return errors.Wrap(err, "Failed to insert record into database")
   308  	}
   309  
   310  	numRowsAffected, err := res.RowsAffected()
   311  
   312  	if numRowsAffected == 0 {
   313  		return errors.New("Failed to insert the certificate record; no rows affected")
   314  	}
   315  
   316  	if numRowsAffected != 1 {
   317  		return errors.Errorf("Expected to affect 1 entry in certificate database but affected %d",
   318  			numRowsAffected)
   319  	}
   320  
   321  	return err
   322  }
   323  
   324  func getCertReq(id, serial, aki string, notrevoked, notexpired bool, revokedTimeStart, revokedTimeEnd, expiredTimeStart, expiredTimeEnd *time.Time) *certificaterequest.Impl {
   325  	return &certificaterequest.Impl{
   326  		ID:               id,
   327  		SerialNumber:     serial,
   328  		Aki:              aki,
   329  		Notexpired:       notexpired,
   330  		Notrevoked:       notrevoked,
   331  		ExpiredTimeStart: expiredTimeStart,
   332  		ExpiredTimeEnd:   expiredTimeEnd,
   333  		RevokedTimeStart: revokedTimeStart,
   334  		RevokedTimeEnd:   revokedTimeEnd,
   335  	}
   336  }