Ejemplo n.º 1
0
// 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); err != nil {
		return core.Registration{}, core.MalformedRequestError(fmt.Sprintf("Invalid public key: %s", err.Error()))
	}
	if err = ra.checkRegistrationLimit(init.InitialIP); err != nil {
		return core.Registration{}, err
	}

	reg = core.Registration{
		Key: init.Key,
	}
	reg.MergeUpdate(init)

	// This field isn't updatable by the end user, so it isn't copied by
	// MergeUpdate. But we need to fill it in for new registrations.
	reg.InitialIP = init.InitialIP

	err = ra.validateContacts(reg.Contact)
	if err != nil {
		return
	}

	// Store the authorization object, then return it
	reg, err = ra.SA.NewRegistration(reg)
	if err != nil {
		// InternalServerError since the user-data was validated before being
		// passed to the SA.
		err = core.InternalServerError(err.Error())
	}

	ra.stats.Inc("RA.NewRegistrations", 1, 1.0)
	return
}
// 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); err != nil {
		return core.Registration{}, core.MalformedRequestError(fmt.Sprintf("Invalid public key: %s", err.Error()))
	}
	reg = core.Registration{
		Key: init.Key,
	}
	reg.MergeUpdate(init)

	err = validateContacts(reg.Contact, ra.DNSResolver, ra.stats)
	if err != nil {
		return
	}

	// Store the authorization object, then return it
	reg, err = ra.SA.NewRegistration(reg)
	if err != nil {
		// InternalServerError since the user-data was validated before being
		// passed to the SA.
		err = core.InternalServerError(err.Error())
	}

	ra.stats.Inc("RA.NewRegistrations", 1, 1.0)
	return
}
Ejemplo n.º 3
0
// IssueCertificate attempts to convert a CSR into a signed Certificate, while
// enforcing all policies.
func (ca *CertificateAuthorityImpl) IssueCertificate(csr x509.CertificateRequest, regID int64) (core.Certificate, error) {
	emptyCert := core.Certificate{}
	var err error
	key, ok := csr.PublicKey.(crypto.PublicKey)
	if !ok {
		err = fmt.Errorf("Invalid public key in CSR.")
		// AUDIT[ Certificate Requests ] 11917fa4-10ef-4e0d-9105-bacbe7836a3c
		ca.log.AuditErr(err)
		return emptyCert, err
	}
	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)
		return emptyCert, err
	}
	if badSignatureAlgorithms[csr.SignatureAlgorithm] {
		err = fmt.Errorf("Invalid signature algorithm in CSR")
		// AUDIT[ Certificate Requests ] 11917fa4-10ef-4e0d-9105-bacbe7836a3c
		ca.log.AuditErr(err)
		return emptyCert, err
	}

	// Pull hostnames from CSR
	// Authorization is checked by the RA
	commonName := ""
	hostNames := make([]string, len(csr.DNSNames))
	copy(hostNames, csr.DNSNames)
	if len(csr.Subject.CommonName) > 0 {
		commonName = csr.Subject.CommonName
		hostNames = append(hostNames, csr.Subject.CommonName)
	} else if len(hostNames) > 0 {
		commonName = hostNames[0]
	} else {
		err = fmt.Errorf("Cannot issue a certificate without a hostname.")
		// AUDIT[ Certificate Requests ] 11917fa4-10ef-4e0d-9105-bacbe7836a3c
		ca.log.AuditErr(err)
		return emptyCert, err
	}

	// Collapse any duplicate names.  Note that this operation may re-order the names
	hostNames = core.UniqueNames(hostNames)
	if ca.MaxNames > 0 && len(hostNames) > ca.MaxNames {
		err = fmt.Errorf("Certificate request has %d > %d names", len(hostNames), ca.MaxNames)
		ca.log.WarningErr(err)
		return emptyCert, err
	}

	// Verify that names are allowed by policy
	identifier := core.AcmeIdentifier{Type: core.IdentifierDNS, Value: commonName}
	if err = ca.PA.WillingToIssue(identifier); err != nil {
		err = fmt.Errorf("Policy forbids issuing for name %s", commonName)
		// AUDIT[ Certificate Requests ] 11917fa4-10ef-4e0d-9105-bacbe7836a3c
		ca.log.AuditErr(err)
		return emptyCert, err
	}
	for _, name := range hostNames {
		identifier = core.AcmeIdentifier{Type: core.IdentifierDNS, Value: name}
		if err = ca.PA.WillingToIssue(identifier); err != nil {
			err = fmt.Errorf("Policy forbids issuing for name %s", name)
			// AUDIT[ Certificate Requests ] 11917fa4-10ef-4e0d-9105-bacbe7836a3c
			ca.log.AuditErr(err)
			return emptyCert, err
		}
	}

	notAfter := ca.Clk.Now().Add(ca.ValidityPeriod)

	if ca.NotAfter.Before(notAfter) {
		// AUDIT[ Certificate Requests ] 11917fa4-10ef-4e0d-9105-bacbe7836a3c
		err = errors.New("Cannot issue a certificate that expires after the intermediate certificate.")
		ca.log.AuditErr(err)
		return emptyCert, err
	}

	// Convert the CSR to PEM
	csrPEM := string(pem.EncodeToMemory(&pem.Block{
		Type:  "CERTIFICATE REQUEST",
		Bytes: csr.Raw,
	}))

	// Get the next serial number
	tx, err := ca.DB.Begin()
	if err != nil {
		// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
		ca.log.AuditErr(err)
		return emptyCert, err
	}

	serialDec, err := ca.DB.IncrementAndGetSerial(tx)
	if err != nil {
		// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
		ca.log.Audit(fmt.Sprintf("Serial increment failed, rolling back: err=[%v]", err))
		tx.Rollback()
		return emptyCert, err
	}
	serialHex := fmt.Sprintf("%02X%014X", ca.Prefix, serialDec)

	// Send the cert off for signing
	req := signer.SignRequest{
		Request: csrPEM,
		Profile: ca.profile,
		Hosts:   hostNames,
		Subject: &signer.Subject{
			CN: commonName,
		},
		SerialSeq: serialHex,
	}

	certPEM, err := ca.Signer.Sign(req)
	if err != nil {
		// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
		ca.log.Audit(fmt.Sprintf("Signer failed, rolling back: serial=[%s] err=[%v]", serialHex, err))
		tx.Rollback()
		return emptyCert, err
	}

	if len(certPEM) == 0 {
		err = fmt.Errorf("No certificate returned by server")
		// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
		ca.log.Audit(fmt.Sprintf("PEM empty from Signer, rolling back: serial=[%s] err=[%v]", serialHex, err))
		tx.Rollback()
		return emptyCert, err
	}

	block, _ := pem.Decode(certPEM)
	if block == nil || block.Type != "CERTIFICATE" {
		err = fmt.Errorf("Invalid certificate value returned")

		// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
		ca.log.Audit(fmt.Sprintf("PEM decode error, aborting and rolling back issuance: pem=[%s] err=[%v]", certPEM, err))
		tx.Rollback()
		return emptyCert, err
	}
	certDER := block.Bytes

	cert := core.Certificate{
		DER: certDER,
	}

	// This is one last check for uncaught errors
	if err != nil {
		// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
		ca.log.Audit(fmt.Sprintf("Uncaught error, aborting and rolling back issuance: pem=[%s] err=[%v]", certPEM, err))
		tx.Rollback()
		return emptyCert, err
	}

	// Store the cert with the certificate authority, if provided
	_, err = ca.SA.AddCertificate(certDER, regID)
	if err != nil {
		// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
		ca.log.Audit(fmt.Sprintf("Failed RPC to store at SA, orphaning certificate: pem=[%s] err=[%v]", certPEM, err))
		tx.Rollback()
		return emptyCert, err
	}

	if err = tx.Commit(); err != nil {
		// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
		ca.log.Audit(fmt.Sprintf("Failed to commit, orphaning certificate: pem=[%s] err=[%v]", certPEM, err))
		return emptyCert, err
	}

	// Attempt to generate the OCSP Response now. If this raises an error, it is
	// logged but is not returned to the caller, as an error at this point does
	// not constitute an issuance failure.

	certObj, err := x509.ParseCertificate(certDER)
	if err != nil {
		ca.log.Warning(fmt.Sprintf("Post-Issuance OCSP failed parsing Certificate: %s", err))
		return cert, nil
	}

	serial := core.SerialToString(certObj.SerialNumber)

	signRequest := ocsp.SignRequest{
		Certificate: certObj,
		Status:      string(core.OCSPStatusGood),
	}

	ocspResponse, err := ca.OCSPSigner.Sign(signRequest)
	if err != nil {
		ca.log.Warning(fmt.Sprintf("Post-Issuance OCSP failed signing: %s", err))
		return cert, nil
	}

	err = ca.SA.UpdateOCSP(serial, ocspResponse)
	if err != nil {
		ca.log.Warning(fmt.Sprintf("Post-Issuance OCSP failed storing: %s", err))
		return cert, nil
	}

	// Do not return an err at this point; caller must know that the Certificate
	// was issued. (Also, it should be impossible for err to be non-nil here)
	return cert, nil
}
Ejemplo n.º 4
0
// NewCertificate is used by clients to request the issuance of a cert for an
// authorized identifier.
func (wfe *WebFrontEndImpl) NewCertificate(logEvent *requestEvent, response http.ResponseWriter, request *http.Request) {
	body, _, reg, err := wfe.verifyPOST(logEvent, request, true, core.ResourceNewCert)
	if err != nil {
		// verifyPOST handles its own setting of logEvent.Errors
		respMsg := malformedJWS
		respCode := statusCodeFromError(err)
		if _, ok := err.(core.NoSuchRegistrationError); ok {
			respMsg = unknownKey
			respCode = http.StatusForbidden
		}
		wfe.sendError(response, logEvent, respMsg, err, respCode)
		return
	}
	// Any version of the agreement is acceptable here. Version match is enforced in
	// wfe.Registration when agreeing the first time. Agreement updates happen
	// by mailing subscribers and don't require a registration update.
	if reg.Agreement == "" {
		wfe.sendError(response, logEvent, "Must agree to subscriber agreement before any further actions", nil, http.StatusForbidden)
		return
	}

	var certificateRequest core.CertificateRequest
	if err = json.Unmarshal(body, &certificateRequest); err != nil {
		logEvent.AddError("unable to JSON unmarshal CertificateRequest: %s", err)
		wfe.sendError(response, logEvent, "Error unmarshaling certificate request", err, http.StatusBadRequest)
		return
	}
	wfe.logCsr(request, 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.AddError("CSR public key failed GoodKey: %s", err)
		wfe.sendError(response, logEvent, "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
	// WFE is compromised, *and* the attacker knows the public key of an account
	// 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(certificateRequest, reg.ID)
	if err != nil {
		logEvent.AddError("unable to create new cert: %s", err)
		wfe.sendError(response, logEvent, "Error creating new cert", err, statusCodeFromError(err))
		return
	}

	// Make a URL for this certificate.
	// We use only the sequential part of the serial number, because it should
	// uniquely identify the certificate, and this makes it easy for anybody to
	// enumerate and mirror our certificates.
	parsedCertificate, err := x509.ParseCertificate([]byte(cert.DER))
	if err != nil {
		logEvent.AddError("unable to parse certificate: %s", err)
		wfe.sendError(response, logEvent, "Error creating new cert", err, http.StatusBadRequest)
		return
	}
	serial := parsedCertificate.SerialNumber
	certURL := wfe.CertBase + core.SerialToString(serial)

	// TODO Content negotiation
	response.Header().Add("Location", certURL)
	response.Header().Add("Link", link(wfe.BaseURL+IssuerPath, "up"))
	response.Header().Set("Content-Type", "application/pkix-cert")
	response.WriteHeader(http.StatusCreated)
	if _, err = response.Write(cert.DER); err != nil {
		logEvent.AddError(err.Error())
		wfe.log.Warning(fmt.Sprintf("Could not write response: %s", err))
	}
}
Ejemplo n.º 5
0
// verifyPOST reads and parses the request body, looks up the Registration
// corresponding to its JWK, verifies the JWS signature, checks that the
// resource field is present and correct in the JWS protected header, and
// returns the JWS payload bytes, the key used to verify, and the corresponding
// Registration (or error).  If regCheck is false, verifyPOST will still try to
// look up a registration object, and will return it if found. However, if no
// registration object is found, verifyPOST will attempt to verify the JWS using
// the key in the JWS headers, and return the key plus a dummy registration if
// successful. If a caller passes regCheck = false, it should plan on validating
// the key itself.  verifyPOST also appends its errors to requestEvent.Errors so
// code calling it does not need to if they imediately return a response to the
// user.
func (wfe *WebFrontEndImpl) verifyPOST(logEvent *requestEvent, request *http.Request, regCheck bool, resource core.AcmeResource) ([]byte, *jose.JsonWebKey, core.Registration, error) {
	var err error
	// TODO: We should return a pointer to a registration, which can be nil,
	// rather the a registration value with a sentinel value.
	// https://github.com/letsencrypt/boulder/issues/877
	reg := core.Registration{ID: 0}

	if _, ok := request.Header["Content-Length"]; !ok {
		err = core.LengthRequiredError("Content-Length header is required for POST.")
		wfe.stats.Inc("WFE.HTTP.ClientErrors.LengthRequiredError", 1, 1.0)
		logEvent.AddError("missing Content-Length header on POST")
		return nil, nil, reg, err
	}

	// Read body
	if request.Body == nil {
		err = core.MalformedRequestError("No body on POST")
		wfe.stats.Inc("WFE.Errors.NoPOSTBody", 1, 1.0)
		logEvent.AddError("no body on POST")
		return nil, nil, reg, err
	}

	bodyBytes, err := ioutil.ReadAll(request.Body)
	if err != nil {
		err = core.InternalServerError("unable to read request body")
		wfe.stats.Inc("WFE.Errors.UnableToReadRequestBody", 1, 1.0)
		logEvent.AddError("unable to read request body")
		return nil, nil, reg, err
	}

	body := string(bodyBytes)
	// Parse as JWS
	parsedJws, err := jose.ParseSigned(body)
	if err != nil {
		puberr := core.SignatureValidationError("Parse error reading JWS")
		wfe.stats.Inc("WFE.Errors.UnableToParseJWS", 1, 1.0)
		logEvent.AddError("could not JSON parse body into JWS: %s", err)
		return nil, nil, reg, puberr
	}

	// Verify JWS
	// NOTE: It might seem insecure for the WFE to be trusted to verify
	// client requests, i.e., that the verification should be done at the
	// RA.  However the WFE is the RA's only view of the outside world
	// *anyway*, so it could always lie about what key was used by faking
	// the signature itself.
	if len(parsedJws.Signatures) > 1 {
		err = core.SignatureValidationError("Too many signatures in POST body")
		wfe.stats.Inc("WFE.Errors.TooManyJWSSignaturesInPOST", 1, 1.0)
		logEvent.AddError("too many signatures in POST body: %d", len(parsedJws.Signatures))
		return nil, nil, reg, err
	}
	if len(parsedJws.Signatures) == 0 {
		err = core.SignatureValidationError("POST JWS not signed")
		wfe.stats.Inc("WFE.Errors.JWSNotSignedInPOST", 1, 1.0)
		logEvent.AddError("no signatures in POST body")
		return nil, nil, reg, err
	}
	submittedKey := parsedJws.Signatures[0].Header.JsonWebKey
	if submittedKey == nil {
		err = core.SignatureValidationError("No JWK in JWS header")
		wfe.stats.Inc("WFE.Errors.NoJWKInJWSSignatureHeader", 1, 1.0)
		logEvent.AddError("no JWK in JWS signature header in POST body")
		return nil, nil, reg, err
	}

	var key *jose.JsonWebKey
	reg, err = wfe.SA.GetRegistrationByKey(*submittedKey)
	// Special case: If no registration was found, but regCheck is false, use an
	// empty registration and the submitted key. The caller is expected to do some
	// validation on the returned key.
	if _, ok := err.(core.NoSuchRegistrationError); ok && !regCheck {
		// When looking up keys from the registrations DB, we can be confident they
		// are "good". But when we are verifying against any submitted key, we want
		// to check its quality before doing the verify.
		if err = core.GoodKey(submittedKey.Key); err != nil {
			wfe.stats.Inc("WFE.Errors.JWKRejectedByGoodKey", 1, 1.0)
			logEvent.AddError("JWK in request was rejected by GoodKey: %s", err)
			return nil, nil, reg, err
		}
		key = submittedKey
	} else if err != nil {
		// For all other errors, or if regCheck is true, return error immediately.
		wfe.stats.Inc("WFE.Errors.UnableToGetRegistrationByKey", 1, 1.0)
		logEvent.AddError("unable to fetch registration by the given JWK: %s", err)
		return nil, nil, reg, err
	} else {
		// If the lookup was successful, use that key.
		key = &reg.Key
		logEvent.Requester = reg.ID
		logEvent.Contacts = reg.Contact
	}

	payload, header, err := parsedJws.Verify(key)
	if err != nil {
		puberr := core.SignatureValidationError("JWS verification error")
		wfe.stats.Inc("WFE.Errors.JWSVerificationFailed", 1, 1.0)
		n := len(body)
		if n > 100 {
			n = 100
		}
		logEvent.AddError("verification of JWS with the JWK failed: %v; body: %s", err, body[:n])
		return nil, nil, reg, puberr
	}

	// Check that the request has a known anti-replay nonce
	// i.e., Nonce is in protected header and
	if err != nil || len(header.Nonce) == 0 {
		wfe.stats.Inc("WFE.Errors.JWSMissingNonce", 1, 1.0)
		logEvent.AddError("JWS is missing an anti-replay nonce")
		err = core.SignatureValidationError("JWS has no anti-replay nonce")
		return nil, nil, reg, err
	} else if !wfe.nonceService.Valid(header.Nonce) {
		wfe.stats.Inc("WFE.Errors.JWSInvalidNonce", 1, 1.0)
		logEvent.AddError("JWS has an invalid anti-replay nonce")
		err = core.SignatureValidationError(fmt.Sprintf("JWS has invalid anti-replay nonce"))
		return nil, nil, reg, err
	}

	// Check that the "resource" field is present and has the correct value
	var parsedRequest struct {
		Resource string `json:"resource"`
	}
	err = json.Unmarshal([]byte(payload), &parsedRequest)
	if err != nil {
		wfe.stats.Inc("WFE.Errors.UnparsableJWSPayload", 1, 1.0)
		logEvent.AddError("unable to JSON parse resource from JWS payload: %s", err)
		puberr := core.SignatureValidationError("Request payload did not parse as JSON")
		return nil, nil, reg, puberr
	}
	if parsedRequest.Resource == "" {
		wfe.stats.Inc("WFE.Errors.NoResourceInJWSPayload", 1, 1.0)
		logEvent.AddError("JWS request payload does not specifiy a resource")
		err = core.MalformedRequestError("Request payload does not specify a resource")
		return nil, nil, reg, err
	} else if resource != core.AcmeResource(parsedRequest.Resource) {
		wfe.stats.Inc("WFE.Errors.MismatchedResourceInJWSPayload", 1, 1.0)
		logEvent.AddError("JWS request payload does not match resource")
		err = core.MalformedRequestError(fmt.Sprintf("JWS resource payload does not match the HTTP resource: %s != %s", parsedRequest.Resource, resource))
		return nil, nil, reg, err
	}

	return []byte(payload), key, reg, nil
}
Ejemplo n.º 6
0
// IssueCertificate attempts to convert a CSR into a signed Certificate, while
// enforcing all policies. Names (domains) in the CertificateRequest will be
// lowercased before storage.
func (ca *CertificateAuthorityImpl) IssueCertificate(csr x509.CertificateRequest, regID int64) (core.Certificate, error) {
	emptyCert := core.Certificate{}
	var err error

	if err := ca.checkHSMFault(); err != nil {
		return emptyCert, err
	}

	key, ok := csr.PublicKey.(crypto.PublicKey)
	if !ok {
		err = core.MalformedRequestError("Invalid public key in CSR.")
		// AUDIT[ Certificate Requests ] 11917fa4-10ef-4e0d-9105-bacbe7836a3c
		ca.log.AuditErr(err)
		return emptyCert, err
	}
	if err = core.GoodKey(key); err != nil {
		err = core.MalformedRequestError(fmt.Sprintf("Invalid public key in CSR: %s", err.Error()))
		// AUDIT[ Certificate Requests ] 11917fa4-10ef-4e0d-9105-bacbe7836a3c
		ca.log.AuditErr(err)
		return emptyCert, err
	}
	if badSignatureAlgorithms[csr.SignatureAlgorithm] {
		err = core.MalformedRequestError("Invalid signature algorithm in CSR")
		// AUDIT[ Certificate Requests ] 11917fa4-10ef-4e0d-9105-bacbe7836a3c
		ca.log.AuditErr(err)
		return emptyCert, err
	}

	// Pull hostnames from CSR
	// Authorization is checked by the RA
	commonName := ""
	hostNames := make([]string, len(csr.DNSNames))
	copy(hostNames, csr.DNSNames)
	if len(csr.Subject.CommonName) > 0 {
		commonName = strings.ToLower(csr.Subject.CommonName)
		hostNames = append(hostNames, commonName)
	} else if len(hostNames) > 0 {
		commonName = strings.ToLower(hostNames[0])
	} else {
		err = core.MalformedRequestError("Cannot issue a certificate without a hostname.")
		// AUDIT[ Certificate Requests ] 11917fa4-10ef-4e0d-9105-bacbe7836a3c
		ca.log.AuditErr(err)
		return emptyCert, err
	}

	// Collapse any duplicate names.  Note that this operation may re-order the names
	hostNames = core.UniqueLowerNames(hostNames)
	if ca.MaxNames > 0 && len(hostNames) > ca.MaxNames {
		err = core.MalformedRequestError(fmt.Sprintf("Certificate request has %d > %d names", len(hostNames), ca.MaxNames))
		ca.log.WarningErr(err)
		return emptyCert, err
	}

	// Verify that names are allowed by policy
	identifier := core.AcmeIdentifier{Type: core.IdentifierDNS, Value: commonName}
	if err = ca.PA.WillingToIssue(identifier, regID); err != nil {
		err = core.MalformedRequestError(fmt.Sprintf("Policy forbids issuing for name %s", commonName))
		// AUDIT[ Certificate Requests ] 11917fa4-10ef-4e0d-9105-bacbe7836a3c
		ca.log.AuditErr(err)
		return emptyCert, err
	}
	for _, name := range hostNames {
		identifier = core.AcmeIdentifier{Type: core.IdentifierDNS, Value: name}
		if err = ca.PA.WillingToIssue(identifier, regID); err != nil {
			err = core.MalformedRequestError(fmt.Sprintf("Policy forbids issuing for name %s", name))
			// AUDIT[ Certificate Requests ] 11917fa4-10ef-4e0d-9105-bacbe7836a3c
			ca.log.AuditErr(err)
			return emptyCert, err
		}
	}

	notAfter := ca.Clk.Now().Add(ca.ValidityPeriod)

	if ca.NotAfter.Before(notAfter) {
		err = core.InternalServerError("Cannot issue a certificate that expires after the intermediate certificate.")
		// AUDIT[ Certificate Requests ] 11917fa4-10ef-4e0d-9105-bacbe7836a3c
		ca.log.AuditErr(err)
		return emptyCert, err
	}

	// Convert the CSR to PEM
	csrPEM := string(pem.EncodeToMemory(&pem.Block{
		Type:  "CERTIFICATE REQUEST",
		Bytes: csr.Raw,
	}))

	// We want 136 bits of random number, plus an 8-bit instance id prefix.
	const randBits = 136
	serialBytes := make([]byte, randBits/8+1)
	serialBytes[0] = byte(ca.Prefix)
	_, err = rand.Read(serialBytes[1:])
	if err != nil {
		err = core.InternalServerError(err.Error())
		// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
		ca.log.Audit(fmt.Sprintf("Serial randomness failed, err=[%v]", err))
		return emptyCert, err
	}
	serialHex := hex.EncodeToString(serialBytes)
	serialBigInt := big.NewInt(0)
	serialBigInt = serialBigInt.SetBytes(serialBytes)

	// Send the cert off for signing
	req := signer.SignRequest{
		Request: csrPEM,
		Profile: ca.profile,
		Hosts:   hostNames,
		Subject: &signer.Subject{
			CN: commonName,
		},
		Serial: serialBigInt,
	}

	certPEM, err := ca.Signer.Sign(req)
	ca.noteHSMFault(err)
	if err != nil {
		err = core.InternalServerError(err.Error())
		// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
		ca.log.Audit(fmt.Sprintf("Signer failed, rolling back: serial=[%s] err=[%v]", serialHex, err))
		return emptyCert, err
	}

	if len(certPEM) == 0 {
		err = core.InternalServerError("No certificate returned by server")
		// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
		ca.log.Audit(fmt.Sprintf("PEM empty from Signer, rolling back: serial=[%s] err=[%v]", serialHex, err))
		return emptyCert, err
	}

	block, _ := pem.Decode(certPEM)
	if block == nil || block.Type != "CERTIFICATE" {
		err = core.InternalServerError("Invalid certificate value returned")
		// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
		ca.log.Audit(fmt.Sprintf("PEM decode error, aborting and rolling back issuance: pem=[%s] err=[%v]", certPEM, err))
		return emptyCert, err
	}
	certDER := block.Bytes

	cert := core.Certificate{
		DER: certDER,
	}

	// This is one last check for uncaught errors
	if err != nil {
		err = core.InternalServerError(err.Error())
		// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
		ca.log.Audit(fmt.Sprintf("Uncaught error, aborting and rolling back issuance: pem=[%s] err=[%v]", certPEM, err))
		return emptyCert, err
	}

	// Store the cert with the certificate authority, if provided
	_, err = ca.SA.AddCertificate(certDER, regID)
	if err != nil {
		err = core.InternalServerError(err.Error())
		// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
		ca.log.Audit(fmt.Sprintf("Failed RPC to store at SA, orphaning certificate: pem=[%s] err=[%v]", certPEM, err))
		return emptyCert, err
	}

	// Submit the certificate to any configured CT logs
	go ca.Publisher.SubmitToCT(certDER)

	// Do not return an err at this point; caller must know that the Certificate
	// was issued. (Also, it should be impossible for err to be non-nil here)
	return cert, nil
}
Ejemplo n.º 7
0
// verifyPOST reads and parses the request body, looks up the Registration
// corresponding to its JWK, verifies the JWS signature,
// checks that the resource field is present and correct in the JWS protected
// header, and returns the JWS payload bytes, the key used to verify, and the
// corresponding Registration (or error).
// If regCheck is false, verifyPOST will still try to look up a registration
// object, and will return it if found. However, if no registration object is
// found, verifyPOST will attempt to verify the JWS using the key in the JWS
// headers, and return the key plus a dummy registration if successful. If a
// caller passes regCheck = false, it should plan on validating the key itself.
func (wfe *WebFrontEndImpl) verifyPOST(request *http.Request, regCheck bool, resource core.AcmeResource) ([]byte, *jose.JsonWebKey, core.Registration, error) {
	var err error
	// TODO: We should return a pointer to a registration, which can be nil,
	// rather the a registration value with a sentinel value.
	// https://github.com/letsencrypt/boulder/issues/877
	reg := core.Registration{ID: -1}

	if _, ok := request.Header["Content-Length"]; !ok {
		err = core.LengthRequiredError("Content-Length header is required for POST.")
		wfe.log.Debug(err.Error())
		return nil, nil, reg, err
	}

	// Read body
	if request.Body == nil {
		err = core.MalformedRequestError("No body on POST")
		wfe.log.Debug(err.Error())
		return nil, nil, reg, err
	}

	bodyBytes, err := ioutil.ReadAll(request.Body)
	if err != nil {
		err = core.InternalServerError(err.Error())
		wfe.log.Debug(err.Error())
		return nil, nil, reg, err
	}

	body := string(bodyBytes)
	// Parse as JWS
	parsedJws, err := jose.ParseSigned(body)
	if err != nil {
		puberr := core.SignatureValidationError("Parse error reading JWS")
		wfe.log.Debug(fmt.Sprintf("%v :: %v", puberr.Error(), err.Error()))
		return nil, nil, reg, puberr
	}

	// Verify JWS
	// NOTE: It might seem insecure for the WFE to be trusted to verify
	// client requests, i.e., that the verification should be done at the
	// RA.  However the WFE is the RA's only view of the outside world
	// *anyway*, so it could always lie about what key was used by faking
	// the signature itself.
	if len(parsedJws.Signatures) > 1 {
		err = core.SignatureValidationError("Too many signatures on POST")
		wfe.log.Debug(err.Error())
		return nil, nil, reg, err
	}
	if len(parsedJws.Signatures) == 0 {
		err = core.SignatureValidationError("POST JWS not signed")
		wfe.log.Debug(err.Error())
		return nil, nil, reg, err
	}
	submittedKey := parsedJws.Signatures[0].Header.JsonWebKey
	if submittedKey == nil {
		err = core.SignatureValidationError("No JWK in JWS header")
		wfe.log.Debug(err.Error())
		return nil, nil, reg, err
	}

	var key *jose.JsonWebKey
	reg, err = wfe.SA.GetRegistrationByKey(*submittedKey)
	// Special case: If no registration was found, but regCheck is false, use an
	// empty registration and the submitted key. The caller is expected to do some
	// validation on the returned key.
	if _, ok := err.(core.NoSuchRegistrationError); ok && !regCheck {
		// When looking up keys from the registrations DB, we can be confident they
		// are "good". But when we are verifying against any submitted key, we want
		// to check its quality before doing the verify.
		if err = core.GoodKey(submittedKey.Key); err != nil {
			return nil, nil, reg, err
		}
		key = submittedKey
	} else if err != nil {
		// For all other errors, or if regCheck is true, return error immediately.
		return nil, nil, reg, err
	} else {
		// If the lookup was successful, use that key.
		key = &reg.Key
	}

	payload, header, err := parsedJws.Verify(key)
	if err != nil {
		puberr := core.SignatureValidationError("JWS verification error")
		wfe.log.Debug(string(body))
		wfe.log.Debug(fmt.Sprintf("%v :: %v", puberr.Error(), err.Error()))
		return nil, nil, reg, puberr
	}

	// Check that the request has a known anti-replay nonce
	// i.e., Nonce is in protected header and
	if err != nil || len(header.Nonce) == 0 {
		err = core.SignatureValidationError("JWS has no anti-replay nonce")
		wfe.log.Debug(err.Error())
		return nil, nil, reg, err
	} else if !wfe.nonceService.Valid(header.Nonce) {
		err = core.SignatureValidationError(fmt.Sprintf("JWS has invalid anti-replay nonce"))
		wfe.log.Debug(err.Error())
		return nil, nil, reg, err
	}

	// Check that the "resource" field is present and has the correct value
	var parsedRequest struct {
		Resource string `json:"resource"`
	}
	err = json.Unmarshal([]byte(payload), &parsedRequest)
	if err != nil {
		puberr := core.SignatureValidationError("Request payload did not parse as JSON")
		wfe.log.Debug(fmt.Sprintf("%v :: %v", puberr.Error(), err.Error()))
		return nil, nil, reg, puberr
	}
	if parsedRequest.Resource == "" {
		err = core.MalformedRequestError("Request payload does not specify a resource")
		wfe.log.Debug(err.Error())
		return nil, nil, reg, err
	} else if resource != core.AcmeResource(parsedRequest.Resource) {
		err = core.MalformedRequestError(fmt.Sprintf("Request payload has invalid resource: %s != %s", parsedRequest.Resource, resource))
		wfe.log.Debug(err.Error())
		return nil, nil, reg, err
	}

	return []byte(payload), key, reg, nil
}