Merge branch 'master' into index-fix

This commit is contained in:
Jeff Hodges 2015-09-10 12:37:03 -07:00
commit def66fc85d
14 changed files with 141 additions and 103 deletions

View File

@ -59,7 +59,6 @@ type CertificateAuthorityImpl struct {
ValidityPeriod time.Duration
NotAfter time.Time
MaxNames int
MaxKeySize int
}
// NewCertificateAuthorityImpl creates a CA that talks to a remote CFSSL
@ -239,7 +238,7 @@ func (ca *CertificateAuthorityImpl) IssueCertificate(csr x509.CertificateRequest
ca.log.AuditErr(err)
return emptyCert, err
}
if err = core.GoodKey(key, ca.MaxKeySize); err != nil {
if err = core.GoodKey(key); err != nil {
err = fmt.Errorf("Invalid public key in CSR: %s", err.Error())
// AUDIT[ Certificate Requests ] 11917fa4-10ef-4e0d-9105-bacbe7836a3c
ca.log.AuditErr(err)

View File

@ -212,7 +212,6 @@ func TestRevoke(t *testing.T) {
ca.PA = ctx.pa
ca.SA = ctx.sa
ca.MaxKeySize = 4096
csr, _ := x509.ParseCertificateRequest(CNandSANCSR)
certObj, err := ca.IssueCertificate(*csr, ctx.reg.ID, FarFuture)
@ -253,7 +252,6 @@ func TestIssueCertificate(t *testing.T) {
test.AssertNotError(t, err, "Failed to create CA")
ca.PA = ctx.pa
ca.SA = ctx.sa
ca.MaxKeySize = 4096
/*
// Uncomment to test with a local signer
@ -330,7 +328,6 @@ func TestRejectNoName(t *testing.T) {
test.AssertNotError(t, err, "Failed to create CA")
ca.PA = ctx.pa
ca.SA = ctx.sa
ca.MaxKeySize = 4096
// Test that the CA rejects CSRs with no names
csr, _ := x509.ParseCertificateRequest(NoNameCSR)
@ -361,7 +358,6 @@ func TestDeduplication(t *testing.T) {
test.AssertNotError(t, err, "Failed to create CA")
ca.PA = ctx.pa
ca.SA = ctx.sa
ca.MaxKeySize = 4096
// Test that the CA collapses duplicate names
csr, _ := x509.ParseCertificateRequest(DupeNameCSR)
@ -391,7 +387,6 @@ func TestRejectValidityTooLong(t *testing.T) {
test.AssertNotError(t, err, "Failed to create CA")
ca.PA = ctx.pa
ca.SA = ctx.sa
ca.MaxKeySize = 4096
// Test that the CA rejects CSRs that would expire after the intermediate cert
csr, _ := x509.ParseCertificateRequest(NoCNCSR)
@ -411,7 +406,6 @@ func TestShortKey(t *testing.T) {
ca, err := NewCertificateAuthorityImpl(ctx.caDB, ctx.caConfig, ctx.fc, caCertFile)
ca.PA = ctx.pa
ca.SA = ctx.sa
ca.MaxKeySize = 4096
// Test that the CA rejects CSRs that would expire after the intermediate cert
csr, _ := x509.ParseCertificateRequest(ShortKeyCSR)
@ -425,7 +419,6 @@ func TestRejectBadAlgorithm(t *testing.T) {
ca, err := NewCertificateAuthorityImpl(ctx.caDB, ctx.caConfig, ctx.fc, caCertFile)
ca.PA = ctx.pa
ca.SA = ctx.sa
ca.MaxKeySize = 4096
// Test that the CA rejects CSRs that would expire after the intermediate cert
csr, _ := x509.ParseCertificateRequest(BadAlgorithmCSR)

View File

@ -46,7 +46,6 @@ func main() {
cai, err := ca.NewCertificateAuthorityImpl(cadb, c.CA, clock.Default(), c.Common.IssuerCert)
cmd.FailOnError(err, "Failed to create CA impl")
cai.MaxKeySize = c.Common.MaxKeySize
cai.PA = pa
go cmd.ProfileCmd("CA", stats)

View File

@ -45,7 +45,6 @@ func main() {
rai := ra.NewRegistrationAuthorityImpl(clock.Default(), auditlogger)
rai.AuthzBase = c.Common.BaseURL + wfe.AuthzPath
rai.MaxKeySize = c.Common.MaxKeySize
rai.PA = pa
raDNSTimeout, err := time.ParseDuration(c.Common.DNSTimeout)
cmd.FailOnError(err, "Couldn't parse RA DNS timeout")

View File

@ -177,7 +177,6 @@ type Config struct {
BaseURL string
// Path to a PEM-encoded copy of the issuer certificate.
IssuerCert string
MaxKeySize int
DNSResolver string
DNSTimeout string

View File

@ -42,17 +42,17 @@ var (
// key use (our requirements are the same for either one), according to basic
// strength and algorithm checking.
// TODO: Support JsonWebKeys once go-jose migration is done.
func GoodKey(key crypto.PublicKey, maxKeySize int) error {
func GoodKey(key crypto.PublicKey) error {
log := blog.GetAuditLogger()
switch t := key.(type) {
case rsa.PublicKey:
return GoodKeyRSA(t, maxKeySize)
return GoodKeyRSA(t)
case *rsa.PublicKey:
return GoodKeyRSA(*t, maxKeySize)
return GoodKeyRSA(*t)
case ecdsa.PublicKey:
return GoodKeyECDSA(t, maxKeySize)
return GoodKeyECDSA(t)
case *ecdsa.PublicKey:
return GoodKeyECDSA(*t, maxKeySize)
return GoodKeyECDSA(*t)
default:
err := MalformedRequestError(fmt.Sprintf("Unknown key type %s", reflect.TypeOf(key)))
log.Debug(err.Error())
@ -61,7 +61,7 @@ func GoodKey(key crypto.PublicKey, maxKeySize int) error {
}
// GoodKeyECDSA determines if an ECDSA pubkey meets our requirements
func GoodKeyECDSA(key ecdsa.PublicKey, maxKeySize int) (err error) {
func GoodKeyECDSA(key ecdsa.PublicKey) (err error) {
log := blog.GetAuditLogger()
err = NotSupportedError("ECDSA keys not yet supported")
log.Debug(err.Error())
@ -69,12 +69,13 @@ func GoodKeyECDSA(key ecdsa.PublicKey, maxKeySize int) (err error) {
}
// GoodKeyRSA determines if a RSA pubkey meets our requirements
func GoodKeyRSA(key rsa.PublicKey, maxKeySize int) (err error) {
func GoodKeyRSA(key rsa.PublicKey) (err error) {
log := blog.GetAuditLogger()
// Baseline Requirements Appendix A
// Modulus must be >= 2048 bits and < maxKeySize
// Modulus must be >= 2048 bits and <= 4096 bits
modulus := key.N
modulusBitLen := modulus.BitLen()
const maxKeySize = 4096
if modulusBitLen < 2048 {
err = MalformedRequestError(fmt.Sprintf("Key too small: %d", modulusBitLen))
log.Debug(err.Error())

View File

@ -15,31 +15,29 @@ import (
"github.com/letsencrypt/boulder/test"
)
var maxKeySize = 2048
func TestUnknownKeyType(t *testing.T) {
notAKey := struct{}{}
test.AssertError(t, GoodKey(notAKey, maxKeySize), "Should have rejected a key of unknown type")
test.AssertError(t, GoodKey(notAKey), "Should have rejected a key of unknown type")
}
func TestWrongKeyType(t *testing.T) {
ecdsaKey := ecdsa.PublicKey{}
test.AssertError(t, GoodKey(&ecdsaKey, maxKeySize), "Should have rejected ECDSA key.")
test.AssertError(t, GoodKey(ecdsaKey, maxKeySize), "Should have rejected ECDSA key.")
test.AssertError(t, GoodKey(&ecdsaKey), "Should have rejected ECDSA key.")
test.AssertError(t, GoodKey(ecdsaKey), "Should have rejected ECDSA key.")
}
func TestSmallModulus(t *testing.T) {
private, err := rsa.GenerateKey(rand.Reader, 2040)
test.AssertNotError(t, err, "Error generating key")
test.AssertError(t, GoodKey(&private.PublicKey, maxKeySize), "Should have rejected too-short key.")
test.AssertError(t, GoodKey(private.PublicKey, maxKeySize), "Should have rejected too-short key.")
test.AssertError(t, GoodKey(&private.PublicKey), "Should have rejected too-short key.")
test.AssertError(t, GoodKey(private.PublicKey), "Should have rejected too-short key.")
}
func TestLargeModulus(t *testing.T) {
private, err := rsa.GenerateKey(rand.Reader, maxKeySize+1)
private, err := rsa.GenerateKey(rand.Reader, 4097)
test.AssertNotError(t, err, "Error generating key")
test.AssertError(t, GoodKey(&private.PublicKey, maxKeySize), "Should have rejected too-long key.")
test.AssertError(t, GoodKey(private.PublicKey, maxKeySize), "Should have rejected too-long key.")
test.AssertError(t, GoodKey(&private.PublicKey), "Should have rejected too-long key.")
test.AssertError(t, GoodKey(private.PublicKey), "Should have rejected too-long key.")
}
func TestSmallExponent(t *testing.T) {
@ -48,7 +46,7 @@ func TestSmallExponent(t *testing.T) {
N: bigOne.Lsh(bigOne, 2048),
E: 5,
}
test.AssertError(t, GoodKey(&key, maxKeySize), "Should have rejected small exponent.")
test.AssertError(t, GoodKey(&key), "Should have rejected small exponent.")
}
func TestEvenExponent(t *testing.T) {
@ -57,7 +55,7 @@ func TestEvenExponent(t *testing.T) {
N: bigOne.Lsh(bigOne, 2048),
E: 1 << 17,
}
test.AssertError(t, GoodKey(&key, maxKeySize), "Should have rejected even exponent.")
test.AssertError(t, GoodKey(&key), "Should have rejected even exponent.")
}
func TestEvenModulus(t *testing.T) {
@ -66,7 +64,7 @@ func TestEvenModulus(t *testing.T) {
N: bigOne.Lsh(bigOne, 2048),
E: (1 << 17) + 1,
}
test.AssertError(t, GoodKey(&key, maxKeySize), "Should have rejected even modulus.")
test.AssertError(t, GoodKey(&key), "Should have rejected even modulus.")
}
func TestModulusDivisibleBy752(t *testing.T) {
@ -78,11 +76,11 @@ func TestModulusDivisibleBy752(t *testing.T) {
N: N,
E: (1 << 17) + 1,
}
test.AssertError(t, GoodKey(&key, maxKeySize), "Should have rejected modulus divisible by 751.")
test.AssertError(t, GoodKey(&key), "Should have rejected modulus divisible by 751.")
}
func TestGoodKey(t *testing.T) {
private, err := rsa.GenerateKey(rand.Reader, 2048)
test.AssertNotError(t, err, "Error generating key")
test.AssertNotError(t, GoodKey(&private.PublicKey, maxKeySize), "Should have accepted good key.")
test.AssertNotError(t, GoodKey(&private.PublicKey), "Should have accepted good key.")
}

View File

@ -17,10 +17,12 @@ import (
"encoding/asn1"
"encoding/base64"
"encoding/json"
"encoding/pem"
"errors"
"fmt"
"hash"
"io"
"io/ioutil"
"math/big"
"net/url"
"strings"
@ -347,3 +349,17 @@ func UniqueNames(names []string) (unique []string) {
}
return
}
// LoadCert loads a PEM certificate specified by filename or returns a error
func LoadCert(filename string) (cert *x509.Certificate, err error) {
certPEM, err := ioutil.ReadFile(filename)
if err != nil {
return
}
block, _ := pem.Decode(certPEM)
if block == nil {
return nil, fmt.Errorf("No data in cert PEM file %s", filename)
}
cert, err = x509.ParseCertificate(block.Bytes)
return
}

View File

@ -32,8 +32,7 @@ type RegistrationAuthorityImpl struct {
clk clock.Clock
log *blog.AuditLogger
AuthzBase string
MaxKeySize int
AuthzBase string
}
// NewRegistrationAuthorityImpl constructs a new RA object.
@ -96,7 +95,7 @@ type certificateRequestEvent struct {
// NewRegistration constructs a new Registration from a request.
func (ra *RegistrationAuthorityImpl) NewRegistration(init core.Registration) (reg core.Registration, err error) {
if err = core.GoodKey(init.Key.Key, ra.MaxKeySize); err != nil {
if err = core.GoodKey(init.Key.Key); err != nil {
return core.Registration{}, core.MalformedRequestError(fmt.Sprintf("Invalid public key: %s", err.Error()))
}
reg = core.Registration{

View File

@ -196,7 +196,6 @@ func initAuthorities(t *testing.T) (*DummyValidationAuthority, *sa.SQLStorageAut
DB: cadb,
ValidityPeriod: time.Hour * 2190,
NotAfter: time.Now().Add(time.Hour * 8761),
MaxKeySize: 4096,
Clk: fc,
}
cleanUp := func() {
@ -216,7 +215,6 @@ func initAuthorities(t *testing.T) (*DummyValidationAuthority, *sa.SQLStorageAut
ra.CA = &ca
ra.PA = pa
ra.AuthzBase = "http://acme.invalid/authz/"
ra.MaxKeySize = 4096
ra.DNSResolver = &mocks.MockDNS{}
AuthzInitial.RegistrationID = Registration.ID

View File

@ -170,7 +170,6 @@
"common": {
"baseURL": "http://localhost:4000",
"issuerCert": "test/test-ca.pem",
"maxKeySize": 4096,
"dnsResolver": "127.0.0.1:8053",
"dnsTimeout": "10s",
"dnsAllowLoopbackAddresses": true

View File

@ -0,0 +1,29 @@
Produced by:
js test.js --agree --email jsha@newview.org --domains not-an-example.com --certFile cert.der --certKey ../../wfe/test/178.key
openssl x509 -text -inform der -in cert.der -outform pem -out ../../wfe/test/not-an-example.com.crt
-----BEGIN CERTIFICATE-----
MIIEYzCCA0ugAwIBAgIRAP8AAAAAAAAOS09n2G6BjEYwDQYJKoZIhvcNAQELBQAw
HzEdMBsGA1UEAwwUaGFwcHkgaGFja2VyIGZha2UgQ0EwHhcNMTUwOTA5MjI1NjAw
WhcNMTUxMjA4MjI1NjAwWjAdMRswGQYDVQQDExJub3QtYW4tZXhhbXBsZS5jb20w
ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCaqzue57mgXEoGTZZoVkkC
ZraebWgXI8irX2BgQB1A3iZa9onxGPMcWQMxhSuUisbEJi4UkMcVST12HX01rUwh
j41UuBxJvI1w4wvdstssTAaa9c9tsQ5+UED2bFRL1MsyBdbmCF/+pu3i+ZIYqWgi
KbjVBe3nlAVbo77zizwp3Y4Tp1/TBOwTAuFkHePmkNT63uPm9My/hNzsSm1o+Q51
9Cf7ry+JQmOVgz/jIgFVGFYJ17EV3KUIpUuDShuyCFATBQspgJSN2DoXRUlQjXXk
NTj23OxxdT/cVLcLJjytyG6e5izME2R2aCkDBWIc1a4/sRJ0R396auPXG6KhJ7o/
AgMBAAGjggGaMIIBljAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUH
AwEGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFBGkJtghSl97/bTR
dyy0TaneZhnDMB8GA1UdIwQYMBaAFPt4TxL5YBWDLJ8XfzQZsy426kGJMGoGCCsG
AQUFBwEBBF4wXDAmBggrBgEFBQcwAYYaaHR0cDovL2xvY2FsaG9zdDo0MDAyL29j
c3AwMgYIKwYBBQUHMAKGJmh0dHA6Ly9sb2NhbGhvc3Q6NDAwMC9hY21lL2lzc3Vl
ci1jZXJ0MB0GA1UdEQQWMBSCEm5vdC1hbi1leGFtcGxlLmNvbTAnBgNVHR8EIDAe
MBygGqAYhhZodHRwOi8vZXhhbXBsZS5jb20vY3JsMGMGA1UdIARcMFowCgYGZ4EM
AQIBMAAwTAYDKgMEMEUwIgYIKwYBBQUHAgEWFmh0dHA6Ly9leGFtcGxlLmNvbS9j
cHMwHwYIKwYBBQUHAgIwEwwRRG8gV2hhdCBUaG91IFdpbHQwDQYJKoZIhvcNAQEL
BQADggEBAJTSscrGO1ymwZ+rMF+mfVeHfplfyMzZ/6SZyvaYgO9DLr42KIETdHBg
Y9AZ6aOKboN/hY98kb9mQ0BpOCsSaCkgTsqCjw3szsRd/FMgUSVn36vFpbX2f5oD
gF40N/51EN5Efbe7aN4Oxmcgijh4IY2sczcskJixAd9T/hjVtv160LJ0xcHRrfji
u/Tc2E0q+E5k4V91D2HajwU6qcGbap02JI+pX/Oq4S36yfggIUyowmXQw4nm1cb0
cFXwrMzg+XtDHj+Ex+yBlauq+MP1rjXiHrNIO2hIiyRU9jdxfITAE4DmqEzEBZKY
NORfB6suv4wLnAlsLbPJEdsraq4/IiU=
-----END CERTIFICATE-----

View File

@ -344,6 +344,11 @@ func (wfe *WebFrontEndImpl) verifyPOST(request *http.Request, regCheck bool, res
wfe.log.Debug(fmt.Sprintf("%v :: %v", puberr.Error(), err.Error()))
return nil, nil, reg, puberr
}
if key == nil {
err = core.SignatureValidationError("No JWK in JWS header")
wfe.log.Debug(err.Error())
return nil, nil, reg, err
}
// Check that the request has a known anti-replay nonce
// i.e., Nonce is in protected header and
@ -713,16 +718,27 @@ func (wfe *WebFrontEndImpl) NewCertificate(response http.ResponseWriter, request
return
}
var init core.CertificateRequest
if err = json.Unmarshal(body, &init); err != nil {
var certificateRequest core.CertificateRequest
if err = json.Unmarshal(body, &certificateRequest); err != nil {
logEvent.Error = err.Error()
wfe.sendError(response, "Error unmarshaling certificate request", err, http.StatusBadRequest)
return
}
wfe.logCsr(request.RemoteAddr, init, reg)
logEvent.Extra["CSRDNSNames"] = init.CSR.DNSNames
logEvent.Extra["CSREmailAddresses"] = init.CSR.EmailAddresses
logEvent.Extra["CSRIPAddresses"] = init.CSR.IPAddresses
wfe.logCsr(request.RemoteAddr, certificateRequest, reg)
// Check that the key in the CSR is good. This will also be checked in the CA
// component, but we want to discard CSRs with bad keys as early as possible
// because (a) it's an easy check and we can save unnecessary requests and
// bytes on the wire, and (b) the CA logs all rejections as audit events, but
// a bad key from the client is just a malformed request and doesn't need to
// be audited.
if err = core.GoodKey(certificateRequest.CSR.PublicKey); err != nil {
logEvent.Error = err.Error()
wfe.sendError(response, "Invalid key in certificate request", err, http.StatusBadRequest)
return
}
logEvent.Extra["CSRDNSNames"] = certificateRequest.CSR.DNSNames
logEvent.Extra["CSREmailAddresses"] = certificateRequest.CSR.EmailAddresses
logEvent.Extra["CSRIPAddresses"] = certificateRequest.CSR.IPAddresses
// Create new certificate and return
// TODO IMPORTANT: The RA trusts the WFE to provide the correct key. If the
@ -730,7 +746,7 @@ func (wfe *WebFrontEndImpl) NewCertificate(response http.ResponseWriter, request
// authorized for target site, they could cause issuance for that site by
// lying to the RA. We should probably pass a copy of the whole rquest to the
// RA for secondary validation.
cert, err := wfe.RA.NewCertificate(init, reg.ID)
cert, err := wfe.RA.NewCertificate(certificateRequest, reg.ID)
if err != nil {
logEvent.Error = err.Error()
wfe.sendError(response, "Error creating new cert", err, statusCodeFromError(err))

View File

@ -10,7 +10,6 @@ import (
"crypto/rsa"
"crypto/x509"
"database/sql"
"encoding/hex"
"encoding/json"
"encoding/pem"
"errors"
@ -112,22 +111,6 @@ TkLlEeVOuQfxTadw05gzKX0jKkMC4igGxvEeilYc6NR6a4nvRulG84Q8VV9Sy9Ie
wk6Oiadty3eQqSBJv0HnpmiEdQVffIK5Pg4M8Dd+aOBnEkbopAJOuA==
-----END RSA PRIVATE KEY-----
`
// Cert generated by Go:
// * Randomly generated key
// * CN = lets-encrypt
// * DNSNames = not-an-example.com
// Used for NewCertificate tests
GoodTestCert = "3082013e3081eba003020102020100300b06092a864886f70d01010b300030221" +
"80f32303539313131303233303030305a180f3230353931313130323330303030" +
"5a3000305c300d06092a864886f70d0101010500034b003048024100e5d1cc1f6" +
"10d20913d88e5bba1f327d32450fa650c6fa8d084b710d883f3372008cf97bc41" +
"2cb1ed3a0b28516fa839073f40b061fdb616b1b33181d28d91a5a90203010001a" +
"34e304c301d0603551d250416301406082b0601050507030106082b0601050507" +
"0302300c0603551d130101ff04023000301d0603551d110416301482126e6f742" +
"d616e2d6578616d706c652e636f6d300b06092a864886f70d01010b0341008cf8" +
"f349efa6d2fadbaf8ed9ba67e5a9b98c3d5a13c06297c4cf36dc76f494e8887e3" +
"5dd9c885526136d810fc7640f5ba56281e2b75fa3ff7c91a7d23bab7fd4"
)
type MockSA struct {
@ -304,11 +287,15 @@ func (ra *MockRegistrationAuthority) OnValidationUpdate(authz core.Authorization
type MockCA struct{}
func (ca *MockCA) IssueCertificate(csr x509.CertificateRequest, regID int64, earliestExpiry time.Time) (cert core.Certificate, err error) {
func (ca *MockCA) IssueCertificate(csr x509.CertificateRequest, regID int64, earliestExpiry time.Time) (core.Certificate, error) {
// Return a basic certificate so NewCertificate can continue
randomCertDer, _ := hex.DecodeString(GoodTestCert)
cert.DER = randomCertDer
return
certPtr, err := core.LoadCert("test/not-an-example.com.crt")
if err != nil {
return core.Certificate{}, err
}
return core.Certificate{
DER: certPtr.Raw,
}, nil
}
func (ca *MockCA) GenerateOCSP(xferObj core.OCSPSigningRequest) (ocsp []byte, err error) {
@ -361,6 +348,11 @@ func setupWFE(t *testing.T) WebFrontEndImpl {
wfe.SubscriberAgreementURL = agreementURL
wfe.log.SyslogWriter = mocks.NewSyslogWriter()
wfe.RA = &MockRegistrationAuthority{}
wfe.SA = &MockSA{}
wfe.Stats, _ = statsd.NewNoopClient()
wfe.SubscriberAgreementURL = agreementURL
return wfe
}
@ -630,46 +622,28 @@ func TestIssueCertificate(t *testing.T) {
`{"type":"urn:acme:error:malformed","detail":"Error unmarshaling certificate request"}`)
// Valid, signed JWS body, payload has a invalid signature on CSR and no authorizations:
// {
// "csr": "MIICU...",
// "authorizations: []
// }
// alias b64url="base64 -w0 | sed -e 's,+,-,g' -e 's,/,_,g'"
// openssl req -outform der -new -nodes -key wfe/test/178.key -subj /CN=foo.com | \
// sed 's/foo.com/fob.com/' | b64url
responseWriter.Body.Reset()
wfe.NewCertificate(responseWriter,
makePostRequest(signRequest(t, `{
"resource":"new-cert",
"csr": "MIICUzCCATsCAQAwDjEMMAoGA1UEAwwDZm9vMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3UWce2PY9y8n4B7jOk3DXZnu2pUgLqs7a5DzRBxnPqL7axis6thjSBI2FO7w5CUjO-m8XjD-GYWgfXebZ3aQVlBiYqdxZ3UG6RDwEbBCeKo7v8W-UUfESNNCXF874ddhJmEw0RF0YWSAEctAYHEGoPFz69gCql6xXDPY1OlpMArkIIlq9EZWwT081ekyJv0GYRfQigCMK4b1gkFvKsHja9-Q5u1b0AZyA-mPTu6z5EWkB2onhAXwWXX90sfUe8DSet9r9GxMln3lgZWT1zh3RMZILp0Uhh3NbXnA8JInukha3HPO8WgmDd4K6uBzWso0A6fp5NpX28ZpKAwM5iQltQIDAQABoAAwDQYJKoZIhvcNAQELBQADggEBAFGJV3OcghJEZvO_hGtIdaRnsu6eX3CeqS0bYcEEza8vizlj4x09ntMH3QooqPOj8suul0vD75HZTpz6FHE7SyLeNKQBGNGp1PMWmXsFqD6xURCyMHvCZoHynpCr7D5HtzIvu9fAV7XRK7qBKXfRxbv21q0ysMWnfwkbS2wrs1wAzPPg4iGJq8uVItrlcFL8buJLzxvKa3lu_OjxNXjzdEt3VVko-AKS1swkYEhsGwKd8ZzNbpF2IQ-okXgR_ZecyW8t83pV-w33GhDL9w6RLRMgSM5aojy8ri7YIoIvc3-9klbw2kwY5oM2lmhoIOGU10TkEyn18myy_5GUEGhNzPA=",
"authorizations": []
"csr": "MIICVzCCAT8CAQAwEjEQMA4GA1UEAwwHZm9iLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKzHhqcMSTVjBu61vufGVmIYM4mMbWXgndHOUWnIqSKcNtFtPQ465tcZRT5ITIZWXGjsmgDrj31qvG3t5qLwyaF5hsTvFHK72nLMAQhdgM6481Qe9yaoaulWpkGr_9LVz4jQ9pGAaLVamXGpSxV-ipTOo79Sev4aZE8ksD9atEfWtcOD9w8_zj74vpWjTAHN49Q88chlChVqakn0zSfHPfS-jF8g0UTddBuF0Ti3sZChjxzbo6LwZ4182xX7XPnOLav3AGj0Su7j5XMl3OpenOrlWulWJeZIHq5itGW321j306XiGdbrdWH4K7JygICFds6oolwQRGBY6yinAtCgkTcCAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IBAQBxPiHOtKuBxtvecMNtLkTSuTyEkusQGnjoFDaKe5oqwGYQgy0YBii2-BbaPmqS4ZaDc-vDz_RLeKH5ZiH-NliYR1V_CRtpFLQi18g_2pLQnZLVO3ENs-SM37nU_nBGn9O93t2bkssoM3fZmtgp3R2W7I_wvx7Z8oWKa4boTeBAg_q9Gmi6QskZBddK7A4S_vOR0frU6QSPK_ksPhvovp9fwb6CVKrlJWf556UwRPWgbkW39hvTxK2KHhrUEg3oawNkWde2jZtnZ9e-9zpw8-_5O0X7-YN0ucbFTfQybce_ReuLlGepiHT5bvVavBZoIvqw1XOgSMvGgZFU8tAWMBlj"
}`, &wfe.nonceService)))
test.AssertEquals(t,
responseWriter.Body.String(),
`{"type":"urn:acme:error:unauthorized","detail":"Error creating new cert :: Invalid signature on CSR"}`)
// Valid, signed JWS body, payload has a CSR with no DNS names
mockLog.Clear()
responseWriter.Body.Reset()
wfe.NewCertificate(responseWriter,
makePostRequest((signRequest(t, `{
"resource":"new-cert",
"csr": "MIIBBTCBsgIBADBNMQowCAYDVQQGEwFjMQowCAYDVQQKEwFvMQswCQYDVQQLEwJvdTEKMAgGA1UEBxMBbDEKMAgGA1UECBMBczEOMAwGA1UEAxMFT2ggaGkwXDANBgkqhkiG9w0BAQEFAANLADBIAkEAsr76ZkU2RTqi41eHfmpE5htDvkr202yjRS8x2M5yzT52ooT2WEVtnSuim0YfOEw6f-fHmbqsasqKmqlsJdgz2QIDAQABoAAwCwYJKoZIhvcNAQEFA0EAHkCv4kVPJa53ltOGrhpdH0mT04qHUqiTllJPPjxXxn6iwiVYL8nQuhs4Q2758ENoODBuM2F8gH19TIoXlcm3LQ=="
}`, &wfe.nonceService))))
test.AssertEquals(t,
responseWriter.Body.String(),
`{"type":"urn:acme:error:unauthorized","detail":"Error creating new cert :: Key not authorized for name Oh hi"}`)
assertCsrLogged(t, mockLog)
// Valid, signed JWS body, payload has a valid CSR but no authorizations:
// {
// "csr": "MIIBK...",
// "authorizations: []
// }
// openssl req -outform der -new -nodes -key wfe/test/178.key -subj /CN=meep.com | b64url
mockLog.Clear()
responseWriter.Body.Reset()
wfe.NewCertificate(responseWriter,
makePostRequest(signRequest(t, `{
"resource":"new-cert",
"csr": "MIIBKzCB2AIBADBNMQowCAYDVQQGEwFjMQowCAYDVQQKEwFvMQswCQYDVQQLEwJvdTEKMAgGA1UEBxMBbDEKMAgGA1UECBMBczEOMAwGA1UEAxMFT2ggaGkwXDANBgkqhkiG9w0BAQEFAANLADBIAkEAqvFEGBNrjAotPbcdTSyDpxsESN0-eYl4TqS0ZLYwLTV-FuPHTPjFiq2oH1BEgmRzjb8YiPVXFMnaOeHE7zuuXQIDAQABoCYwJAYJKoZIhvcNAQkOMRcwFTATBgNVHREEDDAKgghtZWVwLmNvbTALBgkqhkiG9w0BAQUDQQBSEcEq-lMUnzv1DO8jK0hJR8YKc0yV8zuWVfAWN0_dsPg5Ny-OHhtJcOTIrUrLTb_xCU7cjiKxU8i3j1kaT-rt"
}`, &wfe.nonceService)))
"resource":"new-cert",
"csr": "MIICWDCCAUACAQAwEzERMA8GA1UEAwwIbWVlcC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCaqzue57mgXEoGTZZoVkkCZraebWgXI8irX2BgQB1A3iZa9onxGPMcWQMxhSuUisbEJi4UkMcVST12HX01rUwhj41UuBxJvI1w4wvdstssTAaa9c9tsQ5-UED2bFRL1MsyBdbmCF_-pu3i-ZIYqWgiKbjVBe3nlAVbo77zizwp3Y4Tp1_TBOwTAuFkHePmkNT63uPm9My_hNzsSm1o-Q519Cf7ry-JQmOVgz_jIgFVGFYJ17EV3KUIpUuDShuyCFATBQspgJSN2DoXRUlQjXXkNTj23OxxdT_cVLcLJjytyG6e5izME2R2aCkDBWIc1a4_sRJ0R396auPXG6KhJ7o_AgMBAAGgADANBgkqhkiG9w0BAQsFAAOCAQEALu046p76aKgvoAEHFINkMTgKokPXf9mZ4IZx_BKz-qs1MPMxVtPIrQDVweBH6tYT7Hfj2naLry6SpZ3vUNP_FYeTFWgW1V03LiqacX-QQgbEYtn99Dt3ScGyzb7EH833ztb3vDJ_-ha_CJplIrg-kHBBrlLFWXhh-I9K1qLRTNpbhZ18ooFde4Sbhkw9o9fKivGhx9aYr7ZbjRsNtKit_DsG1nwEXz53TMJ2vB9IQY29coJv_n5NFLkvBfzbG5faRNiFcimPYBO2jFdaA2mWzfxltLtwMF_dBwzTXDpMo3TVT9zEdV8YpsWqr63igqGDZVpKenlkqvRTeGJVayVuMA"
}`, &wfe.nonceService)))
test.AssertEquals(t,
responseWriter.Body.String(),
`{"type":"urn:acme:error:unauthorized","detail":"Error creating new cert :: Key not authorized for name meep.com"}`)
@ -677,20 +651,21 @@ func TestIssueCertificate(t *testing.T) {
mockLog.Clear()
responseWriter.Body.Reset()
// openssl req -outform der -new -nodes -key wfe/test/178.key -subj /CN=not-an-example.com | b64url
wfe.NewCertificate(responseWriter,
makePostRequest(signRequest(t, `{
"resource":"new-cert",
"csr": "MIH1MIGiAgEAMA0xCzAJBgNVBAYTAlVTMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAOXRzB9hDSCRPYjlu6HzJ9MkUPplDG-o0IS3ENiD8zcgCM-XvEEsse06CyhRb6g5Bz9AsGH9thaxszGB0o2RpakCAwEAAaAwMC4GCSqGSIb3DQEJDjEhMB8wHQYDVR0RBBYwFIISbm90LWFuLWV4YW1wbGUuY29tMAsGCSqGSIb3DQEBCwNBAFpyURFqjVn-7zx73GKaBvPF_2RhBsdehqSjaJ0BpvPKmzpoIFADjttNzKkWaRRDrTeT-GGMV2Gky8S-E_dzoms=",
"authorizations": ["valid"]
}`, &wfe.nonceService)))
"resource":"new-cert",
"csr": "MIICYjCCAUoCAQAwHTEbMBkGA1UEAwwSbm90LWFuLWV4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmqs7nue5oFxKBk2WaFZJAma2nm1oFyPIq19gYEAdQN4mWvaJ8RjzHFkDMYUrlIrGxCYuFJDHFUk9dh19Na1MIY-NVLgcSbyNcOML3bLbLEwGmvXPbbEOflBA9mxUS9TLMgXW5ghf_qbt4vmSGKloIim41QXt55QFW6O-84s8Kd2OE6df0wTsEwLhZB3j5pDU-t7j5vTMv4Tc7EptaPkOdfQn-68viUJjlYM_4yIBVRhWCdexFdylCKVLg0obsghQEwULKYCUjdg6F0VJUI115DU49tzscXU_3FS3CyY8rchunuYszBNkdmgpAwViHNWuP7ESdEd_emrj1xuioSe6PwIDAQABoAAwDQYJKoZIhvcNAQELBQADggEBAE_T1nWU38XVYL28hNVSXU0rW5IBUKtbvr0qAkD4kda4HmQRTYkt-LNSuvxoZCC9lxijjgtJi-OJe_DCTdZZpYzewlVvcKToWSYHYQ6Wm1-fxxD_XzphvZOujpmBySchdiz7QSVWJmVZu34XD5RJbIcrmj_cjRt42J1hiTFjNMzQu9U6_HwIMmliDL-soFY2RTvvZf-dAFvOUQ-Wbxt97eM1PbbmxJNWRhbAmgEpe9PWDPTpqV5AK56VAa991cQ1P8ZVmPss5hvwGWhOtpnpTZVHN3toGNYFKqxWPboirqushQlfKiFqT9rpRgM3-mFjOHidGqsKEkTdmfSVlVEk3oo="
}`, &wfe.nonceService)))
assertCsrLogged(t, mockLog)
randomCertDer, _ := hex.DecodeString(GoodTestCert)
cert, err := core.LoadCert("test/not-an-example.com.crt")
test.AssertNotError(t, err, "Could not load cert")
test.AssertEquals(t,
responseWriter.Body.String(),
string(randomCertDer))
string(cert.Raw))
test.AssertEquals(
t, responseWriter.Header().Get("Location"),
"/acme/cert/0000000000000000")
"/acme/cert/ff0000000000000e")
test.AssertEquals(
t, responseWriter.Header().Get("Link"),
`</acme/issuer-cert>;rel="up"`)
@ -701,7 +676,7 @@ func TestIssueCertificate(t *testing.T) {
test.AssertEquals(t, len(reqlogs), 1)
test.AssertEquals(t, reqlogs[0].Priority, syslog.LOG_NOTICE)
test.AssertContains(t, reqlogs[0].Message, `[AUDIT] `)
test.AssertContains(t, reqlogs[0].Message, `"Names":["not-an-example.com"]`)
test.AssertContains(t, reqlogs[0].Message, `"CommonName":"not-an-example.com",`)
}
func TestChallenge(t *testing.T) {
@ -1311,3 +1286,21 @@ func TestLengthRequired(t *testing.T) {
_, ok := err.(core.LengthRequiredError)
test.Assert(t, ok, "Error code for missing content-length wasn't 411.")
}
func TestBadKeyCSR(t *testing.T) {
wfe := setupWFE(t)
responseWriter := httptest.NewRecorder()
// CSR with a bad (512 bit RSA) key.
// openssl req -outform der -new -newkey rsa:512 -nodes -keyout foo.com.key
// -subj /CN=foo.com | base64 -w0 | sed -e 's,+,-,g' -e 's,/,_,g'
wfe.NewCertificate(responseWriter,
makePostRequest(signRequest(t, `{
"resource":"new-cert",
"csr": "MIHLMHcCAQAwEjEQMA4GA1UEAwwHZm9vLmNvbTBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQDCZftp4x4owgjBnwOKfzihIPedT-BUmV2fuQPMqaUlc8yJUp13vcO5uxUlaBm8leM7Dj_sgTDP_JgykorlYo73AgMBAAGgADANBgkqhkiG9w0BAQsFAANBAEaQ2QBhweK-kp1ejQCedUhMit_wG-uTBtKnc3M82f6_fztLkhg1vWQ782nmhbEI5orXp6QtNHgJYnBpqA9Ut00"
}`, &wfe.nonceService)))
test.AssertEquals(t,
responseWriter.Body.String(),
`{"type":"urn:acme:error:malformed","detail":"Invalid key in certificate request :: Key too small: 512"}`)
}