Correct most `go lint` warnings. (274 -> 5)

This commit is contained in:
J.C. Jones 2015-06-16 20:32:09 -05:00
parent 383885df08
commit 41f5788c77
48 changed files with 434 additions and 195 deletions

View File

@ -16,16 +16,17 @@ import (
// This file analyzes messages obtained from the Message Broker to determine
// whether the system as a whole is functioning correctly.
// Interface all Analysis Engines share
// AnalysisEngine is the interface all Analysis Engines share
type AnalysisEngine interface {
ProcessMessage(amqp.Delivery) (err error)
}
// An Analysis Engine that just logs to the JSON Logger.
// LoggingAnalysisEngine is an Analysis Engine that just logs to the Logger.
type LoggingAnalysisEngine struct {
log *blog.AuditLogger
}
// ProcessMessage logs the marshaled contents of the AMQP message.
func (eng *LoggingAnalysisEngine) ProcessMessage(delivery amqp.Delivery) (err error) {
// Send the entire message contents to the syslog server for debugging.
encoded, err := json.Marshal(delivery)
@ -38,7 +39,7 @@ func (eng *LoggingAnalysisEngine) ProcessMessage(delivery amqp.Delivery) (err er
return
}
// Construct a new Analysis Engine.
// NewLoggingAnalysisEngine constructs a new Analysis Engine.
func NewLoggingAnalysisEngine() AnalysisEngine {
logger := blog.GetAuditLogger()
logger.Notice("Analysis Engine Starting")

View File

@ -25,7 +25,7 @@ type MockAck struct {
// json.Marshall cannot represent a chan, so this will break
// the json.Marshal attempt in ProcessMessage and let us get
// coverage there.
JsonBreaker chan bool
JSONBreaker chan bool
}
func (m *MockAck) Ack(tag uint64, multiple bool) error {

View File

@ -64,7 +64,7 @@ func (cadb *CertificateAuthorityDatabaseImpl) CreateTablesIfNotExists() (err err
return
}
// GetDbMap gets a pointer to the CA DB's GORP map object.
// Begin starts a transaction at the GORP wrapper.
func (cadb *CertificateAuthorityDatabaseImpl) Begin() (*gorp.Transaction, error) {
return cadb.dbMap.Begin()
}

View File

@ -46,11 +46,14 @@ type Config struct {
CFSSL cfsslConfig.Config
}
// KeyConfig should contain either a File path to a PEM-format private key,
// or a PKCS11Config defining how to load a module for an HSM.
type KeyConfig struct {
File string
PKCS11 PKCS11Config
}
// PKCS11Config defines how to load a module for an HSM.
type PKCS11Config struct {
Module string
Token string
@ -170,12 +173,12 @@ func loadKey(keyConfig KeyConfig) (priv crypto.Signer, err error) {
priv, err = helpers.ParsePrivateKeyPEM(keyBytes)
return
} else {
pkcs11Config := keyConfig.PKCS11
priv, err = pkcs11key.New(pkcs11Config.Module,
pkcs11Config.Token, pkcs11Config.PIN, pkcs11Config.Label)
return
}
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) {

View File

@ -25,7 +25,7 @@ import (
"github.com/letsencrypt/boulder/test"
)
var CA_KEY_PEM = "-----BEGIN RSA PRIVATE KEY-----\n" +
var CAkeyPEM = "-----BEGIN RSA PRIVATE KEY-----\n" +
"MIIJKQIBAAKCAgEAqmM0dEf/J9MCk2ItzevL0dKJ84lVUtf/vQ7AXFi492vFXc3b\n" +
"PrJz2ybtjO08oVkhRrFGGgLufL2JeOBn5pUZQrp6TqyCLoQ4f/yrmu9tCeG8CtDg\n" +
"xi6Ye9LjvlchEHhUKhAHc8uL+ablHzWxHTeuhnuThrsLFUcJQWb10U27LiXp3XCW\n" +
@ -77,7 +77,7 @@ var CA_KEY_PEM = "-----BEGIN RSA PRIVATE KEY-----\n" +
"huu1W6p9RdxJHgphzmGAvTrOmrDAZeKtubsMS69VZVFjQFa1ZD/VMzWK1X2o\n" +
"-----END RSA PRIVATE KEY-----"
var CA_CERT_PEM = "-----BEGIN CERTIFICATE-----\n" +
var CAcertPEM = "-----BEGIN CERTIFICATE-----\n" +
"MIIFxDCCA6ygAwIBAgIJALe2d/gZHJqAMA0GCSqGSIb3DQEBCwUAMDExCzAJBgNV\n" +
"BAYTAlVTMRAwDgYDVQQKDAdUZXN0IENBMRAwDgYDVQQDDAdUZXN0IENBMB4XDTE1\n" +
"MDIxMzAwMzI0NFoXDTI1MDIxMDAwMzI0NFowMTELMAkGA1UEBhMCVVMxEDAOBgNV\n" +
@ -115,7 +115,7 @@ var CA_CERT_PEM = "-----BEGIN CERTIFICATE-----\n" +
// * Random public key
// * CN = not-example.com
// * DNSNames = not-example.com, www.not-example.com
var CN_AND_SAN_CSR_HEX = "308202a130820189020100301a311830160603550403130f6e6f742d6578" +
var CNandSANCSRhex = "308202a130820189020100301a311830160603550403130f6e6f742d6578" +
"616d706c652e636f6d30820122300d06092a864886f70d01010105000382" +
"010f003082010a0282010100e56ccbe37003c150202e6f543f9eb1d0e590" +
"76ac7f1f62654fa82fe131a23c66bd53a2f62ff7852015c84a394e36836d" +
@ -143,7 +143,7 @@ var CN_AND_SAN_CSR_HEX = "308202a130820189020100301a311830160603550403130f6e6f74
// * Random public key
// * CN = not-example.com
// * DNSNames = [none]
var NO_SAN_CSR_HEX = "3082025f30820147020100301a311830160603550403130f6e6f742d6578" +
var NoSANCSRhex = "3082025f30820147020100301a311830160603550403130f6e6f742d6578" +
"616d706c652e636f6d30820122300d06092a864886f70d01010105000382" +
"010f003082010a0282010100aa6e56ff24906f93b855e7871dc8411a3cf7" +
"678d9563627e8ca37ab17dfe814ef7f828d6aa92b717f0da9df56990b953" +
@ -170,7 +170,7 @@ var NO_SAN_CSR_HEX = "3082025f30820147020100301a311830160603550403130f6e6f742d65
// * C = US
// * CN = [none]
// * DNSNames = not-example.com
var NO_CN_CSR_HEX = "3082027f30820167020100300d310b300906035504061302555330820122" +
var NoCNCSRhex = "3082027f30820167020100300d310b300906035504061302555330820122" +
"300d06092a864886f70d01010105000382010f003082010a0282010100d8" +
"b3c11610ce17614f6d78de3f079db430e479c38978da8cd625b7c70dd445" +
"57fd99b9831693e6b9b09fb7c74a82058a1f1a4e1e087f04f93aa73bc35a" +
@ -198,7 +198,7 @@ var NO_CN_CSR_HEX = "3082027f30820167020100300d310b30090603550406130255533082012
// * C = US
// * CN = [none]
// * DNSNames = [none]
var NO_NAME_CSR_HEX = "308202523082013a020100300d310b300906035504061302555330820122" +
var NoNameCSRhex = "308202523082013a020100300d310b300906035504061302555330820122" +
"300d06092a864886f70d01010105000382010f003082010a0282010100bc" +
"fae49f68f02c42500b2faf251628ee19e8ef048a35fef311c9c419c80606" +
"ab37340ad6e25cf4cc63c0283994b4ba705d86950ad5298094e0b9684647" +
@ -223,7 +223,7 @@ var NO_NAME_CSR_HEX = "308202523082013a020100300d310b300906035504061302555330820
// * Random public key
// * CN = [none]
// * DNSNames = a.example.com, a.example.com
var DUPE_NAME_CSR_HEX = "308202943082017c020100300d310b300906035504061302555330820122" +
var DupeNameCSRhex = "308202943082017c020100300d310b300906035504061302555330820122" +
"300d06092a864886f70d01010105000382010f003082010a0282010100ee" +
"7d298c2a8237dd84e75e71dcfbbf8e1124327b103b01f3a99bc76b29be64" +
"55329dc523ad1372ed12853dc74a775f2c79d1e4e28ae2a3ce69b78ec161" +
@ -251,7 +251,7 @@ var DUPE_NAME_CSR_HEX = "308202943082017c020100300d310b3009060355040613025553308
// * Random pulic key
// * CN = [none]
// * DNSNames = not-example.com, www.not-example.com, mail.example.com
var TOO_MANY_NAME_CSR_HEX = "308202aa30820192020100300d310b300906035504061302555330820122" +
var TooManyNameCSRhex = "308202aa30820192020100300d310b300906035504061302555330820122" +
"300d06092a864886f70d01010105000382010f003082010a0282010100a7" +
"75d8f833651d9a4cfa1fa0e134912b772366c7d070ca3183d3c79ffc99bb" +
"c706d328c2389b360b99f60e9a447023a019931d410b4cea0eafb7869a6d" +
@ -362,7 +362,7 @@ func TestRevoke(t *testing.T) {
ca.SA = storageAuthority
ca.MaxKeySize = 4096
csrDER, _ := hex.DecodeString(CN_AND_SAN_CSR_HEX)
csrDER, _ := hex.DecodeString(CNandSANCSRhex)
csr, _ := x509.ParseCertificateRequest(csrDER)
certObj, err := ca.IssueCertificate(*csr, 1, FarFuture)
test.AssertNotError(t, err, "Failed to sign certificate")
@ -399,7 +399,7 @@ func TestIssueCertificate(t *testing.T) {
}
*/
csrs := []string{CN_AND_SAN_CSR_HEX, NO_SAN_CSR_HEX, NO_CN_CSR_HEX}
csrs := []string{CNandSANCSRhex, NoSANCSRhex, NoCNCSRhex}
for _, csrHEX := range csrs {
csrDER, _ := hex.DecodeString(csrHEX)
csr, _ := x509.ParseCertificateRequest(csrDER)
@ -467,7 +467,7 @@ func TestRejectNoName(t *testing.T) {
ca.MaxKeySize = 4096
// Test that the CA rejects CSRs with no names
csrDER, _ := hex.DecodeString(NO_NAME_CSR_HEX)
csrDER, _ := hex.DecodeString(NoNameCSRhex)
csr, _ := x509.ParseCertificateRequest(csrDER)
_, err = ca.IssueCertificate(*csr, 1, FarFuture)
if err == nil {
@ -482,7 +482,7 @@ func TestRejectTooManyNames(t *testing.T) {
ca.SA = storageAuthority
// Test that the CA rejects a CSR with too many names
csrDER, _ := hex.DecodeString(TOO_MANY_NAME_CSR_HEX)
csrDER, _ := hex.DecodeString(TooManyNameCSRhex)
csr, _ := x509.ParseCertificateRequest(csrDER)
_, err = ca.IssueCertificate(*csr, 1, FarFuture)
test.Assert(t, err != nil, "Issued certificate with too many names")
@ -496,7 +496,7 @@ func TestDeduplication(t *testing.T) {
ca.MaxKeySize = 4096
// Test that the CA collapses duplicate names
csrDER, _ := hex.DecodeString(DUPE_NAME_CSR_HEX)
csrDER, _ := hex.DecodeString(DupeNameCSRhex)
csr, _ := x509.ParseCertificateRequest(csrDER)
cert, err := ca.IssueCertificate(*csr, 1, FarFuture)
test.AssertNotError(t, err, "Failed to gracefully handle a CSR with duplicate names")
@ -525,13 +525,13 @@ func TestRejectValidityTooLong(t *testing.T) {
ca.MaxKeySize = 4096
// Test that the CA rejects CSRs that would expire after the intermediate cert
csrDER, _ := hex.DecodeString(NO_CN_CSR_HEX)
csrDER, _ := hex.DecodeString(NoCNCSRhex)
csr, _ := x509.ParseCertificateRequest(csrDER)
_, err = ca.IssueCertificate(*csr, 1, FarPast)
test.Assert(t, err == nil, "Can issue a certificate that expires after the underlying authorization.")
// Test that the CA rejects CSRs that would expire after the intermediate cert
csrDER, _ = hex.DecodeString(NO_CN_CSR_HEX)
csrDER, _ = hex.DecodeString(NoCNCSRhex)
csr, _ = x509.ParseCertificateRequest(csrDER)
ca.NotAfter = time.Now()
_, err = ca.IssueCertificate(*csr, 1, FarFuture)

View File

@ -22,6 +22,7 @@ import (
blog "github.com/letsencrypt/boulder/log"
)
// Constants for AMQP
const (
QueueName = "Monitor"
AmqpExchange = "boulder"
@ -37,17 +38,17 @@ const (
AmqpImmediate = false
)
var openCalls int64 = 0
var openCalls int64
func timeDelivery(d amqp.Delivery, stats statsd.Statter, deliveryTimings map[string]time.Time) {
// If d is a call add to deliveryTimings and increment openCalls, if it is a
// response then get time.Since original call from deliveryTiming, send timing metric, and
// decrement openCalls, in both cases send the gauges RpcCallsOpen and RpcBodySize
if d.ReplyTo != "" {
openCalls += 1
openCalls++
deliveryTimings[fmt.Sprintf("%s:%s", d.CorrelationId, d.ReplyTo)] = time.Now()
} else {
openCalls -= 1
openCalls--
rpcSent := deliveryTimings[fmt.Sprintf("%s:%s", d.CorrelationId, d.RoutingKey)]
if rpcSent != *new(time.Time) {
respTime := time.Since(rpcSent)

View File

@ -31,7 +31,7 @@ import (
gorp "github.com/letsencrypt/boulder/Godeps/_workspace/src/gopkg.in/gorp.v1"
)
var reasons map[int]string = map[int]string{
var reasons = map[int]string{
0: "unspecified",
1: "keyCompromise",
2: "cACompromise",
@ -69,7 +69,7 @@ func setupContext(context *cli.Context) (rpc.CertificateAuthorityClient, *blog.A
ch := cmd.AmqpChannel(c.AMQP.Server)
caRPC, err := rpc.NewAmqpRPCCLient("revoker->CA", c.AMQP.CA.Server, ch)
caRPC, err := rpc.NewAmqpRPCClient("revoker->CA", c.AMQP.CA.Server, ch)
cmd.FailOnError(err, "Unable to create RPC client")
cac, err := rpc.NewCertificateAuthorityClient(caRPC)
@ -147,7 +147,7 @@ func revokeByReg(regID int, reasonCode int, deny bool, cac rpc.CertificateAuthor
return
}
var version string = "0.0.1"
var version = "0.0.1"
func main() {
app := cli.NewApp()
@ -231,7 +231,7 @@ func main() {
Usage: "List all revocation reason codes",
Action: func(c *cli.Context) {
var codes []int
for k, _ := range reasons {
for k := range reasons {
codes = append(codes, k)
}
sort.Ints(codes)

View File

@ -48,7 +48,7 @@ func main() {
ch := cmd.AmqpChannel(c.AMQP.Server)
closeChan := ch.NotifyClose(make(chan *amqp.Error, 1))
saRPC, err := rpc.NewAmqpRPCCLient("CA->SA", c.AMQP.SA.Server, ch)
saRPC, err := rpc.NewAmqpRPCClient("CA->SA", c.AMQP.SA.Server, ch)
cmd.FailOnError(err, "Unable to create RPC client")
sac, err := rpc.NewStorageAuthorityClient(saRPC)

View File

@ -41,13 +41,13 @@ func main() {
ch := cmd.AmqpChannel(c.AMQP.Server)
closeChan := ch.NotifyClose(make(chan *amqp.Error, 1))
vaRPC, err := rpc.NewAmqpRPCCLient("RA->VA", c.AMQP.VA.Server, ch)
vaRPC, err := rpc.NewAmqpRPCClient("RA->VA", c.AMQP.VA.Server, ch)
cmd.FailOnError(err, "Unable to create RPC client")
caRPC, err := rpc.NewAmqpRPCCLient("RA->CA", c.AMQP.CA.Server, ch)
caRPC, err := rpc.NewAmqpRPCClient("RA->CA", c.AMQP.CA.Server, ch)
cmd.FailOnError(err, "Unable to create RPC client")
saRPC, err := rpc.NewAmqpRPCCLient("RA->SA", c.AMQP.SA.Server, ch)
saRPC, err := rpc.NewAmqpRPCClient("RA->SA", c.AMQP.SA.Server, ch)
cmd.FailOnError(err, "Unable to create RPC client")
vac, err := rpc.NewValidationAuthorityClient(vaRPC)

View File

@ -44,7 +44,7 @@ func main() {
ch := cmd.AmqpChannel(c.AMQP.Server)
closeChan := ch.NotifyClose(make(chan *amqp.Error, 1))
raRPC, err := rpc.NewAmqpRPCCLient("VA->RA", c.AMQP.RA.Server, ch)
raRPC, err := rpc.NewAmqpRPCClient("VA->RA", c.AMQP.RA.Server, ch)
cmd.FailOnError(err, "Unable to create RPC client")
rac, err := rpc.NewRegistrationAuthorityClient(raRPC)

View File

@ -23,10 +23,10 @@ func setupWFE(c cmd.Config) (rpc.RegistrationAuthorityClient, rpc.StorageAuthori
ch := cmd.AmqpChannel(c.AMQP.Server)
closeChan := ch.NotifyClose(make(chan *amqp.Error, 1))
raRPC, err := rpc.NewAmqpRPCCLient("WFE->RA", c.AMQP.RA.Server, ch)
raRPC, err := rpc.NewAmqpRPCClient("WFE->RA", c.AMQP.RA.Server, ch)
cmd.FailOnError(err, "Unable to create RPC client")
saRPC, err := rpc.NewAmqpRPCCLient("WFE->SA", c.AMQP.SA.Server, ch)
saRPC, err := rpc.NewAmqpRPCClient("WFE->SA", c.AMQP.SA.Server, ch)
cmd.FailOnError(err, "Unable to create RPC client")
rac, err := rpc.NewRegistrationAuthorityClient(raRPC)
@ -43,17 +43,18 @@ type timedHandler struct {
stats statsd.Statter
}
var openConnections int64 = 0
var openConnections int64
// HandlerTimer monitors HTTP performance and sends the details to StatsD.
func HandlerTimer(handler http.Handler, stats statsd.Statter) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
cStart := time.Now()
openConnections += 1
openConnections++
stats.Gauge("HttpConnectionsOpen", openConnections, 1.0)
handler.ServeHTTP(w, r)
openConnections -= 1
openConnections--
stats.Gauge("HttpConnectionsOpen", openConnections, 1.0)
// (FIX: this doesn't seem to really work at catching errors...)

View File

@ -28,17 +28,18 @@ type timedHandler struct {
stats statsd.Statter
}
var openConnections int64 = 0
var openConnections int64
// HandlerTimer monitors HTTP performance and sends the details to StatsD.
func HandlerTimer(handler http.Handler, stats statsd.Statter) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
cStart := time.Now()
openConnections += 1
openConnections++
stats.Gauge("HttpConnectionsOpen", openConnections, 1.0)
handler.ServeHTTP(w, r)
openConnections -= 1
openConnections--
stats.Gauge("HttpConnectionsOpen", openConnections, 1.0)
// (FIX: this doesn't seem to really work at catching errors...)

View File

@ -22,6 +22,7 @@ var pin = flag.String("pkcs11-pin", "", "PKCS#11 password")
var token = flag.String("pkcs11-token", "", "PKCS#11 token name")
var label = flag.String("pkcs11-label", "", "PKCS#11 key label")
// Config defines the configuration loaded from listFile.
type Config struct {
ThisUpdate time.Time
NextUpdate time.Time

View File

@ -23,6 +23,7 @@ var pin = flag.String("pkcs11-pin", "", "PKCS#11 password")
var token = flag.String("pkcs11-token", "", "PKCS#11 token name")
var label = flag.String("pkcs11-label", "", "PKCS#11 key label")
// Config defines the configuration loaded from configFile.
type Config struct {
Name struct {
C string

View File

@ -29,17 +29,18 @@ type timedHandler struct {
stats statsd.Statter
}
var openConnections int64 = 0
var openConnections int64
// HandlerTimer monitors HTTP performance and sends the details to StatsD.
func HandlerTimer(handler http.Handler, stats statsd.Statter) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
cStart := time.Now()
openConnections += 1
openConnections++
stats.Gauge("HttpConnectionsOpen", openConnections, 1.0)
handler.ServeHTTP(w, r)
openConnections -= 1
openConnections--
stats.Gauge("HttpConnectionsOpen", openConnections, 1.0)
// (FIX: this doesn't seem to really work at catching errors...)
@ -56,6 +57,8 @@ func HandlerTimer(handler http.Handler, stats statsd.Statter) http.Handler {
}
/*
DBSource maps a given Database schema to a CA Key Hash, so we can pick
from among them when presented with OCSP requests for different certs.
We assume that OCSP responses are stored in a very simple database table,
with two columns: serialNumber and response
@ -73,11 +76,14 @@ type DBSource struct {
caKeyHash []byte
}
// NewSourceFromDatabase produces a DBSource representing the binding of a
// given DB schema to a CA key.
func NewSourceFromDatabase(dbMap *gorp.DbMap, caKeyHash []byte) (src *DBSource, err error) {
src = &DBSource{dbMap: dbMap, caKeyHash: caKeyHash}
return
}
// Response is called by the HTTP server to handle a new OCSP request.
func (src *DBSource) Response(req *ocsp.Request) (response []byte, present bool) {
log := blog.GetAuditLogger()

View File

@ -30,7 +30,7 @@ func setupClients(c cmd.Config) (rpc.CertificateAuthorityClient, chan *amqp.Erro
ch := cmd.AmqpChannel(c.AMQP.Server)
closeChan := ch.NotifyClose(make(chan *amqp.Error, 1))
caRPC, err := rpc.NewAmqpRPCCLient("OCSP->CA", c.AMQP.CA.Server, ch)
caRPC, err := rpc.NewAmqpRPCClient("OCSP->CA", c.AMQP.CA.Server, ch)
cmd.FailOnError(err, "Unable to create RPC client")
cac, err := rpc.NewCertificateAuthorityClient(caRPC)
@ -127,10 +127,10 @@ func findStaleResponses(cac rpc.CertificateAuthorityClient, dbMap *gorp.DbMap, o
log.Err(fmt.Sprintf("Could not process OCSP Response for %s: %s", status.Serial, err))
tx.Rollback()
return err
} else {
log.Info(fmt.Sprintf("OCSP %d: %s OK", i, status.Serial))
tx.Commit()
}
log.Info(fmt.Sprintf("OCSP %d: %s OK", i, status.Serial))
tx.Commit()
}
}

View File

@ -227,6 +227,7 @@ func RunUntilSignaled(logger *blog.AuditLogger, server *rpc.AmqpRPCServer, close
logger.Warning("Reconnecting to AMQP...")
}
// ProfileCmd runs forever, sending Go statistics to StatsD.
func ProfileCmd(profileName string, stats statsd.Statter) {
for {
var memoryStats runtime.MemStats
@ -248,6 +249,8 @@ func ProfileCmd(profileName string, stats statsd.Statter) {
}
}
// LoadCert loads a PEM-formatted certificate from the provided path, returning
// it as a byte array, or an error if it couldn't be decoded.
func LoadCert(path string) (cert []byte, err error) {
if path == "" {
err = errors.New("Issuer certificate was not provided in config.")

View File

@ -11,6 +11,7 @@ import (
blog "github.com/letsencrypt/boulder/log"
)
// SimpleHTTPChallenge constructs a random HTTP challenge
func SimpleHTTPChallenge() Challenge {
tls := true
return Challenge{
@ -21,6 +22,7 @@ func SimpleHTTPChallenge() Challenge {
}
}
// DvsniChallenge constructs a random DVSNI challenge
func DvsniChallenge() Challenge {
nonce := make([]byte, 16)
_, err := rand.Read(nonce)
@ -39,6 +41,7 @@ func DvsniChallenge() Challenge {
}
}
// DNSChallenge constructs a random DNS challenge
func DNSChallenge() Challenge {
return Challenge{
Type: ChallengeTypeDNS,

View File

@ -41,16 +41,16 @@ func NewDNSResolver(dialTimeout time.Duration, servers []string) *DNSResolver {
// ExchangeOne performs a single DNS exchange with a randomly chosen server
// out of the server list, returning the response, time, and error (if any)
func (r *DNSResolver) ExchangeOne(m *dns.Msg) (rsp *dns.Msg, rtt time.Duration, err error) {
if len(r.Servers) < 1 {
func (dnsResolver *DNSResolver) ExchangeOne(m *dns.Msg) (rsp *dns.Msg, rtt time.Duration, err error) {
if len(dnsResolver.Servers) < 1 {
err = fmt.Errorf("Not configured with at least one DNS Server")
return
}
// Randomly pick a server
chosenServer := r.Servers[rand.Intn(len(r.Servers))]
chosenServer := dnsResolver.Servers[rand.Intn(len(dnsResolver.Servers))]
return r.DNSClient.Exchange(m, chosenServer)
return dnsResolver.DNSClient.Exchange(m, chosenServer)
}
// LookupDNSSEC sends the provided DNS message to a randomly chosen server (see

View File

@ -60,6 +60,7 @@ func GoodKey(key crypto.PublicKey, maxKeySize int) error {
}
}
// GoodKeyECDSA determines if an ECDSA pubkey meets our requirements
func GoodKeyECDSA(key ecdsa.PublicKey, maxKeySize int) (err error) {
log := blog.GetAuditLogger()
err = fmt.Errorf("ECDSA keys not yet supported")
@ -67,6 +68,7 @@ func GoodKeyECDSA(key ecdsa.PublicKey, maxKeySize int) (err error) {
return
}
// GoodKeyRSA determines if a RSA pubkey meets our requirements
func GoodKeyRSA(key rsa.PublicKey, maxKeySize int) (err error) {
log := blog.GetAuditLogger()
// Baseline Requirements Appendix A

View File

@ -15,7 +15,7 @@ import (
"github.com/letsencrypt/boulder/test"
)
var maxKeySize int = 2048
var maxKeySize = 2048
func TestUnknownKeyType(t *testing.T) {
notAKey := struct{}{}

View File

@ -51,6 +51,7 @@ type WebFrontEnd interface {
Cert(response http.ResponseWriter, request *http.Request)
}
// RegistrationAuthority defines the public interface for the Boulder RA
type RegistrationAuthority interface {
// [WebFrontEnd]
NewRegistration(Registration) (Registration, error)
@ -74,12 +75,14 @@ type RegistrationAuthority interface {
OnValidationUpdate(Authorization) error
}
// ValidationAuthority defines the public interface for the Boulder VA
type ValidationAuthority interface {
// [RegistrationAuthority]
UpdateValidations(Authorization, int) error
CheckCAARecords(AcmeIdentifier) (bool, bool, error)
}
// CertificateAuthority defines the public interface for the Boulder CA
type CertificateAuthority interface {
// [RegistrationAuthority]
IssueCertificate(x509.CertificateRequest, int64, time.Time) (Certificate, error)
@ -87,11 +90,13 @@ type CertificateAuthority interface {
GenerateOCSP(OCSPSigningRequest) ([]byte, error)
}
// PolicyAuthority defines the public interface for the Boulder PA
type PolicyAuthority interface {
WillingToIssue(AcmeIdentifier) error
ChallengesFor(AcmeIdentifier) ([]Challenge, [][]int)
}
// StorageGetter are the Boulder SA's read-only methods
type StorageGetter interface {
GetRegistration(int64) (Registration, error)
GetRegistrationByKey(jose.JsonWebKey) (Registration, error)
@ -102,6 +107,7 @@ type StorageGetter interface {
AlreadyDeniedCSR([]string) (bool, error)
}
// StorageAdder are the Boulder SA's write/update methods
type StorageAdder interface {
NewRegistration(Registration) (Registration, error)
UpdateRegistration(Registration) error

View File

@ -2,6 +2,7 @@
// 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 core
import (
@ -11,8 +12,11 @@ import (
"math/big"
)
// MaxUsed defines the maximum number of Nonces we're willing to hold in
// memory.
const MaxUsed = 65536
// NonceService generates, cancels, and tracks Nonces.
type NonceService struct {
latest int64
earliest int64
@ -21,6 +25,7 @@ type NonceService struct {
maxUsed int
}
// NewNonceService constructs a NonceService with defaults
func NewNonceService() NonceService {
// XXX ignoring possible error due to entropy starvation
key := make([]byte, 16)
@ -44,7 +49,7 @@ func (ns NonceService) encrypt(counter int64) string {
// Generate a nonce with upper 4 bytes zero
// XXX ignoring possible error due to entropy starvation
nonce := make([]byte, 12)
for i := 0; i < 4; i += 1 {
for i := 0; i < 4; i++ {
nonce[i] = 0
}
rand.Read(nonce[4:])
@ -70,7 +75,7 @@ func (ns NonceService) decrypt(nonce string) (int64, error) {
}
n := make([]byte, 12)
for i := 0; i < 4; i += 1 {
for i := 0; i < 4; i++ {
n[i] = 0
}
copy(n[4:], decoded[:8])
@ -85,8 +90,9 @@ func (ns NonceService) decrypt(nonce string) (int64, error) {
return ctr.Int64(), nil
}
// Nonce provides a new Nonce.
func (ns *NonceService) Nonce() string {
ns.latest += 1
ns.latest++
return ns.encrypt(ns.latest)
}
@ -100,6 +106,8 @@ func (ns *NonceService) minUsed() int64 {
return min
}
// Valid determines whether the provided Nonce string is valid, returning
// true if so.
func (ns *NonceService) Valid(nonce string) bool {
c, err := ns.decrypt(nonce)
if err != nil {

View File

@ -18,11 +18,19 @@ import (
"time"
)
// IdentifierType defines the available identification mechanisms for domains
type IdentifierType string
// AcmeStatus defines the state of a given authorization
type AcmeStatus string
// OCSPStatus defines the state of OCSP for a domain
type OCSPStatus string
// Buffer is a variable-length collection of bytes
type Buffer []byte
// These statuses are the states of authorizations
const (
StatusUnknown = AcmeStatus("unknown") // Unknown status; the default
StatusPending = AcmeStatus("pending") // In process; client has next action
@ -32,11 +40,13 @@ const (
StatusRevoked = AcmeStatus("revoked") // Object no longer valid
)
// These status are the states of OCSP
const (
OCSPStatusGood = OCSPStatus("good")
OCSPStatusRevoked = OCSPStatus("revoked")
)
// These types are the available challenges
const (
ChallengeTypeSimpleHTTP = "simpleHttp"
ChallengeTypeDVSNI = "dvsni"
@ -44,6 +54,7 @@ const (
ChallengeTypeRecoveryToken = "recoveryToken"
)
// These types are the available identification mechanisms
const (
IdentifierDNS = IdentifierType("dns")
)
@ -88,7 +99,7 @@ type AcmeIdentifier struct {
Value string `json:"value"` // The identifier itself
}
// An ACME certificate request is just a CSR together with
// CertificateRequest is just a CSR together with
// URIs pointing to authorizations that should collectively
// authorize the certificate being requsted.
//
@ -102,10 +113,11 @@ type CertificateRequest struct {
}
type rawCertificateRequest struct {
CSR JsonBuffer `json:"csr"` // The encoded CSR
CSR JSONBuffer `json:"csr"` // The encoded CSR
Authorizations []AcmeURL `json:"authorizations"` // Authorizations
}
// UnmarshalJSON provides an implementation for decoding CertificateRequest objects.
func (cr *CertificateRequest) UnmarshalJSON(data []byte) error {
var raw rawCertificateRequest
if err := json.Unmarshal(data, &raw); err != nil {
@ -122,6 +134,7 @@ func (cr *CertificateRequest) UnmarshalJSON(data []byte) error {
return nil
}
// MarshalJSON provides an implementation for encoding CertificateRequest objects.
func (cr CertificateRequest) MarshalJSON() ([]byte, error) {
return json.Marshal(rawCertificateRequest{
CSR: cr.CSR.Raw,
@ -150,6 +163,8 @@ type Registration struct {
LockCol int64 `json:"-"`
}
// MergeUpdate copies a subset of information from the input Registration
// into this one.
func (r *Registration) MergeUpdate(input Registration) {
if len(input.Contact) > 0 {
r.Contact = input.Contact
@ -160,6 +175,8 @@ func (r *Registration) MergeUpdate(input Registration) {
}
}
// Challenge is an aggregate of all data needed for any challenges.
//
// Rather than define individual types for different types of
// challenge, we just throw all the elements into one bucket,
// together with the common metadata elements.
@ -190,8 +207,8 @@ type Challenge struct {
Nonce string `json:"nonce,omitempty"`
}
// Check the sanity of a challenge object before issued to the client (completed = false)
// and before validation (completed = true).
// IsSane checks the sanity of a challenge object before issued to the client
// (completed = false) and before validation (completed = true).
func (ch Challenge) IsSane(completed bool) bool {
if ch.Status != StatusPending {
return false
@ -211,8 +228,8 @@ func (ch Challenge) IsSane(completed bool) bool {
return false
}
// Composed path should be a clean filepath (i.e. no double slashes, dot segments, etc)
vaUrl := fmt.Sprintf("/.well-known/acme-challenge/%s", ch.Path)
if vaUrl != filepath.Clean(vaUrl) {
vaURL := fmt.Sprintf("/.well-known/acme-challenge/%s", ch.Path)
if vaURL != filepath.Clean(vaURL) {
return false
}
} else {
@ -286,7 +303,7 @@ func (ch Challenge) IsSane(completed bool) bool {
return true
}
// Merge a client-provide response to a challenge with the issued challenge
// MergeResponse copies a subset of client-provided data to the current Challenge.
// Note: This method does not update the challenge on the left side of the '.'
func (ch Challenge) MergeResponse(resp Challenge) Challenge {
// Only override fields that are supposed to be client-provided
@ -305,11 +322,10 @@ func (ch Challenge) MergeResponse(resp Challenge) Challenge {
return ch
}
// An ACME authorization object represents the authorization
// of an account key holder to act on behalf of a domain. This
// struct is intended to be used both internally and for JSON
// marshaling on the wire. Any fields that should be suppressed
// on the wire (e.g., ID, regID) must be made empty before marshaling.
// Authorization represents the authorization of an account key holder
// to act on behalf of a domain. This struct is intended to be used both
// internally and for JSON marshaling on the wire. Any fields that should be
// suppressed on the wire (e.g., ID, regID) must be made empty before marshaling.
type Authorization struct {
// An identifier for this authorization, unique across
// authorizations and certificates within this instance.
@ -340,28 +356,30 @@ type Authorization struct {
Combinations [][]int `json:"combinations,omitempty" db:"combinations"`
}
// Fields of this type get encoded and decoded JOSE-style, in base64url encoding
// JSONBuffer fields get encoded and decoded JOSE-style, in base64url encoding
// with stripped padding.
type JsonBuffer []byte
type JSONBuffer []byte
// Url-safe base64 encode that strips padding
// URL-safe base64 encode that strips padding
func base64URLEncode(data []byte) string {
var result = base64.URLEncoding.EncodeToString(data)
return strings.TrimRight(result, "=")
}
// Url-safe base64 decoder that adds padding
// URL-safe base64 decoder that adds padding
func base64URLDecode(data string) ([]byte, error) {
var missing = (4 - len(data)%4) % 4
data += strings.Repeat("=", missing)
return base64.URLEncoding.DecodeString(data)
}
func (jb JsonBuffer) MarshalJSON() (result []byte, err error) {
// MarshalJSON encodes a JSONBuffer for transmission.
func (jb JSONBuffer) MarshalJSON() (result []byte, err error) {
return json.Marshal(base64URLEncode(jb))
}
func (jb *JsonBuffer) UnmarshalJSON(data []byte) (err error) {
// UnmarshalJSON decodes a JSONBuffer to an object.
func (jb *JSONBuffer) UnmarshalJSON(data []byte) (err error) {
var str string
err = json.Unmarshal(data, &str)
if err != nil {
@ -383,14 +401,14 @@ type Certificate struct {
Serial string `db:"serial"`
Digest string `db:"digest"`
DER JsonBuffer `db:"der"`
DER JSONBuffer `db:"der"`
Issued time.Time `db:"issued"`
Expires time.Time `db:"expires"`
}
// Certificate.MatchesCSR tests the contents of a generated certificate to
// make sure that the PublicKey, CommonName, and DNSNames match those provided
// in the CSR that was used to generate the certificate. It also checks the
// MatchesCSR tests the contents of a generated certificate to make sure
// that the PublicKey, CommonName, and DNSNames match those provided in
// the CSR that was used to generate the certificate. It also checks the
// following fields for:
// * notAfter is after earliestExpiry
// * notBefore is not more than 24 hours ago
@ -487,9 +505,10 @@ type CertificateStatus struct {
LockCol int64 `json:"-"`
}
// A large table of OCSP responses. This contains all historical OCSP
// responses we've signed, is append-only, and is likely to get quite
// large. We'll probably want administratively truncate it at some point.
// OCSPResponse is a (large) table of OCSP responses. This contains all
// historical OCSP responses we've signed, is append-only, and is likely to get
// quite large.
// It must be administratively truncated outside of Boulder.
type OCSPResponse struct {
ID int `db:"id"`
@ -503,8 +522,9 @@ type OCSPResponse struct {
Response []byte `db:"response"`
}
// A large table of signed CRLs. This contains all historical CRLs
// CRL is a large table of signed CRLs. This contains all historical CRLs
// we've signed, is append-only, and is likely to get quite large.
// It must be administratively truncated outside of Boulder.
type CRL struct {
// serial: Same as certificate serial.
Serial string `db:"serial"`
@ -516,6 +536,7 @@ type CRL struct {
CRL string `db:"crl"`
}
// DeniedCSR is a list of names we deny issuing.
type DeniedCSR struct {
ID int `db:"id"`

View File

@ -13,7 +13,7 @@ import (
"github.com/letsencrypt/boulder/test"
)
func TestRegistrationUupdate(t *testing.T) {
func TestRegistrationUpdate(t *testing.T) {
oldURL, _ := url.Parse("http://old.invalid")
newURL, _ := url.Parse("http://new.invalid")
@ -102,9 +102,9 @@ func TestSanityCheck(t *testing.T) {
test.Assert(t, !chall.IsSane(true), "IsSane should be false")
}
func TestJsonBufferUnmarshal(t *testing.T) {
func TestJSONBufferUnmarshal(t *testing.T) {
testStruct := struct {
Buffer JsonBuffer
Buffer JSONBuffer
}{}
notValidBase64 := []byte(`{"Buffer":"!!!!"}`)

View File

@ -49,12 +49,29 @@ var BuildTime string
// Consequently, you should only use this error when Boulder's internal
// constraints have been violated.
type InternalServerError string
// NotSupportedError indicates a method is not yet supported
type NotSupportedError string
// MalformedRequestError indicates the user data was improper
type MalformedRequestError string
// UnauthorizedError indicates the user did not satisfactorily prove identity
type UnauthorizedError string
// NotFoundError indicates the destination was unknown. Whoa oh oh ohhh.
type NotFoundError string
// SyntaxError indicates the user improperly formatted their data.
type SyntaxError string
// SignatureValidationError indicates that the user's signature could not
// be verified, either through adversarial activity, or misconfiguration of
// the user client.
type SignatureValidationError string
// CertificateIssuanceError indicates the certificate failed to be issued
// for some reason.
type CertificateIssuanceError string
func (e InternalServerError) Error() string { return string(e) }
@ -82,10 +99,12 @@ func unpad(x string) string {
return strings.Replace(x, "=", "", -1)
}
// B64enc encodes a byte array as unpadded, URL-safe Base64
func B64enc(x []byte) string {
return unpad(base64.URLEncoding.EncodeToString(x))
}
// B64dec decodes a byte array from unpadded, URL-safe Base64
func B64dec(x string) ([]byte, error) {
return base64.URLEncoding.DecodeString(pad(x))
}
@ -104,18 +123,23 @@ func RandomString(byteLength int) string {
return B64enc(b)
}
// NewToken produces a random string for Challenges, etc.
func NewToken() string {
return RandomString(32)
}
// Fingerprints
// Fingerprint256 produces an unpadded, URL-safe Base64-encoded SHA256 digest
// of the data.
func Fingerprint256(data []byte) string {
d := sha256.New()
_, _ = d.Write(data) // Never returns an error
return B64enc(d.Sum(nil))
}
// KeyDigest produces a padded, standard Base64-encoded SHA256 digest of a
// provided public key.
func KeyDigest(key crypto.PublicKey) (string, error) {
switch t := key.(type) {
case *jose.JsonWebKey:
@ -134,18 +158,19 @@ func KeyDigest(key crypto.PublicKey) (string, error) {
}
}
// KeyDigestEquals determines whether two public keys have the same digest.
func KeyDigestEquals(j, k crypto.PublicKey) bool {
jDigest, jErr := KeyDigest(j)
kDigest, kErr := KeyDigest(k)
digestJ, errJ := KeyDigest(j)
digestK, errK := KeyDigest(k)
// Keys that don't have a valid digest (due to marshalling problems)
// are never equal. So, e.g. nil keys are not equal.
if jErr != nil || kErr != nil {
if errJ != nil || errK != nil {
return false
}
return jDigest == kDigest
return digestJ == digestK
}
// URLs that automatically marshal/unmarshal to JSON strings
// AcmeURL is a URL that automatically marshal/unmarshal to JSON strings
type AcmeURL url.URL
func (u AcmeURL) String() string {
@ -153,6 +178,7 @@ func (u AcmeURL) String() string {
return url.String()
}
// PathSegments splits an AcmeURL into segments on the '/' characters
func (u AcmeURL) PathSegments() (segments []string) {
segments = strings.Split(u.Path, "/")
if len(segments) > 0 && len(segments[0]) == 0 {
@ -161,11 +187,13 @@ func (u AcmeURL) PathSegments() (segments []string) {
return
}
// MarshalJSON encodes an AcmeURL for transfer
func (u AcmeURL) MarshalJSON() ([]byte, error) {
uu := url.URL(u)
return json.Marshal(uu.String())
}
// UnmarshalJSON decodes an AcmeURL from transfer
func (u *AcmeURL) UnmarshalJSON(data []byte) error {
var str string
if err := json.Unmarshal(data, &str); err != nil {
@ -177,7 +205,9 @@ func (u *AcmeURL) UnmarshalJSON(data []byte) error {
return err
}
// The missing CertificateRequest.Verify() method
// VerifyCSR verifies that a Certificate Signature Request is well-formed.
//
// Note: this is the missing CertificateRequest.Verify() method
func VerifyCSR(csr *x509.CertificateRequest) error {
// Compute the hash of the TBSCertificateRequest
var hashID crypto.Hash
@ -237,18 +267,22 @@ func VerifyCSR(csr *x509.CertificateRequest) error {
if ecdsa.Verify(ecKey, inputHash, sig.R, sig.S) {
return nil
} else {
return errors.New("Invalid ECDSA signature on CSR")
}
return errors.New("Invalid ECDSA signature on CSR")
}
return errors.New("Unsupported CSR signing algorithm")
}
// SerialToString converts a certificate serial number (big.Int) to a String
// consistently.
func SerialToString(serial *big.Int) string {
return fmt.Sprintf("%032x", serial)
}
// StringToSerial converts a string into a certificate serial number (big.Int)
// consistently.
func StringToSerial(serial string) (*big.Int, error) {
var serialNum big.Int
if len(serial) != 32 {
@ -285,6 +319,7 @@ func GetBuildHost() (retID string) {
return
}
// UniqueNames returns the set of all unique names in the input.
func UniqueNames(names []string) (unique []string) {
nameMap := make(map[string]int, len(names))
for _, name := range names {

View File

@ -51,13 +51,13 @@ func TestBuildID(t *testing.T) {
test.AssertEquals(t, "Unspecified", GetBuildID())
}
const JWK_1_JSON = `{
const JWK1JSON = `{
"kty": "RSA",
"n": "vuc785P8lBj3fUxyZchF_uZw6WtbxcorqgTyq-qapF5lrO1U82Tp93rpXlmctj6fyFHBVVB5aXnUHJ7LZeVPod7Wnfl8p5OyhlHQHC8BnzdzCqCMKmWZNX5DtETDId0qzU7dPzh0LP0idt5buU7L9QNaabChw3nnaL47iu_1Di5Wp264p2TwACeedv2hfRDjDlJmaQXuS8Rtv9GnRWyC9JBu7XmGvGDziumnJH7Hyzh3VNu-kSPQD3vuAFgMZS6uUzOztCkT0fpOalZI6hqxtWLvXUMj-crXrn-Maavz8qRhpAyp5kcYk3jiHGgQIi7QSK2JIdRJ8APyX9HlmTN5AQ",
"e": "AAEAAQ"
}`
const JWK_1_DIGEST = `ul04Iq07ulKnnrebv2hv3yxCGgVvoHs8hjq2tVKx3mc=`
const JWK_2_JSON = `{
const JWK1Digest = `ul04Iq07ulKnnrebv2hv3yxCGgVvoHs8hjq2tVKx3mc=`
const JWK2JSON = `{
"kty":"RSA",
"n":"yTsLkI8n4lg9UuSKNRC0UPHsVjNdCYk8rGXIqeb_rRYaEev3D9-kxXY8HrYfGkVt5CiIVJ-n2t50BKT8oBEMuilmypSQqJw0pCgtUm-e6Z0Eg3Ly6DMXFlycyikegiZ0b-rVX7i5OCEZRDkENAYwFNX4G7NNCwEZcH7HUMUmty9dchAqDS9YWzPh_dde1A9oy9JMH07nRGDcOzIh1rCPwc71nwfPPYeeS4tTvkjanjeigOYBFkBLQuv7iBB4LPozsGF1XdoKiIIi-8ye44McdhOTPDcQp3xKxj89aO02pQhBECv61rmbPinvjMG9DYxJmZvjsKF4bN2oy0DxdC1jDw",
"e":"AAEAAQ"
@ -66,13 +66,13 @@ const JWK_2_JSON = `{
func TestKeyDigest(t *testing.T) {
// Test with JWK (value, reference, and direct)
var jwk jose.JsonWebKey
json.Unmarshal([]byte(JWK_1_JSON), &jwk)
json.Unmarshal([]byte(JWK1JSON), &jwk)
digest, err := KeyDigest(jwk)
test.Assert(t, err == nil && digest == JWK_1_DIGEST, "Failed to digest JWK by value")
test.Assert(t, err == nil && digest == JWK1Digest, "Failed to digest JWK by value")
digest, err = KeyDigest(&jwk)
test.Assert(t, err == nil && digest == JWK_1_DIGEST, "Failed to digest JWK by reference")
test.Assert(t, err == nil && digest == JWK1Digest, "Failed to digest JWK by reference")
digest, err = KeyDigest(jwk.Key)
test.Assert(t, err == nil && digest == JWK_1_DIGEST, "Failed to digest bare key")
test.Assert(t, err == nil && digest == JWK1Digest, "Failed to digest bare key")
// Test with unknown key type
digest, err = KeyDigest(struct{}{})
@ -81,8 +81,8 @@ func TestKeyDigest(t *testing.T) {
func TestKeyDigestEquals(t *testing.T) {
var jwk1, jwk2 jose.JsonWebKey
json.Unmarshal([]byte(JWK_1_JSON), &jwk1)
json.Unmarshal([]byte(JWK_2_JSON), &jwk2)
json.Unmarshal([]byte(JWK1JSON), &jwk1)
json.Unmarshal([]byte(JWK2JSON), &jwk2)
test.Assert(t, KeyDigestEquals(jwk1, jwk1), "Key digests for same key should match")
test.Assert(t, !KeyDigestEquals(jwk1, jwk2), "Key digests for different keys should not match")

View File

@ -9,6 +9,7 @@ import (
"net/smtp"
)
// Mailer defines a mail transfer agent to use for sending mail
type Mailer struct {
Server string
Port string
@ -16,6 +17,8 @@ type Mailer struct {
From string
}
// NewMailer constructs a Mailer to represent an account at a particular mail
// transfer agent.
func NewMailer(server, port, username, password string) Mailer {
auth := smtp.PlainAuth("", username, password, server)
return Mailer{
@ -26,6 +29,8 @@ func NewMailer(server, port, username, password string) Mailer {
}
}
// SendMail sends an email to the provided list of recipients. The email body
// is simple text.
func (m *Mailer) SendMail(to []string, msg string) (err error) {
err = smtp.SendMail(m.Server+":"+m.Port, m.Auth, m.From, to, []byte(msg))
return

View File

@ -6,7 +6,6 @@
package policy
import (
"errors"
"net"
"regexp"
"strings"
@ -15,6 +14,7 @@ import (
blog "github.com/letsencrypt/boulder/log"
)
// PolicyAuthorityImpl enforces CA policy decisions.
type PolicyAuthorityImpl struct {
log *blog.AuditLogger
@ -22,6 +22,7 @@ type PolicyAuthorityImpl struct {
Blacklist map[string]bool // A blacklist of denied names
}
// NewPolicyAuthorityImpl constructs a Policy Authority.
func NewPolicyAuthorityImpl() *PolicyAuthorityImpl {
logger := blog.GetAuditLogger()
logger.Notice("Policy Authority Starting")
@ -52,7 +53,7 @@ func isDNSCharacter(ch byte) bool {
// set, then the name is required to not be in the suffix set (i.e., it must
// have at least one label beyond any suffix in the set).
func suffixMatch(labels []string, suffixSet map[string]bool, properSuffix bool) bool {
for i, _ := range labels {
for i := range labels {
if domain := strings.Join(labels[i:], "."); suffixSet[domain] {
// If we match on the whole domain, gate on properSuffix
return !properSuffix || (i > 0)
@ -61,11 +62,28 @@ func suffixMatch(labels []string, suffixSet map[string]bool, properSuffix bool)
return false
}
var InvalidIdentifierError = errors.New("Invalid identifier type")
var SyntaxError = errors.New("Syntax error")
var NonPublicError = errors.New("Name does not end in a public suffix")
var BlacklistedError = errors.New("Name is blacklisted")
// InvalidIdentifierError indicates that we didn't understand the IdentifierType
// provided.
type InvalidIdentifierError struct{}
// SyntaxError indicates that the user input was not well formatted.
type SyntaxError struct{}
// NonPublicError indicates that one or more identifiers were not on the public
// Internet.
type NonPublicError struct{}
// BlacklistedError indicates we have blacklisted one or more of these identifiers.
type BlacklistedError struct{}
func (e InvalidIdentifierError) Error() string { return "Invalid identifier type" }
func (e SyntaxError) Error() string { return "Syntax error" }
func (e NonPublicError) Error() string { return "Name does not end in a public suffix" }
func (e BlacklistedError) Error() string { return "Name is blacklisted" }
// WillingToIssue determines whether the CA is willing to issue for the provided
// identifier.
//
// We place several criteria on identifiers we are willing to issue for:
//
// * MUST self-identify as DNS identifiers
@ -88,59 +106,62 @@ var BlacklistedError = errors.New("Name is blacklisted")
// XXX: We should probably fold everything to lower-case somehow.
func (pa PolicyAuthorityImpl) WillingToIssue(id core.AcmeIdentifier) error {
if id.Type != core.IdentifierDNS {
return InvalidIdentifierError
return InvalidIdentifierError{}
}
domain := id.Value
for _, ch := range []byte(domain) {
if !isDNSCharacter(ch) {
return SyntaxError
return SyntaxError{}
}
}
domain = strings.ToLower(domain)
if len(domain) > 255 {
return SyntaxError
return SyntaxError{}
}
if ip := net.ParseIP(domain); ip != nil {
return SyntaxError
return SyntaxError{}
}
labels := strings.Split(domain, ".")
if len(labels) > maxLabels || len(labels) < 2 {
return SyntaxError
return SyntaxError{}
}
for _, label := range labels {
// DNS defines max label length as 63 characters. Some implementations allow
// more, but we will be conservative.
if len(label) < 1 || len(label) > 63 {
return SyntaxError
return SyntaxError{}
}
if !dnsLabelRegexp.MatchString(label) {
return SyntaxError
return SyntaxError{}
}
if punycodeRegexp.MatchString(label) {
return SyntaxError
return SyntaxError{}
}
}
// Require match to PSL, plus at least one label
if !suffixMatch(labels, pa.PublicSuffixList, true) {
return NonPublicError
return NonPublicError{}
}
// Require no match against blacklist
if suffixMatch(labels, pa.Blacklist, false) {
return BlacklistedError
return BlacklistedError{}
}
return nil
}
// For now, we just issue DVSNI and SimpleHTTP challenges for everything
// ChallengesFor makes a decision of what challenges, and combinations, are
// acceptable for the given identifier.
//
// Note: Current implementation is static, but future versions may not be.
func (pa PolicyAuthorityImpl) ChallengesFor(identifier core.AcmeIdentifier) (challenges []core.Challenge, combinations [][]int) {
challenges = []core.Challenge{
core.SimpleHTTPChallenge(),

View File

@ -92,14 +92,17 @@ func TestWillingToIssue(t *testing.T) {
// Test for invalid identifier type
identifier := core.AcmeIdentifier{Type: "ip", Value: "example.com"}
err := pa.WillingToIssue(identifier)
if err != InvalidIdentifierError {
_, ok := err.(InvalidIdentifierError)
if !ok {
t.Error("Identifier was not correctly forbidden: ", identifier)
}
// Test syntax errors
for _, domain := range shouldBeSyntaxError {
identifier := core.AcmeIdentifier{Type: core.IdentifierDNS, Value: domain}
if err := pa.WillingToIssue(identifier); err != SyntaxError {
err := pa.WillingToIssue(identifier)
_, ok := err.(SyntaxError)
if !ok {
t.Error("Identifier was not correctly forbidden: ", identifier, err)
}
}
@ -107,7 +110,9 @@ func TestWillingToIssue(t *testing.T) {
// Test public suffix matching
for _, domain := range shouldBeNonPublic {
identifier := core.AcmeIdentifier{Type: core.IdentifierDNS, Value: domain}
if err := pa.WillingToIssue(identifier); err != NonPublicError {
err := pa.WillingToIssue(identifier)
_, ok := err.(NonPublicError)
if !ok {
t.Error("Identifier was not correctly forbidden: ", identifier, err)
}
}
@ -115,7 +120,9 @@ func TestWillingToIssue(t *testing.T) {
// Test blacklisting
for _, domain := range shouldBeBlacklisted {
identifier := core.AcmeIdentifier{Type: core.IdentifierDNS, Value: domain}
if err := pa.WillingToIssue(identifier); err != BlacklistedError {
err := pa.WillingToIssue(identifier)
_, ok := err.(BlacklistedError)
if !ok {
t.Error("Identifier was not correctly forbidden: ", identifier, err)
}
}

View File

@ -23,7 +23,9 @@ import (
"github.com/letsencrypt/boulder/policy"
)
// All of the fields in RegistrationAuthorityImpl need to be
// RegistrationAuthorityImpl defines an RA.
//
// NOTE: All of the fields in RegistrationAuthorityImpl need to be
// populated, or there is a risk of panic.
type RegistrationAuthorityImpl struct {
CA core.CertificateAuthority
@ -36,6 +38,7 @@ type RegistrationAuthorityImpl struct {
MaxKeySize int
}
// NewRegistrationAuthorityImpl constructs a new RA object.
func NewRegistrationAuthorityImpl() RegistrationAuthorityImpl {
logger := blog.GetAuditLogger()
logger.Notice("Registration Authority Starting")
@ -103,6 +106,7 @@ type certificateRequestEvent struct {
Error string `json:",omitempty"`
}
// NewRegistration constructs a new Registration from a request.
func (ra *RegistrationAuthorityImpl) NewRegistration(init core.Registration) (reg core.Registration, err error) {
if err = core.GoodKey(init.Key.Key, ra.MaxKeySize); err != nil {
return core.Registration{}, core.MalformedRequestError(fmt.Sprintf("Invalid public key: %s", err.Error()))
@ -129,6 +133,7 @@ func (ra *RegistrationAuthorityImpl) NewRegistration(init core.Registration) (re
return
}
// NewAuthorization constuct a new Authz from a request.
func (ra *RegistrationAuthorityImpl) NewAuthorization(request core.Authorization, regID int64) (authz core.Authorization, err error) {
if regID <= 0 {
err = core.MalformedRequestError(fmt.Sprintf("Invalid registration ID: %d", regID))
@ -202,6 +207,7 @@ func (ra *RegistrationAuthorityImpl) NewAuthorization(request core.Authorization
return authz, err
}
// NewCertificate requests the issuance of a certificate.
func (ra *RegistrationAuthorityImpl) NewCertificate(req core.CertificateRequest, regID int64) (cert core.Certificate, err error) {
emptyCert := core.Certificate{}
var logEventResult string
@ -306,7 +312,7 @@ func (ra *RegistrationAuthorityImpl) NewCertificate(req core.CertificateRequest,
authorizedDomains[authz.Identifier.Value] = true
}
verificationMethods := []string{}
for method, _ := range verificationMethodSet {
for method := range verificationMethodSet {
verificationMethods = append(verificationMethods, method)
}
logEvent.VerificationMethods = verificationMethods
@ -358,6 +364,7 @@ func (ra *RegistrationAuthorityImpl) NewCertificate(req core.CertificateRequest,
return cert, nil
}
// UpdateRegistration updates an existing Registration with new values.
func (ra *RegistrationAuthorityImpl) UpdateRegistration(base core.Registration, update core.Registration) (reg core.Registration, err error) {
base.MergeUpdate(update)
@ -376,6 +383,7 @@ func (ra *RegistrationAuthorityImpl) UpdateRegistration(base core.Registration,
return
}
// UpdateAuthorization updates an authorization with new values.
func (ra *RegistrationAuthorityImpl) UpdateAuthorization(base core.Authorization, challengeIndex int, response core.Challenge) (authz core.Authorization, err error) {
// Copy information over that the client is allowed to supply
authz = base
@ -399,6 +407,7 @@ func (ra *RegistrationAuthorityImpl) UpdateAuthorization(base core.Authorization
return
}
// RevokeCertificate terminates trust in the certificate provided.
func (ra *RegistrationAuthorityImpl) RevokeCertificate(cert x509.Certificate) (err error) {
serialString := core.SerialToString(cert.SerialNumber)
err = ra.CA.RevokeCertificate(serialString, 0)
@ -413,6 +422,7 @@ func (ra *RegistrationAuthorityImpl) RevokeCertificate(cert x509.Certificate) (e
return err
}
// OnValidationUpdate is called when a given Authorization is updated by the VA.
func (ra *RegistrationAuthorityImpl) OnValidationUpdate(authz core.Authorization) error {
// Consider validation successful if any of the combinations
// specified in the authorization has been fulfilled

View File

@ -154,9 +154,9 @@ func initAuthorities(t *testing.T) (core.CertificateAuthority, *DummyValidationA
va := &DummyValidationAuthority{}
// PEM files in certificate-authority_test.go
caKeyPEM, _ := pem.Decode([]byte(CA_KEY_PEM))
caKeyPEM, _ := pem.Decode([]byte(CAkeyPEM))
caKey, _ := x509.ParsePKCS1PrivateKey(caKeyPEM.Bytes)
caCertPEM, _ := pem.Decode([]byte(CA_CERT_PEM))
caCertPEM, _ := pem.Decode([]byte(CAcertPEM))
caCert, _ := x509.ParseCertificate(caCertPEM.Bytes)
basicPolicy := &cfsslConfig.Signing{
Default: &cfsslConfig.SigningProfile{
@ -184,7 +184,7 @@ func initAuthorities(t *testing.T) (core.CertificateAuthority, *DummyValidationA
NotAfter: time.Now().Add(time.Hour * 8761),
MaxKeySize: 4096,
}
csrDER, _ := hex.DecodeString(CSR_HEX)
csrDER, _ := hex.DecodeString(CSRhex)
ExampleCSR, _ = x509.ParseCertificateRequest(csrDER)
// This registration implicitly gets ID = 1
@ -373,8 +373,8 @@ func TestUpdateAuthorization(t *testing.T) {
// Verify that the responses are reflected
test.Assert(t, len(va.Argument.Challenges) > 0, "Authz passed to VA has no challenges")
simpleHttp := va.Argument.Challenges[0]
test.Assert(t, simpleHttp.Path == Response.Path, "simpleHttp changed")
simpleHTTP := va.Argument.Challenges[0]
test.Assert(t, simpleHTTP.Path == Response.Path, "simpleHTTP changed")
t.Log("DONE TestUpdateAuthorization")
}
@ -503,7 +503,7 @@ func TestNewCertificate(t *testing.T) {
t.Log("DONE TestOnValidationUpdate")
}
var CA_KEY_PEM = "-----BEGIN RSA PRIVATE KEY-----\n" +
var CAkeyPEM = "-----BEGIN RSA PRIVATE KEY-----\n" +
"MIIJKQIBAAKCAgEAqmM0dEf/J9MCk2ItzevL0dKJ84lVUtf/vQ7AXFi492vFXc3b\n" +
"PrJz2ybtjO08oVkhRrFGGgLufL2JeOBn5pUZQrp6TqyCLoQ4f/yrmu9tCeG8CtDg\n" +
"xi6Ye9LjvlchEHhUKhAHc8uL+ablHzWxHTeuhnuThrsLFUcJQWb10U27LiXp3XCW\n" +
@ -555,7 +555,7 @@ var CA_KEY_PEM = "-----BEGIN RSA PRIVATE KEY-----\n" +
"huu1W6p9RdxJHgphzmGAvTrOmrDAZeKtubsMS69VZVFjQFa1ZD/VMzWK1X2o\n" +
"-----END RSA PRIVATE KEY-----"
var CA_CERT_PEM = "-----BEGIN CERTIFICATE-----\n" +
var CAcertPEM = "-----BEGIN CERTIFICATE-----\n" +
"MIIFxDCCA6ygAwIBAgIJALe2d/gZHJqAMA0GCSqGSIb3DQEBCwUAMDExCzAJBgNV\n" +
"BAYTAlVTMRAwDgYDVQQKDAdUZXN0IENBMRAwDgYDVQQDDAdUZXN0IENBMB4XDTE1\n" +
"MDIxMzAwMzI0NFoXDTI1MDIxMDAwMzI0NFowMTELMAkGA1UEBhMCVVMxEDAOBgNV\n" +
@ -594,7 +594,7 @@ var CA_CERT_PEM = "-----BEGIN CERTIFICATE-----\n" +
// * CN = not-example.com
// * DNSNames = not-example.com, www.not-example.com
/*
var CSR_HEX = "3082028c30820174020100301a311830160603550403130f" +
var CSRhex = "3082028c30820174020100301a311830160603550403130f" +
"6e6f742d6578616d706c652e636f6d30820122300d06092a" +
"864886f70d01010105000382010f003082010a0282010100" +
"aac67dd1e11fae980048b0ac91be005f21d9df8bb38461cc" +
@ -624,7 +624,7 @@ var CSR_HEX = "3082028c30820174020100301a311830160603550403130f" +
"f277b6d23fa24f9b"
*/
var CSR_HEX = "308202ae308201960201003027310b300906035504061302" +
var CSRhex = "308202ae308201960201003027310b300906035504061302" +
"5553311830160603550403130f6e6f742d6578616d706c65" +
"2e636f6d30820122300d06092a864886f70d010101050003" +
"82010f003082010a0282010100a4f507b52ca2766e2cea7b" +

View File

@ -107,7 +107,7 @@ func amqpSubscribe(ch *amqp.Channel, name string, log *blog.AuditLogger) (msgs <
return
}
// An AMQP-RPC Server listens on a specified queue within an AMQP channel.
// AmqpRPCServer listens on a specified queue within an AMQP channel.
// When messages arrive on that queue, it dispatches them based on type,
// and returns the response to the ReplyTo queue.
//
@ -120,7 +120,7 @@ type AmqpRPCServer struct {
dispatchTable map[string]func([]byte) ([]byte, error)
}
// Create a new AMQP-RPC server on the given queue and channel.
// NewAmqpRPCServer creates a new RPC server on the given queue and channel.
// Note that you must call Start() to actually start the server
// listening for requests.
func NewAmqpRPCServer(serverQueue string, channel *amqp.Channel) *AmqpRPCServer {
@ -133,11 +133,12 @@ func NewAmqpRPCServer(serverQueue string, channel *amqp.Channel) *AmqpRPCServer
}
}
// Handle registers a function to handle a particular method.
func (rpc *AmqpRPCServer) Handle(method string, handler func([]byte) ([]byte, error)) {
rpc.dispatchTable[method] = handler
}
// A JSON wrapper for error as it cannot be un/marshalled
// RPCError is a JSON wrapper for error as it cannot be un/marshalled
// due to type interface{}.
type RPCError struct {
Value string `json:"value"`
@ -198,12 +199,14 @@ func unwrapError(rpcError RPCError) (err error) {
return
}
// RPCResponse is a stuct for wire-representation of response messages
// used by DispatchSync
type RPCResponse struct {
ReturnVal []byte `json:"returnVal,omitempty"`
Error RPCError `json:"error,omitempty"`
}
// Starts the AMQP-RPC server running in a separate thread.
// Start starts the AMQP-RPC server running in a separate thread.
// There is currently no Stop() method.
func (rpc *AmqpRPCServer) Start() (err error) {
msgs, err := amqpSubscribe(rpc.channel, rpc.serverQueue, rpc.log)
@ -246,8 +249,8 @@ func (rpc *AmqpRPCServer) Start() (err error) {
return
}
// An AMQP-RPC client sends requests to a specific server queue,
// and uses a dedicated response queue for responses.
// AmqpRPCCLient is an AMQP-RPC client that sends requests to a specific server
// queue, and uses a dedicated response queue for responses.
//
// To implement specific functionality, using code uses the Dispatch()
// method to send a method name and body, and get back a response. So
@ -273,7 +276,8 @@ type AmqpRPCCLient struct {
log *blog.AuditLogger
}
func NewAmqpRPCCLient(clientQueuePrefix, serverQueue string, channel *amqp.Channel) (rpc *AmqpRPCCLient, err error) {
// NewAmqpRPCClient constructs an RPC client using AMQP
func NewAmqpRPCClient(clientQueuePrefix, serverQueue string, channel *amqp.Channel) (rpc *AmqpRPCCLient, err error) {
hostname, err := os.Hostname()
if err != nil {
return nil, err
@ -316,10 +320,15 @@ func NewAmqpRPCCLient(clientQueuePrefix, serverQueue string, channel *amqp.Chann
return rpc, err
}
// SetTimeout configures the maximum time DispatchSync will wait for a response
// before returning an error.
func (rpc *AmqpRPCCLient) SetTimeout(ttl time.Duration) {
rpc.timeout = ttl
}
// Dispatch sends a body to the destination, and returns a response channel
// that can be used to monitor for responses, or discarded for one-shot
// actions.
func (rpc *AmqpRPCCLient) Dispatch(method string, body []byte) chan []byte {
// Create a channel on which to direct the response
// At least in some cases, it's important that this channel
@ -345,6 +354,7 @@ func (rpc *AmqpRPCCLient) Dispatch(method string, body []byte) chan []byte {
return responseChan
}
// DispatchSync sends a body to the destination, and blocks waiting on a response.
func (rpc *AmqpRPCCLient) DispatchSync(method string, body []byte) (response []byte, err error) {
select {
case jsonResponse := <-rpc.Dispatch(method, body):
@ -365,8 +375,3 @@ func (rpc *AmqpRPCCLient) DispatchSync(method string, body []byte) (response []b
return
}
}
func (rpc *AmqpRPCCLient) SyncDispatchWithTimeout(method string, body []byte, ttl time.Duration) (response []byte, err error) {
err = errors.New("Not Implemented")
return
}

View File

@ -14,7 +14,6 @@ type RPCClient interface {
SetTimeout(time.Duration)
Dispatch(string, []byte) chan []byte
DispatchSync(string, []byte) ([]byte, error)
SyncDispatchWithTimeout(string, []byte, time.Duration) ([]byte, error)
}
// RPCServer describes the functions an RPC Server performs

View File

@ -32,6 +32,7 @@ import (
// The WebFrontEnd role does not expose any functionality over RPC,
// so it doesn't need wrappers.
// These strings are used by the RPC layer to identify function points.
const (
MethodNewRegistration = "NewRegistration" // RA, SA
MethodNewAuthorization = "NewAuthorization" // RA
@ -144,6 +145,7 @@ func errorCondition(method string, err error, obj interface{}) {
log.Audit(fmt.Sprintf("Error condition. method: %s err: %s data: %+v", method, err, obj))
}
// NewRegistrationAuthorityServer constructs an RPC server
func NewRegistrationAuthorityServer(rpc RPCServer, impl core.RegistrationAuthority) error {
log := blog.GetAuditLogger()
@ -289,15 +291,18 @@ func NewRegistrationAuthorityServer(rpc RPCServer, impl core.RegistrationAuthori
return nil
}
// RegistrationAuthorityClient represents an RA RPC client
type RegistrationAuthorityClient struct {
rpc RPCClient
}
// NewRegistrationAuthorityClient constructs an RPC client
func NewRegistrationAuthorityClient(client RPCClient) (rac RegistrationAuthorityClient, err error) {
rac = RegistrationAuthorityClient{rpc: client}
return
}
// NewRegistration sends a New Registration request
func (rac RegistrationAuthorityClient) NewRegistration(reg core.Registration) (newReg core.Registration, err error) {
data, err := json.Marshal(registrationRequest{reg})
if err != nil {
@ -313,6 +318,7 @@ func (rac RegistrationAuthorityClient) NewRegistration(reg core.Registration) (n
return
}
// NewAuthorization sends a New Authorization request
func (rac RegistrationAuthorityClient) NewAuthorization(authz core.Authorization, regID int64) (newAuthz core.Authorization, err error) {
data, err := json.Marshal(authorizationRequest{authz, regID})
if err != nil {
@ -328,6 +334,7 @@ func (rac RegistrationAuthorityClient) NewAuthorization(authz core.Authorization
return
}
// NewCertificate sends a New Certificate request
func (rac RegistrationAuthorityClient) NewCertificate(cr core.CertificateRequest, regID int64) (cert core.Certificate, err error) {
data, err := json.Marshal(certificateRequest{cr, regID})
if err != nil {
@ -343,6 +350,7 @@ func (rac RegistrationAuthorityClient) NewCertificate(cr core.CertificateRequest
return
}
// UpdateRegistration sends an Update Registration request
func (rac RegistrationAuthorityClient) UpdateRegistration(base core.Registration, update core.Registration) (newReg core.Registration, err error) {
var urReq updateRegistrationRequest
urReq.Base = base
@ -362,6 +370,7 @@ func (rac RegistrationAuthorityClient) UpdateRegistration(base core.Registration
return
}
// UpdateAuthorization sends an Update Authorization request
func (rac RegistrationAuthorityClient) UpdateAuthorization(authz core.Authorization, index int, response core.Challenge) (newAuthz core.Authorization, err error) {
var uaReq updateAuthorizationRequest
uaReq.Authz = authz
@ -382,11 +391,13 @@ func (rac RegistrationAuthorityClient) UpdateAuthorization(authz core.Authorizat
return
}
// RevokeCertificate sends a Revoke Certificate request
func (rac RegistrationAuthorityClient) RevokeCertificate(cert x509.Certificate) (err error) {
_, err = rac.rpc.DispatchSync(MethodRevokeCertificate, cert.Raw)
return
}
// OnValidationUpdate senda a notice that a validation has updated
func (rac RegistrationAuthorityClient) OnValidationUpdate(authz core.Authorization) (err error) {
data, err := json.Marshal(authz)
if err != nil {
@ -397,6 +408,8 @@ func (rac RegistrationAuthorityClient) OnValidationUpdate(authz core.Authorizati
return
}
// NewValidationAuthorityServer constructs an RPC server
//
// ValidationAuthorityClient / Server
// -> UpdateValidations
func NewValidationAuthorityServer(rpc RPCServer, impl core.ValidationAuthority) (err error) {
@ -441,15 +454,18 @@ func NewValidationAuthorityServer(rpc RPCServer, impl core.ValidationAuthority)
return nil
}
// ValidationAuthorityClient represents an RPC client for the VA
type ValidationAuthorityClient struct {
rpc RPCClient
}
// NewValidationAuthorityClient constructs an RPC client
func NewValidationAuthorityClient(client RPCClient) (vac ValidationAuthorityClient, err error) {
vac = ValidationAuthorityClient{rpc: client}
return
}
// UpdateValidations sends an Update Validations request
func (vac ValidationAuthorityClient) UpdateValidations(authz core.Authorization, index int) error {
var vaReq validationRequest
vaReq.Authz = authz
@ -463,6 +479,7 @@ func (vac ValidationAuthorityClient) UpdateValidations(authz core.Authorization,
return nil
}
// CheckCAARecords sends a request to check CAA records
func (vac ValidationAuthorityClient) CheckCAARecords(ident core.AcmeIdentifier) (present bool, valid bool, err error) {
var caaReq caaRequest
caaReq.Ident = ident
@ -487,6 +504,8 @@ func (vac ValidationAuthorityClient) CheckCAARecords(ident core.AcmeIdentifier)
return
}
// NewCertificateAuthorityServer constructs an RPC server
//
// CertificateAuthorityClient / Server
// -> IssueCertificate
func NewCertificateAuthorityServer(rpc RPCServer, impl core.CertificateAuthority) (err error) {
@ -554,15 +573,18 @@ func NewCertificateAuthorityServer(rpc RPCServer, impl core.CertificateAuthority
return nil
}
// CertificateAuthorityClient is a client to communicate with the CA.
type CertificateAuthorityClient struct {
rpc RPCClient
}
// NewCertificateAuthorityClient constructs an RPC client
func NewCertificateAuthorityClient(client RPCClient) (cac CertificateAuthorityClient, err error) {
cac = CertificateAuthorityClient{rpc: client}
return
}
// IssueCertificate sends a request to issue a certificate
func (cac CertificateAuthorityClient) IssueCertificate(csr x509.CertificateRequest, regID int64, earliestExpiry time.Time) (cert core.Certificate, err error) {
var icReq issueCertificateRequest
icReq.Bytes = csr.Raw
@ -581,6 +603,7 @@ func (cac CertificateAuthorityClient) IssueCertificate(csr x509.CertificateReque
return
}
// RevokeCertificate sends a request to revoke a certificate
func (cac CertificateAuthorityClient) RevokeCertificate(serial string, reasonCode int) (err error) {
var revokeReq revokeCertificateRequest
revokeReq.Serial = serial
@ -597,6 +620,7 @@ func (cac CertificateAuthorityClient) RevokeCertificate(serial string, reasonCod
return
}
// GenerateOCSP sends a request to generate an OCSP response
func (cac CertificateAuthorityClient) GenerateOCSP(signRequest core.OCSPSigningRequest) (resp []byte, err error) {
data, err := json.Marshal(signRequest)
if err != nil {
@ -616,6 +640,7 @@ func (cac CertificateAuthorityClient) GenerateOCSP(signRequest core.OCSPSigningR
return
}
// NewStorageAuthorityServer constructs an RPC server
func NewStorageAuthorityServer(rpc RPCServer, impl core.StorageAuthority) error {
rpc.Handle(MethodUpdateRegistration, func(req []byte) (response []byte, err error) {
var reg core.Registration
@ -874,15 +899,18 @@ func NewStorageAuthorityServer(rpc RPCServer, impl core.StorageAuthority) error
return nil
}
// StorageAuthorityClient is a client to communicate with the Storage Authority
type StorageAuthorityClient struct {
rpc RPCClient
}
// NewStorageAuthorityClient constructs an RPC client
func NewStorageAuthorityClient(client RPCClient) (sac StorageAuthorityClient, err error) {
sac = StorageAuthorityClient{rpc: client}
return
}
// GetRegistration sends a request to get a registration by ID
func (cac StorageAuthorityClient) GetRegistration(id int64) (reg core.Registration, err error) {
var grReq getRegistrationRequest
grReq.ID = id
@ -901,6 +929,7 @@ func (cac StorageAuthorityClient) GetRegistration(id int64) (reg core.Registrati
return
}
// GetRegistrationByKey sends a request to get a registration by JWK
func (cac StorageAuthorityClient) GetRegistrationByKey(key jose.JsonWebKey) (reg core.Registration, err error) {
jsonKey, err := key.MarshalJSON()
if err != nil {
@ -916,6 +945,7 @@ func (cac StorageAuthorityClient) GetRegistrationByKey(key jose.JsonWebKey) (reg
return
}
// GetAuthorization sends a request to get an Authorization by ID
func (cac StorageAuthorityClient) GetAuthorization(id string) (authz core.Authorization, err error) {
jsonAuthz, err := cac.rpc.DispatchSync(MethodGetAuthorization, []byte(id))
if err != nil {
@ -926,6 +956,7 @@ func (cac StorageAuthorityClient) GetAuthorization(id string) (authz core.Author
return
}
// GetCertificate sends a request to get a Certificate by ID
func (cac StorageAuthorityClient) GetCertificate(id string) (cert core.Certificate, err error) {
jsonCert, err := cac.rpc.DispatchSync(MethodGetCertificate, []byte(id))
if err != nil {
@ -936,6 +967,8 @@ func (cac StorageAuthorityClient) GetCertificate(id string) (cert core.Certifica
return
}
// GetCertificateByShortSerial sends a request to search for a certificate by
// the predictable portion of its serial number.
func (cac StorageAuthorityClient) GetCertificateByShortSerial(id string) (cert core.Certificate, err error) {
jsonCert, err := cac.rpc.DispatchSync(MethodGetCertificateByShortSerial, []byte(id))
if err != nil {
@ -946,6 +979,8 @@ func (cac StorageAuthorityClient) GetCertificateByShortSerial(id string) (cert c
return
}
// GetCertificateStatus sends a request to obtain the current status of a
// certificate by ID
func (cac StorageAuthorityClient) GetCertificateStatus(id string) (status core.CertificateStatus, err error) {
jsonStatus, err := cac.rpc.DispatchSync(MethodGetCertificateStatus, []byte(id))
if err != nil {
@ -956,6 +991,7 @@ func (cac StorageAuthorityClient) GetCertificateStatus(id string) (status core.C
return
}
// MarkCertificateRevoked sends a request to mark a certificate as revoked
func (cac StorageAuthorityClient) MarkCertificateRevoked(serial string, ocspResponse []byte, reasonCode int) (err error) {
var mcrReq markCertificateRevokedRequest
@ -972,6 +1008,7 @@ func (cac StorageAuthorityClient) MarkCertificateRevoked(serial string, ocspResp
return
}
// UpdateOCSP sends a request to store an updated OCSP response
func (cac StorageAuthorityClient) UpdateOCSP(serial string, ocspResponse []byte) (err error) {
var updateOCSPReq updateOCSPRequest
@ -987,6 +1024,7 @@ func (cac StorageAuthorityClient) UpdateOCSP(serial string, ocspResponse []byte)
return
}
// UpdateRegistration sends a request to store an updated registration
func (cac StorageAuthorityClient) UpdateRegistration(reg core.Registration) (err error) {
jsonReg, err := json.Marshal(reg)
if err != nil {
@ -997,6 +1035,7 @@ func (cac StorageAuthorityClient) UpdateRegistration(reg core.Registration) (err
return
}
// NewRegistration sends a request to store a new registration
func (cac StorageAuthorityClient) NewRegistration(reg core.Registration) (output core.Registration, err error) {
jsonReg, err := json.Marshal(reg)
if err != nil {
@ -1015,6 +1054,7 @@ func (cac StorageAuthorityClient) NewRegistration(reg core.Registration) (output
return output, nil
}
// NewPendingAuthorization sends a request to store a pending authorization
func (cac StorageAuthorityClient) NewPendingAuthorization(authz core.Authorization) (output core.Authorization, err error) {
jsonAuthz, err := json.Marshal(authz)
if err != nil {
@ -1032,6 +1072,8 @@ func (cac StorageAuthorityClient) NewPendingAuthorization(authz core.Authorizati
return
}
// UpdatePendingAuthorization sends a request to update the data in a pending
// authorization
func (cac StorageAuthorityClient) UpdatePendingAuthorization(authz core.Authorization) (err error) {
jsonAuthz, err := json.Marshal(authz)
if err != nil {
@ -1042,6 +1084,8 @@ func (cac StorageAuthorityClient) UpdatePendingAuthorization(authz core.Authoriz
return
}
// FinalizeAuthorization sends a request to finalize an authorization (convert
// from pending)
func (cac StorageAuthorityClient) FinalizeAuthorization(authz core.Authorization) (err error) {
jsonAuthz, err := json.Marshal(authz)
if err != nil {
@ -1052,6 +1096,7 @@ func (cac StorageAuthorityClient) FinalizeAuthorization(authz core.Authorization
return
}
// AddCertificate sends a request to record the issuance of a certificate
func (cac StorageAuthorityClient) AddCertificate(cert []byte, regID int64) (id string, err error) {
var acReq addCertificateRequest
acReq.Bytes = cert
@ -1069,6 +1114,7 @@ func (cac StorageAuthorityClient) AddCertificate(cert []byte, regID int64) (id s
return
}
// AlreadyDeniedCSR sends a request to search for denied names
func (cac StorageAuthorityClient) AlreadyDeniedCSR(names []string) (exists bool, err error) {
var adcReq alreadyDeniedCSRReq
adcReq.Names = names

View File

@ -16,7 +16,7 @@ import (
"github.com/letsencrypt/boulder/test"
)
const JWK_1_JSON = `{
const JWK1JSON = `{
"kty": "RSA",
"n": "vuc785P8lBj3fUxyZchF_uZw6WtbxcorqgTyq-qapF5lrO1U82Tp93rpXlmctj6fyFHBVVB5aXnUHJ7LZeVPod7Wnfl8p5OyhlHQHC8BnzdzCqCMKmWZNX5DtETDId0qzU7dPzh0LP0idt5buU7L9QNaabChw3nnaL47iu_1Di5Wp264p2TwACeedv2hfRDjDlJmaQXuS8Rtv9GnRWyC9JBu7XmGvGDziumnJH7Hyzh3VNu-kSPQD3vuAFgMZS6uUzOztCkT0fpOalZI6hqxtWLvXUMj-crXrn-Maavz8qRhpAyp5kcYk3jiHGgQIi7QSK2JIdRJ8APyX9HlmTN5AQ",
"e": "AAEAAQ"
@ -59,12 +59,6 @@ func (rpc *MockRPCClient) DispatchSync(method string, body []byte) (response []b
return
}
func (rpc *MockRPCClient) SyncDispatchWithTimeout(method string, body []byte, ttl time.Duration) (response []byte, err error) {
rpc.LastMethod = method
rpc.LastBody = body
return body, nil
}
func TestRANewRegistration(t *testing.T) {
mock := &MockRPCClient{}
client, err := NewRegistrationAuthorityClient(mock)
@ -72,7 +66,7 @@ func TestRANewRegistration(t *testing.T) {
test.AssertNotNil(t, client, "Client construction")
var jwk jose.JsonWebKey
json.Unmarshal([]byte(JWK_1_JSON), &jwk)
json.Unmarshal([]byte(JWK1JSON), &jwk)
reg := core.Registration{
ID: 1,

View File

@ -19,7 +19,7 @@ import (
blog "github.com/letsencrypt/boulder/log"
)
var dialectMap map[string]interface{} = map[string]interface{}{
var dialectMap = map[string]interface{}{
"sqlite3": gorp.SqliteDialect{},
"mysql": gorp.MySQLDialect{Engine: "InnoDB", Encoding: "UTF8"},
"postgres": gorp.PostgresDialect{},

View File

@ -22,6 +22,7 @@ import (
blog "github.com/letsencrypt/boulder/log"
)
// SQLStorageAuthority defines a Storage Authority
type SQLStorageAuthority struct {
dbMap *gorp.DbMap
bucket map[string]interface{} // XXX included only for backward compat
@ -99,6 +100,7 @@ func existingRegistration(tx *gorp.Transaction, id int64) bool {
return count > 0
}
// GetRegistration obtains a Registration by ID
func (ssa *SQLStorageAuthority) GetRegistration(id int64) (reg core.Registration, err error) {
regObj, err := ssa.dbMap.Get(core.Registration{}, id)
if err != nil {
@ -117,16 +119,18 @@ func (ssa *SQLStorageAuthority) GetRegistration(id int64) (reg core.Registration
return
}
// GetRegistrationByKey obtains a Registration by JWK
func (ssa *SQLStorageAuthority) GetRegistrationByKey(key jose.JsonWebKey) (reg core.Registration, err error) {
keyJson, err := json.Marshal(key)
keyJSON, err := json.Marshal(key)
if err != nil {
return
}
err = ssa.dbMap.SelectOne(&reg, "SELECT * FROM registrations WHERE jwk = :key", map[string]interface{}{"key": string(keyJson)})
err = ssa.dbMap.SelectOne(&reg, "SELECT * FROM registrations WHERE jwk = :key", map[string]interface{}{"key": string(keyJSON)})
return
}
// GetAuthorization obtains an Authorization by ID
func (ssa *SQLStorageAuthority) GetAuthorization(id string) (authz core.Authorization, err error) {
tx, err := ssa.dbMap.Begin()
if err != nil {
@ -220,6 +224,7 @@ func (ssa *SQLStorageAuthority) GetCertificateStatus(serial string) (status core
return
}
// NewRegistration stores a new Registration
func (ssa *SQLStorageAuthority) NewRegistration(reg core.Registration) (core.Registration, error) {
tx, err := ssa.dbMap.Begin()
if err != nil {
@ -240,8 +245,8 @@ func (ssa *SQLStorageAuthority) NewRegistration(reg core.Registration) (core.Reg
func (ssa *SQLStorageAuthority) UpdateOCSP(serial string, ocspResponse []byte) (err error) {
status, err := ssa.GetCertificateStatus(serial)
if err != nil {
return errors.New(fmt.Sprintf(
"Unable to update OCSP for certificate %s: cert status not found.", serial))
return fmt.Errorf(
"Unable to update OCSP for certificate %s: cert status not found.", serial)
}
tx, err := ssa.dbMap.Begin()
@ -275,13 +280,13 @@ func (ssa *SQLStorageAuthority) UpdateOCSP(serial string, ocspResponse []byte) (
// with a timestamp and a reason.
func (ssa *SQLStorageAuthority) MarkCertificateRevoked(serial string, ocspResponse []byte, reasonCode int) (err error) {
if _, err = ssa.GetCertificate(serial); err != nil {
return errors.New(fmt.Sprintf(
"Unable to mark certificate %s revoked: cert not found.", serial))
return fmt.Errorf(
"Unable to mark certificate %s revoked: cert not found.", serial)
}
if _, err = ssa.GetCertificateStatus(serial); err != nil {
return errors.New(fmt.Sprintf(
"Unable to mark certificate %s revoked: cert status not found.", serial))
return fmt.Errorf(
"Unable to mark certificate %s revoked: cert status not found.", serial)
}
tx, err := ssa.dbMap.Begin()
@ -321,6 +326,7 @@ func (ssa *SQLStorageAuthority) MarkCertificateRevoked(serial string, ocspRespon
return
}
// UpdateRegistration stores an updated Registration
func (ssa *SQLStorageAuthority) UpdateRegistration(reg core.Registration) (err error) {
tx, err := ssa.dbMap.Begin()
if err != nil {
@ -343,6 +349,7 @@ func (ssa *SQLStorageAuthority) UpdateRegistration(reg core.Registration) (err e
return
}
// NewPendingAuthorization stores a new Pending Authorization
func (ssa *SQLStorageAuthority) NewPendingAuthorization(authz core.Authorization) (output core.Authorization, err error) {
tx, err := ssa.dbMap.Begin()
if err != nil {
@ -356,18 +363,19 @@ func (ssa *SQLStorageAuthority) NewPendingAuthorization(authz core.Authorization
}
// Insert a stub row in pending
pending_authz := pendingauthzModel{Authorization: authz}
err = tx.Insert(&pending_authz)
pendingAuthz := pendingauthzModel{Authorization: authz}
err = tx.Insert(&pendingAuthz)
if err != nil {
tx.Rollback()
return
}
err = tx.Commit()
output = pending_authz.Authorization
output = pendingAuthz.Authorization
return
}
// UpdatePendingAuthorization updates a Pending Authorization
func (ssa *SQLStorageAuthority) UpdatePendingAuthorization(authz core.Authorization) (err error) {
tx, err := ssa.dbMap.Begin()
if err != nil {
@ -409,6 +417,7 @@ func (ssa *SQLStorageAuthority) UpdatePendingAuthorization(authz core.Authorizat
return
}
// FinalizeAuthorization converts a Pending Authorization to a final one
func (ssa *SQLStorageAuthority) FinalizeAuthorization(authz core.Authorization) (err error) {
tx, err := ssa.dbMap.Begin()
if err != nil {
@ -463,6 +472,7 @@ func (ssa *SQLStorageAuthority) FinalizeAuthorization(authz core.Authorization)
return
}
// AddCertificate stores an issued certificate.
func (ssa *SQLStorageAuthority) AddCertificate(certDER []byte, regID int64) (digest string, err error) {
var parsedCertificate *x509.Certificate
parsedCertificate, err = x509.ParseCertificate(certDER)
@ -512,6 +522,7 @@ func (ssa *SQLStorageAuthority) AddCertificate(certDER []byte, regID int64) (dig
return
}
// AlreadyDeniedCSR queries to find if the name list has already been denied.
func (ssa *SQLStorageAuthority) AlreadyDeniedCSR(names []string) (already bool, err error) {
sort.Strings(names)

View File

@ -34,7 +34,7 @@ func initSA(t *testing.T) *SQLStorageAuthority {
return sa
}
var theKey string = `{
var theKey = `{
"kty": "RSA",
"n": "n4EPtAOCc9AlkeQHPzHStgAbgs7bTZLwUBZdR8_KuKPEHLd4rHVTeT-O-XV2jRojdNhxJWTDvNd7nqQ0VEiZQHz_AJmSCpMaJMRBSFKrKb2wqVwGU_NsYOYL-QtiWN2lbzcEe6XC0dApr5ydQLrHqkHHig3RBordaZ6Aj-oBHqFEHYpPe7Tpe-OfVfHd1E6cS6M1FZcD1NNLYD5lFHpPI9bTwJlsde3uhGqC0ZCuEHg8lhzwOHrtIQbS0FVbb9k3-tVTU4fg_3L_vniUFAKwuCLqKnS2BYwdq_mzSnbLY7h_qixoR7jig3__kRhuaxwUkRz5iaiQkqgc5gHdrNP5zw",
"e": "AQAB"

View File

@ -38,7 +38,7 @@ func (tc BoulderTypeConverter) ToDb(val interface{}) (interface{}, error) {
return string(t), nil
case core.OCSPStatus:
return string(t), nil
case core.JsonBuffer:
case core.JSONBuffer:
return []byte(t), nil
default:
return val, nil
@ -48,7 +48,7 @@ func (tc BoulderTypeConverter) ToDb(val interface{}) (interface{}, error) {
// FromDb converts a DB representation back into a Boulder object.
func (tc BoulderTypeConverter) FromDb(target interface{}) (gorp.CustomScanner, bool) {
switch target.(type) {
case *core.AcmeIdentifier, *[]core.Challenge, *[]core.AcmeURL, *[][]int, core.JsonBuffer:
case *core.AcmeIdentifier, *[]core.Challenge, *[]core.AcmeURL, *[][]int, core.JSONBuffer:
binder := func(holder, target interface{}) error {
s, ok := holder.(*string)
if !ok {

View File

@ -15,7 +15,7 @@ import (
jose "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/square/go-jose"
)
const JWK_1_JSON = `{
const JWK1JSON = `{
"kty": "RSA",
"n": "vuc785P8lBj3fUxyZchF_uZw6WtbxcorqgTyq-qapF5lrO1U82Tp93rpXlmctj6fyFHBVVB5aXnUHJ7LZeVPod7Wnfl8p5OyhlHQHC8BnzdzCqCMKmWZNX5DtETDId0qzU7dPzh0LP0idt5buU7L9QNaabChw3nnaL47iu_1Di5Wp264p2TwACeedv2hfRDjDlJmaQXuS8Rtv9GnRWyC9JBu7XmGvGDziumnJH7Hyzh3VNu-kSPQD3vuAFgMZS6uUzOztCkT0fpOalZI6hqxtWLvXUMj-crXrn-Maavz8qRhpAyp5kcYk3jiHGgQIi7QSK2JIdRJ8APyX9HlmTN5AQ",
"e": "AAEAAQ"
@ -46,7 +46,7 @@ func TestJsonWebKey(t *testing.T) {
tc := BoulderTypeConverter{}
var jwk, out jose.JsonWebKey
json.Unmarshal([]byte(JWK_1_JSON), &jwk)
json.Unmarshal([]byte(JWK1JSON), &jwk)
marshaledI, err := tc.ToDb(jwk)
test.AssertNotError(t, err, "Could not ToDb")

View File

@ -8,15 +8,18 @@ package test
import (
"database/sql"
// Load SQLite3 for test purposes
_ "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/mattn/go-sqlite3"
gorp "github.com/letsencrypt/boulder/Godeps/_workspace/src/gopkg.in/gorp.v1"
)
// MockCADatabase is a mock
type MockCADatabase struct {
db *gorp.DbMap
count int64
}
// NewMockCertificateAuthorityDatabase is a mock
func NewMockCertificateAuthorityDatabase() (mock *MockCADatabase, err error) {
db, err := sql.Open("sqlite3", ":memory:")
dbmap := &gorp.DbMap{Db: db, Dialect: gorp.SqliteDialect{}}
@ -24,15 +27,18 @@ func NewMockCertificateAuthorityDatabase() (mock *MockCADatabase, err error) {
return mock, err
}
// Begin is a mock
func (cadb *MockCADatabase) Begin() (*gorp.Transaction, error) {
return cadb.db.Begin()
}
// IncrementAndGetSerial is a mock
func (cadb *MockCADatabase) IncrementAndGetSerial(*gorp.Transaction) (int64, error) {
cadb.count = cadb.count + 1
return cadb.count, nil
}
// CreateTablesIfNotExists is a mock
func (cadb *MockCADatabase) CreateTablesIfNotExists() error {
return nil
}

View File

@ -26,42 +26,50 @@ func caller() string {
return fmt.Sprintf("%s:%d:", filename, line)
}
// Assert a boolean
func Assert(t *testing.T, result bool, message string) {
if !result {
t.Error(caller(), message)
}
}
// AssertNotNil checks an object to be non-nil
func AssertNotNil(t *testing.T, obj interface{}, message string) {
if obj == nil {
t.Error(caller(), message)
}
}
// AssertNotError checks that err is nil
func AssertNotError(t *testing.T, err error, message string) {
if err != nil {
t.Error(caller(), message, ":", err)
}
}
// AssertError checks that err is non-nil
func AssertError(t *testing.T, err error, message string) {
if err == nil {
t.Error(caller(), message, ":", err)
}
}
// AssertEquals uses the equality operator (=) to measure one and two
func AssertEquals(t *testing.T, one interface{}, two interface{}) {
if one != two {
t.Errorf("%s [%v] != [%v]", caller(), one, two)
}
}
// AssertDeepEquals uses the reflect.DeepEqual method to measure one and two
func AssertDeepEquals(t *testing.T, one interface{}, two interface{}) {
if !reflect.DeepEqual(one, two) {
t.Errorf("%s [%+v] !(deep)= [%+v]", caller(), one, two)
}
}
// AssertMarshaledEquals marshals one and two to JSON, and then uses
// the equality operator to measure them
func AssertMarshaledEquals(t *testing.T, one interface{}, two interface{}) {
oneJSON, err := json.Marshal(one)
AssertNotError(t, err, "Could not marshal 1st argument")
@ -73,12 +81,15 @@ func AssertMarshaledEquals(t *testing.T, one interface{}, two interface{}) {
}
}
// AssertNotEquals uses the equality operator to measure that one and two
// are different
func AssertNotEquals(t *testing.T, one interface{}, two interface{}) {
if one == two {
t.Errorf("%s [%v] == [%v]", caller(), one, two)
}
}
// AssertByteEquals uses bytes.Equal to measure one and two for equality.
func AssertByteEquals(t *testing.T, one []byte, two []byte) {
if !bytes.Equal(one, two) {
t.Errorf("%s Byte [%s] != [%s]",
@ -88,30 +99,36 @@ func AssertByteEquals(t *testing.T, one []byte, two []byte) {
}
}
// AssertIntEquals uses the equality operator to measure one and two.
func AssertIntEquals(t *testing.T, one int, two int) {
if one != two {
t.Errorf("%s Int [%d] != [%d]", caller(), one, two)
}
}
// AssertBigIntEquals uses the big.Int.cmp() method to measure whether
// one and two are equal
func AssertBigIntEquals(t *testing.T, one *big.Int, two *big.Int) {
if one.Cmp(two) != 0 {
t.Errorf("%s Int [%d] != [%d]", caller(), one, two)
}
}
// AssertContains determines whether needle can be found in haystack
func AssertContains(t *testing.T, haystack string, needle string) {
if !strings.Contains(haystack, needle) {
t.Errorf("%s String [%s] does not contain [%s]", caller(), haystack, needle)
}
}
// AssertNotContains determines if needle is not found in haystack
func AssertNotContains(t *testing.T, haystack string, needle string) {
if strings.Contains(haystack, needle) {
t.Errorf("%s String [%s] contains [%s]", caller(), haystack, needle)
}
}
// AssertSeverity determines if a string matches the Severity formatting
func AssertSeverity(t *testing.T, data string, severity int) {
expected := fmt.Sprintf("\"severity\":%d", severity)
AssertContains(t, data, expected)

View File

@ -58,7 +58,7 @@ func newCAA(encodedRDATA []byte) *CAA {
return &CAA{flag: flag, tag: tag, valueBuf: valueBuf, value: value}
}
// Filtered CAA records
// CAASet consists of filtered CAA records
type CAASet struct {
issue []*CAA
issuewild []*CAA

View File

@ -20,6 +20,7 @@ import (
blog "github.com/letsencrypt/boulder/log"
)
// ValidationAuthorityImpl represents a VA
type ValidationAuthorityImpl struct {
RA core.RegistrationAuthority
log *blog.AuditLogger
@ -28,6 +29,8 @@ type ValidationAuthorityImpl struct {
TestMode bool
}
// NewValidationAuthorityImpl constructs a new VA, and may place it
// into Test Mode (tm)
func NewValidationAuthorityImpl(tm bool) ValidationAuthorityImpl {
logger := blog.GetAuditLogger()
logger.Notice("Validation Authority Starting")
@ -131,8 +134,8 @@ func (va ValidationAuthorityImpl) validateDvsni(identifier core.AcmeIdentifier,
return challenge, err
}
const DVSNI_SUFFIX = ".acme.invalid"
nonceName := challenge.Nonce + DVSNI_SUFFIX
const DVSNIsuffix = ".acme.invalid"
nonceName := challenge.Nonce + DVSNIsuffix
R, err := core.B64dec(challenge.R)
if err != nil {
@ -266,12 +269,13 @@ func (va ValidationAuthorityImpl) validate(authz core.Authorization, challengeIn
va.RA.OnValidationUpdate(authz)
}
// UpdateValidations runs the validate() method asynchronously using goroutines.
func (va ValidationAuthorityImpl) UpdateValidations(authz core.Authorization, challengeIndex int) error {
go va.validate(authz, challengeIndex)
return nil
}
// CheckCAA verifies that, if the indicated subscriber domain has any CAA
// CheckCAARecords verifies that, if the indicated subscriber domain has any CAA
// records, they authorize the configured CA domain to issue a certificate
func (va *ValidationAuthorityImpl) CheckCAARecords(identifier core.AcmeIdentifier) (present, valid bool, err error) {
domain := strings.ToLower(identifier.Value)

View File

@ -36,19 +36,19 @@ func intFromB64(b64 string) int {
return int(bigIntFromB64(b64).Int64())
}
var n *big.Int = bigIntFromB64("n4EPtAOCc9AlkeQHPzHStgAbgs7bTZLwUBZdR8_KuKPEHLd4rHVTeT-O-XV2jRojdNhxJWTDvNd7nqQ0VEiZQHz_AJmSCpMaJMRBSFKrKb2wqVwGU_NsYOYL-QtiWN2lbzcEe6XC0dApr5ydQLrHqkHHig3RBordaZ6Aj-oBHqFEHYpPe7Tpe-OfVfHd1E6cS6M1FZcD1NNLYD5lFHpPI9bTwJlsde3uhGqC0ZCuEHg8lhzwOHrtIQbS0FVbb9k3-tVTU4fg_3L_vniUFAKwuCLqKnS2BYwdq_mzSnbLY7h_qixoR7jig3__kRhuaxwUkRz5iaiQkqgc5gHdrNP5zw==")
var e int = intFromB64("AQAB")
var d *big.Int = bigIntFromB64("bWUC9B-EFRIo8kpGfh0ZuyGPvMNKvYWNtB_ikiH9k20eT-O1q_I78eiZkpXxXQ0UTEs2LsNRS-8uJbvQ-A1irkwMSMkK1J3XTGgdrhCku9gRldY7sNA_AKZGh-Q661_42rINLRCe8W-nZ34ui_qOfkLnK9QWDDqpaIsA-bMwWWSDFu2MUBYwkHTMEzLYGqOe04noqeq1hExBTHBOBdkMXiuFhUq1BU6l-DqEiWxqg82sXt2h-LMnT3046AOYJoRioz75tSUQfGCshWTBnP5uDjd18kKhyv07lhfSJdrPdM5Plyl21hsFf4L_mHCuoFau7gdsPfHPxxjVOcOpBrQzwQ==")
var p *big.Int = bigIntFromB64("uKE2dh-cTf6ERF4k4e_jy78GfPYUIaUyoSSJuBzp3Cubk3OCqs6grT8bR_cu0Dm1MZwWmtdqDyI95HrUeq3MP15vMMON8lHTeZu2lmKvwqW7anV5UzhM1iZ7z4yMkuUwFWoBvyY898EXvRD-hdqRxHlSqAZ192zB3pVFJ0s7pFc=")
var q *big.Int = bigIntFromB64("uKE2dh-cTf6ERF4k4e_jy78GfPYUIaUyoSSJuBzp3Cubk3OCqs6grT8bR_cu0Dm1MZwWmtdqDyI95HrUeq3MP15vMMON8lHTeZu2lmKvwqW7anV5UzhM1iZ7z4yMkuUwFWoBvyY898EXvRD-hdqRxHlSqAZ192zB3pVFJ0s7pFc=")
var n = bigIntFromB64("n4EPtAOCc9AlkeQHPzHStgAbgs7bTZLwUBZdR8_KuKPEHLd4rHVTeT-O-XV2jRojdNhxJWTDvNd7nqQ0VEiZQHz_AJmSCpMaJMRBSFKrKb2wqVwGU_NsYOYL-QtiWN2lbzcEe6XC0dApr5ydQLrHqkHHig3RBordaZ6Aj-oBHqFEHYpPe7Tpe-OfVfHd1E6cS6M1FZcD1NNLYD5lFHpPI9bTwJlsde3uhGqC0ZCuEHg8lhzwOHrtIQbS0FVbb9k3-tVTU4fg_3L_vniUFAKwuCLqKnS2BYwdq_mzSnbLY7h_qixoR7jig3__kRhuaxwUkRz5iaiQkqgc5gHdrNP5zw==")
var e = intFromB64("AQAB")
var d = bigIntFromB64("bWUC9B-EFRIo8kpGfh0ZuyGPvMNKvYWNtB_ikiH9k20eT-O1q_I78eiZkpXxXQ0UTEs2LsNRS-8uJbvQ-A1irkwMSMkK1J3XTGgdrhCku9gRldY7sNA_AKZGh-Q661_42rINLRCe8W-nZ34ui_qOfkLnK9QWDDqpaIsA-bMwWWSDFu2MUBYwkHTMEzLYGqOe04noqeq1hExBTHBOBdkMXiuFhUq1BU6l-DqEiWxqg82sXt2h-LMnT3046AOYJoRioz75tSUQfGCshWTBnP5uDjd18kKhyv07lhfSJdrPdM5Plyl21hsFf4L_mHCuoFau7gdsPfHPxxjVOcOpBrQzwQ==")
var p = bigIntFromB64("uKE2dh-cTf6ERF4k4e_jy78GfPYUIaUyoSSJuBzp3Cubk3OCqs6grT8bR_cu0Dm1MZwWmtdqDyI95HrUeq3MP15vMMON8lHTeZu2lmKvwqW7anV5UzhM1iZ7z4yMkuUwFWoBvyY898EXvRD-hdqRxHlSqAZ192zB3pVFJ0s7pFc=")
var q = bigIntFromB64("uKE2dh-cTf6ERF4k4e_jy78GfPYUIaUyoSSJuBzp3Cubk3OCqs6grT8bR_cu0Dm1MZwWmtdqDyI95HrUeq3MP15vMMON8lHTeZu2lmKvwqW7anV5UzhM1iZ7z4yMkuUwFWoBvyY898EXvRD-hdqRxHlSqAZ192zB3pVFJ0s7pFc=")
var TheKey rsa.PrivateKey = rsa.PrivateKey{
var TheKey = rsa.PrivateKey{
PublicKey: rsa.PublicKey{N: n, E: e},
D: d,
Primes: []*big.Int{p, q},
}
var ident core.AcmeIdentifier = core.AcmeIdentifier{Type: core.IdentifierDNS, Value: "localhost"}
var ident = core.AcmeIdentifier{Type: core.IdentifierDNS, Value: "localhost"}
const expectedToken = "THETOKEN"
const pathWrongToken = "wrongtoken"
@ -545,7 +545,7 @@ func TestDNSValidationLive(t *testing.T) {
Value: "good.bin.coffee",
}
var badIdent core.AcmeIdentifier = core.AcmeIdentifier{
var badIdent = core.AcmeIdentifier{
Type: core.IdentifierType("dns"),
Value: "bad.bin.coffee",
}

View File

@ -27,6 +27,7 @@ import (
blog "github.com/letsencrypt/boulder/log"
)
// Paths are the ACME-spec identified URL path-segments for various methods
const (
NewRegPath = "/acme/new-reg"
RegPath = "/acme/reg/"
@ -99,6 +100,8 @@ func NewWebFrontEndImpl() WebFrontEndImpl {
}
}
// HandlePaths configures the HTTP engine to use various functions
// as methods for various ACME-specified paths.
func (wfe *WebFrontEndImpl) HandlePaths() {
wfe.NewReg = wfe.BaseURL + NewRegPath
wfe.RegBase = wfe.BaseURL + RegPath
@ -122,6 +125,7 @@ func (wfe *WebFrontEndImpl) HandlePaths() {
// Method implementations
// Index serves a simple identification page. It is not part of the ACME spec.
func (wfe *WebFrontEndImpl) Index(response http.ResponseWriter, request *http.Request) {
wfe.sendStandardHeaders(response)
@ -167,6 +171,7 @@ type problem struct {
Detail string `json:"detail,omitempty"`
}
// These are defined problems
const (
MalformedProblem = ProblemType("urn:acme:error:malformed")
UnauthorizedProblem = ProblemType("urn:acme:error:unauthorized")
@ -240,11 +245,10 @@ func (wfe *WebFrontEndImpl) verifyPOST(request *http.Request, regCheck bool) ([]
// registration is an overall failure to verify.
if regCheck {
return nil, nil, reg, err
} else {
// Otherwise we just return an empty registration. The caller is expected
// to use the returned key instead.
reg = core.Registration{}
}
// Otherwise we just return an empty registration. The caller is expected
// to use the returned key instead.
reg = core.Registration{}
}
return []byte(payload), key, reg, nil
@ -293,6 +297,7 @@ func link(url, relation string) string {
return fmt.Sprintf("<%s>;rel=\"%s\"", url, relation)
}
// NewRegistration is used by clients to submit a new registration/account
func (wfe *WebFrontEndImpl) NewRegistration(response http.ResponseWriter, request *http.Request) {
wfe.sendStandardHeaders(response)
@ -356,6 +361,7 @@ func (wfe *WebFrontEndImpl) NewRegistration(response http.ResponseWriter, reques
wfe.Stats.Inc("Registrations", 1, 1.0)
}
// NewAuthorization is used by clients to submit a new ID Authorization
func (wfe *WebFrontEndImpl) NewAuthorization(response http.ResponseWriter, request *http.Request) {
wfe.sendStandardHeaders(response)
@ -417,6 +423,7 @@ func (wfe *WebFrontEndImpl) NewAuthorization(response http.ResponseWriter, reque
wfe.Stats.Inc("PendingAuthorizations", 1, 1.0)
}
// RevokeCertificate is used by clients to request the revocation of a cert.
func (wfe *WebFrontEndImpl) RevokeCertificate(response http.ResponseWriter, request *http.Request) {
wfe.sendStandardHeaders(response)
@ -435,7 +442,7 @@ func (wfe *WebFrontEndImpl) RevokeCertificate(response http.ResponseWriter, requ
}
type RevokeRequest struct {
CertificateDER core.JsonBuffer `json:"certificate"`
CertificateDER core.JSONBuffer `json:"certificate"`
}
var revokeRequest RevokeRequest
if err = json.Unmarshal(body, &revokeRequest); err != nil {
@ -496,6 +503,8 @@ func (wfe *WebFrontEndImpl) RevokeCertificate(response http.ResponseWriter, requ
}
}
// NewCertificate is used by clients to request the issuance of a cert for an
// authorized identifier.
func (wfe *WebFrontEndImpl) NewCertificate(response http.ResponseWriter, request *http.Request) {
wfe.sendStandardHeaders(response)
@ -684,6 +693,7 @@ func (wfe *WebFrontEndImpl) challenge(authz core.Authorization, response http.Re
}
}
// Registration is used by a client to submit an update to their registration.
func (wfe *WebFrontEndImpl) Registration(response http.ResponseWriter, request *http.Request) {
wfe.sendStandardHeaders(response)
@ -759,6 +769,8 @@ func (wfe *WebFrontEndImpl) Registration(response http.ResponseWriter, request *
response.Write(jsonReply)
}
// Authorization is used by clients to submit an update to one of their
// authorizations.
func (wfe *WebFrontEndImpl) Authorization(response http.ResponseWriter, request *http.Request) {
wfe.sendStandardHeaders(response)
@ -812,6 +824,8 @@ func (wfe *WebFrontEndImpl) Authorization(response http.ResponseWriter, request
var allHex = regexp.MustCompile("^[0-9a-f]+$")
// Certificate is used by clients to request a copy of their current certificate, or to
// request a reissuance of the certificate.
func (wfe *WebFrontEndImpl) Certificate(response http.ResponseWriter, request *http.Request) {
wfe.sendStandardHeaders(response)
@ -859,9 +873,15 @@ func (wfe *WebFrontEndImpl) Certificate(response http.ResponseWriter, request *h
if _, err = response.Write(cert.DER); err != nil {
wfe.log.Warning(fmt.Sprintf("Could not write response: %s", err))
}
return
case "POST":
wfe.sendError(response, "Not yet supported", "", http.StatusNotFound)
return
}
}
// Terms is used by the client to obtain the current Terms of Service /
// Subscriber Agreement to which the subscriber must agree.
func (wfe *WebFrontEndImpl) Terms(response http.ResponseWriter, request *http.Request) {
wfe.sendStandardHeaders(response)
@ -874,6 +894,7 @@ func (wfe *WebFrontEndImpl) Terms(response http.ResponseWriter, request *http.Re
fmt.Fprintf(response, "TODO: Add terms of use here")
}
// Issuer obtains the issuer certificate used by this instance of Boulder.
func (wfe *WebFrontEndImpl) Issuer(response http.ResponseWriter, request *http.Request) {
wfe.sendStandardHeaders(response)

View File

@ -710,7 +710,7 @@ func TestRevokeCertificate(t *testing.T) {
certBlock, _ := pem.Decode(certPemBytes)
test.Assert(t, certBlock != nil, "Failed to decode PEM")
var revokeRequest struct {
CertificateDER core.JsonBuffer `json:"certificate"`
CertificateDER core.JSONBuffer `json:"certificate"`
}
revokeRequest.CertificateDER = certBlock.Bytes
revokeRequestJSON, err := json.Marshal(revokeRequest)
@ -767,7 +767,7 @@ func TestRevokeCertificateAlreadyRevoked(t *testing.T) {
certBlock, _ := pem.Decode(certPemBytes)
test.Assert(t, certBlock != nil, "Failed to decode PEM")
var revokeRequest struct {
CertificateDER core.JsonBuffer `json:"certificate"`
CertificateDER core.JSONBuffer `json:"certificate"`
}
revokeRequest.CertificateDER = certBlock.Bytes
revokeRequestJSON, err := json.Marshal(revokeRequest)