Move boulder to using local signer.
This allows us to use the same PKCS#11 key for both cert signing and OCSP
signing, and simplifies config and startup.
This also starts building with -tags pkcs11 in all scripts, which is required
now that the CA can choose between pkcs11 and non-pkcs11.
In order to successfully issue using a pkcs11 key, you'll need to run a version
of Go built off the master branch. The released versions are missing this
commit:
fe40cdd756
,
which is necessary for PKCS#11 signing.
This commit is contained in:
parent
eb7bcc793d
commit
625eab5ad3
|
@ -8,6 +8,7 @@ package ca
|
|||
import (
|
||||
"crypto"
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
@ -18,33 +19,40 @@ import (
|
|||
blog "github.com/letsencrypt/boulder/log"
|
||||
"github.com/letsencrypt/boulder/policy"
|
||||
|
||||
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/auth"
|
||||
cfsslConfig "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/config"
|
||||
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/crypto/pkcs11key"
|
||||
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/helpers"
|
||||
cfsslOCSP "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/ocsp"
|
||||
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/ocsp"
|
||||
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/signer"
|
||||
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/remote"
|
||||
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local"
|
||||
)
|
||||
|
||||
// Config defines the JSON configuration file schema
|
||||
type Config struct {
|
||||
Server string
|
||||
AuthKey string
|
||||
Profile string
|
||||
TestMode bool
|
||||
DBDriver string
|
||||
DBName string
|
||||
SerialPrefix int
|
||||
// This field is only allowed if TestMode is true, indicating that we are
|
||||
// signing with a local key. In production we will use an HSM and this
|
||||
// IssuerKey must be empty (and TestMode must be false). PEM-encoded private
|
||||
// key used for signing certificates and OCSP responses.
|
||||
IssuerKey string
|
||||
Key KeyConfig
|
||||
// How long issue certificates are valid for, should match expiry field
|
||||
// in cfssl config.
|
||||
Expiry string
|
||||
// The maximum number of subjectAltNames in a single certificate
|
||||
MaxNames int
|
||||
CFSSL cfsslConfig.Config
|
||||
}
|
||||
|
||||
type KeyConfig struct {
|
||||
File string
|
||||
PKCS11 PKCS11Config
|
||||
}
|
||||
|
||||
type PKCS11Config struct {
|
||||
Module string
|
||||
Token string
|
||||
PIN string
|
||||
Label string
|
||||
}
|
||||
|
||||
// CertificateAuthorityImpl represents a CA that signs certificates, CRLs, and
|
||||
|
@ -52,7 +60,7 @@ type Config struct {
|
|||
type CertificateAuthorityImpl struct {
|
||||
profile string
|
||||
Signer signer.Signer
|
||||
OCSPSigner cfsslOCSP.Signer
|
||||
OCSPSigner ocsp.Signer
|
||||
SA core.StorageAuthority
|
||||
PA core.PolicyAuthority
|
||||
DB core.CertificateAuthorityDatabase
|
||||
|
@ -80,20 +88,19 @@ func NewCertificateAuthorityImpl(cadb core.CertificateAuthorityDatabase, config
|
|||
return nil, err
|
||||
}
|
||||
|
||||
// Create the remote signer
|
||||
localProfile := cfsslConfig.SigningProfile{
|
||||
Expiry: time.Hour, // BOGUS: Required by CFSSL, but not used
|
||||
RemoteName: config.Server, // BOGUS: Only used as a flag by CFSSL
|
||||
RemoteServer: config.Server,
|
||||
UseSerialSeq: true,
|
||||
// CFSSL requires processing JSON configs through its own LoadConfig, so we
|
||||
// serialize and then deserialize.
|
||||
cfsslJSON, err := json.Marshal(config.CFSSL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
localProfile.Provider, err = auth.New(config.AuthKey, nil)
|
||||
cfsslConfigObj, err := cfsslConfig.LoadConfig(cfsslJSON)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
signer, err := remote.NewSigner(&cfsslConfig.Signing{Default: &localProfile})
|
||||
// Load the private key, which can be a file or a PKCS#11 key.
|
||||
priv, err := loadKey(config.Key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -103,18 +110,14 @@ func NewCertificateAuthorityImpl(cadb core.CertificateAuthorityDatabase, config
|
|||
return nil, err
|
||||
}
|
||||
|
||||
// In test mode, load a private key from a file.
|
||||
// TODO: This should rely on the CFSSL config, to make it easy to use a key
|
||||
// from a file vs an HSM. https://github.com/letsencrypt/boulder/issues/163
|
||||
issuerKey, err := loadIssuerKey(config.IssuerKey)
|
||||
signer, err := local.NewSigner(priv, issuer, x509.SHA256WithRSA, cfsslConfigObj.Signing)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Set up our OCSP signer. Note this calls for both the issuer cert and the
|
||||
// OCSP signing cert, which are the same in our case.
|
||||
ocspSigner, err := cfsslOCSP.NewSigner(issuer, issuer, issuerKey,
|
||||
time.Hour*24*4)
|
||||
ocspSigner, err := ocsp.NewSigner(issuer, issuer, priv, time.Hour)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -145,6 +148,24 @@ func NewCertificateAuthorityImpl(cadb core.CertificateAuthorityDatabase, config
|
|||
return ca, nil
|
||||
}
|
||||
|
||||
func loadKey(keyConfig KeyConfig) (priv crypto.Signer, err error) {
|
||||
if keyConfig.File != "" {
|
||||
var keyBytes []byte
|
||||
keyBytes, err = ioutil.ReadFile(keyConfig.File)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Could not read key file %s", keyConfig.File)
|
||||
}
|
||||
|
||||
priv, err = helpers.ParsePrivateKeyPEM(keyBytes)
|
||||
return
|
||||
} else {
|
||||
pkcs11Config := keyConfig.PKCS11
|
||||
priv, err = pkcs11key.New(pkcs11Config.Module,
|
||||
pkcs11Config.Token, pkcs11Config.PIN, pkcs11Config.Label)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func loadIssuer(filename string) (issuerCert *x509.Certificate, err error) {
|
||||
if filename == "" {
|
||||
err = errors.New("Issuer certificate was not provided in config.")
|
||||
|
@ -181,7 +202,7 @@ func (ca *CertificateAuthorityImpl) GenerateOCSP(xferObj core.OCSPSigningRequest
|
|||
return nil, err
|
||||
}
|
||||
|
||||
signRequest := cfsslOCSP.SignRequest{
|
||||
signRequest := ocsp.SignRequest{
|
||||
Certificate: cert,
|
||||
Status: xferObj.Status,
|
||||
Reason: xferObj.Reason,
|
||||
|
@ -207,7 +228,7 @@ func (ca *CertificateAuthorityImpl) RevokeCertificate(serial string, reasonCode
|
|||
return err
|
||||
}
|
||||
|
||||
signRequest := cfsslOCSP.SignRequest{
|
||||
signRequest := ocsp.SignRequest{
|
||||
Certificate: cert,
|
||||
Status: string(core.OCSPStatusRevoked),
|
||||
Reason: reasonCode,
|
||||
|
|
|
@ -7,22 +7,17 @@ package ca
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
"crypto/x509"
|
||||
"encoding/asn1"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
apisign "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/api/sign"
|
||||
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/auth"
|
||||
cfsslConfig "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/config"
|
||||
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/helpers"
|
||||
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local"
|
||||
ocspConfig "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/ocsp/config"
|
||||
_ "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/mattn/go-sqlite3"
|
||||
|
||||
"github.com/letsencrypt/boulder/core"
|
||||
|
@ -285,57 +280,11 @@ var FarFuture = time.Date(2100, 1, 1, 0, 0, 0, 0, time.UTC)
|
|||
var FarPast = time.Date(1950, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
|
||||
// CFSSL config
|
||||
const hostPort = "localhost:9000"
|
||||
const authKey = "79999d86250c367a2b517a1ae7d409c1"
|
||||
const profileName = "ee"
|
||||
const caKeyFile = "../test/test-ca.key"
|
||||
const caCertFile = "../test/test-ca.pem"
|
||||
|
||||
var cfsslSigner *local.Signer
|
||||
var caKey crypto.PrivateKey
|
||||
var caCert x509.Certificate
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
caKeyPEM, _ := ioutil.ReadFile(caKeyFile)
|
||||
caKey, _ := helpers.ParsePrivateKeyPEM(caKeyPEM)
|
||||
|
||||
caCertPEM, _ := ioutil.ReadFile(caCertFile)
|
||||
caCert, _ := helpers.ParseCertificatePEM(caCertPEM)
|
||||
|
||||
// Create an online CFSSL instance
|
||||
// This is designed to mimic what LE plans to do
|
||||
authHandler, _ := auth.New(authKey, nil)
|
||||
policy := &cfsslConfig.Signing{
|
||||
Profiles: map[string]*cfsslConfig.SigningProfile{
|
||||
profileName: &cfsslConfig.SigningProfile{
|
||||
Usage: []string{"server auth"},
|
||||
CA: false,
|
||||
IssuerURL: []string{"http://not-example.com/issuer-url"},
|
||||
OCSP: "http://not-example.com/ocsp",
|
||||
CRL: "http://not-example.com/crl",
|
||||
|
||||
Policies: []asn1.ObjectIdentifier{
|
||||
asn1.ObjectIdentifier{2, 23, 140, 1, 2, 1},
|
||||
},
|
||||
Expiry: 8760 * time.Hour,
|
||||
Backdate: time.Hour,
|
||||
Provider: authHandler,
|
||||
CSRWhitelist: &cfsslConfig.CSRWhitelist{
|
||||
PublicKeyAlgorithm: true,
|
||||
PublicKey: true,
|
||||
SignatureAlgorithm: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
Default: &cfsslConfig.SigningProfile{
|
||||
Expiry: time.Hour,
|
||||
},
|
||||
}
|
||||
cfsslSigner, _ = local.NewSigner(caKey, caCert, x509.SHA256WithRSA, policy)
|
||||
signHandler, _ := apisign.NewAuthHandlerFromSigner(cfsslSigner)
|
||||
http.Handle("/api/v1/cfssl/authsign", signHandler)
|
||||
// This goroutine should get killed when main() return
|
||||
go (func() { http.ListenAndServe(hostPort, nil) })()
|
||||
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
@ -350,16 +299,47 @@ func setup(t *testing.T) (cadb core.CertificateAuthorityDatabase, storageAuthori
|
|||
cadb, _ = test.NewMockCertificateAuthorityDatabase()
|
||||
|
||||
// Create a CA
|
||||
// Uncomment to test with a remote signer
|
||||
caConfig = Config{
|
||||
Server: hostPort,
|
||||
AuthKey: authKey,
|
||||
Profile: profileName,
|
||||
SerialPrefix: 17,
|
||||
IssuerKey: "../test/test-ca.key",
|
||||
TestMode: true,
|
||||
Expiry: "8760h",
|
||||
MaxNames: 2,
|
||||
Key: KeyConfig{
|
||||
File: caKeyFile,
|
||||
},
|
||||
TestMode: true,
|
||||
Expiry: "8760h",
|
||||
MaxNames: 2,
|
||||
CFSSL: cfsslConfig.Config{
|
||||
Signing: &cfsslConfig.Signing{
|
||||
Profiles: map[string]*cfsslConfig.SigningProfile{
|
||||
profileName: &cfsslConfig.SigningProfile{
|
||||
Usage: []string{"server auth"},
|
||||
CA: false,
|
||||
IssuerURL: []string{"http://not-example.com/issuer-url"},
|
||||
OCSP: "http://not-example.com/ocsp",
|
||||
CRL: "http://not-example.com/crl",
|
||||
|
||||
Policies: []asn1.ObjectIdentifier{
|
||||
asn1.ObjectIdentifier{2, 23, 140, 1, 2, 1},
|
||||
},
|
||||
ExpiryString: "8760h",
|
||||
Backdate: time.Hour,
|
||||
CSRWhitelist: &cfsslConfig.CSRWhitelist{
|
||||
PublicKeyAlgorithm: true,
|
||||
PublicKey: true,
|
||||
SignatureAlgorithm: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
Default: &cfsslConfig.SigningProfile{
|
||||
ExpiryString: "8760h",
|
||||
},
|
||||
},
|
||||
OCSP: &ocspConfig.Config{
|
||||
CACertFile: caCertFile,
|
||||
ResponderCertFile: caCertFile,
|
||||
KeyFile: caKeyFile,
|
||||
},
|
||||
},
|
||||
}
|
||||
return cadb, storageAuthority, caConfig
|
||||
}
|
||||
|
@ -375,6 +355,9 @@ func TestRevoke(t *testing.T) {
|
|||
cadb, storageAuthority, caConfig := setup(t)
|
||||
ca, err := NewCertificateAuthorityImpl(cadb, caConfig, caCertFile)
|
||||
test.AssertNotError(t, err, "Failed to create CA")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
ca.SA = storageAuthority
|
||||
|
||||
csrDER, _ := hex.DecodeString(CN_AND_SAN_CSR_HEX)
|
||||
|
|
|
@ -419,7 +419,7 @@ func (cert Certificate) MatchesCSR(csr *x509.CertificateRequest, earliestExpiry
|
|||
err = InternalServerError("Generated certificate can sign other certificates")
|
||||
return
|
||||
}
|
||||
if !cmpExtKeyUsageSlice(parsedCertificate.ExtKeyUsage, []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth}) {
|
||||
if !cmpExtKeyUsageSlice(parsedCertificate.ExtKeyUsage, []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}) {
|
||||
err = InternalServerError("Generated certificate doesn't have correct key usage extensions")
|
||||
return
|
||||
}
|
||||
|
|
25
start.py
25
start.py
|
@ -17,13 +17,10 @@ tempdir = tempfile.mkdtemp()
|
|||
config = os.environ.get('BOULDER_CONFIG')
|
||||
if config is None:
|
||||
config = 'test/boulder-config.json'
|
||||
cfsslConfig = os.environ.get('CFSSL_CONFIG')
|
||||
if cfsslConfig is None:
|
||||
cfsslConfig = 'test/cfssl-config.json'
|
||||
|
||||
def run(path):
|
||||
binary = os.path.join(tempdir, os.path.basename(path))
|
||||
cmd = 'go build -o %s %s' % (binary, path)
|
||||
cmd = 'go build -tags pkcs11 -o %s %s' % (binary, path)
|
||||
print(cmd)
|
||||
if subprocess.Popen(cmd, shell=True).wait() != 0:
|
||||
sys.exit(1)
|
||||
|
@ -34,31 +31,13 @@ def run(path):
|
|||
processes = []
|
||||
|
||||
def start():
|
||||
# A strange Go bug: If cfssl is up-to-date, we'll get a failure building
|
||||
# Boulder. Work around by touching cfssl.go.
|
||||
subprocess.Popen('touch Godeps/_workspace/src/github.com/cloudflare/cfssl/cmd/cfssl/cfssl.go', shell=True).wait()
|
||||
|
||||
cmd = 'go build -o %s/cfssl ./Godeps/_workspace/src/github.com/cloudflare/cfssl/cmd/cfssl' % (tempdir)
|
||||
print(cmd)
|
||||
if subprocess.Popen(cmd, shell=True).wait() != 0:
|
||||
die()
|
||||
|
||||
global processes
|
||||
processes = [
|
||||
run('./cmd/boulder-wfe'),
|
||||
run('./cmd/boulder-ra'),
|
||||
run('./cmd/boulder-sa'),
|
||||
run('./cmd/boulder-ca'),
|
||||
run('./cmd/boulder-va'),
|
||||
subprocess.Popen('''
|
||||
exec %s/cfssl \
|
||||
-loglevel 0 \
|
||||
serve \
|
||||
-port 9000 \
|
||||
-ca test/test-ca.pem \
|
||||
-ca-key test/test-ca.key \
|
||||
-config %s
|
||||
''' % (tempdir, cfsslConfig), shell=True, stdout=None)]
|
||||
run('./cmd/boulder-va')]
|
||||
time.sleep(100000)
|
||||
|
||||
try:
|
||||
|
|
13
start.sh
13
start.sh
|
@ -5,17 +5,6 @@ if type realpath >/dev/null 2>/dev/null; then
|
|||
fi
|
||||
|
||||
# Kill all children on exit.
|
||||
trap "trap - SIGTERM && kill -- -$$" SIGINT SIGTERM EXIT
|
||||
|
||||
export BOULDER_CONFIG=${BOULDER_CONFIG:-test/boulder-config.json}
|
||||
|
||||
go run ./cmd/boulder/main.go &
|
||||
go run Godeps/_workspace/src/github.com/cloudflare/cfssl/cmd/cfssl/cfssl.go \
|
||||
-loglevel 0 \
|
||||
serve \
|
||||
-port 9000 \
|
||||
-ca test/test-ca.pem \
|
||||
-ca-key test/test-ca.key \
|
||||
-config test/cfssl-config.json &
|
||||
|
||||
sleep 100000
|
||||
exec go run ./cmd/boulder/main.go
|
||||
|
|
4
test.sh
4
test.sh
|
@ -42,7 +42,7 @@ go install ./Godeps/_workspace/src/github.com/mattn/go-sqlite3
|
|||
if [ "${TRAVIS}" == "true" ] ; then
|
||||
# Run each test by itself for Travis, so we can get coverage
|
||||
for dir in ${TESTDIRS}; do
|
||||
run go test -covermode=count -coverprofile=${dir}.coverprofile ./${dir}/
|
||||
run go test -tags pkcs11 -covermode=count -coverprofile=${dir}.coverprofile ./${dir}/
|
||||
done
|
||||
|
||||
# Gather all the coverprofiles
|
||||
|
@ -60,7 +60,7 @@ else
|
|||
dirlist="${dirlist} ./${dir}/"
|
||||
done
|
||||
|
||||
run go test ${dirlist}
|
||||
run go test -tags pkcs11 ${dirlist}
|
||||
fi
|
||||
|
||||
[ ${FAILURE} == 0 ] && run python test/amqp-integration-test.py
|
||||
|
|
|
@ -21,7 +21,7 @@ processes = []
|
|||
def run(path):
|
||||
global processes
|
||||
binary = os.path.join(tempdir, os.path.basename(path))
|
||||
cmd = 'go build -o %s %s' % (binary, path)
|
||||
cmd = 'go build -tags pkcs11 -o %s %s' % (binary, path)
|
||||
print(cmd)
|
||||
if subprocess.Popen(cmd, shell=True).wait() != 0:
|
||||
die()
|
||||
|
@ -30,29 +30,12 @@ def run(path):
|
|||
''' % binary, shell=True))
|
||||
|
||||
def start():
|
||||
# A strange Go bug: If cfssl is up-to-date, we'll get a failure building
|
||||
# Boulder. Work around by touching cfssl.go.
|
||||
subprocess.Popen('touch Godeps/_workspace/src/github.com/cloudflare/cfssl/cmd/cfssl/cfssl.go', shell=True).wait()
|
||||
cmd = 'go build -o %s/cfssl ./Godeps/_workspace/src/github.com/cloudflare/cfssl/cmd/cfssl' % (tempdir)
|
||||
print(cmd)
|
||||
if subprocess.Popen(cmd, shell=True).wait() != 0:
|
||||
die()
|
||||
run('./cmd/boulder-wfe')
|
||||
run('./cmd/boulder-ra')
|
||||
run('./cmd/boulder-sa')
|
||||
run('./cmd/boulder-ca')
|
||||
run('./cmd/boulder-va')
|
||||
|
||||
processes.append(subprocess.Popen('''
|
||||
exec %s/cfssl \
|
||||
-loglevel 0 \
|
||||
serve \
|
||||
-port 9300 \
|
||||
-ca test/test-ca.pem \
|
||||
-ca-key test/test-ca.key \
|
||||
-config test/cfssl-config.json
|
||||
''' % tempdir, shell=True, stdout=None))
|
||||
|
||||
def run_test():
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
try:
|
||||
|
|
|
@ -31,21 +31,58 @@
|
|||
},
|
||||
|
||||
"wfe": {
|
||||
"listenAddress": "0.0.0.0:4000"
|
||||
"listenAddress": "127.0.0.1:4000"
|
||||
},
|
||||
|
||||
"ca": {
|
||||
"server": "localhost:9000",
|
||||
"authKey": "79999d86250c367a2b517a1ae7d409c1",
|
||||
"serialPrefix": 255,
|
||||
"profile": "ee",
|
||||
"dbDriver": "sqlite3",
|
||||
"dbName": ":memory:",
|
||||
"testMode": true,
|
||||
"_comment": "This should only be present in testMode. In prod use an HSM.",
|
||||
"issuerKey": "test/test-ca.key",
|
||||
"Key": {
|
||||
"File": "test/test-ca.key"
|
||||
},
|
||||
"expiry": "2160h",
|
||||
"maxNames": 1000
|
||||
"maxNames": 1000,
|
||||
"cfssl": {
|
||||
"signing": {
|
||||
"profiles": {
|
||||
"ee": {
|
||||
"usages": [
|
||||
"digital signature",
|
||||
"key encipherment",
|
||||
"server auth"
|
||||
],
|
||||
"backdate": "1h",
|
||||
"is_ca": false,
|
||||
"issuer_urls": [
|
||||
"http://int-x1.letsencrypt.org/cert"
|
||||
],
|
||||
"ocsp_url": "http://int-x1.letsencrypt.org/ocsp",
|
||||
"crl_url": "http://int-x1.letsencrypt.org/crl",
|
||||
"policies": [
|
||||
"1.3.6.1.4.1.44947.1.1.1",
|
||||
"2.23.140.1.2.1"
|
||||
],
|
||||
"expiry": "8760h",
|
||||
"CSRWhitelist": {
|
||||
"PublicKeyAlgorithm": true,
|
||||
"PublicKey": true,
|
||||
"SignatureAlgorithm": true
|
||||
},
|
||||
"UseSerialSeq": true
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"usages": [
|
||||
"digital signature"
|
||||
],
|
||||
"expiry": "8760h"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"sa": {
|
||||
|
|
|
@ -0,0 +1,135 @@
|
|||
{
|
||||
"syslog": {
|
||||
"network": "",
|
||||
"server": "",
|
||||
"tag": "boulder"
|
||||
},
|
||||
|
||||
"amqp": {
|
||||
"server": "amqp://guest:guest@localhost:5672",
|
||||
"RA": {
|
||||
"client": "RA.client",
|
||||
"server": "RA.server"
|
||||
},
|
||||
"VA": {
|
||||
"client": "VA.client",
|
||||
"server": "VA.server"
|
||||
},
|
||||
"SA": {
|
||||
"client": "SA.client",
|
||||
"server": "SA.server"
|
||||
},
|
||||
"CA": {
|
||||
"client": "CA.client",
|
||||
"server": "CA.server"
|
||||
}
|
||||
},
|
||||
|
||||
"statsd": {
|
||||
"server": "localhost:8125",
|
||||
"prefix": "Boulder"
|
||||
},
|
||||
|
||||
"wfe": {
|
||||
"listenAddress": "127.0.0.1:4000"
|
||||
},
|
||||
|
||||
"ca": {
|
||||
"serialPrefix": 255,
|
||||
"profile": "ee",
|
||||
"dbDriver": "sqlite3",
|
||||
"dbName": ":memory:",
|
||||
"testMode": true,
|
||||
"_comment": "This should only be present in testMode. In prod use an HSM.",
|
||||
"expiry": "2160h",
|
||||
"maxNames": 1000,
|
||||
"Key": {
|
||||
"PKCS11": {
|
||||
"_comment": "On OS X, the module will likely be /Library/OpenSC/lib/opensc-pkcs11.so",
|
||||
"Module": "/usr/lib/x86_64-linux-gnu/opensc-pkcs11.so",
|
||||
"Token": "Yubico Yubikey NEO OTP+CCID 00 00",
|
||||
"Label": "SIGN key",
|
||||
"PIN": "1234"
|
||||
}
|
||||
},
|
||||
"cfssl": {
|
||||
"signing": {
|
||||
"profiles": {
|
||||
"ee": {
|
||||
"usages": [
|
||||
"digital signature",
|
||||
"key encipherment",
|
||||
"server auth"
|
||||
],
|
||||
"backdate": "1h",
|
||||
"is_ca": false,
|
||||
"issuer_urls": [
|
||||
"http://int-x1.letsencrypt.org/cert"
|
||||
],
|
||||
"ocsp_url": "http://int-x1.letsencrypt.org/ocsp",
|
||||
"crl_url": "http://int-x1.letsencrypt.org/crl",
|
||||
"policies": [
|
||||
"1.3.6.1.4.1.44947.1.1.1",
|
||||
"2.23.140.1.2.1"
|
||||
],
|
||||
"expiry": "8760h",
|
||||
"CSRWhitelist": {
|
||||
"PublicKeyAlgorithm": true,
|
||||
"PublicKey": true,
|
||||
"SignatureAlgorithm": true
|
||||
},
|
||||
"UseSerialSeq": true
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"usages": [
|
||||
"digital signature"
|
||||
],
|
||||
"expiry": "8760h"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"sa": {
|
||||
"dbDriver": "sqlite3",
|
||||
"dbName": ":memory:"
|
||||
},
|
||||
|
||||
"sql": {
|
||||
"SQLDebug": true,
|
||||
"CreateTables": true
|
||||
},
|
||||
|
||||
"revoker": {
|
||||
"dbDriver": "sqlite3",
|
||||
"dbName": ":memory:"
|
||||
},
|
||||
|
||||
"ocspResponder": {
|
||||
"dbDriver": "sqlite3",
|
||||
"dbName": ":memory:",
|
||||
"path": "http://localhost:4001",
|
||||
"listenAddress": "localhost:4001"
|
||||
},
|
||||
|
||||
"ocspUpdater": {
|
||||
"dbDriver": "sqlite3",
|
||||
"dbName": ":memory:",
|
||||
"minTimeToExpiry": "72h"
|
||||
},
|
||||
|
||||
"mail": {
|
||||
"server": "mail.example.com",
|
||||
"port": "25",
|
||||
"username": "cert-master@example.com",
|
||||
"password": "password"
|
||||
},
|
||||
|
||||
"common": {
|
||||
"baseURL": "http://localhost:4000",
|
||||
"issuerCert": "/home/jsha/yubi-ca.pem"
|
||||
},
|
||||
|
||||
"subscriberAgreementURL": "http://localhost:4000/terms"
|
||||
}
|
|
@ -35,17 +35,54 @@
|
|||
},
|
||||
|
||||
"ca": {
|
||||
"server": "localhost:9300",
|
||||
"authKey": "79999d86250c367a2b517a1ae7d409c1",
|
||||
"serialPrefix": 255,
|
||||
"profile": "ee",
|
||||
"dbDriver": "sqlite3",
|
||||
"dbName": ":memory:",
|
||||
"testMode": true,
|
||||
"_comment": "This should only be present in testMode. In prod use an HSM.",
|
||||
"issuerKey": "test/test-ca.key",
|
||||
"Key": {
|
||||
"File": "test/test-ca.key"
|
||||
},
|
||||
"expiry": "2160h",
|
||||
"maxNames": 1000
|
||||
"maxNames": 1000,
|
||||
"cfssl": {
|
||||
"signing": {
|
||||
"profiles": {
|
||||
"ee": {
|
||||
"usages": [
|
||||
"digital signature",
|
||||
"key encipherment",
|
||||
"server auth"
|
||||
],
|
||||
"backdate": "1h",
|
||||
"is_ca": false,
|
||||
"issuer_urls": [
|
||||
"http://int-x1.letsencrypt.org/cert"
|
||||
],
|
||||
"ocsp_url": "http://int-x1.letsencrypt.org/ocsp",
|
||||
"crl_url": "http://int-x1.letsencrypt.org/crl",
|
||||
"policies": [
|
||||
"1.3.6.1.4.1.44947.1.1.1",
|
||||
"2.23.140.1.2.1"
|
||||
],
|
||||
"expiry": "8760h",
|
||||
"CSRWhitelist": {
|
||||
"PublicKeyAlgorithm": true,
|
||||
"PublicKey": true,
|
||||
"SignatureAlgorithm": true
|
||||
},
|
||||
"UseSerialSeq": true
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"usages": [
|
||||
"digital signature"
|
||||
],
|
||||
"expiry": "8760h"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"sa": {
|
||||
|
|
|
@ -17,31 +17,17 @@ def die():
|
|||
sys.exit(1)
|
||||
|
||||
def build(path):
|
||||
cmd = 'go build -o %s/%s %s' % (tempdir, os.path.basename(path), path)
|
||||
cmd = 'go build -tags pkcs11 -o %s/%s %s' % (tempdir, os.path.basename(path), path)
|
||||
print(cmd)
|
||||
if subprocess.Popen(cmd, shell=True).wait() != 0:
|
||||
die()
|
||||
|
||||
# A strange Go bug: If cfssl is up-to-date, we'll get a failure building
|
||||
# Boulder. Work around by touching cfssl.go.
|
||||
subprocess.Popen('touch Godeps/_workspace/src/github.com/cloudflare/cfssl/cmd/cfssl/cfssl.go', shell=True).wait()
|
||||
build('./cmd/boulder')
|
||||
build('./Godeps/_workspace/src/github.com/cloudflare/cfssl/cmd/cfssl')
|
||||
|
||||
boulder = subprocess.Popen('''
|
||||
exec %s/boulder --config test/boulder-test-config.json
|
||||
''' % tempdir, shell=True)
|
||||
|
||||
cfssl = subprocess.Popen('''
|
||||
exec %s/cfssl \
|
||||
-loglevel 0 \
|
||||
serve \
|
||||
-port 9300 \
|
||||
-ca test/test-ca.pem \
|
||||
-ca-key test/test-ca.key \
|
||||
-config test/cfssl-config.json
|
||||
''' % tempdir, shell=True, stdout=None)
|
||||
|
||||
def run_test():
|
||||
os.chdir('test/js')
|
||||
|
||||
|
@ -85,12 +71,6 @@ finally:
|
|||
else:
|
||||
boulder.kill()
|
||||
|
||||
if cfssl.poll() is not None:
|
||||
print("CFSSL died")
|
||||
exit_status = 1
|
||||
else:
|
||||
cfssl.kill()
|
||||
|
||||
shutil.rmtree(tempdir)
|
||||
|
||||
if exit_status == 0:
|
||||
|
|
|
@ -2,26 +2,18 @@
|
|||
|
||||
The node.js scripts in this directory provide a simple end-to-end test of Boulder. (Using some pieces from [node-acme](https://github.com/letsencrypt/node-acme/)) To run:
|
||||
|
||||
# Install dependencies (run in this directory).
|
||||
# Run boulder in default test mode:
|
||||
|
||||
npm install
|
||||
cd ../../
|
||||
./start.py
|
||||
|
||||
# Run boulder in default test mode (no Yubikey, start cfssl automatically):
|
||||
# To run cfssl with a Yubikey, edit test/boulder-pkcs11-example-config.json to
|
||||
# add your PKCS#11 PIN (and module name, token name, and label). Then run:
|
||||
|
||||
cd ../
|
||||
./start.sh
|
||||
|
||||
# To run cfssl with a Yubikey:
|
||||
# (You'll need to make your own key, cert, and policy.)
|
||||
|
||||
go install -tags pkcs11 github.com/cloudflare/cfssl/cmd/cfssl
|
||||
cfssl serve -port 9000 -ca ca.cert.pem \
|
||||
-pkcs11-module "/Library/OpenSC/lib/opensc-pkcs11.so" \
|
||||
-pkcs11-token "Yubico Yubik NEO CCID" \
|
||||
-pkcs11-pin 123456 \
|
||||
-pkcs11-label "PIV AUTH key" \
|
||||
-config policy.json
|
||||
cd ../../
|
||||
BOULDER_CONFIG=test/boulder-pkcs11-example-config.json ./start.py
|
||||
|
||||
# Client side
|
||||
|
||||
npm install
|
||||
node test.js
|
||||
|
|
Loading…
Reference in New Issue