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:
Jacob Hoffman-Andrews 2015-05-20 18:14:30 -07:00
parent eb7bcc793d
commit 625eab5ad3
12 changed files with 325 additions and 189 deletions

View File

@ -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,

View File

@ -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)

View File

@ -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
}

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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": {

View File

@ -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"
}

View File

@ -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": {

22
test/integration-test.py Normal file → Executable file
View File

@ -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:

View File

@ -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