Merge branch 'master' into index-fix
This commit is contained in:
commit
def66fc85d
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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.")
|
||||
}
|
||||
|
|
|
|||
16
core/util.go
16
core/util.go
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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-----
|
||||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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"}`)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue