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