merge upstream/master
This commit is contained in:
commit
97ff1c8423
|
|
@ -8,6 +8,9 @@ _obj
|
|||
_test
|
||||
bin
|
||||
|
||||
# Test files
|
||||
test/js/node_modules
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@ WebFE -> WebFE: [ verify authorization signature ]
|
|||
WebFE -> RA: UpdateAuthorization(Authorization)
|
||||
RA -> RA: [ add responses to authorization ]
|
||||
RA -> SA: Update(Authorization.ID, Authorization)
|
||||
WebFE -> VA: UpdateValidations(Authorization)
|
||||
RA -> VA: UpdateValidations(Authorization)
|
||||
WebFE -> Client: defer(authorizationID)
|
||||
|
||||
VA -> SA: Update(Authorization.ID, Authorization)
|
||||
|
|
|
|||
|
|
@ -7,16 +7,16 @@ package ca
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/x509"
|
||||
"crypto"
|
||||
"crypto/x509"
|
||||
"encoding/asn1"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
"os"
|
||||
|
||||
apisign "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/api/sign"
|
||||
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/auth"
|
||||
|
|
@ -260,7 +260,6 @@ func TestMain(m *testing.M) {
|
|||
caCertPEM, _ := ioutil.ReadFile(caCertFile)
|
||||
caCert, _ := helpers.ParseCertificatePEM(caCertPEM)
|
||||
|
||||
|
||||
// Create an online CFSSL instance
|
||||
// This is designed to mimic what LE plans to do
|
||||
authHandler, _ := auth.New(authKey, nil)
|
||||
|
|
@ -330,7 +329,6 @@ func setup(t *testing.T) (cadb core.CertificateAuthorityDatabase, storageAuthori
|
|||
ssa.InitTables()
|
||||
storageAuthority = ssa
|
||||
|
||||
|
||||
cadb, _ = NewMockCertificateAuthorityDatabase()
|
||||
|
||||
// Create a CA
|
||||
|
|
|
|||
|
|
@ -28,6 +28,9 @@ func main() {
|
|||
auditlogger, err := blog.Dial(c.Syslog.Network, c.Syslog.Server, c.Syslog.Tag, stats)
|
||||
cmd.FailOnError(err, "Could not connect to Syslog")
|
||||
|
||||
// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
|
||||
defer auditlogger.AuditPanic()
|
||||
|
||||
blog.SetAuditLogger(auditlogger)
|
||||
|
||||
cadb, err := ca.NewCertificateAuthorityDatabaseImpl(c.CA.DBDriver, c.CA.DBName)
|
||||
|
|
|
|||
|
|
@ -25,6 +25,9 @@ func main() {
|
|||
auditlogger, err := blog.Dial(c.Syslog.Network, c.Syslog.Server, c.Syslog.Tag, stats)
|
||||
cmd.FailOnError(err, "Could not connect to Syslog")
|
||||
|
||||
// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
|
||||
defer auditlogger.AuditPanic()
|
||||
|
||||
blog.SetAuditLogger(auditlogger)
|
||||
|
||||
rai := ra.NewRegistrationAuthorityImpl()
|
||||
|
|
|
|||
|
|
@ -28,6 +28,9 @@ func main() {
|
|||
auditlogger, err := blog.Dial(c.Syslog.Network, c.Syslog.Server, c.Syslog.Tag, stats)
|
||||
cmd.FailOnError(err, "Could not connect to Syslog")
|
||||
|
||||
// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
|
||||
defer auditlogger.AuditPanic()
|
||||
|
||||
blog.SetAuditLogger(auditlogger)
|
||||
|
||||
sai, err := sa.NewSQLStorageAuthority(c.SA.DBDriver, c.SA.DBName)
|
||||
|
|
|
|||
|
|
@ -25,6 +25,9 @@ func main() {
|
|||
auditlogger, err := blog.Dial(c.Syslog.Network, c.Syslog.Server, c.Syslog.Tag, stats)
|
||||
cmd.FailOnError(err, "Could not connect to Syslog")
|
||||
|
||||
// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
|
||||
defer auditlogger.AuditPanic()
|
||||
|
||||
blog.SetAuditLogger(auditlogger)
|
||||
|
||||
go cmd.ProfileCmd("VA", stats)
|
||||
|
|
|
|||
|
|
@ -73,6 +73,9 @@ func main() {
|
|||
auditlogger, err := blog.Dial(c.Syslog.Network, c.Syslog.Server, c.Syslog.Tag, stats)
|
||||
cmd.FailOnError(err, "Could not connect to Syslog")
|
||||
|
||||
// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
|
||||
defer auditlogger.AuditPanic()
|
||||
|
||||
blog.SetAuditLogger(auditlogger)
|
||||
|
||||
wfe := wfe.NewWebFrontEndImpl()
|
||||
|
|
|
|||
|
|
@ -65,6 +65,9 @@ func main() {
|
|||
auditlogger, err := blog.Dial(c.Syslog.Network, c.Syslog.Server, c.Syslog.Tag, stats)
|
||||
cmd.FailOnError(err, "Could not connect to Syslog")
|
||||
|
||||
// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
|
||||
defer auditlogger.AuditPanic()
|
||||
|
||||
blog.SetAuditLogger(auditlogger)
|
||||
|
||||
// Run StatsD profiling
|
||||
|
|
|
|||
|
|
@ -37,9 +37,9 @@ import (
|
|||
_ "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/cmd/cfssl"
|
||||
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/codegangsta/cli"
|
||||
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/streadway/amqp"
|
||||
"github.com/letsencrypt/boulder/ca"
|
||||
blog "github.com/letsencrypt/boulder/log"
|
||||
"github.com/letsencrypt/boulder/rpc"
|
||||
"github.com/letsencrypt/boulder/ca"
|
||||
)
|
||||
|
||||
// Config stores configuration parameters that applications
|
||||
|
|
@ -140,8 +140,8 @@ func (as *AppShell) Run() {
|
|||
// FailOnError exits and prints an error message if we encountered a problem
|
||||
func FailOnError(err error, msg string) {
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%s: %s\n", msg, err)
|
||||
os.Exit(1)
|
||||
// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
|
||||
panic(fmt.Sprintf("%s: %s", msg, err))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ type RegistrationAuthority interface {
|
|||
RevokeCertificate(x509.Certificate) error
|
||||
|
||||
// [ValidationAuthority]
|
||||
OnValidationUpdate(Authorization)
|
||||
OnValidationUpdate(Authorization) error
|
||||
}
|
||||
|
||||
type ValidationAuthority interface {
|
||||
|
|
|
|||
|
|
@ -6,12 +6,12 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
jose "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/square/go-jose"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
|
@ -288,7 +288,7 @@ type Authorization struct {
|
|||
|
||||
// Fields of this type 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
|
||||
func base64URLEncode(data []byte) string {
|
||||
|
|
|
|||
|
|
@ -19,8 +19,8 @@ import (
|
|||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
blog "github.com/letsencrypt/boulder/log"
|
||||
jose "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/square/go-jose"
|
||||
blog "github.com/letsencrypt/boulder/log"
|
||||
"hash"
|
||||
"io"
|
||||
"math/big"
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"fmt"
|
||||
"github.com/letsencrypt/boulder/test"
|
||||
"math"
|
||||
"math/big"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// challenges.go
|
||||
|
|
@ -18,14 +18,14 @@ func TestNewToken(t *testing.T) {
|
|||
token := NewToken()
|
||||
fmt.Println(token)
|
||||
tokenLength := int(math.Ceil(32 * 8 / 6.0)) // 32 bytes, b64 encoded
|
||||
test.AssertIntEquals(t,len(token),tokenLength)
|
||||
test.AssertIntEquals(t, len(token), tokenLength)
|
||||
collider := map[string]bool{}
|
||||
// Test for very blatant RNG failures:
|
||||
// Try 2^20 birthdays in a 2^72 search space...
|
||||
// our naive collision probability here is 2^-32...
|
||||
for i:=0; i < 1000000; i++ {
|
||||
for i := 0; i < 1000000; i++ {
|
||||
token = NewToken()[:12] // just sample a portion
|
||||
test.Assert(t,!collider[token],"Token collision!")
|
||||
test.Assert(t, !collider[token], "Token collision!")
|
||||
collider[token] = true
|
||||
}
|
||||
return
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
This folder tracks software requirements using UUIDs interspersed with the code.
|
||||
|
||||
This is a best-effort mechanism, and while ugly, all other mechanisms for requirements traceability are similarly ugly.
|
||||
|
||||
All UUID sets are stored as CSV files in this directory; standard tools such as `grep` should be used to detect all
|
||||
implementing code.
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
UUID,Shortname,CPS Reference,Description
|
||||
11917fa4-10ef-4e0d-9105-bacbe7836a3c,Certificate Requests,,"All Certificate requests – Date and time of request, type of event, and request information are automatically logged by the application. This includes Issuance, renewal, and re-key requests as well as sender/requester DN, Certificate serial number, initial application, method of request (online, in-person), source of verification, name of document presented for identity proofing, all fields verified in the application, Certificate common name, new validity period dates, date and time of response and success or failure indication are automatically logged by the application, and all associated error messages and codes. Manual interactions with participants such as telephone or in person inquiries and results of verification calls will be logged manually in a logbook or in a computer-based recording/tracking system and include date/time, description of interaction and identity provided."
|
||||
4e85d791-09c0-4ab3-a837-d3d67e945134,Revocation Requests,,"All Certificate Revocation requests – Date and time of Revocation request, sender/requester DN, Certificate serial number, subject DN of Certificate to revoke, Subscriber’s common name, Revocation reason, date and time of response and success or failure indication are automatically logged by the application; manual interactions with requestors such as telephone or in person inquiries and requests for Revocation are logged manually in a logbook or in a computer-based recording/tracking system. The date/time, description of interaction and identity provided are also recorded."
|
||||
a88fd00b-fa62-4a2f-9226-3eef27e2a50e,Certificate Updates,,"The approval or rejection of a Certificate status change request – Identity of equipment operator who initiated the request, message contents, message source, destination, and success or failure indication are automatically logged by the application."
|
||||
d510aa7e-ce9d-44ea-aa6d-4479a5652439,Software Updates and Migrations,,"Any security-relevant changes to the configuration of a component – Date and time of modification, name of modifier, description of modification, build information (i.e. size, version number) of any modified files and the reason for modification are manually logged during change management processes."
|
||||
78722466-9519-42bd-8a16-9c1ec1ca29ea,Compromise Notifications,,"All Certificate compromise notification requests – Date and time of notification, identity of person making the notification, identification of entity compromised, and a description of the compromise are logged manually by the personnel who receive the notification (e.g. Help Desk, RA Operators, etc.) and by RA/RA Operators’ system processing logs."
|
||||
9cc4d537-8534-4970-8665-4b382abe82f3,Error Conditions,,"Software error conditions – Date and time of event, and description of event are automatically logged by the application reporting the event or by the operating system."
|
||||
03806e9f-b6f3-4b29-b0a2-46fae57646d5,Software Integrity Failures,,"Software check integrity failures – Date and time of event, and description of event are automatically logged by the application reporting the event or by the operating system."
|
||||
0786b6f2-91ca-4f48-9883-842a19084c64,Improper Messages,,"Receipt of improper messages – Date and time of event, and description of event are automatically logged by the application reporting the event or by the operating system."
|
||||
f523f21f-12d2-4c31-b2eb-ee4b7d96d60e,Misrouted Messages,,"Misrouted messages – Date and time of event, and description of event are automatically logged by the application reporting the event or by the operating system."
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# This method finds all instances of each UUID in the codebase.
|
||||
#
|
||||
|
||||
audit_dir=$(cd $(dirname ${0}); pwd)
|
||||
root=$(dirname $(dirname ${audit_dir}))
|
||||
cat ${audit_dir}/audit_events.csv | tail -n +2 | while read r; do
|
||||
uuid=$(echo $r | awk -F "," '{print $1;}')
|
||||
desc=$(echo $r | awk -F "," '{print $2;}')
|
||||
echo "==================================="
|
||||
echo "==================================="
|
||||
echo ${desc} ${uuid}
|
||||
echo ""
|
||||
grep -C 3 -R --include "*.go" "${uuid}" "${root}"
|
||||
done
|
||||
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Provides comment lines for each requirement that can be located with tools
|
||||
|
||||
echo "Insert these comments into the codebase where appropriate, formatted exactly as printed."
|
||||
|
||||
cat audit_events.csv | tail -n +2 | awk -F "," '{print "// AUDIT[", $2, "]", $1;}'
|
||||
|
|
@ -27,6 +27,17 @@ var _Singleton singleton
|
|||
// The constant used to identify audit-specific messages
|
||||
const auditTag = "[AUDIT]"
|
||||
|
||||
// Constant used to indicate an emergency exit to the executor
|
||||
const emergencyReturnValue = 13
|
||||
|
||||
// exitFunction closes the running system
|
||||
type exitFunction func()
|
||||
|
||||
// Default to calling os.Exit()
|
||||
func defaultEmergencyExit() {
|
||||
os.Exit(emergencyReturnValue)
|
||||
}
|
||||
|
||||
// AuditLogger is a System Logger with additional audit-specific methods.
|
||||
// In addition to all the standard syslog.Writer methods from
|
||||
// http://golang.org/pkg/log/syslog/#Writer, you can also call
|
||||
|
|
@ -35,6 +46,7 @@ const auditTag = "[AUDIT]"
|
|||
type AuditLogger struct {
|
||||
*syslog.Writer
|
||||
Stats statsd.Statter
|
||||
exitFunction exitFunction
|
||||
}
|
||||
|
||||
// Dial establishes a connection to the log daemon by passing through
|
||||
|
|
@ -54,7 +66,12 @@ func NewAuditLogger(log *syslog.Writer, stats statsd.Statter) (*AuditLogger, err
|
|||
if log == nil {
|
||||
return nil, errors.New("Attempted to use a nil System Logger.")
|
||||
}
|
||||
return &AuditLogger{log, stats}, nil
|
||||
audit := &AuditLogger{
|
||||
log,
|
||||
stats,
|
||||
defaultEmergencyExit,
|
||||
}
|
||||
return audit, nil
|
||||
}
|
||||
|
||||
// initializeAuditLogger should only be used in unit tests. Failures in this
|
||||
|
|
@ -96,90 +113,118 @@ func GetAuditLogger() *AuditLogger {
|
|||
return _Singleton.log
|
||||
}
|
||||
|
||||
// Log the provided message at the appropriate level, writing to
|
||||
// both stdout and the Logger, as well as informing statsd.
|
||||
func (log *AuditLogger) logAtLevel(level, msg string) (err error) {
|
||||
fmt.Printf("%s\n", msg)
|
||||
log.Stats.Inc(level, 1, 1.0)
|
||||
|
||||
switch level {
|
||||
case "Logging.Alert":
|
||||
err = log.Writer.Alert(msg)
|
||||
case "Logging.Crit":
|
||||
err = log.Writer.Crit(msg)
|
||||
case "Logging.Debug":
|
||||
err = log.Writer.Debug(msg)
|
||||
case "Logging.Emerg":
|
||||
err = log.Writer.Emerg(msg)
|
||||
case "Logging.Err":
|
||||
err = log.Writer.Err(msg)
|
||||
case "Logging.Info":
|
||||
err = log.Writer.Info(msg)
|
||||
case "Logging.Warning":
|
||||
err = log.Writer.Warning(msg)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
|
||||
func (log *AuditLogger) auditAtLevel(level, msg string) (err error) {
|
||||
// Submit a separate counter that marks an Audit event
|
||||
log.Stats.Inc("Logging.Audit", 1, 1.0)
|
||||
|
||||
text := fmt.Sprintf("%s %s", auditTag, msg)
|
||||
return log.logAtLevel(level, text)
|
||||
}
|
||||
|
||||
// AuditPanic catches panicking executables. This method should be added
|
||||
// in a defer statement as early as possible
|
||||
// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
|
||||
func (log *AuditLogger) AuditPanic() {
|
||||
if err := recover(); err != nil {
|
||||
log.Audit(fmt.Sprintf("Panic: %v", err))
|
||||
}
|
||||
}
|
||||
|
||||
// WarningErr formats an error for the Warn level.
|
||||
func (log *AuditLogger) WarningErr(msg error) (err error) {
|
||||
return log.logAtLevel("Logging.Warning", msg.Error())
|
||||
}
|
||||
|
||||
// Alert level messages pass through normally.
|
||||
func (log *AuditLogger) Alert(msg string) (err error) {
|
||||
return log.logAtLevel("Logging.Alert", msg)
|
||||
}
|
||||
|
||||
// Crit level messages are automatically marked for audit
|
||||
func (log *AuditLogger) Crit(msg string) (err error) {
|
||||
return log.auditAtLevel("Logging.Crit", msg)
|
||||
}
|
||||
|
||||
// Debug level messages pass through normally.
|
||||
func (log *AuditLogger) Debug(msg string) (err error) {
|
||||
return log.logAtLevel("Logging.Debug", msg)
|
||||
}
|
||||
|
||||
// Emerg level messages are automatically marked for audit
|
||||
func (log *AuditLogger) Emerg(msg string) (err error) {
|
||||
return log.auditAtLevel("Logging.Emerg", msg)
|
||||
}
|
||||
|
||||
// Err level messages are automatically marked for audit
|
||||
func (log *AuditLogger) Err(msg string) (err error) {
|
||||
return log.auditAtLevel("Logging.Err", msg)
|
||||
}
|
||||
|
||||
// Info level messages pass through normally.
|
||||
func (log *AuditLogger) Info(msg string) (err error) {
|
||||
return log.logAtLevel("Logging.Info", msg)
|
||||
}
|
||||
|
||||
// Warning level messages pass through normally.
|
||||
func (log *AuditLogger) Warning(msg string) (err error) {
|
||||
return log.logAtLevel("Logging.Warning", msg)
|
||||
}
|
||||
|
||||
// Notice level messages pass through normally.
|
||||
func (log *AuditLogger) Notice(msg string) (err error) {
|
||||
return log.logAtLevel("Logging.Notice", msg)
|
||||
}
|
||||
|
||||
// Audit sends a NOTICE-severity message that is prefixed with the
|
||||
// audit tag, for special handling at the upstream system logger.
|
||||
// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
|
||||
func (log *AuditLogger) Audit(msg string) (err error) {
|
||||
fmt.Println(msg)
|
||||
err = log.Notice(fmt.Sprintf("%s %s", auditTag, msg))
|
||||
|
||||
log.Stats.Inc("Logging.Audit", 1, 1.0)
|
||||
|
||||
return
|
||||
return log.auditAtLevel("Logging.Notice", msg)
|
||||
}
|
||||
|
||||
// Audit can format an error for auditing; it does so at ERR level.
|
||||
// AuditErr can format an error for auditing; it does so at ERR level.
|
||||
// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
|
||||
func (log *AuditLogger) AuditErr(msg error) (err error) {
|
||||
fmt.Println(msg)
|
||||
err = log.Err(fmt.Sprintf("%s %s", auditTag, msg))
|
||||
|
||||
log.Stats.Inc("Logging.Audit", 1, 1.0)
|
||||
|
||||
return
|
||||
return log.auditAtLevel("Logging.Err", msg.Error())
|
||||
}
|
||||
|
||||
// Warning formats an error for the Warn level.
|
||||
func (log *AuditLogger) WarningErr(msg error) (err error) {
|
||||
fmt.Println(msg)
|
||||
err = log.Warning(fmt.Sprintf("%s", msg))
|
||||
|
||||
return
|
||||
// SetEmergencyExitFunc changes the systems' behavior on an emergency exit.
|
||||
func (log *AuditLogger) SetEmergencyExitFunc(exit exitFunction) {
|
||||
log.exitFunction = exit
|
||||
}
|
||||
|
||||
func (log *AuditLogger) Alert(msg string) (err error) {
|
||||
fmt.Println(msg)
|
||||
log.Stats.Inc("Logging.Alert", 1, 1.0)
|
||||
return log.Writer.Alert(msg)
|
||||
}
|
||||
|
||||
func (log *AuditLogger) Crit(msg string) (err error) {
|
||||
fmt.Println(msg)
|
||||
log.Stats.Inc("Logging.Crit", 1, 1.0)
|
||||
return log.Writer.Crit(msg)
|
||||
}
|
||||
|
||||
func (log *AuditLogger) Debug(msg string) (err error) {
|
||||
fmt.Println(msg)
|
||||
log.Stats.Inc("Logging.Debug", 1, 1.0)
|
||||
return log.Writer.Debug(msg)
|
||||
}
|
||||
|
||||
func (log *AuditLogger) Emerg(msg string) (err error) {
|
||||
fmt.Println(msg)
|
||||
log.Stats.Inc("Logging.Emerg", 1, 1.0)
|
||||
return log.Writer.Emerg(msg)
|
||||
}
|
||||
|
||||
func (log *AuditLogger) Err(msg string) (err error) {
|
||||
fmt.Println(msg)
|
||||
log.Stats.Inc("Logging.Err", 1, 1.0)
|
||||
return log.Writer.Err(msg)
|
||||
}
|
||||
|
||||
func (log *AuditLogger) Info(msg string) (err error) {
|
||||
fmt.Println(msg)
|
||||
log.Stats.Inc("Logging.Info", 1, 1.0)
|
||||
return log.Writer.Info(msg)
|
||||
}
|
||||
|
||||
func (log *AuditLogger) Warning(msg string) (err error) {
|
||||
fmt.Println(msg)
|
||||
log.Stats.Inc("Logging.Warning", 1, 1.0)
|
||||
return log.Writer.Warning(msg)
|
||||
}
|
||||
|
||||
func (log *AuditLogger) Notice(msg string) (err error) {
|
||||
fmt.Println(msg)
|
||||
log.Stats.Inc("Logging.Notice", 1, 1.0)
|
||||
return log.Writer.Notice(msg)
|
||||
}
|
||||
|
||||
const EMERGENCY_RETVAL = 13
|
||||
|
||||
// EmergencyExit triggers an immediate Boulder shutdown in the event of serious
|
||||
// errors. This function will provide the necessary housekeeping.
|
||||
// Currently, make an emergency log entry and exit; the Activity Monitor
|
||||
// should notice the Emerg level event and shut down all components.
|
||||
// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
|
||||
func (log *AuditLogger) EmergencyExit(msg string) {
|
||||
// Some errors may be serious enough to trigger an immediate Boulder
|
||||
// shutdown. This function will provide the necessary housekeeping.
|
||||
// Currently, make an emergency log entry and exit; the Activity Monitor
|
||||
// should notice the Emerg level event and shut down all components.
|
||||
log.Emerg(msg)
|
||||
os.Exit(EMERGENCY_RETVAL)
|
||||
log.auditAtLevel("Logging.Emerg", msg)
|
||||
log.exitFunction()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import (
|
|||
)
|
||||
|
||||
func TestConstruction(t *testing.T) {
|
||||
t.Parallel()
|
||||
writer, err := syslog.New(syslog.LOG_EMERG|syslog.LOG_KERN, "tag")
|
||||
test.AssertNotError(t, err, "Could not construct syslog object")
|
||||
|
||||
|
|
@ -24,6 +25,7 @@ func TestConstruction(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestSingleton(t *testing.T) {
|
||||
t.Parallel()
|
||||
log1 := GetAuditLogger()
|
||||
test.AssertNotNil(t, log1, "Logger shouldn't be nil")
|
||||
|
||||
|
|
@ -53,24 +55,28 @@ func TestSingleton(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestDial(t *testing.T) {
|
||||
t.Parallel()
|
||||
stats, _ := statsd.NewNoopClient(nil)
|
||||
_, err := Dial("", "", "tag", stats)
|
||||
test.AssertNotError(t, err, "Could not construct audit logger")
|
||||
}
|
||||
|
||||
func TestDialError(t *testing.T) {
|
||||
t.Parallel()
|
||||
stats, _ := statsd.NewNoopClient(nil)
|
||||
_, err := Dial("_fail", "_fail", "tag", stats)
|
||||
test.AssertError(t, err, "Audit Logger should have failed")
|
||||
}
|
||||
|
||||
func TestConstructionNil(t *testing.T) {
|
||||
t.Parallel()
|
||||
stats, _ := statsd.NewNoopClient(nil)
|
||||
_, err := NewAuditLogger(nil, stats)
|
||||
test.AssertError(t, err, "Nil shouldn't be permitted.")
|
||||
}
|
||||
|
||||
func TestEmit(t *testing.T) {
|
||||
t.Parallel()
|
||||
writer, err := syslog.New(syslog.LOG_EMERG|syslog.LOG_KERN, "tag")
|
||||
test.AssertNotError(t, err, "Could not construct syslog object")
|
||||
|
||||
|
|
@ -82,6 +88,7 @@ func TestEmit(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestEmitEmpty(t *testing.T) {
|
||||
t.Parallel()
|
||||
writer, err := syslog.New(syslog.LOG_EMERG|syslog.LOG_KERN, "tag")
|
||||
test.AssertNotError(t, err, "Could not construct syslog object")
|
||||
|
||||
|
|
@ -93,6 +100,7 @@ func TestEmitEmpty(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestEmitErrors(t *testing.T) {
|
||||
t.Parallel()
|
||||
stats, _ := statsd.NewNoopClient(nil)
|
||||
audit, _ := Dial("", "", "tag", stats)
|
||||
|
||||
|
|
@ -101,6 +109,7 @@ func TestEmitErrors(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestSyslogMethods(t *testing.T) {
|
||||
t.Parallel()
|
||||
// Write all logs to UDP on a high port so as to not bother the system
|
||||
// which is running the test, particularly for Emerg()
|
||||
writer, err := syslog.Dial("udp", "127.0.0.1:65530", syslog.LOG_INFO|syslog.LOG_LOCAL0, "")
|
||||
|
|
@ -120,3 +129,30 @@ func TestSyslogMethods(t *testing.T) {
|
|||
audit.Warning("audit-logger_test.go: warning")
|
||||
audit.Alert("audit-logger_test.go: alert")
|
||||
}
|
||||
|
||||
func TestPanic(t *testing.T) {
|
||||
t.Parallel()
|
||||
stats, _ := statsd.NewNoopClient(nil)
|
||||
audit, _ := Dial("", "", "tag", stats)
|
||||
defer audit.AuditPanic()
|
||||
panic("Test panic")
|
||||
// Can't assert anything here or golint gets angry
|
||||
}
|
||||
|
||||
func TestEmergencyExit(t *testing.T) {
|
||||
t.Parallel()
|
||||
// Write all logs to UDP on a high port so as to not bother the system
|
||||
// which is running the test, particularly for Emerg()
|
||||
writer, err := syslog.Dial("udp", "127.0.0.1:65530", syslog.LOG_INFO|syslog.LOG_LOCAL0, "")
|
||||
test.AssertNotError(t, err, "Could not construct syslog object")
|
||||
|
||||
stats, _ := statsd.NewNoopClient(nil)
|
||||
audit, err := NewAuditLogger(writer, stats)
|
||||
test.AssertNotError(t, err, "Could not construct audit logger")
|
||||
|
||||
called := false
|
||||
|
||||
audit.SetEmergencyExitFunc(func() { called = true })
|
||||
audit.EmergencyExit("Emergency!")
|
||||
test.AssertEquals(t, called, true)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,9 @@ package ra
|
|||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strconv"
|
||||
|
|
@ -46,6 +48,22 @@ func lastPathSegment(url core.AcmeURL) string {
|
|||
return allButLastPathSegment.ReplaceAllString(url.Path, "")
|
||||
}
|
||||
|
||||
type certificateRequestEvent struct {
|
||||
ID string `json:"omitempty"`
|
||||
Requester int64 `json:"omitempty"`
|
||||
SerialNumber *big.Int `json:"omitempty"`
|
||||
RequestMethod string `json:"omitempty"`
|
||||
VerificationMethods []string `json:"omitempty"`
|
||||
VerifiedFields []string `json:"omitempty"`
|
||||
CommonName string `json:"omitempty"`
|
||||
Names []string `json:"omitempty"`
|
||||
NotBefore time.Time `json:"omitempty"`
|
||||
NotAfter time.Time `json:"omitempty"`
|
||||
RequestTime time.Time `json:"omitempty"`
|
||||
ResponseTime time.Time `json:"omitempty"`
|
||||
Error string `json:"omitempty"`
|
||||
}
|
||||
|
||||
func (ra *RegistrationAuthorityImpl) NewRegistration(init core.Registration, key jose.JsonWebKey) (reg core.Registration, err error) {
|
||||
reg = core.Registration{
|
||||
Key: key,
|
||||
|
|
@ -107,6 +125,31 @@ func (ra *RegistrationAuthorityImpl) NewAuthorization(request core.Authorization
|
|||
func (ra *RegistrationAuthorityImpl) NewCertificate(req core.CertificateRequest, regID int64) (core.Certificate, error) {
|
||||
emptyCert := core.Certificate{}
|
||||
var err error
|
||||
var logEventResult string
|
||||
|
||||
// Assume the worst
|
||||
logEventResult = "error"
|
||||
|
||||
// Construct the log event
|
||||
logEvent := certificateRequestEvent{
|
||||
ID: core.NewToken(),
|
||||
Requester: regID,
|
||||
RequestMethod: "online",
|
||||
RequestTime: time.Now(),
|
||||
}
|
||||
|
||||
// No matter what, log the request
|
||||
defer func() {
|
||||
jsonLogEvent, logErr := json.Marshal(logEvent)
|
||||
if logErr != nil {
|
||||
// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
|
||||
ra.log.Audit(fmt.Sprintf("Certificate request logEvent could not be serialized. Raw: %+v", logEvent))
|
||||
return
|
||||
}
|
||||
|
||||
// AUDIT[ Certificate Requests ] 11917fa4-10ef-4e0d-9105-bacbe7836a3c
|
||||
ra.log.Audit(fmt.Sprintf("Certificate request %s - %s", logEventResult, string(jsonLogEvent)))
|
||||
}()
|
||||
|
||||
if regID <= 0 {
|
||||
err = fmt.Errorf("Invalid registration ID")
|
||||
|
|
@ -117,23 +160,28 @@ func (ra *RegistrationAuthorityImpl) NewCertificate(req core.CertificateRequest,
|
|||
// TODO: Verify that other aspects of the CSR are appropriate
|
||||
csr := req.CSR
|
||||
if err = core.VerifyCSR(csr); err != nil {
|
||||
ra.log.Debug("Invalid signature on CSR:" + err.Error())
|
||||
logEvent.Error = err.Error()
|
||||
err = core.UnauthorizedError("Invalid signature on CSR")
|
||||
return emptyCert, err
|
||||
}
|
||||
|
||||
logEvent.CommonName = csr.Subject.CommonName
|
||||
logEvent.Names = csr.DNSNames
|
||||
|
||||
csrPreviousDenied, err := ra.SA.AlreadyDeniedCSR(append(csr.DNSNames, csr.Subject.CommonName))
|
||||
if err != nil {
|
||||
logEvent.Error = err.Error()
|
||||
return emptyCert, err
|
||||
}
|
||||
if csrPreviousDenied {
|
||||
ra.log.Audit(fmt.Sprintf("CSR for names %v was previously revoked/denied", csr.DNSNames))
|
||||
err = core.UnauthorizedError("CSR has already been revoked/denied")
|
||||
logEvent.Error = err.Error()
|
||||
return emptyCert, err
|
||||
}
|
||||
|
||||
registration, err := ra.SA.GetRegistration(regID)
|
||||
if err != nil {
|
||||
logEvent.Error = err.Error()
|
||||
return emptyCert, err
|
||||
}
|
||||
|
||||
|
|
@ -144,6 +192,7 @@ func (ra *RegistrationAuthorityImpl) NewCertificate(req core.CertificateRequest,
|
|||
|
||||
// Gather authorized domains from the referenced authorizations
|
||||
authorizedDomains := map[string]bool{}
|
||||
verificationMethodSet := map[string]bool{}
|
||||
now := time.Now()
|
||||
for _, url := range req.Authorizations {
|
||||
id := lastPathSegment(url)
|
||||
|
|
@ -159,32 +208,54 @@ func (ra *RegistrationAuthorityImpl) NewCertificate(req core.CertificateRequest,
|
|||
continue
|
||||
}
|
||||
|
||||
for _, challenge := range authz.Challenges {
|
||||
if challenge.Status == core.StatusValid {
|
||||
verificationMethodSet[challenge.Type] = true
|
||||
}
|
||||
}
|
||||
|
||||
authorizedDomains[authz.Identifier.Value] = true
|
||||
}
|
||||
verificationMethods := []string{}
|
||||
for method, _ := range verificationMethodSet {
|
||||
verificationMethods = append(verificationMethods, method)
|
||||
}
|
||||
logEvent.VerificationMethods = verificationMethods
|
||||
|
||||
// Validate that authorization key is authorized for all domains
|
||||
names := csr.DNSNames
|
||||
if len(csr.Subject.CommonName) > 0 {
|
||||
names = append(names, csr.Subject.CommonName)
|
||||
}
|
||||
|
||||
// Validate all domains
|
||||
for _, name := range names {
|
||||
if !authorizedDomains[name] {
|
||||
err = core.UnauthorizedError(fmt.Sprintf("Key not authorized for name %s", name))
|
||||
logEvent.Error = err.Error()
|
||||
return emptyCert, err
|
||||
}
|
||||
}
|
||||
|
||||
// Create the certificate
|
||||
// Mark that we verified the CN and SANs
|
||||
logEvent.VerifiedFields = []string{"subject.commonName", "subjectAltName"}
|
||||
|
||||
// Create the certificate and log the result
|
||||
var cert core.Certificate
|
||||
ra.log.Audit(fmt.Sprintf("Issuing certificate for %s", names))
|
||||
if cert, err = ra.CA.IssueCertificate(*csr, regID); err != nil {
|
||||
return emptyCert, err
|
||||
}
|
||||
cert.ParsedCertificate, err = x509.ParseCertificate([]byte(cert.DER))
|
||||
if err != nil {
|
||||
return emptyCert, err
|
||||
logEvent.Error = err.Error()
|
||||
return emptyCert, nil
|
||||
}
|
||||
|
||||
cert.ParsedCertificate, err = x509.ParseCertificate([]byte(cert.DER))
|
||||
|
||||
logEvent.SerialNumber = cert.ParsedCertificate.SerialNumber
|
||||
logEvent.CommonName = cert.ParsedCertificate.Subject.CommonName
|
||||
logEvent.NotBefore = cert.ParsedCertificate.NotBefore
|
||||
logEvent.NotAfter = cert.ParsedCertificate.NotAfter
|
||||
logEvent.ResponseTime = time.Now()
|
||||
|
||||
logEventResult = "successful"
|
||||
return cert, nil
|
||||
}
|
||||
|
||||
|
|
@ -216,10 +287,20 @@ func (ra *RegistrationAuthorityImpl) UpdateAuthorization(base core.Authorization
|
|||
}
|
||||
|
||||
func (ra *RegistrationAuthorityImpl) RevokeCertificate(cert x509.Certificate) error {
|
||||
return ra.CA.RevokeCertificate(core.SerialToString(cert.SerialNumber))
|
||||
serialString := core.SerialToString(cert.SerialNumber)
|
||||
err := ra.CA.RevokeCertificate(serialString)
|
||||
|
||||
// AUDIT[ Revocation Requests ] 4e85d791-09c0-4ab3-a837-d3d67e945134
|
||||
if err != nil {
|
||||
ra.log.Audit(fmt.Sprintf("Revocation error - %s - %s", serialString, err))
|
||||
} else {
|
||||
ra.log.Audit(fmt.Sprintf("Revocation - %s", serialString))
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (ra *RegistrationAuthorityImpl) OnValidationUpdate(authz core.Authorization) {
|
||||
func (ra *RegistrationAuthorityImpl) OnValidationUpdate(authz core.Authorization) error {
|
||||
// Check to see whether the updated validations are sufficient
|
||||
// Current policy is to accept if any validation succeeded
|
||||
for _, val := range authz.Challenges {
|
||||
|
|
@ -239,5 +320,5 @@ func (ra *RegistrationAuthorityImpl) OnValidationUpdate(authz core.Authorization
|
|||
}
|
||||
|
||||
// Finalize the authorization (error ignored)
|
||||
_ = ra.SA.FinalizeAuthorization(authz)
|
||||
return ra.SA.FinalizeAuthorization(authz)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,11 +7,12 @@ package rpc
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"log"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/streadway/amqp"
|
||||
"github.com/letsencrypt/boulder/core"
|
||||
blog "github.com/letsencrypt/boulder/log"
|
||||
)
|
||||
|
||||
// TODO: AMQP-RPC messages should be wrapped in JWS. To implement that,
|
||||
|
|
@ -51,7 +52,7 @@ func amqpConnect(url string) (ch *amqp.Channel, err error) {
|
|||
}
|
||||
|
||||
// A simplified way to declare and subscribe to an AMQP queue
|
||||
func amqpSubscribe(ch *amqp.Channel, name string) (msgs <-chan amqp.Delivery, err error) {
|
||||
func amqpSubscribe(ch *amqp.Channel, name string, log *blog.AuditLogger) (msgs <-chan amqp.Delivery, err error) {
|
||||
err = ch.ExchangeDeclare(
|
||||
AmqpExchange,
|
||||
AmqpExchangeType,
|
||||
|
|
@ -61,7 +62,7 @@ func amqpSubscribe(ch *amqp.Channel, name string) (msgs <-chan amqp.Delivery, er
|
|||
AmqpNoWait,
|
||||
nil)
|
||||
if err != nil {
|
||||
log.Fatalf("Could not declare exchange: %s", err)
|
||||
log.Crit(fmt.Sprintf("Could not declare exchange: %s", err))
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -73,7 +74,7 @@ func amqpSubscribe(ch *amqp.Channel, name string) (msgs <-chan amqp.Delivery, er
|
|||
AmqpNoWait,
|
||||
nil)
|
||||
if err != nil {
|
||||
log.Fatalf("Could not declare queue: %s", err)
|
||||
log.Crit(fmt.Sprintf("Could not declare queue: %s", err))
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -84,7 +85,7 @@ func amqpSubscribe(ch *amqp.Channel, name string) (msgs <-chan amqp.Delivery, er
|
|||
false,
|
||||
nil)
|
||||
if err != nil {
|
||||
log.Fatalf("Could not bind queue: %s", err)
|
||||
log.Crit(fmt.Sprintf("Could not bind queue: %s", err))
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -97,7 +98,7 @@ func amqpSubscribe(ch *amqp.Channel, name string) (msgs <-chan amqp.Delivery, er
|
|||
AmqpNoWait,
|
||||
nil)
|
||||
if err != nil {
|
||||
log.Fatalf("Could not subscribe to queue: %s", err)
|
||||
log.Crit(fmt.Sprintf("Could not subscribe to queue: %s", err))
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -113,6 +114,7 @@ func amqpSubscribe(ch *amqp.Channel, name string) (msgs <-chan amqp.Delivery, er
|
|||
type AmqpRPCServer struct {
|
||||
serverQueue string
|
||||
channel *amqp.Channel
|
||||
log *blog.AuditLogger
|
||||
dispatchTable map[string]func([]byte) []byte
|
||||
}
|
||||
|
||||
|
|
@ -120,9 +122,11 @@ type AmqpRPCServer struct {
|
|||
// Note that you must call Start() to actually start the server
|
||||
// listening for requests.
|
||||
func NewAmqpRPCServer(serverQueue string, channel *amqp.Channel) *AmqpRPCServer {
|
||||
log := blog.GetAuditLogger()
|
||||
return &AmqpRPCServer{
|
||||
serverQueue: serverQueue,
|
||||
channel: channel,
|
||||
log: log,
|
||||
dispatchTable: make(map[string]func([]byte) []byte),
|
||||
}
|
||||
}
|
||||
|
|
@ -134,7 +138,7 @@ func (rpc *AmqpRPCServer) Handle(method string, handler func([]byte) []byte) {
|
|||
// 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)
|
||||
msgs, err := amqpSubscribe(rpc.channel, rpc.serverQueue, rpc.log)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
|
@ -143,12 +147,14 @@ func (rpc *AmqpRPCServer) Start() (err error) {
|
|||
for msg := range msgs {
|
||||
// XXX-JWS: jws.Verify(body)
|
||||
cb, present := rpc.dispatchTable[msg.Type]
|
||||
log.Printf(" [s<] received %s(%s) [%s]", msg.Type, core.B64enc(msg.Body), msg.CorrelationId)
|
||||
rpc.log.Info(fmt.Sprintf(" [s<] received %s(%s) [%s]", msg.Type, core.B64enc(msg.Body), msg.CorrelationId))
|
||||
if !present {
|
||||
// AUDIT[ Misrouted Messages ] f523f21f-12d2-4c31-b2eb-ee4b7d96d60e
|
||||
rpc.log.Audit(fmt.Sprintf("Misrouted message: %s - %s - %s", msg.Type, core.B64enc(msg.Body), msg.CorrelationId))
|
||||
continue
|
||||
}
|
||||
response := cb(msg.Body)
|
||||
log.Printf(" [s>] sending %s(%s) [%s]", msg.Type, core.B64enc(response), msg.CorrelationId)
|
||||
rpc.log.Info(fmt.Sprintf(" [s>] sending %s(%s) [%s]", msg.Type, core.B64enc(response), msg.CorrelationId))
|
||||
rpc.channel.Publish(
|
||||
AmqpExchange,
|
||||
msg.ReplyTo,
|
||||
|
|
@ -188,6 +194,7 @@ type AmqpRPCCLient struct {
|
|||
channel *amqp.Channel
|
||||
pending map[string]chan []byte
|
||||
timeout time.Duration
|
||||
log *blog.AuditLogger
|
||||
}
|
||||
|
||||
func NewAmqpRPCCLient(clientQueue, serverQueue string, channel *amqp.Channel) (rpc *AmqpRPCCLient, err error) {
|
||||
|
|
@ -197,10 +204,11 @@ func NewAmqpRPCCLient(clientQueue, serverQueue string, channel *amqp.Channel) (r
|
|||
channel: channel,
|
||||
pending: make(map[string]chan []byte),
|
||||
timeout: 10 * time.Second,
|
||||
log: blog.GetAuditLogger(),
|
||||
}
|
||||
|
||||
// Subscribe to the response queue and dispatch
|
||||
msgs, err := amqpSubscribe(rpc.channel, clientQueue)
|
||||
msgs, err := amqpSubscribe(rpc.channel, clientQueue, nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
|
@ -211,7 +219,7 @@ func NewAmqpRPCCLient(clientQueue, serverQueue string, channel *amqp.Channel) (r
|
|||
corrID := msg.CorrelationId
|
||||
responseChan, present := rpc.pending[corrID]
|
||||
|
||||
log.Printf(" [c<] received %s(%s) [%s]", msg.Type, core.B64enc(msg.Body), corrID)
|
||||
rpc.log.Debug(fmt.Sprintf(" [c<] received %s(%s) [%s]", msg.Type, core.B64enc(msg.Body), corrID))
|
||||
if !present {
|
||||
continue
|
||||
}
|
||||
|
|
@ -236,7 +244,7 @@ func (rpc *AmqpRPCCLient) Dispatch(method string, body []byte) chan []byte {
|
|||
rpc.pending[corrID] = responseChan
|
||||
|
||||
// Send the request
|
||||
log.Printf(" [c>] sending %s(%s) [%s]", method, core.B64enc(body), corrID)
|
||||
rpc.log.Debug(fmt.Sprintf(" [c>] sending %s(%s) [%s]", method, core.B64enc(body), corrID))
|
||||
rpc.channel.Publish(
|
||||
AmqpExchange,
|
||||
rpc.serverQueue,
|
||||
|
|
@ -257,15 +265,13 @@ func (rpc *AmqpRPCCLient) DispatchSync(method string, body []byte) (response []b
|
|||
case response = <-rpc.Dispatch(method, body):
|
||||
return
|
||||
case <-time.After(rpc.timeout):
|
||||
log.Printf(" [c!] AMQP-RPC timeout [%s]", method)
|
||||
rpc.log.Warning(fmt.Sprintf(" [c!] AMQP-RPC timeout [%s]", method))
|
||||
err = errors.New("AMQP-RPC timeout")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (rpc *AmqpRPCCLient) SyncDispatchWithTimeout(method string, body []byte, ttl time.Duration) (response []byte, err error) {
|
||||
switch {
|
||||
|
||||
}
|
||||
err = errors.New("Not Implemented")
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,11 +9,12 @@ import (
|
|||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"log"
|
||||
"fmt"
|
||||
|
||||
jose "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/square/go-jose"
|
||||
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/streadway/amqp"
|
||||
"github.com/letsencrypt/boulder/core"
|
||||
jose "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/square/go-jose"
|
||||
blog "github.com/letsencrypt/boulder/log"
|
||||
)
|
||||
|
||||
// This file defines RPC wrappers around the ${ROLE}Impl classes,
|
||||
|
|
@ -78,18 +79,31 @@ type certificateRequest struct {
|
|||
RegID int64
|
||||
}
|
||||
|
||||
func improperMessage(method string, err error, obj interface{}) {
|
||||
log := blog.GetAuditLogger()
|
||||
log.Audit(fmt.Sprintf("Improper message. method: %s err: %s data: %+v", method, err, obj))
|
||||
}
|
||||
func errorCondition(method string, err error, obj interface{}) {
|
||||
log := blog.GetAuditLogger()
|
||||
log.Audit(fmt.Sprintf("Error condition. method: %s err: %s data: %+v", method, err, obj))
|
||||
}
|
||||
|
||||
func NewRegistrationAuthorityServer(serverQueue string, channel *amqp.Channel, impl core.RegistrationAuthority) (*AmqpRPCServer, error) {
|
||||
log := blog.GetAuditLogger()
|
||||
rpc := NewAmqpRPCServer(serverQueue, channel)
|
||||
|
||||
rpc.Handle(MethodNewRegistration, func(req []byte) (response []byte) {
|
||||
var rr registrationRequest
|
||||
err := json.Unmarshal(req, &rr)
|
||||
if err != nil {
|
||||
if err := json.Unmarshal(req, &rr); err != nil {
|
||||
// AUDIT[ Improper Messages ] 0786b6f2-91ca-4f48-9883-842a19084c64
|
||||
improperMessage(MethodNewRegistration, err, req)
|
||||
return nil
|
||||
}
|
||||
|
||||
reg, err := impl.NewRegistration(rr.Reg, rr.Key)
|
||||
if err != nil {
|
||||
// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
|
||||
errorCondition(MethodNewRegistration, err, reg)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -103,11 +117,15 @@ func NewRegistrationAuthorityServer(serverQueue string, channel *amqp.Channel, i
|
|||
rpc.Handle(MethodNewAuthorization, func(req []byte) (response []byte) {
|
||||
var ar authorizationRequest
|
||||
if err := json.Unmarshal(req, &ar); err != nil {
|
||||
// AUDIT[ Improper Messages ] 0786b6f2-91ca-4f48-9883-842a19084c64
|
||||
improperMessage(MethodNewAuthorization, err, req)
|
||||
return nil
|
||||
}
|
||||
|
||||
authz, err := impl.NewAuthorization(ar.Authz, ar.RegID)
|
||||
if err != nil {
|
||||
// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
|
||||
errorCondition(MethodNewAuthorization, err, ar)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -119,21 +137,22 @@ func NewRegistrationAuthorityServer(serverQueue string, channel *amqp.Channel, i
|
|||
})
|
||||
|
||||
rpc.Handle(MethodNewCertificate, func(req []byte) []byte {
|
||||
log.Printf(" [.] Entering MethodNewCertificate")
|
||||
log.Info(fmt.Sprintf(" [.] Entering MethodNewCertificate"))
|
||||
var cr certificateRequest
|
||||
if err := json.Unmarshal(req, &cr); err != nil {
|
||||
log.Printf(" [!] Error unmarshaling certificate request: %s", err.Error())
|
||||
log.Printf(" JSON data: %s", string(req))
|
||||
// AUDIT[ Improper Messages ] 0786b6f2-91ca-4f48-9883-842a19084c64
|
||||
improperMessage(MethodNewCertificate, err, req)
|
||||
return nil
|
||||
}
|
||||
log.Printf(" [.] No problem unmarshaling request")
|
||||
log.Info(fmt.Sprintf(" [.] No problem unmarshaling request"))
|
||||
|
||||
cert, err := impl.NewCertificate(cr.Req, cr.RegID)
|
||||
if err != nil {
|
||||
log.Printf(" [!] Error issuing new certificate: %s", err.Error())
|
||||
// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
|
||||
errorCondition(MethodNewCertificate, err, cr)
|
||||
return nil
|
||||
}
|
||||
log.Printf(" [.] No problem issuing new cert")
|
||||
log.Info(fmt.Sprintf(" [.] No problem issuing new cert"))
|
||||
|
||||
response, err := json.Marshal(cert)
|
||||
if err != nil {
|
||||
|
|
@ -148,11 +167,15 @@ func NewRegistrationAuthorityServer(serverQueue string, channel *amqp.Channel, i
|
|||
}
|
||||
err := json.Unmarshal(req, &request)
|
||||
if err != nil {
|
||||
// AUDIT[ Improper Messages ] 0786b6f2-91ca-4f48-9883-842a19084c64
|
||||
improperMessage(MethodUpdateRegistration, err, req)
|
||||
return nil
|
||||
}
|
||||
|
||||
reg, err := impl.UpdateRegistration(request.Base, request.Update)
|
||||
if err != nil {
|
||||
// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
|
||||
errorCondition(MethodUpdateRegistration, err, request)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -171,11 +194,15 @@ func NewRegistrationAuthorityServer(serverQueue string, channel *amqp.Channel, i
|
|||
}
|
||||
err := json.Unmarshal(req, &authz)
|
||||
if err != nil {
|
||||
// AUDIT[ Improper Messages ] 0786b6f2-91ca-4f48-9883-842a19084c64
|
||||
improperMessage(MethodUpdateAuthorization, err, req)
|
||||
return nil
|
||||
}
|
||||
|
||||
newAuthz, err := impl.UpdateAuthorization(authz.Authz, authz.Index, authz.Response)
|
||||
if err != nil {
|
||||
// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
|
||||
errorCondition(MethodUpdateAuthorization, err, authz)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -189,21 +216,32 @@ func NewRegistrationAuthorityServer(serverQueue string, channel *amqp.Channel, i
|
|||
rpc.Handle(MethodRevokeCertificate, func(req []byte) []byte {
|
||||
certs, err := x509.ParseCertificates(req)
|
||||
if err != nil || len(certs) == 0 {
|
||||
// AUDIT[ Improper Messages ] 0786b6f2-91ca-4f48-9883-842a19084c64
|
||||
improperMessage(MethodRevokeCertificate, err, req)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Error explicitly ignored since response is nil anyway
|
||||
_ = impl.RevokeCertificate(*certs[0])
|
||||
err = impl.RevokeCertificate(*certs[0])
|
||||
if err != nil {
|
||||
// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
|
||||
errorCondition(MethodRevokeCertificate, err, certs)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
rpc.Handle(MethodOnValidationUpdate, func(req []byte) []byte {
|
||||
var authz core.Authorization
|
||||
if err := json.Unmarshal(req, &authz); err != nil {
|
||||
// AUDIT[ Improper Messages ] 0786b6f2-91ca-4f48-9883-842a19084c64
|
||||
improperMessage(MethodOnValidationUpdate, err, req)
|
||||
return nil
|
||||
}
|
||||
|
||||
impl.OnValidationUpdate(authz)
|
||||
if err := impl.OnValidationUpdate(authz); err != nil {
|
||||
// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
|
||||
errorCondition(MethodOnValidationUpdate, err, authz)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
|
|
@ -317,7 +355,7 @@ func (rac RegistrationAuthorityClient) RevokeCertificate(cert x509.Certificate)
|
|||
return
|
||||
}
|
||||
|
||||
func (rac RegistrationAuthorityClient) OnValidationUpdate(authz core.Authorization) {
|
||||
func (rac RegistrationAuthorityClient) OnValidationUpdate(authz core.Authorization) (err error) {
|
||||
data, err := json.Marshal(authz)
|
||||
if err != nil {
|
||||
return
|
||||
|
|
@ -335,11 +373,15 @@ func NewValidationAuthorityServer(serverQueue string, channel *amqp.Channel, imp
|
|||
rpc.Handle(MethodUpdateValidations, func(req []byte) []byte {
|
||||
var authz core.Authorization
|
||||
if err := json.Unmarshal(req, &authz); err != nil {
|
||||
// AUDIT[ Improper Messages ] 0786b6f2-91ca-4f48-9883-842a19084c64
|
||||
improperMessage(MethodUpdateValidations, err, req)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Error explicitly ignored since response is nil anyway
|
||||
_ = impl.UpdateValidations(authz)
|
||||
if err := impl.UpdateValidations(authz); err != nil {
|
||||
// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
|
||||
errorCondition(MethodUpdateValidations, err, authz)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
|
|
@ -387,11 +429,15 @@ func NewCertificateAuthorityServer(serverQueue string, channel *amqp.Channel, im
|
|||
|
||||
csr, err := x509.ParseCertificateRequest(icReq.Bytes)
|
||||
if err != nil {
|
||||
// AUDIT[ Improper Messages ] 0786b6f2-91ca-4f48-9883-842a19084c64
|
||||
improperMessage(MethodIssueCertificate, err, req)
|
||||
return nil // XXX
|
||||
}
|
||||
|
||||
cert, err := impl.IssueCertificate(*csr, icReq.RegID)
|
||||
if err != nil {
|
||||
// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
|
||||
errorCondition(MethodIssueCertificate, err, csr)
|
||||
return nil // XXX
|
||||
}
|
||||
|
||||
|
|
@ -404,7 +450,11 @@ func NewCertificateAuthorityServer(serverQueue string, channel *amqp.Channel, im
|
|||
})
|
||||
|
||||
rpc.Handle(MethodRevokeCertificateCA, func(req []byte) []byte {
|
||||
_ = impl.RevokeCertificate(string(req)) // XXX
|
||||
if err := impl.RevokeCertificate(string(req)); err != nil {
|
||||
// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
|
||||
errorCondition(MethodRevokeCertificateCA, err, req)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
|
|
@ -466,37 +516,44 @@ func NewStorageAuthorityServer(serverQueue string, channel *amqp.Channel, impl c
|
|||
|
||||
reg, err := impl.GetRegistration(intReq.ID)
|
||||
if err != nil {
|
||||
// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
|
||||
errorCondition(MethodGetRegistration, err, req)
|
||||
return nil
|
||||
}
|
||||
|
||||
jsonReg, err := json.Marshal(reg)
|
||||
response, err = json.Marshal(reg)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
response = jsonReg
|
||||
return response
|
||||
})
|
||||
|
||||
rpc.Handle(MethodGetRegistrationByKey, func(req []byte) (response []byte) {
|
||||
var jwk jose.JsonWebKey
|
||||
err := json.Unmarshal(req, &jwk)
|
||||
if err := json.Unmarshal(req, &jwk); err != nil {
|
||||
// AUDIT[ Improper Messages ] 0786b6f2-91ca-4f48-9883-842a19084c64
|
||||
improperMessage(MethodGetRegistrationByKey, err, req)
|
||||
}
|
||||
|
||||
reg, err := impl.GetRegistrationByKey(jwk)
|
||||
if err != nil {
|
||||
// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
|
||||
errorCondition(MethodGetRegistrationByKey, err, jwk)
|
||||
return nil
|
||||
}
|
||||
|
||||
jsonReg, err := json.Marshal(reg)
|
||||
response, err = json.Marshal(reg)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
response = jsonReg
|
||||
return response
|
||||
})
|
||||
|
||||
rpc.Handle(MethodGetAuthorization, func(req []byte) []byte {
|
||||
authz, err := impl.GetAuthorization(string(req))
|
||||
if err != nil {
|
||||
// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
|
||||
errorCondition(MethodGetAuthorization, err, req)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -519,6 +576,8 @@ func NewStorageAuthorityServer(serverQueue string, channel *amqp.Channel, impl c
|
|||
|
||||
id, err := impl.AddCertificate(icReq.Bytes, icReq.RegID)
|
||||
if err != nil {
|
||||
// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
|
||||
errorCondition(MethodAddCertificate, err, req)
|
||||
return nil
|
||||
}
|
||||
return []byte(id)
|
||||
|
|
@ -528,12 +587,18 @@ func NewStorageAuthorityServer(serverQueue string, channel *amqp.Channel, impl c
|
|||
var registration core.Registration
|
||||
err := json.Unmarshal(req, registration)
|
||||
if err != nil {
|
||||
// AUDIT[ Improper Messages ] 0786b6f2-91ca-4f48-9883-842a19084c64
|
||||
improperMessage(MethodNewRegistration, err, req)
|
||||
return nil
|
||||
}
|
||||
|
||||
output, err := impl.NewRegistration(registration)
|
||||
if err != nil {
|
||||
// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
|
||||
errorCondition(MethodNewRegistration, err, registration)
|
||||
return nil
|
||||
}
|
||||
|
||||
jsonOutput, err := json.Marshal(output)
|
||||
if err != nil {
|
||||
return nil
|
||||
|
|
@ -543,7 +608,10 @@ func NewStorageAuthorityServer(serverQueue string, channel *amqp.Channel, impl c
|
|||
|
||||
rpc.Handle(MethodNewPendingAuthorization, func(req []byte) (response []byte) {
|
||||
id, err := impl.NewPendingAuthorization()
|
||||
if err == nil {
|
||||
if err != nil {
|
||||
// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
|
||||
errorCondition(MethodNewPendingAuthorization, err, req)
|
||||
} else {
|
||||
response = []byte(id)
|
||||
}
|
||||
return response
|
||||
|
|
@ -551,31 +619,40 @@ func NewStorageAuthorityServer(serverQueue string, channel *amqp.Channel, impl c
|
|||
|
||||
rpc.Handle(MethodUpdatePendingAuthorization, func(req []byte) []byte {
|
||||
var authz core.Authorization
|
||||
err := json.Unmarshal(req, authz)
|
||||
if err != nil {
|
||||
if err := json.Unmarshal(req, authz); err != nil {
|
||||
// AUDIT[ Improper Messages ] 0786b6f2-91ca-4f48-9883-842a19084c64
|
||||
improperMessage(MethodUpdatePendingAuthorization, err, req)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Error explicitly ignored since response is nil anyway
|
||||
_ = impl.UpdatePendingAuthorization(authz)
|
||||
if err := impl.UpdatePendingAuthorization(authz); err != nil {
|
||||
// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
|
||||
errorCondition(MethodUpdatePendingAuthorization, err, authz)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
rpc.Handle(MethodFinalizeAuthorization, func(req []byte) []byte {
|
||||
var authz core.Authorization
|
||||
err := json.Unmarshal(req, authz)
|
||||
if err != nil {
|
||||
if err := json.Unmarshal(req, authz); err != nil {
|
||||
// AUDIT[ Improper Messages ] 0786b6f2-91ca-4f48-9883-842a19084c64
|
||||
improperMessage(MethodFinalizeAuthorization, err, req)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Error explicitly ignored since response is nil anyway
|
||||
_ = impl.FinalizeAuthorization(authz)
|
||||
if err := impl.FinalizeAuthorization(authz); err != nil {
|
||||
// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
|
||||
errorCondition(MethodFinalizeAuthorization, err, authz)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
rpc.Handle(MethodGetCertificate, func(req []byte) (response []byte) {
|
||||
cert, err := impl.GetCertificate(string(req))
|
||||
if err == nil {
|
||||
if err != nil {
|
||||
// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
|
||||
errorCondition(MethodGetCertificate, err, req)
|
||||
} else {
|
||||
response = []byte(cert)
|
||||
}
|
||||
return response
|
||||
|
|
@ -583,7 +660,10 @@ func NewStorageAuthorityServer(serverQueue string, channel *amqp.Channel, impl c
|
|||
|
||||
rpc.Handle(MethodGetCertificateByShortSerial, func(req []byte) (response []byte) {
|
||||
cert, err := impl.GetCertificateByShortSerial(string(req))
|
||||
if err == nil {
|
||||
if err != nil {
|
||||
// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
|
||||
errorCondition(MethodGetCertificateByShortSerial, err, req)
|
||||
} else {
|
||||
response = []byte(cert)
|
||||
}
|
||||
return response
|
||||
|
|
@ -592,6 +672,8 @@ func NewStorageAuthorityServer(serverQueue string, channel *amqp.Channel, impl c
|
|||
rpc.Handle(MethodGetCertificateStatus, func(req []byte) (response []byte) {
|
||||
status, err := impl.GetCertificateStatus(string(req))
|
||||
if err != nil {
|
||||
// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
|
||||
errorCondition(MethodGetCertificateStatus, err, req)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -609,13 +691,18 @@ func NewStorageAuthorityServer(serverQueue string, channel *amqp.Channel, impl c
|
|||
ReasonCode int
|
||||
}
|
||||
|
||||
err := json.Unmarshal(req, revokeReq)
|
||||
if err != nil {
|
||||
if err := json.Unmarshal(req, revokeReq); err != nil {
|
||||
// AUDIT[ Improper Messages ] 0786b6f2-91ca-4f48-9883-842a19084c64
|
||||
improperMessage(MethodMarkCertificateRevoked, err, req)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Error explicitly ignored since response is nil anyway
|
||||
_ = impl.MarkCertificateRevoked(revokeReq.Serial, revokeReq.OcspResponse, revokeReq.ReasonCode)
|
||||
err := impl.MarkCertificateRevoked(revokeReq.Serial, revokeReq.OcspResponse, revokeReq.ReasonCode)
|
||||
if err != nil {
|
||||
// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
|
||||
errorCondition(MethodMarkCertificateRevoked, err, revokeReq)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
|
|
@ -624,12 +711,16 @@ func NewStorageAuthorityServer(serverQueue string, channel *amqp.Channel, impl c
|
|||
Names []string
|
||||
}
|
||||
|
||||
err := json.Unmarshal(req, csrReq)
|
||||
if err != nil {
|
||||
if err := json.Unmarshal(req, csrReq); err != nil {
|
||||
// AUDIT[ Improper Messages ] 0786b6f2-91ca-4f48-9883-842a19084c64
|
||||
improperMessage(MethodAddDeniedCSR, err, req)
|
||||
return nil
|
||||
}
|
||||
|
||||
err = impl.AddDeniedCSR(csrReq.Names)
|
||||
if err := impl.AddDeniedCSR(csrReq.Names); err != nil {
|
||||
// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
|
||||
errorCondition(MethodAddDeniedCSR, err, csrReq)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
|
|
@ -640,11 +731,15 @@ func NewStorageAuthorityServer(serverQueue string, channel *amqp.Channel, impl c
|
|||
|
||||
err := json.Unmarshal(req, csrReq)
|
||||
if err != nil {
|
||||
// AUDIT[ Improper Messages ] 0786b6f2-91ca-4f48-9883-842a19084c64
|
||||
improperMessage(MethodAlreadyDeniedCSR, err, req)
|
||||
return nil
|
||||
}
|
||||
|
||||
exists, err := impl.AlreadyDeniedCSR(csrReq.Names)
|
||||
if err != nil {
|
||||
// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
|
||||
errorCondition(MethodAlreadyDeniedCSR, err, csrReq)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@ import (
|
|||
|
||||
gorp "github.com/letsencrypt/boulder/Godeps/_workspace/src/gopkg.in/gorp.v1"
|
||||
|
||||
"github.com/letsencrypt/boulder/core"
|
||||
jose "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/square/go-jose"
|
||||
"github.com/letsencrypt/boulder/core"
|
||||
blog "github.com/letsencrypt/boulder/log"
|
||||
)
|
||||
|
||||
|
|
@ -293,21 +293,21 @@ func statusIsPending(status core.AcmeStatus) bool {
|
|||
return status == core.StatusPending || status == core.StatusProcessing || status == core.StatusUnknown
|
||||
}
|
||||
|
||||
func existingPending(tx *gorp.Transaction, id string) (bool) {
|
||||
func existingPending(tx *gorp.Transaction, id string) bool {
|
||||
var count int64
|
||||
_ = tx.SelectOne(&count, "SELECT count(*) FROM pending_authz WHERE id = :id", map[string]interface{} {"id": id})
|
||||
_ = tx.SelectOne(&count, "SELECT count(*) FROM pending_authz WHERE id = :id", map[string]interface{}{"id": id})
|
||||
return count > 0
|
||||
}
|
||||
|
||||
func existingFinal(tx *gorp.Transaction, id string) (bool) {
|
||||
func existingFinal(tx *gorp.Transaction, id string) bool {
|
||||
var count int64
|
||||
_ = tx.SelectOne(&count, "SELECT count(*) FROM authz WHERE id = :id", map[string]interface{} {"id": id})
|
||||
_ = tx.SelectOne(&count, "SELECT count(*) FROM authz WHERE id = :id", map[string]interface{}{"id": id})
|
||||
return count > 0
|
||||
}
|
||||
|
||||
func existingRegistration(tx *gorp.Transaction, id int64) (bool) {
|
||||
func existingRegistration(tx *gorp.Transaction, id int64) bool {
|
||||
var count int64
|
||||
_ = tx.SelectOne(&count, "SELECT count(*) FROM registrations WHERE id = :id", map[string]interface{} {"id": id})
|
||||
_ = tx.SelectOne(&count, "SELECT count(*) FROM registrations WHERE id = :id", map[string]interface{}{"id": id})
|
||||
return count > 0
|
||||
}
|
||||
|
||||
|
|
@ -330,7 +330,7 @@ func (ssa *SQLStorageAuthority) GetRegistrationByKey(key jose.JsonWebKey) (reg c
|
|||
return
|
||||
}
|
||||
|
||||
err = ssa.dbMap.SelectOne(®, "SELECT * FROM registrations WHERE key = :key", map[string]interface{} {"key": string(keyJson)})
|
||||
err = ssa.dbMap.SelectOne(®, "SELECT * FROM registrations WHERE key = :key", map[string]interface{}{"key": string(keyJson)})
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -383,7 +383,7 @@ func (ssa *SQLStorageAuthority) GetCertificateByShortSerial(shortSerial string)
|
|||
|
||||
var certificate core.Certificate
|
||||
err = ssa.dbMap.SelectOne(&certificate, "SELECT * FROM certificates WHERE serial LIKE :shortSerial",
|
||||
map[string]interface{} {"shortSerial": shortSerial+"%"})
|
||||
map[string]interface{}{"shortSerial": shortSerial + "%"})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
|
@ -400,7 +400,7 @@ func (ssa *SQLStorageAuthority) GetCertificate(serial string) (cert []byte, err
|
|||
|
||||
var certificate core.Certificate
|
||||
err = ssa.dbMap.SelectOne(&certificate, "SELECT * FROM certificates WHERE serial = :serial",
|
||||
map[string]interface{} {"serial": serial})
|
||||
map[string]interface{}{"serial": serial})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
|
@ -706,7 +706,7 @@ func (ssa *SQLStorageAuthority) AlreadyDeniedCSR(names []string) (already bool,
|
|||
err = ssa.dbMap.SelectOne(
|
||||
&denied,
|
||||
"SELECT count(*) FROM deniedCsrs WHERE names = :names",
|
||||
map[string]interface{} {"names": strings.ToLower(strings.Join(names, ","))},
|
||||
map[string]interface{}{"names": strings.ToLower(strings.Join(names, ","))},
|
||||
)
|
||||
if err != nil {
|
||||
return
|
||||
|
|
@ -717,4 +717,3 @@ func (ssa *SQLStorageAuthority) AlreadyDeniedCSR(names []string) (already bool,
|
|||
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
11
test.sh
11
test.sh
|
|
@ -63,4 +63,15 @@ else
|
|||
run go test ${dirlist}
|
||||
fi
|
||||
|
||||
echo "Checking for unformatted files:"
|
||||
unformatted=$(find . -name "*.go" -not -path "./Godeps/*" -print | xargs -n1 gofmt -l)
|
||||
if [ "x${unformatted}" != "x" ] ; then
|
||||
echo "Unformatted files found; setting failure state."
|
||||
echo "Please run 'go fmt' on each of these files and amend your commit to continue."
|
||||
FAILURE=1
|
||||
for f in ${unformatted}; do
|
||||
echo "- ${f}"
|
||||
done
|
||||
fi
|
||||
|
||||
exit ${FAILURE}
|
||||
|
|
|
|||
|
|
@ -87,6 +87,12 @@ func AssertContains(t *testing.T, haystack string, needle string) {
|
|||
}
|
||||
}
|
||||
|
||||
func AssertNotContains(t *testing.T, haystack string, needle string) {
|
||||
if strings.Contains(haystack, needle) {
|
||||
t.Errorf("%s String [%s] contains [%s]", caller(), haystack, needle)
|
||||
}
|
||||
}
|
||||
|
||||
func AssertSeverity(t *testing.T, data string, severity int) {
|
||||
expected := fmt.Sprintf("\"severity\":%d", severity)
|
||||
AssertContains(t, data, expected)
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ func NewValidationAuthorityImpl(tm bool) ValidationAuthorityImpl {
|
|||
|
||||
// Validation methods
|
||||
|
||||
func (va ValidationAuthorityImpl) validateSimpleHTTPS(identifier core.AcmeIdentifier, input core.Challenge) (core.Challenge) {
|
||||
func (va ValidationAuthorityImpl) validateSimpleHTTPS(identifier core.AcmeIdentifier, input core.Challenge) core.Challenge {
|
||||
challenge := input
|
||||
|
||||
if len(challenge.Path) == 0 {
|
||||
|
|
@ -105,7 +105,7 @@ func (va ValidationAuthorityImpl) validateSimpleHTTPS(identifier core.AcmeIdenti
|
|||
return challenge
|
||||
}
|
||||
|
||||
func (va ValidationAuthorityImpl) validateDvsni(identifier core.AcmeIdentifier, input core.Challenge) (core.Challenge) {
|
||||
func (va ValidationAuthorityImpl) validateDvsni(identifier core.AcmeIdentifier, input core.Challenge) core.Challenge {
|
||||
challenge := input
|
||||
|
||||
if identifier.Type != "dns" {
|
||||
|
|
|
|||
|
|
@ -6,24 +6,24 @@
|
|||
package va
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"net"
|
||||
"net/http"
|
||||
"fmt"
|
||||
"strings"
|
||||
"math/big"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/sha256"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
jose "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/square/go-jose"
|
||||
"github.com/letsencrypt/boulder/core"
|
||||
"github.com/letsencrypt/boulder/test"
|
||||
jose "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/square/go-jose"
|
||||
)
|
||||
|
||||
func bigIntFromB64(b64 string) *big.Int {
|
||||
|
|
@ -160,7 +160,7 @@ func TestSimpleHttps(t *testing.T) {
|
|||
func TestDvsni(t *testing.T) {
|
||||
va := NewValidationAuthorityImpl(true)
|
||||
|
||||
a := []byte{1,2,3,4,5,6,7,8,9,0}
|
||||
a := []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0}
|
||||
ba := core.B64enc(a)
|
||||
chall := core.Challenge{R: ba, S: ba}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@
|
|||
package wfe
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"bytes"
|
||||
"crypto/x509"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
|
@ -26,6 +26,7 @@ import (
|
|||
blog "github.com/letsencrypt/boulder/log"
|
||||
)
|
||||
|
||||
// WebFrontEndImpl represents a Boulder web service and its resources
|
||||
type WebFrontEndImpl struct {
|
||||
RA core.RegistrationAuthority
|
||||
SA core.StorageGetter
|
||||
|
|
@ -54,6 +55,7 @@ type WebFrontEndImpl struct {
|
|||
IssuerCert []byte
|
||||
}
|
||||
|
||||
// NewWebFrontEndImpl constructs a web service for Boulder
|
||||
func NewWebFrontEndImpl() WebFrontEndImpl {
|
||||
logger := blog.GetAuditLogger()
|
||||
logger.Notice("Web Front End Starting")
|
||||
|
|
@ -122,7 +124,7 @@ func parseIDFromPath(path string) string {
|
|||
return re.ReplaceAllString(path, "")
|
||||
}
|
||||
|
||||
// Problem objects represent problem documents, which are
|
||||
// ProblemType objects represent problem documents, which are
|
||||
// returned with HTTP error responses
|
||||
// https://tools.ietf.org/html/draft-ietf-appsawg-http-problem-00
|
||||
type ProblemType string
|
||||
|
|
@ -194,8 +196,9 @@ func (wfe *WebFrontEndImpl) verifyPOST(request *http.Request, regCheck bool) ([]
|
|||
return []byte(payload), key, reg, nil
|
||||
}
|
||||
|
||||
func (wfe *WebFrontEndImpl) sendError(response http.ResponseWriter, message string, code int) {
|
||||
problem := problem{Detail: message}
|
||||
// Notify the client of an error condition and log it for audit purposes.
|
||||
func (wfe *WebFrontEndImpl) sendError(response http.ResponseWriter, details string, debug interface{}, code int) {
|
||||
problem := problem{Detail: details}
|
||||
switch code {
|
||||
case http.StatusForbidden:
|
||||
problem.Type = UnauthorizedProblem
|
||||
|
|
@ -208,11 +211,26 @@ func (wfe *WebFrontEndImpl) sendError(response http.ResponseWriter, message stri
|
|||
case http.StatusInternalServerError:
|
||||
problem.Type = ServerInternalProblem
|
||||
}
|
||||
|
||||
problemDoc, err := json.Marshal(problem)
|
||||
if err != nil {
|
||||
// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
|
||||
wfe.log.Audit(fmt.Sprintf("Could not marshal error message: %s - %+v", err.Error(), problem))
|
||||
problemDoc = []byte("{\"detail\": \"Problem marshalling error message.\"}")
|
||||
}
|
||||
wfe.log.Debug("Sending error to client: " + string(problemDoc))
|
||||
|
||||
switch problem.Type {
|
||||
case ServerInternalProblem:
|
||||
// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
|
||||
wfe.log.Audit(fmt.Sprintf("Internal error - %s - %s", details, debug))
|
||||
case MalformedProblem:
|
||||
// AUDIT[ Improper Messages ] 0786b6f2-91ca-4f48-9883-842a19084c64
|
||||
wfe.log.Audit(fmt.Sprintf("Improper HTTP request - %s - %s", details, debug))
|
||||
case UnauthorizedProblem:
|
||||
// AUDIT[ Improper Messages ] 0786b6f2-91ca-4f48-9883-842a19084c64
|
||||
wfe.log.Audit(fmt.Sprintf("Unauthorized HTTP request - %s - %s", details, debug))
|
||||
}
|
||||
|
||||
// Paraphrased from
|
||||
// https://golang.org/src/net/http/server.go#L1272
|
||||
response.Header().Set("Content-Type", "application/problem+json")
|
||||
|
|
@ -226,36 +244,34 @@ func link(url, relation string) string {
|
|||
|
||||
func (wfe *WebFrontEndImpl) NewRegistration(response http.ResponseWriter, request *http.Request) {
|
||||
if request.Method != "POST" {
|
||||
wfe.sendError(response, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
wfe.sendError(response, "Method not allowed", "", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
body, key, _, err := wfe.verifyPOST(request, false)
|
||||
if err != nil {
|
||||
wfe.sendError(response, "Unable to read/verify body", http.StatusBadRequest)
|
||||
wfe.sendError(response, "Unable to read/verify body", err, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
var init, unmarshalled core.Registration
|
||||
err = json.Unmarshal(body, &unmarshalled)
|
||||
if err != nil {
|
||||
wfe.sendError(response, "Error unmarshaling JSON", http.StatusBadRequest)
|
||||
wfe.sendError(response, "Error unmarshaling JSON", err, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
init.MergeUpdate(unmarshalled)
|
||||
|
||||
reg, err := wfe.RA.NewRegistration(init, *key)
|
||||
if err != nil {
|
||||
wfe.sendError(response,
|
||||
fmt.Sprintf("Error creating new registration: %+v", err),
|
||||
http.StatusInternalServerError)
|
||||
wfe.sendError(response, "Error creating new registration", err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
regURL := wfe.RegBase + string(reg.ID)
|
||||
responseBody, err := json.Marshal(reg)
|
||||
if err != nil {
|
||||
wfe.sendError(response, "Error marshaling authz", http.StatusInternalServerError)
|
||||
wfe.sendError(response, "Error marshaling authz", err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -275,24 +291,23 @@ func (wfe *WebFrontEndImpl) NewRegistration(response http.ResponseWriter, reques
|
|||
|
||||
func (wfe *WebFrontEndImpl) NewAuthorization(response http.ResponseWriter, request *http.Request) {
|
||||
if request.Method != "POST" {
|
||||
wfe.sendError(response, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
wfe.sendError(response, "Method not allowed", request.Method, http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
body, _, currReg, err := wfe.verifyPOST(request, true)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
wfe.sendError(response, "No registration exists matching provided key", http.StatusForbidden)
|
||||
wfe.sendError(response, "No registration exists matching provided key", err, http.StatusForbidden)
|
||||
} else {
|
||||
wfe.sendError(response, "Unable to read/verify body", http.StatusBadRequest)
|
||||
wfe.sendError(response, "Unable to read/verify body", err, http.StatusBadRequest)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
var init core.Authorization
|
||||
if err = json.Unmarshal(body, &init); err != nil {
|
||||
wfe.sendError(response, "Error unmarshaling JSON", http.StatusBadRequest)
|
||||
wfe.sendError(response, "Error unmarshaling JSON", err, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -300,7 +315,7 @@ func (wfe *WebFrontEndImpl) NewAuthorization(response http.ResponseWriter, reque
|
|||
authz, err := wfe.RA.NewAuthorization(init, currReg.ID)
|
||||
if err != nil {
|
||||
wfe.sendError(response,
|
||||
fmt.Sprintf("Error creating new authz: %+v", err),
|
||||
"Error creating new authz", err,
|
||||
http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
|
@ -310,7 +325,7 @@ func (wfe *WebFrontEndImpl) NewAuthorization(response http.ResponseWriter, reque
|
|||
authz.ID = ""
|
||||
responseBody, err := json.Marshal(authz)
|
||||
if err != nil {
|
||||
wfe.sendError(response, "Error marshaling authz", http.StatusInternalServerError)
|
||||
wfe.sendError(response, "Error marshaling authz", err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -327,13 +342,13 @@ func (wfe *WebFrontEndImpl) NewAuthorization(response http.ResponseWriter, reque
|
|||
|
||||
func (wfe *WebFrontEndImpl) RevokeCertificate(response http.ResponseWriter, request *http.Request) {
|
||||
if request.Method != "POST" {
|
||||
wfe.sendError(response, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
wfe.sendError(response, "Method not allowed", request.Method, http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
body, requestKey, _, err := wfe.verifyPOST(request, false)
|
||||
if err != nil {
|
||||
wfe.sendError(response, "Unable to read/verify body", http.StatusBadRequest)
|
||||
wfe.sendError(response, "Unable to read/verify body", err, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -343,36 +358,36 @@ func (wfe *WebFrontEndImpl) RevokeCertificate(response http.ResponseWriter, requ
|
|||
var revokeRequest RevokeRequest
|
||||
if err = json.Unmarshal(body, &revokeRequest); err != nil {
|
||||
wfe.log.Debug(fmt.Sprintf("Couldn't unmarshal in revoke request %s", string(body)))
|
||||
wfe.sendError(response, "Unable to read/verify body", http.StatusBadRequest)
|
||||
wfe.sendError(response, "Unable to read/verify body", err, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
providedCert, err := x509.ParseCertificate(revokeRequest.CertificateDER)
|
||||
if err != nil {
|
||||
wfe.log.Debug("Couldn't parse cert in revoke request.")
|
||||
wfe.sendError(response, "Unable to read/verify body", http.StatusBadRequest)
|
||||
wfe.sendError(response, "Unable to read/verify body", err, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
serial := core.SerialToString(providedCert.SerialNumber)
|
||||
certDER, err := wfe.SA.GetCertificate(serial)
|
||||
if err != nil || !bytes.Equal(certDER, revokeRequest.CertificateDER) {
|
||||
wfe.sendError(response, "No such certificate", http.StatusNotFound)
|
||||
wfe.sendError(response, "No such certificate", err, http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
parsedCertificate, err := x509.ParseCertificate(certDER)
|
||||
if err != nil {
|
||||
wfe.sendError(response, "Invalid certificate", http.StatusInternalServerError)
|
||||
wfe.sendError(response, "Invalid certificate", err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
certStatus, err := wfe.SA.GetCertificateStatus(serial)
|
||||
if err != nil {
|
||||
wfe.sendError(response, "No such certificate", http.StatusNotFound)
|
||||
wfe.sendError(response, "No such certificate", err, http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
if certStatus.Status == core.OCSPStatusRevoked {
|
||||
wfe.sendError(response, "Certificate already revoked", http.StatusConflict)
|
||||
wfe.sendError(response, "Certificate already revoked", "", http.StatusConflict)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -382,6 +397,7 @@ func (wfe *WebFrontEndImpl) RevokeCertificate(response http.ResponseWriter, requ
|
|||
wfe.log.Debug("Key mismatch for revoke")
|
||||
wfe.sendError(response,
|
||||
"Revocation request must be signed by private key of cert to be revoked",
|
||||
requestKey,
|
||||
http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
|
@ -390,6 +406,7 @@ func (wfe *WebFrontEndImpl) RevokeCertificate(response http.ResponseWriter, requ
|
|||
if err != nil {
|
||||
wfe.sendError(response,
|
||||
"Failed to revoke certificate",
|
||||
err,
|
||||
http.StatusInternalServerError)
|
||||
} else {
|
||||
wfe.log.Debug(fmt.Sprintf("Revoked %v", serial))
|
||||
|
|
@ -401,25 +418,24 @@ func (wfe *WebFrontEndImpl) RevokeCertificate(response http.ResponseWriter, requ
|
|||
|
||||
func (wfe *WebFrontEndImpl) NewCertificate(response http.ResponseWriter, request *http.Request) {
|
||||
if request.Method != "POST" {
|
||||
wfe.sendError(response, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
wfe.sendError(response, "Method not allowed", request.Method, http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
body, key, reg, err := wfe.verifyPOST(request, true)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
wfe.sendError(response, "No registration exists matching provided key", http.StatusForbidden)
|
||||
wfe.sendError(response, "No registration exists matching provided key", err, http.StatusForbidden)
|
||||
} else {
|
||||
wfe.sendError(response, "Unable to read/verify body", http.StatusBadRequest)
|
||||
wfe.sendError(response, "Unable to read/verify body", err, http.StatusBadRequest)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
var init core.CertificateRequest
|
||||
if err = json.Unmarshal(body, &init); err != nil {
|
||||
fmt.Println(err)
|
||||
wfe.sendError(response, "Error unmarshaling certificate request", http.StatusBadRequest)
|
||||
wfe.sendError(response, "Error unmarshaling certificate request", err, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -435,7 +451,7 @@ func (wfe *WebFrontEndImpl) NewCertificate(response http.ResponseWriter, request
|
|||
cert, err := wfe.RA.NewCertificate(init, reg.ID)
|
||||
if err != nil {
|
||||
wfe.sendError(response,
|
||||
fmt.Sprintf("Error creating new cert: %+v", err),
|
||||
"Error creating new cert", err,
|
||||
http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
|
@ -474,46 +490,45 @@ func (wfe *WebFrontEndImpl) Challenge(authz core.Authorization, response http.Re
|
|||
}
|
||||
|
||||
if !found {
|
||||
wfe.sendError(response,
|
||||
fmt.Sprintf("Unable to find challenge"),
|
||||
http.StatusNotFound)
|
||||
wfe.sendError(response, "Unable to find challenge", request.URL.RawQuery, http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
switch request.Method {
|
||||
default:
|
||||
wfe.sendError(response, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
wfe.sendError(response, "Method not allowed", "", http.StatusMethodNotAllowed)
|
||||
return
|
||||
|
||||
case "POST":
|
||||
body, _, currReg, err := wfe.verifyPOST(request, true)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
wfe.sendError(response, "No registration exists matching provided key", http.StatusForbidden)
|
||||
wfe.sendError(response, "No registration exists matching provided key", err, http.StatusForbidden)
|
||||
} else {
|
||||
wfe.sendError(response, "Unable to read/verify body", http.StatusBadRequest)
|
||||
wfe.sendError(response, "Unable to read/verify body", err, http.StatusBadRequest)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
var challengeResponse core.Challenge
|
||||
if err = json.Unmarshal(body, &challengeResponse); err != nil {
|
||||
wfe.sendError(response, "Error unmarshaling authorization", http.StatusBadRequest)
|
||||
wfe.sendError(response, "Error unmarshaling authorization", err, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Check that the registration ID matching the key used matches
|
||||
// the registration ID on the authz object
|
||||
if currReg.ID != authz.RegistrationID {
|
||||
wfe.sendError(response, "User registration ID doesn't match registration ID in authorization", http.StatusForbidden)
|
||||
wfe.sendError(response, "User registration ID doesn't match registration ID in authorization",
|
||||
fmt.Sprintf("User: %v != Authorization: %v", currReg.ID, authz.RegistrationID),
|
||||
http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
// Ask the RA to update this authorization
|
||||
updatedAuthz, err := wfe.RA.UpdateAuthorization(authz, challengeIndex, challengeResponse)
|
||||
if err != nil {
|
||||
wfe.sendError(response, "Unable to update authorization", http.StatusInternalServerError)
|
||||
wfe.sendError(response, "Unable to update authorization", err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -521,7 +536,7 @@ func (wfe *WebFrontEndImpl) Challenge(authz core.Authorization, response http.Re
|
|||
// assumption: UpdateAuthorization does not modify order of challenges
|
||||
jsonReply, err := json.Marshal(challenge)
|
||||
if err != nil {
|
||||
wfe.sendError(response, "Failed to marshal challenge", http.StatusInternalServerError)
|
||||
wfe.sendError(response, "Failed to marshal authz", err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -544,16 +559,16 @@ func (wfe *WebFrontEndImpl) Registration(response http.ResponseWriter, request *
|
|||
idStr := parseIDFromPath(request.URL.Path)
|
||||
id, err := strconv.ParseInt(idStr, 10, 64)
|
||||
if err != nil {
|
||||
wfe.sendError(response, "Registration ID must be an integer", http.StatusBadRequest)
|
||||
wfe.sendError(response, "Registration ID must be an integer", err, http.StatusBadRequest)
|
||||
return
|
||||
} else if id <= 0 {
|
||||
wfe.sendError(response, "Registration ID must be a positive non-zero integer", http.StatusBadRequest)
|
||||
wfe.sendError(response, "Registration ID must be a positive non-zero integer", id, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
reg, err := wfe.SA.GetRegistration(id)
|
||||
if err != nil {
|
||||
wfe.sendError(response,
|
||||
fmt.Sprintf("Unable to find registration: %+v", err),
|
||||
"Unable to find registration", err,
|
||||
http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
|
@ -561,13 +576,13 @@ func (wfe *WebFrontEndImpl) Registration(response http.ResponseWriter, request *
|
|||
|
||||
switch request.Method {
|
||||
default:
|
||||
wfe.sendError(response, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
wfe.sendError(response, "Method not allowed", "", http.StatusMethodNotAllowed)
|
||||
return
|
||||
|
||||
case "GET":
|
||||
jsonReply, err := json.Marshal(reg)
|
||||
if err != nil {
|
||||
wfe.sendError(response, "Failed to marshal authz", http.StatusInternalServerError)
|
||||
wfe.sendError(response, "Failed to marshal authz", err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
response.Header().Set("Content-Type", "application/json")
|
||||
|
|
@ -578,9 +593,9 @@ func (wfe *WebFrontEndImpl) Registration(response http.ResponseWriter, request *
|
|||
body, _, currReg, err := wfe.verifyPOST(request, true)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
wfe.sendError(response, "No registration exists matching provided key", http.StatusForbidden)
|
||||
wfe.sendError(response, "No registration exists matching provided key", err, http.StatusForbidden)
|
||||
} else {
|
||||
wfe.sendError(response, "Unable to read/verify body", http.StatusBadRequest)
|
||||
wfe.sendError(response, "Unable to read/verify body", err, http.StatusBadRequest)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
@ -588,20 +603,20 @@ func (wfe *WebFrontEndImpl) Registration(response http.ResponseWriter, request *
|
|||
var update core.Registration
|
||||
err = json.Unmarshal(body, &update)
|
||||
if err != nil {
|
||||
wfe.sendError(response, "Error unmarshaling registration", http.StatusBadRequest)
|
||||
wfe.sendError(response, "Error unmarshaling registration", err, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Ask the RA to update this authorization
|
||||
updatedReg, err := wfe.RA.UpdateRegistration(currReg, update)
|
||||
if err != nil {
|
||||
wfe.sendError(response, "Unable to update registration", http.StatusInternalServerError)
|
||||
wfe.sendError(response, "Unable to update registration", err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
jsonReply, err := json.Marshal(updatedReg)
|
||||
if err != nil {
|
||||
wfe.sendError(response, "Failed to marshal authz", http.StatusInternalServerError)
|
||||
wfe.sendError(response, "Failed to marshal authz", err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
response.Header().Set("Content-Type", "application/json")
|
||||
|
|
@ -617,7 +632,7 @@ func (wfe *WebFrontEndImpl) Authorization(response http.ResponseWriter, request
|
|||
authz, err := wfe.SA.GetAuthorization(id)
|
||||
if err != nil {
|
||||
wfe.sendError(response,
|
||||
fmt.Sprintf("Unable to find authorization: %+v", err),
|
||||
"Unable to find authorization", err,
|
||||
http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
|
@ -630,13 +645,13 @@ func (wfe *WebFrontEndImpl) Authorization(response http.ResponseWriter, request
|
|||
|
||||
switch request.Method {
|
||||
default:
|
||||
wfe.sendError(response, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
wfe.sendError(response, "Method not allowed", request.Method, http.StatusMethodNotAllowed)
|
||||
return
|
||||
|
||||
case "GET":
|
||||
jsonReply, err := json.Marshal(authz)
|
||||
if err != nil {
|
||||
wfe.sendError(response, "Failed to marshal authz", http.StatusInternalServerError)
|
||||
wfe.sendError(response, "Failed to marshal authz", err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
response.Header().Set("Content-Type", "application/json")
|
||||
|
|
@ -649,35 +664,30 @@ func (wfe *WebFrontEndImpl) Authorization(response http.ResponseWriter, request
|
|||
|
||||
var allHex = regexp.MustCompile("^[0-9a-f]+$")
|
||||
|
||||
func (wfe *WebFrontEndImpl) notFound(response http.ResponseWriter) {
|
||||
wfe.sendError(response, "Not found", http.StatusNotFound)
|
||||
}
|
||||
|
||||
func (wfe *WebFrontEndImpl) Certificate(response http.ResponseWriter, request *http.Request) {
|
||||
path := request.URL.Path
|
||||
switch request.Method {
|
||||
default:
|
||||
wfe.sendError(response, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
wfe.sendError(response, "Method not allowed", request.Method, http.StatusMethodNotAllowed)
|
||||
return
|
||||
|
||||
case "GET":
|
||||
// Certificate paths consist of the CertBase path, plus exactly sixteen hex
|
||||
// digits.
|
||||
if !strings.HasPrefix(path, wfe.CertPath) {
|
||||
wfe.notFound(response)
|
||||
wfe.sendError(response, "Not found", path, http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
serial := path[len(wfe.CertPath):]
|
||||
if len(serial) != 16 || !allHex.Match([]byte(serial)) {
|
||||
wfe.notFound(response)
|
||||
wfe.sendError(response, "Not found", serial, http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
wfe.log.Debug(fmt.Sprintf("Requested certificate ID %s", serial))
|
||||
|
||||
cert, err := wfe.SA.GetCertificateByShortSerial(serial)
|
||||
if err != nil {
|
||||
wfe.log.Debug(fmt.Sprintf("Not found cert: %v", err))
|
||||
wfe.notFound(response)
|
||||
wfe.sendError(response, "Not found", err, http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,9 @@ package wfe
|
|||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
|
@ -29,11 +31,85 @@ type MockSA struct {
|
|||
// empty
|
||||
}
|
||||
|
||||
func (sa *MockSA) GetRegistration(int64) (core.Registration, error) {
|
||||
const (
|
||||
test1KeyPublicJSON = `
|
||||
{
|
||||
"kty":"RSA",
|
||||
"n":"yNWVhtYEKJR21y9xsHV-PD_bYwbXSeNuFal46xYxVfRL5mqha7vttvjB_vc7Xg2RvgCxHPCqoxgMPTzHrZT75LjCwIW2K_klBYN8oYvTwwmeSkAz6ut7ZxPv-nZaT5TJhGk0NT2kh_zSpdriEJ_3vW-mqxYbbBmpvHqsa1_zx9fSuHYctAZJWzxzUZXykbWMWQZpEiE0J4ajj51fInEzVn7VxV-mzfMyboQjujPh7aNJxAWSq4oQEJJDgWwSh9leyoJoPpONHxh5nEE5AjE01FkGICSxjpZsF-w8hOTI3XXohUdu29Se26k2B0PolDSuj0GIQU6-W9TdLXSjBb2SpQ",
|
||||
"e":"AAEAAQ"
|
||||
}`
|
||||
|
||||
test1KeyPrivatePEM = `
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEowIBAAKCAQEAyNWVhtYEKJR21y9xsHV+PD/bYwbXSeNuFal46xYxVfRL5mqh
|
||||
a7vttvjB/vc7Xg2RvgCxHPCqoxgMPTzHrZT75LjCwIW2K/klBYN8oYvTwwmeSkAz
|
||||
6ut7ZxPv+nZaT5TJhGk0NT2kh/zSpdriEJ/3vW+mqxYbbBmpvHqsa1/zx9fSuHYc
|
||||
tAZJWzxzUZXykbWMWQZpEiE0J4ajj51fInEzVn7VxV+mzfMyboQjujPh7aNJxAWS
|
||||
q4oQEJJDgWwSh9leyoJoPpONHxh5nEE5AjE01FkGICSxjpZsF+w8hOTI3XXohUdu
|
||||
29Se26k2B0PolDSuj0GIQU6+W9TdLXSjBb2SpQIDAQABAoIBAHw58SXYV/Yp72Cn
|
||||
jjFSW+U0sqWMY7rmnP91NsBjl9zNIe3C41pagm39bTIjB2vkBNR8ZRG7pDEB/QAc
|
||||
Cn9Keo094+lmTArjL407ien7Ld+koW7YS8TyKADYikZo0vAK3qOy14JfQNiFAF9r
|
||||
Bw61hG5/E58cK5YwQZe+YcyBK6/erM8fLrJEyw4CV49wWdq/QqmNYU1dx4OExAkl
|
||||
KMfvYXpjzpvyyTnZuS4RONfHsO8+JTyJVm+lUv2x+bTce6R4W++UhQY38HakJ0x3
|
||||
XRfXooRv1Bletu5OFlpXfTSGz/5gqsfemLSr5UHncsCcFMgoFBsk2t/5BVukBgC7
|
||||
PnHrAjkCgYEA887PRr7zu3OnaXKxylW5U5t4LzdMQLpslVW7cLPD4Y08Rye6fF5s
|
||||
O/jK1DNFXIoUB7iS30qR7HtaOnveW6H8/kTmMv/YAhLO7PAbRPCKxxcKtniEmP1x
|
||||
ADH0tF2g5uHB/zeZhCo9qJiF0QaJynvSyvSyJFmY6lLvYZsAW+C+PesCgYEA0uCi
|
||||
Q8rXLzLpfH2NKlLwlJTi5JjE+xjbabgja0YySwsKzSlmvYJqdnE2Xk+FHj7TCnSK
|
||||
KUzQKR7+rEk5flwEAf+aCCNh3W4+Hp9MmrdAcCn8ZsKmEW/o7oDzwiAkRCmLw/ck
|
||||
RSFJZpvFoxEg15riT37EjOJ4LBZ6SwedsoGA/a8CgYEA2Ve4sdGSR73/NOKZGc23
|
||||
q4/B4R2DrYRDPhEySnMGoPCeFrSU6z/lbsUIU4jtQWSaHJPu4n2AfncsZUx9WeSb
|
||||
OzTCnh4zOw33R4N4W8mvfXHODAJ9+kCc1tax1YRN5uTEYzb2dLqPQtfNGxygA1DF
|
||||
BkaC9CKnTeTnH3TlKgK8tUcCgYB7J1lcgh+9ntwhKinBKAL8ox8HJfkUM+YgDbwR
|
||||
sEM69E3wl1c7IekPFvsLhSFXEpWpq3nsuMFw4nsVHwaGtzJYAHByhEdpTDLXK21P
|
||||
heoKF1sioFbgJB1C/Ohe3OqRLDpFzhXOkawOUrbPjvdBM2Erz/r11GUeSlpNazs7
|
||||
vsoYXQKBgFwFM1IHmqOf8a2wEFa/a++2y/WT7ZG9nNw1W36S3P04K4lGRNRS2Y/S
|
||||
snYiqxD9nL7pVqQP2Qbqbn0yD6d3G5/7r86F7Wu2pihM8g6oyMZ3qZvvRIBvKfWo
|
||||
eROL1ve1vmQF3kjrMPhhK2kr6qdWnTE5XlPllVSZFQenSTzj98AO
|
||||
-----END RSA PRIVATE KEY-----
|
||||
`
|
||||
|
||||
test2KeyPublicJSON = `
|
||||
{
|
||||
"kty":"RSA",
|
||||
"n":"m5Cpx3vZ0CjATirDpbILvq78fm3Dv5RBkO1VLWFmJj5Mb54vc9oYZWc1V1k-LJoESuuPHhaNO2Eu8T9tslQWcZSzr5NImxAwMk970gVQa-Hqv-Jr6xstrBpq7TKpXHTx2FnfA2wQrfIQSlBXu0t4jdUOr3oJh-QXvma8nLITdtjpC0AZNtqd0QkRJX_90SaNrl18Rr_0JrBH9ZmUSFcf3mo_BtL0Gx0jE3n-iwCI8rQtfyVP__9-n__r4IhalKLzaeio6o-qrdemh0EZgjKGCS1_RpTIeArkO8uia1KgOq-z-GfemKEm4s07WO_a0_9dLqbvpnyyZvUi405m3vGDfQ",
|
||||
"e":"AAEAAQ"
|
||||
}`
|
||||
)
|
||||
|
||||
func (sa *MockSA) GetRegistration(id int64) (core.Registration, error) {
|
||||
if id == 100 {
|
||||
// Tag meaning "Missing"
|
||||
return core.Registration{}, errors.New("missing")
|
||||
}
|
||||
if id == 101 {
|
||||
// Tag meaning "Malformed"
|
||||
return core.Registration{}, nil
|
||||
}
|
||||
|
||||
keyJSON := []byte(test1KeyPublicJSON)
|
||||
var parsedKey jose.JsonWebKey
|
||||
parsedKey.UnmarshalJSON(keyJSON)
|
||||
|
||||
return core.Registration{Key: parsedKey}, nil
|
||||
}
|
||||
|
||||
func (sa *MockSA) GetRegistrationByKey(jose.JsonWebKey) (core.Registration, error) {
|
||||
func (sa *MockSA) GetRegistrationByKey(jwk jose.JsonWebKey) (core.Registration, error) {
|
||||
var test1KeyPublic jose.JsonWebKey
|
||||
var test2KeyPublic jose.JsonWebKey
|
||||
test1KeyPublic.UnmarshalJSON([]byte(test1KeyPublicJSON))
|
||||
test2KeyPublic.UnmarshalJSON([]byte(test2KeyPublicJSON))
|
||||
|
||||
if core.KeyDigestEquals(jwk, test1KeyPublic) {
|
||||
return core.Registration{ID: 1, Key: jwk}, nil
|
||||
}
|
||||
|
||||
if core.KeyDigestEquals(jwk, test2KeyPublic) {
|
||||
// No key found
|
||||
return core.Registration{}, sql.ErrNoRows
|
||||
}
|
||||
|
||||
// Return a fake registration
|
||||
return core.Registration{ID: 1}, nil
|
||||
}
|
||||
|
||||
|
|
@ -234,7 +310,7 @@ func TestIssueCertificate(t *testing.T) {
|
|||
test.AssertEquals(t,
|
||||
responseWriter.Body.String(),
|
||||
// TODO: I think this is wrong. The CSR in the payload above was created by openssl and should be valid.
|
||||
"{\"type\":\"urn:acme:error:malformed\",\"detail\":\"Error creating new cert: Invalid signature on CSR\"}")
|
||||
"{\"type\":\"urn:acme:error:malformed\",\"detail\":\"Error creating new cert\"}")
|
||||
}
|
||||
|
||||
type MockRegistrationAuthority struct{}
|
||||
|
|
@ -265,7 +341,8 @@ func (ra *MockRegistrationAuthority) RevokeCertificate(cert x509.Certificate) er
|
|||
return nil
|
||||
}
|
||||
|
||||
func (ra *MockRegistrationAuthority) OnValidationUpdate(authz core.Authorization) {
|
||||
func (ra *MockRegistrationAuthority) OnValidationUpdate(authz core.Authorization) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestChallenge(t *testing.T) {
|
||||
|
|
@ -329,7 +406,7 @@ func TestChallenge(t *testing.T) {
|
|||
"{\"type\":\"dns\",\"uri\":\"/acme/authz/asdf?challenge=foo\"}")
|
||||
}
|
||||
|
||||
func TestRegistration(t *testing.T) {
|
||||
func TestNewRegistration(t *testing.T) {
|
||||
wfe := NewWebFrontEndImpl()
|
||||
wfe.RA = &MockRegistrationAuthority{}
|
||||
wfe.SA = &MockSA{}
|
||||
|
|
@ -505,3 +582,96 @@ func TestAuthorization(t *testing.T) {
|
|||
err := json.Unmarshal([]byte(responseWriter.Body.String()), &authz)
|
||||
test.AssertNotError(t, err, "Couldn't unmarshal returned authorization object")
|
||||
}
|
||||
|
||||
func TestRegistration(t *testing.T) {
|
||||
wfe := NewWebFrontEndImpl()
|
||||
wfe.RA = &MockRegistrationAuthority{}
|
||||
wfe.SA = &MockSA{}
|
||||
wfe.Stats, _ = statsd.NewNoopClient()
|
||||
responseWriter := httptest.NewRecorder()
|
||||
|
||||
// Test invalid method
|
||||
path, _ := url.Parse("/1")
|
||||
wfe.Registration(responseWriter, &http.Request{
|
||||
Method: "MAKE-COFFEE",
|
||||
Body: makeBody("invalid"),
|
||||
URL: path,
|
||||
})
|
||||
test.AssertEquals(t,
|
||||
responseWriter.Body.String(),
|
||||
"{\"type\":\"urn:acme:error:malformed\",\"detail\":\"Method not allowed\"}")
|
||||
responseWriter.Body.Reset()
|
||||
|
||||
// Test GET missing entry
|
||||
path, _ = url.Parse("/100")
|
||||
wfe.Registration(responseWriter, &http.Request{
|
||||
Method: "GET",
|
||||
URL: path,
|
||||
})
|
||||
test.AssertEquals(t,
|
||||
responseWriter.Body.String(),
|
||||
"{\"type\":\"urn:acme:error:malformed\",\"detail\":\"Unable to find registration\"}")
|
||||
responseWriter.Body.Reset()
|
||||
|
||||
// Test GET malformed entry
|
||||
path, _ = url.Parse("/101")
|
||||
wfe.Registration(responseWriter, &http.Request{
|
||||
Method: "GET",
|
||||
URL: path,
|
||||
})
|
||||
test.AssertEquals(t,
|
||||
responseWriter.Body.String(),
|
||||
"{\"type\":\"urn:acme:error:serverInternal\",\"detail\":\"Failed to marshal authz\"}")
|
||||
responseWriter.Body.Reset()
|
||||
|
||||
// Test GET proper entry
|
||||
path, _ = url.Parse("/1")
|
||||
wfe.Registration(responseWriter, &http.Request{
|
||||
Method: "GET",
|
||||
URL: path,
|
||||
})
|
||||
test.AssertNotContains(t, responseWriter.Body.String(), "urn:acme:error")
|
||||
responseWriter.Body.Reset()
|
||||
|
||||
// Test POST invalid JSON
|
||||
path, _ = url.Parse("/2")
|
||||
wfe.Registration(responseWriter, &http.Request{
|
||||
Method: "POST",
|
||||
Body: makeBody("invalid"),
|
||||
URL: path,
|
||||
})
|
||||
test.AssertEquals(t,
|
||||
responseWriter.Body.String(),
|
||||
"{\"type\":\"urn:acme:error:malformed\",\"detail\":\"Unable to read/verify body\"}")
|
||||
responseWriter.Body.Reset()
|
||||
|
||||
// Test POST valid JSON but key is not registered
|
||||
path, _ = url.Parse("/1")
|
||||
wfe.Registration(responseWriter, &http.Request{
|
||||
Method: "POST",
|
||||
Body: makeBody(`{
|
||||
"payload" : "ewogICJjb250YWN0IjogWwogICAgIm1haWx0bzpjZXJ0LWFkbWluQGV4YW1wbGUuY28ubnoiLAogICAgInRlbDorMjQ5NTU1MTIxMiIKICBdLAogICJhZ3JlZW1lbnQiOiAieWVzIgp9Cg",
|
||||
"protected" : "eyJhbGciOiJQUzI1NiIsImp3ayI6eyJrdHkiOiJSU0EiLCJuIjoibTVDcHgzdlowQ2pBVGlyRHBiSUx2cTc4Zm0zRHY1UkJrTzFWTFdGbUpqNU1iNTR2YzlvWVpXYzFWMWstTEpvRVN1dVBIaGFOTzJFdThUOXRzbFFXY1pTenI1TklteEF3TWs5NzBnVlFhLUhxdi1KcjZ4c3RyQnBxN1RLcFhIVHgyRm5mQTJ3UXJmSVFTbEJYdTB0NGpkVU9yM29KaC1RWHZtYThuTElUZHRqcEMwQVpOdHFkMFFrUkpYXzkwU2FOcmwxOFJyXzBKckJIOVptVVNGY2YzbW9fQnRMMEd4MGpFM24taXdDSThyUXRmeVZQX185LW5fX3I0SWhhbEtMemFlaW82by1xcmRlbWgwRVpnaktHQ1MxX1JwVEllQXJrTzh1aWExS2dPcS16LUdmZW1LRW00czA3V09fYTBfOWRMcWJ2cG55eVp2VWk0MDVtM3ZHRGZRIiwiZSI6IkFBRUFBUSJ9fQ",
|
||||
"signature" : "exg0HJRHk-oSDiaOlgtTkT_COqDRyIAJr4g9fDAJh5GF5evXAfT0Hbkfy4TYzqvF6oOldIaCylYhXjYtve4JLXEMdAj1DaR7kGVALskLg-XbiZ0-IaFBiDDaT6mwyLBTfstX4DD2OL7x0vyuTK16bHEIF0hncwHYVSoX5eFOBQLVu_gjxc7J5OZK4ugSJxZEilTVta0A9EdXdUxth0qqbZg_hJDmGOyNge03C71GbhMs-DF-rujlhe7L4VhcV3U0Wj8kSuAGn_DIHBJ1zM0H46PRgyz_9DgkJ6XnE5W8ZA3kF0VPFSp4ofqBhkFUXLXPPJJUEurAQxBJMaU31ef8bg"
|
||||
}`),
|
||||
URL: path,
|
||||
})
|
||||
test.AssertEquals(t,
|
||||
responseWriter.Body.String(),
|
||||
"{\"type\":\"urn:acme:error:unauthorized\",\"detail\":\"No registration exists matching provided key\"}")
|
||||
responseWriter.Body.Reset()
|
||||
|
||||
// Test POST valid JSON with registration up in the mock
|
||||
path, _ = url.Parse("/2")
|
||||
wfe.Registration(responseWriter, &http.Request{
|
||||
Method: "POST",
|
||||
Body: makeBody(`{
|
||||
"payload" : "ewogICJjb250YWN0IjogWwogICAgIm1haWx0bzpjZXJ0LWFkbWluQGV4YW1wbGUuY29tIiwKICAgICJ0ZWw6KzEyMDI1NTUxMjEyIgogIF0sCiAgImFncmVlbWVudCI6ICJ5ZXMiCn0K",
|
||||
"protected" : "eyJhbGciOiJQUzI1NiIsImp3ayI6eyJrdHkiOiJSU0EiLCJuIjoieU5XVmh0WUVLSlIyMXk5eHNIVi1QRF9iWXdiWFNlTnVGYWw0NnhZeFZmUkw1bXFoYTd2dHR2akJfdmM3WGcyUnZnQ3hIUENxb3hnTVBUekhyWlQ3NUxqQ3dJVzJLX2tsQllOOG9ZdlR3d21lU2tBejZ1dDdaeFB2LW5aYVQ1VEpoR2swTlQya2hfelNwZHJpRUpfM3ZXLW1xeFliYkJtcHZIcXNhMV96eDlmU3VIWWN0QVpKV3p4elVaWHlrYldNV1FacEVpRTBKNGFqajUxZkluRXpWbjdWeFYtbXpmTXlib1FqdWpQaDdhTkp4QVdTcTRvUUVKSkRnV3dTaDlsZXlvSm9QcE9OSHhoNW5FRTVBakUwMUZrR0lDU3hqcFpzRi13OGhPVEkzWFhvaFVkdTI5U2UyNmsyQjBQb2xEU3VqMEdJUVU2LVc5VGRMWFNqQmIyU3BRIiwiZSI6IkFBRUFBUSJ9fQ",
|
||||
"signature" : "qZ5WWZJxhub1VCNdgAv-y02YLIc9QtHS7lKxVAiRqXPynENsL7_x63whkfvvHHEUiSyyf9pJCLY9NJfiFr-b4QiBOS7QB4JGj8NTghAeFycPerb6e4XCVx9xKljefybAm5yDOUFjG8PYW-XqrxarnVuykRUBIZuBR2d7sxhH09D5uZzJC9I96D7qEliqiglTdzBCAupDY_V7YQc46UzmQ3O_NGWOHr9Z7WYNOZpADwBzfIyWZQlmq3HxS0xYPYbY8FLYI6NzsHTQFkVGCTmZ7KmsyYsYj6uldchn88zcG9KO-53hZh8S5Kdy5FXh8iB_HqUn4j8yKGC9YmK4ERLlGg"
|
||||
}`),
|
||||
URL: path,
|
||||
})
|
||||
test.AssertNotContains(t, responseWriter.Body.String(), "urn:acme:error")
|
||||
responseWriter.Body.Reset()
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue