Correct most `go lint` warnings. (274 -> 5)
This commit is contained in:
parent
383885df08
commit
41f5788c77
|
@ -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")
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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...)
|
||||
|
|
|
@ -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...)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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.")
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -15,7 +15,7 @@ import (
|
|||
"github.com/letsencrypt/boulder/test"
|
||||
)
|
||||
|
||||
var maxKeySize int = 2048
|
||||
var maxKeySize = 2048
|
||||
|
||||
func TestUnknownKeyType(t *testing.T) {
|
||||
notAKey := struct{}{}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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"`
|
||||
|
||||
|
|
|
@ -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":"!!!!"}`)
|
||||
|
|
51
core/util.go
51
core/util.go
|
@ -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 {
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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" +
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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{},
|
||||
|
|
|
@ -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(®, "SELECT * FROM registrations WHERE jwk = :key", map[string]interface{}{"key": string(keyJson)})
|
||||
err = ssa.dbMap.SelectOne(®, "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)
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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",
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue