Skip to content

Commit

Permalink
Merge a5ef858 into bae699f
Browse files Browse the repository at this point in the history
  • Loading branch information
aarongable committed Mar 18, 2021
2 parents bae699f + a5ef858 commit 1bd6d86
Show file tree
Hide file tree
Showing 39 changed files with 308 additions and 6,510 deletions.
376 changes: 31 additions & 345 deletions ca/ca.go

Large diffs are not rendered by default.

770 changes: 222 additions & 548 deletions ca/ca_test.go

Large diffs are not rendered by default.

Binary file removed ca/testdata/tls_feature_unknown.der.csr
Binary file not shown.
126 changes: 5 additions & 121 deletions cmd/boulder-ca/main.go
@@ -1,26 +1,18 @@
package main

import (
"crypto"
"crypto/x509"
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"os"
"sync"

"github.com/beeker1121/goque"
cfsslConfig "github.com/cloudflare/cfssl/config"
"github.com/cloudflare/cfssl/helpers"
pkcs11key "github.com/letsencrypt/pkcs11key/v4"
"google.golang.org/grpc/health"
healthpb "google.golang.org/grpc/health/grpc_health_v1"

"github.com/letsencrypt/boulder/ca"
capb "github.com/letsencrypt/boulder/ca/proto"
"github.com/letsencrypt/boulder/cmd"
"github.com/letsencrypt/boulder/core"
"github.com/letsencrypt/boulder/features"
"github.com/letsencrypt/boulder/goodkey"
bgrpc "github.com/letsencrypt/boulder/grpc"
Expand All @@ -45,30 +37,17 @@ type config struct {

SAService *cmd.GRPCClientConfig

// CFSSL contains CFSSL-specific configs as specified by that library.
CFSSL cfsslConfig.Config
// RSAProfile and ECDSAProfile name which of the profiles specified in the
// CFSSL config should be used when issuing RSA and ECDSA certs, respectively.
RSAProfile string
ECDSAProfile string
// Issuers contains configuration information for each issuer cert and key
// this CA knows about. The first in the list is used as the default.
// Only used by CFSSL.
Issuers []IssuerConfig

// Issuance contains all information necessary to load and initialize non-CFSSL issuers.
// Issuance contains all information necessary to load and initialize issuers.
Issuance struct {
Profile issuance.ProfileConfig
Issuers []issuance.IssuerConfig
IgnoredLints []string
}

// How long issued certificates are valid for, should match expiry field
// in cfssl config.
// How long issued certificates are valid for.
Expiry cmd.ConfigDuration

// How far back certificates should be backdated, should match backdate
// field in cfssl config.
// How far back certificates should be backdated.
Backdate cmd.ConfigDuration

// What digits we should prepend to serials after randomly generating them.
Expand Down Expand Up @@ -125,91 +104,6 @@ type config struct {
Syslog cmd.SyslogConfig
}

// IssuerConfig contains info about an issuer: private key and issuer cert.
// It should contain either a File path to a PEM-format private key,
// or a PKCS11Config defining how to load a module for an HSM. Used by CFSSL.
type IssuerConfig struct {
// A file from which a pkcs11key.Config will be read and parsed, if present
ConfigFile string
File string
PKCS11 *pkcs11key.Config
CertFile string
// Number of sessions to open with the HSM. For maximum performance,
// this should be equal to the number of cores in the HSM. Defaults to 1.
NumSessions int
}

func loadCFSSLIssuers(configs []IssuerConfig) ([]ca.Issuer, error) {
var issuers []ca.Issuer
for _, issuerConfig := range configs {
signer, cert, err := loadCFSSLIssuer(issuerConfig)
cmd.FailOnError(err, "Couldn't load private key")
issuers = append(issuers, ca.Issuer{
Signer: signer,
Cert: cert,
})
}
return issuers, nil
}

func loadCFSSLIssuer(issuerConfig IssuerConfig) (crypto.Signer, *issuance.Certificate, error) {
cert, err := issuance.LoadCertificate(issuerConfig.CertFile)
if err != nil {
return nil, nil, err
}

signer, err := loadCFSSLSigner(issuerConfig, cert.Certificate)
if err != nil {
return nil, nil, err
}

if !core.KeyDigestEquals(signer.Public(), cert.PublicKey) {
return nil, nil, fmt.Errorf("Issuer key did not match issuer cert %s", issuerConfig.CertFile)
}
return signer, cert, err
}

func loadCFSSLSigner(issuerConfig IssuerConfig, cert *x509.Certificate) (crypto.Signer, error) {
if issuerConfig.File != "" {
keyBytes, err := ioutil.ReadFile(issuerConfig.File)
if err != nil {
return nil, fmt.Errorf("Could not read key file %s", issuerConfig.File)
}

signer, err := helpers.ParsePrivateKeyPEM(keyBytes)
if err != nil {
return nil, err
}
return signer, nil
}

var pkcs11Config *pkcs11key.Config
if issuerConfig.ConfigFile != "" {
contents, err := ioutil.ReadFile(issuerConfig.ConfigFile)
if err != nil {
return nil, err
}
pkcs11Config = new(pkcs11key.Config)
err = json.Unmarshal(contents, pkcs11Config)
if err != nil {
return nil, err
}
} else {
pkcs11Config = issuerConfig.PKCS11
}
if pkcs11Config.Module == "" ||
pkcs11Config.TokenLabel == "" ||
pkcs11Config.PIN == "" {
return nil, fmt.Errorf("Missing a field in pkcs11Config %#v", pkcs11Config)
}
numSessions := issuerConfig.NumSessions
if numSessions <= 0 {
numSessions = 1
}
return pkcs11key.NewPool(numSessions, pkcs11Config.Module,
pkcs11Config.TokenLabel, pkcs11Config.PIN, cert.PublicKey)
}

func loadBoulderIssuers(profileConfig issuance.ProfileConfig, issuerConfigs []issuance.IssuerConfig, ignoredLints []string) ([]*issuance.Issuer, error) {
issuers := make([]*issuance.Issuer, 0, len(issuerConfigs))
for _, issuerConfig := range issuerConfigs {
Expand Down Expand Up @@ -285,15 +179,9 @@ func main() {
err = pa.SetHostnamePolicyFile(c.CA.HostnamePolicyFile)
cmd.FailOnError(err, "Couldn't load hostname policy file")

var cfsslIssuers []ca.Issuer
var boulderIssuers []*issuance.Issuer
if features.Enabled(features.NonCFSSLSigner) {
boulderIssuers, err = loadBoulderIssuers(c.CA.Issuance.Profile, c.CA.Issuance.Issuers, c.CA.Issuance.IgnoredLints)
cmd.FailOnError(err, "Couldn't load issuers")
} else {
cfsslIssuers, err = loadCFSSLIssuers(c.CA.Issuers)
cmd.FailOnError(err, "Couldn't load issuers")
}
boulderIssuers, err = loadBoulderIssuers(c.CA.Issuance.Profile, c.CA.Issuance.Issuers, c.CA.Issuance.IgnoredLints)
cmd.FailOnError(err, "Couldn't load issuers")

tlsConfig, err := c.CA.TLS.Load()
cmd.FailOnError(err, "TLS config")
Expand All @@ -318,10 +206,6 @@ func main() {
cai, err := ca.NewCertificateAuthorityImpl(
sa,
pa,
c.CA.CFSSL,
c.CA.RSAProfile,
c.CA.ECDSAProfile,
cfsslIssuers,
boulderIssuers,
c.CA.ECDSAAllowedAccounts,
c.CA.Expiry.Duration,
Expand Down
40 changes: 0 additions & 40 deletions cmd/boulder-ca/main_test.go
@@ -1,41 +1 @@
package main

import (
"testing"
)

func TestLoadIssuerSuccess(t *testing.T) {
signer, cert, err := loadCFSSLIssuer(IssuerConfig{
File: "../../test/test-ca.key",
CertFile: "../../test/test-ca2.pem",
})
if err != nil {
t.Fatal(err)
}
if signer == nil {
t.Fatal("loadIssuer returned nil signer")
}
if cert == nil {
t.Fatal("loadIssuer returned nil cert")
}
}

func TestLoadIssuerBadKey(t *testing.T) {
_, _, err := loadCFSSLIssuer(IssuerConfig{
File: "/dev/null",
CertFile: "../../test/test-ca2.pem",
})
if err == nil {
t.Fatal("loadIssuer succeeded when loading key from /dev/null")
}
}

func TestLoadIssuerBadCert(t *testing.T) {
_, _, err := loadCFSSLIssuer(IssuerConfig{
File: "../../test/test-ca.key",
CertFile: "/dev/null",
})
if err == nil {
t.Fatal("loadIssuer succeeded when loading key from /dev/null")
}
}
24 changes: 1 addition & 23 deletions cmd/shell.go
Expand Up @@ -20,7 +20,6 @@ import (

"google.golang.org/grpc/grpclog"

cfsslLog "github.com/cloudflare/cfssl/log"
"github.com/go-sql-driver/mysql"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
Expand Down Expand Up @@ -50,20 +49,6 @@ func (m mysqlLogger) Print(v ...interface{}) {
m.AuditErrf("[mysql] %s", fmt.Sprint(v...))
}

// cfsslLogger provides two additional methods that are expected by CFSSL's
// logger but not supported by Boulder's Logger.
type cfsslLogger struct {
blog.Logger
}

func (cl cfsslLogger) Crit(msg string) {
cl.AuditErr(msg)
}

func (cl cfsslLogger) Emerg(msg string) {
cl.AuditErr(msg)
}

type grpcLogger struct {
blog.Logger
}
Expand Down Expand Up @@ -146,7 +131,7 @@ func (lw logWriter) Write(p []byte) (n int, err error) {
// server on the provided port to report the stats and provide pprof profiling
// handlers. NewLogger and newStatsRegistry will call os.Exit on errors.
// Also sets the constructed AuditLogger as the default logger, and configures
// the cfssl, mysql, and grpc packages to use our logger.
// the mysql and grpc packages to use our logger.
// This must be called before any gRPC code is called, because gRPC's SetLogger
// doesn't use any locking.
func StatsAndLogging(logConf SyslogConfig, addr string) (prometheus.Registerer, blog.Logger) {
Expand All @@ -170,13 +155,6 @@ func NewLogger(logConf SyslogConfig) blog.Logger {
FailOnError(err, "Could not connect to Syslog")

_ = blog.Set(logger)
// We set the cfssl logging level to Debug as it
// won't actually call logging methods for any
// level less than what is set. We will ignore
// any logging we don't care about at the syslog
// level, so this doesn't cause extraneous logging.
cfsslLog.Level = cfsslLog.LevelDebug
cfsslLog.SetLogger(cfsslLogger{logger})
_ = mysql.SetLogger(mysqlLogger{logger})
grpclog.SetLoggerV2(grpcLogger{logger})
log.SetOutput(logWriter{logger})
Expand Down
32 changes: 0 additions & 32 deletions cmd/shell_test.go
Expand Up @@ -91,38 +91,6 @@ func TestMysqlLogger(t *testing.T) {
}
}

func TestCfsslLogger(t *testing.T) {
log := blog.UseMock()
cLog := cfsslLogger{log}

testCases := []struct {
msg, expected string
}{
{
"",
"ERR: [AUDIT] ",
},
{
"Test",
"ERR: [AUDIT] Test",
},
}

for _, tc := range testCases {
// cfsslLogger proxies blog.AuditLogger to provide Crit() and Emerg()
// methods that are expected by CFSSL's logger
cLog.Crit(tc.msg)
cLog.Emerg(tc.msg)
logged := log.GetAll()
// Calling Crit and Emerg should produce two AuditErr outputs matching the
// testCase expected output
test.AssertEquals(t, len(logged), 2)
test.AssertEquals(t, logged[0], tc.expected)
test.AssertEquals(t, logged[1], tc.expected)
log.Clear()
}
}

func TestCaptureStdlibLog(t *testing.T) {
logger := blog.UseMock()
oldDest := log.Writer()
Expand Down
28 changes: 14 additions & 14 deletions features/featureflag_string.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 1 addition & 3 deletions features/features.go
Expand Up @@ -14,6 +14,7 @@ const (
// Deprecated features, these can be removed once stripped from production configs
PrecertificateRevocation
StripDefaultSchemePort
NonCFSSLSigner

// Currently in-use features
// Check CAA and respect validationmethods parameter.
Expand Down Expand Up @@ -46,9 +47,6 @@ const (
// FasterNewOrdersRateLimit enables use of a separate table for counting the
// new orders rate limit.
FasterNewOrdersRateLimit
// NonCFSSLSigner enables usage of our own certificate signer instead of the
// CFSSL signer.
NonCFSSLSigner
// ECDSAForAll enables all accounts, regardless of their presence in the CA's
// ecdsaAllowedAccounts config value, to get issuance from ECDSA issuers.
ECDSAForAll
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Expand Up @@ -4,7 +4,7 @@ go 1.12

require (
github.com/beeker1121/goque v0.0.0-20170321141813-4044bc29b280
github.com/cloudflare/cfssl v1.4.2-0.20200324225241-abef926615f4
github.com/cloudflare/cfssl v1.4.2-0.20200324225241-abef926615f4 // indirect
github.com/eggsampler/acme/v3 v3.0.0
github.com/go-gorp/gorp/v3 v3.0.2
github.com/go-sql-driver/mysql v1.5.0
Expand Down

0 comments on commit 1bd6d86

Please sign in to comment.