Add a Certificate Authority Database stub

* A few tests, but they don't all pass
* needs actual DB code
This commit is contained in:
J.C. Jones 2015-04-08 23:04:23 -07:00
parent ea4b0be56c
commit 97b356fcd4
8 changed files with 247 additions and 4 deletions

View File

@ -0,0 +1,80 @@
// Copyright 2015 ISRG. All rights reserved
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package ca
import (
"database/sql"
"errors"
"github.com/letsencrypt/boulder/core"
blog "github.com/letsencrypt/boulder/log"
)
type CertificateAuthorityDatabaseImpl struct {
log *blog.AuditLogger
db *sql.DB
activeTx *sql.Tx
}
func NewCertificateAuthorityDatabaseImpl(logger *blog.AuditLogger, driver string, name string) (cadb core.CertificateAuthorityDatabase, err error) {
if logger == nil {
err = errors.New("Nil logger not permitted")
return
}
db, err := sql.Open(driver, name)
if err != nil {
return
}
if err = db.Ping(); err != nil {
return
}
cadb = &CertificateAuthorityDatabaseImpl{
db: db,
log: logger,
}
return
}
func (cadb *CertificateAuthorityDatabaseImpl) Begin() (err error) {
if cadb.activeTx != nil {
err = errors.New("Transaction already open")
return
}
cadb.activeTx, err = cadb.db.Begin()
return
}
func (cadb *CertificateAuthorityDatabaseImpl) Commit() (err error) {
if cadb.activeTx == nil {
err = errors.New("Transaction already closed")
return
}
err = cadb.activeTx.Commit()
cadb.activeTx = nil
return
}
func (cadb *CertificateAuthorityDatabaseImpl) GetNextNumber() (val int, err error) {
if cadb.activeTx == nil {
err = errors.New("No transaction open")
return
}
return 1, nil
}
func (cadb *CertificateAuthorityDatabaseImpl) IncrementNumber() (err error) {
if cadb.activeTx == nil {
err = errors.New("No transaction open")
return
}
return nil
}

View File

@ -0,0 +1,107 @@
// Copyright 2015 ISRG. All rights reserved
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package ca
import (
"testing"
_ "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/mattn/go-sqlite3"
blog "github.com/letsencrypt/boulder/log"
"github.com/letsencrypt/boulder/test"
)
const badDriver = "nothing"
const badFilename = "/doesnotexist/nofile"
const sqliteDriver = "sqlite3"
const sqliteName = ":memory:"
func TestConstruction(t *testing.T) {
log, err := blog.Dial("", "", "tag")
test.AssertNotError(t, err, "Could not construct audit logger")
// Successful case
_, err = NewCertificateAuthorityDatabaseImpl(log, sqliteDriver, sqliteName)
test.AssertNotError(t, err, "Could not construct CA DB")
// Covers "sql.Open" error
_, err = NewCertificateAuthorityDatabaseImpl(log, badDriver, sqliteName)
test.AssertError(t, err, "Should have failed construction")
// Covers "db.Ping" error
_, err = NewCertificateAuthorityDatabaseImpl(log, sqliteDriver, badFilename)
test.AssertError(t, err, "Should have failed construction")
// Ensures no nil pointer exception in logging
_, err = NewCertificateAuthorityDatabaseImpl(nil, sqliteDriver, sqliteName)
test.AssertError(t, err, "Should have failed construction")
}
func TestBeginCommit(t *testing.T) {
log, err := blog.Dial("", "", "tag")
test.AssertNotError(t, err, "Could not construct audit logger")
cadb, err := NewCertificateAuthorityDatabaseImpl(log, sqliteDriver, sqliteName)
test.AssertNotError(t, err, "Could not construct CA DB")
err = cadb.Begin()
test.AssertNotError(t, err, "Could not begin")
err = cadb.Begin()
test.AssertError(t, err, "Should have already begun")
err = cadb.Commit()
test.AssertNotError(t, err, "Could not commit")
err = cadb.Commit()
test.AssertError(t, err, "Should have already committed")
}
func TestGetSetSequenceOutsideTx(t *testing.T) {
log, err := blog.Dial("", "", "tag")
test.AssertNotError(t, err, "Could not construct audit logger")
cadb, err := NewCertificateAuthorityDatabaseImpl(log, sqliteDriver, sqliteName)
test.AssertNotError(t, err, "Could not construct CA DB")
_, err = cadb.GetNextNumber()
test.AssertError(t, err, "Not permitted")
err = cadb.IncrementNumber()
test.AssertError(t, err, "Not permitted")
}
func TestGetSetSequenceNumber(t *testing.T) {
log, err := blog.Dial("", "", "tag")
test.AssertNotError(t, err, "Could not construct audit logger")
cadb, err := NewCertificateAuthorityDatabaseImpl(log, sqliteDriver, sqliteName)
test.AssertNotError(t, err, "Could not construct CA DB")
err = cadb.Begin()
test.AssertNotError(t, err, "Could not begin")
num, err := cadb.GetNextNumber()
test.AssertNotError(t, err, "Could not get number")
num2, err := cadb.GetNextNumber()
test.AssertNotError(t, err, "Could not get number")
test.Assert(t, num == num2, "Numbers should be the same")
err = cadb.IncrementNumber()
test.AssertNotError(t, err, "Could not get number")
num3, err := cadb.GetNextNumber()
test.AssertNotError(t, err, "Could not get number")
test.Assert(t, num3 != num2, "Numbers should not be the same")
num4, err := cadb.GetNextNumber()
test.AssertNotError(t, err, "Could not get number")
test.Assert(t, num4 == num3, "Numbers should be the same")
err = cadb.Commit()
test.AssertNotError(t, err, "Could not commit")
}

View File

@ -26,6 +26,7 @@ type CertificateAuthorityImpl struct {
Signer signer.Signer
SA core.StorageAuthority
PA core.PolicyAuthority
DB core.CertificateAuthorityDatabase
log *blog.AuditLogger
}
@ -35,7 +36,7 @@ type CertificateAuthorityImpl struct {
// using CFSSL's authenticated signature scheme. A CA created in this way
// issues for a single profile on the remote signer, which is indicated
// by name in this constructor.
func NewCertificateAuthorityImpl(logger *blog.AuditLogger, hostport string, authKey string, profile string) (ca *CertificateAuthorityImpl, err error) {
func NewCertificateAuthorityImpl(logger *blog.AuditLogger, hostport string, authKey string, profile string, cadb core.CertificateAuthorityDatabase) (ca *CertificateAuthorityImpl, err error) {
logger.Notice("Certificate Authority Starting")
// Create the remote signer
@ -57,7 +58,13 @@ func NewCertificateAuthorityImpl(logger *blog.AuditLogger, hostport string, auth
pa := policy.NewPolicyAuthorityImpl(logger)
ca = &CertificateAuthorityImpl{Signer: signer, profile: profile, PA: pa, log: logger}
ca = &CertificateAuthorityImpl{
Signer: signer,
profile: profile,
PA: pa,
DB: cadb,
log: logger,
}
return
}

View File

@ -19,6 +19,7 @@ import (
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/config"
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local"
_ "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/mattn/go-sqlite3"
"github.com/letsencrypt/boulder/core"
blog "github.com/letsencrypt/boulder/log"
"github.com/letsencrypt/boulder/sa"
"github.com/letsencrypt/boulder/test"
@ -218,6 +219,33 @@ var NO_NAME_CSR_HEX = "308202523082013a020100300d310b300906035504061302555330820
"58c004d9e1e55af59ea517dfbd2bccca58216d8130b9f77c90328b2aa54b" +
"1778a629b584f2bc059489a236131de9b444adca90218c31a499a485"
type MockCADatabase struct {
// empty
}
func NewMockCertificateAuthorityDatabase() (core.CertificateAuthorityDatabase, error) {
return &MockCADatabase{}, nil
}
func (cadb *MockCADatabase) Begin() error {
return nil
}
func (cadb *MockCADatabase) Commit() error {
return nil
}
func (cadb *MockCADatabase) GetNextNumber() (int, error) {
return 1, nil
}
func (cadb *MockCADatabase) IncrementNumber() error {
return nil
}
func TestIssueCertificate(t *testing.T) {
// Audit logger
audit, _ := blog.Dial("", "", "tag")
@ -274,9 +302,11 @@ func TestIssueCertificate(t *testing.T) {
// This goroutine should get killed when main() return
go (func() { http.ListenAndServe(hostPort, nil) })()
cadb, err := NewMockCertificateAuthorityDatabase()
// Create a CA
// Uncomment to test with a remote signer
ca, err := NewCertificateAuthorityImpl(audit, hostPort, authKey, profileName)
ca, err := NewCertificateAuthorityImpl(audit, hostPort, authKey, profileName, cadb)
test.AssertNotError(t, err, "Failed to create CA")
ca.SA = sa

View File

@ -7,6 +7,9 @@ package main
import (
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/streadway/amqp"
// Load both drivers to allow configuring either
_ "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/go-sql-driver/mysql"
_ "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/mattn/go-sqlite3"
"github.com/letsencrypt/boulder/ca"
"github.com/letsencrypt/boulder/cmd"
@ -21,7 +24,10 @@ func main() {
auditlogger, err := blog.Dial(c.Syslog.Network, c.Syslog.Server, c.Syslog.Tag)
cmd.FailOnError(err, "Could not connect to Syslog")
cai, err := ca.NewCertificateAuthorityImpl(auditlogger, c.CA.Server, c.CA.AuthKey, c.CA.Profile)
cadb, err := ca.NewCertificateAuthorityDatabaseImpl(auditlogger, c.CA.DBDriver, c.CA.DBName)
cmd.FailOnError(err, "Failed to create CA database")
cai, err := ca.NewCertificateAuthorityImpl(auditlogger, c.CA.Server, c.CA.AuthKey, c.CA.Profile, cadb)
cmd.FailOnError(err, "Failed to create CA impl")
for {

View File

@ -62,6 +62,8 @@ type Config struct {
AuthKey string
Profile string
TestMode bool
DBDriver string
DBName string
}
SA struct {

View File

@ -110,3 +110,12 @@ type StorageAuthority interface {
StorageGetter
StorageAdder
}
// The CA Database represents an atomic sequence source
type CertificateAuthorityDatabase interface {
Begin() error
Commit() error
GetNextNumber() (int, error)
IncrementNumber() error
}

View File

@ -34,6 +34,8 @@
"server": "localhost:9000",
"authKey": "79999d86250c367a2b517a1ae7d409c1",
"profile": "ee",
"dbDriver": "sqlite3",
"dbName": ":memory:",
"testMode": true
},