func (ra *RegistrationAuthorityImpl) validateContacts(ctx context.Context, contacts *[]*core.AcmeURL) error { if contacts == nil || len(*contacts) == 0 { return nil // Nothing to validate } if ra.maxContactsPerReg > 0 && len(*contacts) > ra.maxContactsPerReg { return core.MalformedRequestError(fmt.Sprintf("Too many contacts provided: %d > %d", len(*contacts), ra.maxContactsPerReg)) } for _, contact := range *contacts { if contact == nil { return core.MalformedRequestError("Invalid contact") } if contact.Scheme != "mailto" { return core.MalformedRequestError(fmt.Sprintf("Contact method %s is not supported", contact.Scheme)) } start := ra.clk.Now() ra.stats.Inc("RA.ValidateEmail.Calls", 1, 1.0) problem := validateEmail(ctx, contact.Opaque, ra.DNSResolver) ra.stats.TimingDuration("RA.ValidateEmail.Latency", ra.clk.Now().Sub(start), 1.0) if problem != nil { ra.stats.Inc("RA.ValidateEmail.Errors", 1, 1.0) return problem } ra.stats.Inc("RA.ValidateEmail.Successes", 1, 1.0) } return nil }
func (ra *RegistrationAuthorityImpl) validateContacts(contacts []*core.AcmeURL) (err error) { if ra.maxContactsPerReg > 0 && len(contacts) > ra.maxContactsPerReg { return core.MalformedRequestError(fmt.Sprintf("Too many contacts provided: %d > %d", len(contacts), ra.maxContactsPerReg)) } for _, contact := range contacts { switch contact.Scheme { case "tel": continue case "mailto": rtt, err := validateEmail(contact.Opaque, ra.DNSResolver) ra.stats.TimingDuration("RA.DNS.RTT.A", rtt, 1.0) ra.stats.Inc("RA.DNS.Rate", 1, 1.0) if err != nil { return core.MalformedRequestError(fmt.Sprintf( "Validation of contact %s failed: %s", contact, err)) } default: err = core.MalformedRequestError(fmt.Sprintf("Contact method %s is not supported", contact.Scheme)) return } } return }
func (ra *RegistrationAuthorityImpl) validateContacts(contacts []*core.AcmeURL) (err error) { if ra.maxContactsPerReg > 0 && len(contacts) > ra.maxContactsPerReg { return core.MalformedRequestError(fmt.Sprintf("Too many contacts provided: %d > %d", len(contacts), ra.maxContactsPerReg)) } for _, contact := range contacts { if contact == nil { return core.MalformedRequestError("Invalid contact") } switch contact.Scheme { case "tel": continue case "mailto": start := ra.clk.Now() ra.stats.Inc("RA.ValidateEmail.Calls", 1, 1.0) problem := validateEmail(contact.Opaque, ra.DNSResolver) ra.stats.TimingDuration("RA.ValidateEmail.Latency", ra.clk.Now().Sub(start), 1.0) if problem != nil { ra.stats.Inc("RA.ValidateEmail.Errors", 1, 1.0) return problem } ra.stats.Inc("RA.ValidateEmail.Successes", 1, 1.0) default: err = core.MalformedRequestError(fmt.Sprintf("Contact method %s is not supported", contact.Scheme)) return } } return }
// UpdateAuthorization updates an authorization with new values. func (ra *RegistrationAuthorityImpl) UpdateAuthorization(base core.Authorization, challengeIndex int, response core.Challenge) (authz core.Authorization, err error) { // Copy information over that the client is allowed to supply authz = base if challengeIndex >= len(authz.Challenges) { err = core.MalformedRequestError(fmt.Sprintf("Invalid challenge index: %d", challengeIndex)) return } authz.Challenges[challengeIndex] = authz.Challenges[challengeIndex].MergeResponse(response) // Store the updated version if err = ra.SA.UpdatePendingAuthorization(authz); err != nil { // This can pretty much only happen when the client corrupts the Challenge // data. err = core.MalformedRequestError("Challenge data was corrupted") return } // Look up the account key for this authorization reg, err := ra.SA.GetRegistration(authz.RegistrationID) if err != nil { err = core.InternalServerError(err.Error()) return } // Dispatch to the VA for service ra.VA.UpdateValidations(authz, challengeIndex, reg.Key) return }
// UpdateAuthorization updates an authorization with new values. func (ra *RegistrationAuthorityImpl) UpdateAuthorization(base core.Authorization, challengeIndex int, response core.Challenge) (authz core.Authorization, err error) { // Refuse to update expired authorizations if base.Expires == nil || base.Expires.Before(ra.clk.Now()) { err = core.NotFoundError("Expired authorization") return } // Copy information over that the client is allowed to supply authz = base if challengeIndex >= len(authz.Challenges) { err = core.MalformedRequestError(fmt.Sprintf("Invalid challenge index: %d", challengeIndex)) return } authz.Challenges[challengeIndex].KeyAuthorization = response.KeyAuthorization // At this point, the challenge should be sane as a complete challenge if !authz.Challenges[challengeIndex].IsSane(true) { err = core.MalformedRequestError("Response does not complete challenge") return } // Store the updated version if err = ra.SA.UpdatePendingAuthorization(authz); err != nil { // This can pretty much only happen when the client corrupts the Challenge // data. err = core.MalformedRequestError("Challenge data was corrupted") return } ra.stats.Inc("RA.NewPendingAuthorizations", 1, 1.0) // Look up the account key for this authorization reg, err := ra.SA.GetRegistration(authz.RegistrationID) if err != nil { err = core.InternalServerError(err.Error()) return } // Reject the update if the challenge in question was created // with a different account key if !core.KeyDigestEquals(reg.Key, authz.Challenges[challengeIndex].AccountKey) { err = core.UnauthorizedError("Challenge cannot be updated with a different key") return } // Dispatch to the VA for service ra.VA.UpdateValidations(authz, challengeIndex) ra.stats.Inc("RA.UpdatedPendingAuthorizations", 1, 1.0) return }
// Unwraps a rpcError and returns the correct error type. func unwrapError(rpcError *rpcError) error { if rpcError != nil { switch rpcError.Type { case "InternalServerError": return core.InternalServerError(rpcError.Value) case "NotSupportedError": return core.NotSupportedError(rpcError.Value) case "MalformedRequestError": return core.MalformedRequestError(rpcError.Value) case "UnauthorizedError": return core.UnauthorizedError(rpcError.Value) case "NotFoundError": return core.NotFoundError(rpcError.Value) case "SyntaxError": return core.SyntaxError(rpcError.Value) case "SignatureValidationError": return core.SignatureValidationError(rpcError.Value) case "CertificateIssuanceError": return core.CertificateIssuanceError(rpcError.Value) case "NoSuchRegistrationError": return core.NoSuchRegistrationError(rpcError.Value) case "TooManyRPCRequestsError": return core.TooManyRPCRequestsError(rpcError.Value) case "RateLimitedError": return core.RateLimitedError(rpcError.Value) case "ServiceUnavailableError": return core.ServiceUnavailableError(rpcError.Value) default: return errors.New(rpcError.Value) } } return nil }
// Unwraps a rpcError and returns the correct error type. func unwrapError(rpcError *rpcError) error { if rpcError != nil { switch rpcError.Type { case "InternalServerError": return core.InternalServerError(rpcError.Value) case "NotSupportedError": return core.NotSupportedError(rpcError.Value) case "MalformedRequestError": return core.MalformedRequestError(rpcError.Value) case "UnauthorizedError": return core.UnauthorizedError(rpcError.Value) case "NotFoundError": return core.NotFoundError(rpcError.Value) case "SignatureValidationError": return core.SignatureValidationError(rpcError.Value) case "NoSuchRegistrationError": return core.NoSuchRegistrationError(rpcError.Value) case "TooManyRPCRequestsError": return core.TooManyRPCRequestsError(rpcError.Value) case "RateLimitedError": return core.RateLimitedError(rpcError.Value) default: if strings.HasPrefix(rpcError.Type, "urn:") { return &probs.ProblemDetails{ Type: probs.ProblemType(rpcError.Type), Detail: rpcError.Value, HTTPStatus: rpcError.HTTPStatus, } } return errors.New(rpcError.Value) } } return nil }
// 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 }
// Unwraps a RPCError and returns the correct error type. func unwrapError(rpcError RPCError) (err error) { if rpcError.Value != "" { switch rpcError.Type { case "InternalServerError": err = core.InternalServerError(rpcError.Value) case "NotSupportedError": err = core.NotSupportedError(rpcError.Value) case "MalformedRequestError": err = core.MalformedRequestError(rpcError.Value) case "UnauthorizedError": err = core.UnauthorizedError(rpcError.Value) case "NotFoundError": err = core.NotFoundError(rpcError.Value) case "SyntaxError": err = core.SyntaxError(rpcError.Value) case "SignatureValidationError": err = core.SignatureValidationError(rpcError.Value) case "CertificateIssuanceError": err = core.CertificateIssuanceError(rpcError.Value) default: err = errors.New(rpcError.Value) } } return }
func validateEmail(address string, resolver core.DNSResolver) (err error) { _, err = mail.ParseAddress(address) if err != nil { err = core.MalformedRequestError(fmt.Sprintf("%s is not a valid e-mail address", address)) return } splitEmail := strings.SplitN(address, "@", -1) domain := strings.ToLower(splitEmail[len(splitEmail)-1]) var mx []string mx, _, err = resolver.LookupMX(domain) if err != nil || len(mx) == 0 { err = core.MalformedRequestError(fmt.Sprintf("No MX record for domain %s", domain)) return } 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())) } 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 }
func unwrapError(err error) error { code := grpc.Code(err) errBody := grpc.ErrorDesc(err) switch code { case InternalServerError: return core.InternalServerError(errBody) case NotSupportedError: return core.NotSupportedError(errBody) case MalformedRequestError: return core.MalformedRequestError(errBody) case UnauthorizedError: return core.UnauthorizedError(errBody) case NotFoundError: return core.NotFoundError(errBody) case SignatureValidationError: return core.SignatureValidationError(errBody) case NoSuchRegistrationError: return core.NoSuchRegistrationError(errBody) case RateLimitedError: return core.RateLimitedError(errBody) case LengthRequiredError: return core.LengthRequiredError(errBody) case BadNonceError: return core.BadNonceError(errBody) default: return err } }
func TestWrapError(t *testing.T) { testCases := []error{ core.InternalServerError("foo"), core.NotSupportedError("foo"), core.MalformedRequestError("foo"), core.UnauthorizedError("foo"), core.NotFoundError("foo"), core.SignatureValidationError("foo"), core.CertificateIssuanceError("foo"), core.NoSuchRegistrationError("foo"), core.RateLimitedError("foo"), core.TooManyRPCRequestsError("foo"), errors.New("foo"), } for _, c := range testCases { wrapped := wrapError(c) test.AssertEquals(t, wrapped.Type, reflect.TypeOf(c).Name()) test.AssertEquals(t, wrapped.Value, "foo") unwrapped := unwrapError(wrapped) test.AssertEquals(t, wrapped.Type, reflect.TypeOf(unwrapped).Name()) test.AssertEquals(t, unwrapped.Error(), "foo") } complicated := []struct { given error expected error }{ { &probs.ProblemDetails{ Type: probs.ConnectionProblem, Detail: "whoops", HTTPStatus: 417, }, &probs.ProblemDetails{ Type: probs.ConnectionProblem, Detail: "whoops", HTTPStatus: 417, }, }, { &probs.ProblemDetails{Type: "invalid", Detail: "hm"}, errors.New("hm"), }, { errors.New(""), errors.New(""), }, } for i, tc := range complicated { actual := unwrapError(wrapError(tc.given)) if !reflect.DeepEqual(tc.expected, actual) { t.Errorf("rpc error wrapping case %d: want %#v, got %#v", i, tc.expected, actual) } } }
// DeactivateAuthorization deactivates a currently valid authorization func (ra *RegistrationAuthorityImpl) DeactivateAuthorization(ctx context.Context, auth core.Authorization) error { if auth.Status != core.StatusValid && auth.Status != core.StatusPending { return core.MalformedRequestError("Only valid and pending authorizations can be deactivated") } err := ra.SA.DeactivateAuthorization(ctx, auth.ID) if err != nil { return core.InternalServerError(err.Error()) } return nil }
// DeactivateRegistration deactivates a valid registration func (ra *RegistrationAuthorityImpl) DeactivateRegistration(ctx context.Context, reg core.Registration) error { if reg.Status != core.StatusValid { return core.MalformedRequestError("Only valid registrations can be deactivated") } err := ra.SA.DeactivateRegistration(ctx, reg.ID) if err != nil { return core.InternalServerError(err.Error()) } return nil }
// GoodCurve determines if an elliptic curve meets our requirements. func (policy *KeyPolicy) goodCurve(c elliptic.Curve) (err error) { // Simply use a whitelist for now. params := c.Params() switch { case policy.AllowECDSANISTP256 && params == elliptic.P256().Params(): return nil case policy.AllowECDSANISTP384 && params == elliptic.P384().Params(): return nil default: return core.MalformedRequestError(fmt.Sprintf("ECDSA curve %v not allowed", params.Name)) } }
func (ra *RegistrationAuthorityImpl) validateContacts(ctx context.Context, contacts *[]string) error { if contacts == nil || len(*contacts) == 0 { return nil // Nothing to validate } if ra.maxContactsPerReg > 0 && len(*contacts) > ra.maxContactsPerReg { return core.MalformedRequestError(fmt.Sprintf("Too many contacts provided: %d > %d", len(*contacts), ra.maxContactsPerReg)) } for _, contact := range *contacts { if contact == "" { return core.MalformedRequestError("Empty contact") } parsed, err := url.Parse(contact) if err != nil { return core.MalformedRequestError("Invalid contact") } if parsed.Scheme != "mailto" { return core.MalformedRequestError(fmt.Sprintf("Contact method %s is not supported", parsed.Scheme)) } if !core.IsASCII(contact) { return core.MalformedRequestError( fmt.Sprintf("Contact email [%s] contains non-ASCII characters", contact)) } start := ra.clk.Now() ra.stats.Inc("ValidateEmail.Calls", 1) problem := validateEmail(ctx, parsed.Opaque, ra.DNSResolver) ra.stats.TimingDuration("ValidateEmail.Latency", ra.clk.Now().Sub(start)) if problem != nil { ra.stats.Inc("ValidateEmail.Errors", 1) return problem } ra.stats.Inc("ValidateEmail.Successes", 1) } return nil }
// GoodKey returns true iff the key is acceptable for both TLS use and account // 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 (policy *KeyPolicy) GoodKey(key crypto.PublicKey) error { switch t := key.(type) { case rsa.PublicKey: return policy.goodKeyRSA(t) case *rsa.PublicKey: return policy.goodKeyRSA(*t) case ecdsa.PublicKey: return policy.goodKeyECDSA(t) case *ecdsa.PublicKey: return policy.goodKeyECDSA(*t) default: return core.MalformedRequestError(fmt.Sprintf("Unknown key type %s", reflect.TypeOf(key))) } }
func validateEmail(address string, resolver core.DNSResolver) (rtt time.Duration, err error) { _, err = mail.ParseAddress(address) if err != nil { return time.Duration(0), errUnparseableEmail } splitEmail := strings.SplitN(address, "@", -1) domain := strings.ToLower(splitEmail[len(splitEmail)-1]) result, rtt, err := resolver.LookupHost(domain) if err == nil && len(result) == 0 { err = errEmptyDNSResponse } if err != nil { problem := dns.ProblemDetailsFromDNSError(err) err = core.MalformedRequestError(problem.Detail) } return }
func validateContacts(contacts []*core.AcmeURL, resolver core.DNSResolver) (err error) { for _, contact := range contacts { switch contact.Scheme { case "tel": continue case "mailto": err = validateEmail(contact.Opaque, resolver) if err != nil { return } default: err = core.MalformedRequestError(fmt.Sprintf("Contact method %s is not supported", contact.Scheme)) return } } return }
func (ra *RegistrationAuthorityImpl) UpdateAuthorization(base core.Authorization, challengeIndex int, response core.Challenge) (authz core.Authorization, err error) { // Copy information over that the client is allowed to supply authz = base if challengeIndex >= len(authz.Challenges) { err = core.MalformedRequestError("Invalid challenge index") return } authz.Challenges[challengeIndex] = authz.Challenges[challengeIndex].MergeResponse(response) // Store the updated version if err = ra.SA.UpdatePendingAuthorization(authz); err != nil { return } // Dispatch to the VA for service ra.VA.UpdateValidations(authz) return }
func validateContacts(contacts []*core.AcmeURL, resolver core.DNSResolver, stats statsd.Statter) (err error) { for _, contact := range contacts { switch contact.Scheme { case "tel": continue case "mailto": rtt, err := validateEmail(contact.Opaque, resolver) stats.TimingDuration("RA.DNS.RTT.MX", rtt, 1.0) stats.Inc("RA.DNS.Rate", 1, 1.0) if err != nil { return err } default: err = core.MalformedRequestError(fmt.Sprintf("Contact method %s is not supported", contact.Scheme)) return } } return }
func TestErrors(t *testing.T) { testcases := []struct { err error expectedCode codes.Code }{ {core.MalformedRequestError("test 1"), MalformedRequestError}, {core.NotSupportedError("test 2"), NotSupportedError}, {core.UnauthorizedError("test 3"), UnauthorizedError}, {core.NotFoundError("test 4"), NotFoundError}, {core.LengthRequiredError("test 5"), LengthRequiredError}, {core.SignatureValidationError("test 6"), SignatureValidationError}, {core.RateLimitedError("test 7"), RateLimitedError}, {core.BadNonceError("test 8"), BadNonceError}, {core.NoSuchRegistrationError("test 9"), NoSuchRegistrationError}, {core.InternalServerError("test 10"), InternalServerError}, } for _, tc := range testcases { wrappedErr := wrapError(tc.err) test.AssertEquals(t, grpc.Code(wrappedErr), tc.expectedCode) test.AssertEquals(t, tc.err, unwrapError(wrappedErr)) } }
func TestWrapError(t *testing.T) { testCases := []error{ core.InternalServerError("foo"), core.NotSupportedError("foo"), core.MalformedRequestError("foo"), core.UnauthorizedError("foo"), core.NotFoundError("foo"), core.SyntaxError("foo"), core.SignatureValidationError("foo"), core.CertificateIssuanceError("foo"), core.NoSuchRegistrationError("foo"), core.RateLimitedError("foo"), core.TooManyRPCRequestsError("foo"), } for _, c := range testCases { wrapped := wrapError(c) test.AssertEquals(t, wrapped.Type, reflect.TypeOf(c).Name()) test.AssertEquals(t, wrapped.Value, "foo") unwrapped := unwrapError(wrapped) test.AssertEquals(t, wrapped.Type, reflect.TypeOf(unwrapped).Name()) test.AssertEquals(t, unwrapped.Error(), "foo") } }
// GoodKeyRSA determines if a RSA pubkey meets our requirements func (policy *KeyPolicy) goodKeyRSA(key rsa.PublicKey) (err error) { if !policy.AllowRSA { return core.MalformedRequestError("RSA keys are not allowed") } // Baseline Requirements Appendix A // Modulus must be >= 2048 bits and <= 4096 bits modulus := key.N modulusBitLen := modulus.BitLen() const maxKeySize = 4096 if modulusBitLen < 2048 { return core.MalformedRequestError(fmt.Sprintf("Key too small: %d", modulusBitLen)) } if modulusBitLen > maxKeySize { return core.MalformedRequestError(fmt.Sprintf("Key too large: %d > %d", modulusBitLen, maxKeySize)) } // Bit lengths that are not a multiple of 8 may cause problems on some // client implementations. if modulusBitLen%8 != 0 { return core.MalformedRequestError(fmt.Sprintf("Key length wasn't a multiple of 8: %d", modulusBitLen)) } // The CA SHALL confirm that the value of the public exponent is an // odd number equal to 3 or more. Additionally, the public exponent // SHOULD be in the range between 2^16 + 1 and 2^256-1. // NOTE: rsa.PublicKey cannot represent an exponent part greater than // 2^32 - 1 or 2^64 - 1, because it stores E as an integer. So we // don't need to check the upper bound. if (key.E%2) == 0 || key.E < ((1<<16)+1) { return core.MalformedRequestError(fmt.Sprintf("Key exponent should be odd and >2^16: %d", key.E)) } // The modulus SHOULD also have the following characteristics: an odd // number, not the power of a prime, and have no factors smaller than 752. // TODO: We don't yet check for "power of a prime." if checkSmallPrimes(modulus) { return core.MalformedRequestError("Key divisible by small prime") } return nil }
// NewCertificate requests the issuance of a certificate. func (ra *RegistrationAuthorityImpl) NewCertificate(req core.CertificateRequest, regID int64) (cert core.Certificate, err error) { emptyCert := core.Certificate{} var logEventResult string // 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() { // AUDIT[ Certificate Requests ] 11917fa4-10ef-4e0d-9105-bacbe7836a3c ra.log.AuditObject(fmt.Sprintf("Certificate request - %s", logEventResult), logEvent) }() if regID <= 0 { err = core.MalformedRequestError(fmt.Sprintf("Invalid registration ID: %d", regID)) return emptyCert, err } registration, err := ra.SA.GetRegistration(regID) if err != nil { logEvent.Error = err.Error() return emptyCert, err } // Verify the CSR csr := req.CSR if err = core.VerifyCSR(csr); err != nil { logEvent.Error = err.Error() err = core.UnauthorizedError("Invalid signature on CSR") return emptyCert, err } logEvent.CommonName = csr.Subject.CommonName logEvent.Names = csr.DNSNames // Validate that authorization key is authorized for all domains names := make([]string, len(csr.DNSNames)) copy(names, csr.DNSNames) if len(csr.Subject.CommonName) > 0 { names = append(names, csr.Subject.CommonName) } if len(names) == 0 { err = core.UnauthorizedError("CSR has no names in it") logEvent.Error = err.Error() return emptyCert, err } csrPreviousDenied, err := ra.SA.AlreadyDeniedCSR(names) if err != nil { logEvent.Error = err.Error() return emptyCert, err } if csrPreviousDenied { err = core.UnauthorizedError("CSR has already been revoked/denied") logEvent.Error = err.Error() return emptyCert, err } if core.KeyDigestEquals(csr.PublicKey, registration.Key) { err = core.MalformedRequestError("Certificate public key must be different than account key") return emptyCert, err } // Check that each requested name has a valid authorization now := time.Now() earliestExpiry := time.Date(2100, 01, 01, 0, 0, 0, 0, time.UTC) for _, name := range names { authz, err := ra.SA.GetLatestValidAuthorization(registration.ID, core.AcmeIdentifier{Type: core.IdentifierDNS, Value: name}) if err != nil || authz.Expires.Before(now) { // unable to find a valid authorization or authz is expired err = core.UnauthorizedError(fmt.Sprintf("Key not authorized for name %s", name)) logEvent.Error = err.Error() return emptyCert, err } if authz.Expires.Before(earliestExpiry) { earliestExpiry = *authz.Expires } } // Mark that we verified the CN and SANs logEvent.VerifiedFields = []string{"subject.commonName", "subjectAltName"} // Create the certificate and log the result if cert, err = ra.CA.IssueCertificate(*csr, regID, earliestExpiry); err != nil { // While this could be InternalServerError for certain conditions, most // of the failure reasons (such as GoodKey failing) are caused by malformed // requests. logEvent.Error = err.Error() err = core.MalformedRequestError("Certificate request was invalid") return emptyCert, err } err = cert.MatchesCSR(csr, earliestExpiry) if err != nil { logEvent.Error = err.Error() return emptyCert, err } parsedCertificate, err := x509.ParseCertificate([]byte(cert.DER)) if err != nil { // InternalServerError because the certificate from the CA should be // parseable. err = core.InternalServerError(err.Error()) logEvent.Error = err.Error() return emptyCert, err } logEvent.SerialNumber = core.SerialToString(parsedCertificate.SerialNumber) logEvent.CommonName = parsedCertificate.Subject.CommonName logEvent.NotBefore = parsedCertificate.NotBefore logEvent.NotAfter = parsedCertificate.NotAfter logEvent.ResponseTime = time.Now() logEventResult = "successful" return cert, nil }
// NewAuthorization constuct a new Authz from a request. func (ra *RegistrationAuthorityImpl) NewAuthorization(request core.Authorization, regID int64) (authz core.Authorization, err error) { reg, err := ra.SA.GetRegistration(regID) if err != nil { err = core.MalformedRequestError(fmt.Sprintf("Invalid registration ID: %d", regID)) return authz, err } identifier := request.Identifier // Check that the identifier is present and appropriate if err = ra.PA.WillingToIssue(identifier); err != nil { err = core.UnauthorizedError(err.Error()) return authz, err } // Check CAA records for the requested identifier present, valid, err := ra.VA.CheckCAARecords(identifier) if err != nil { return authz, err } // AUDIT[ Certificate Requests ] 11917fa4-10ef-4e0d-9105-bacbe7836a3c ra.log.Audit(fmt.Sprintf("Checked CAA records for %s, registration ID %d [Present: %t, Valid for issuance: %t]", identifier.Value, regID, present, valid)) if !valid { err = errors.New("CAA check for identifier failed") return authz, err } // Create validations, but we have to update them with URIs later challenges, combinations := ra.PA.ChallengesFor(identifier) // Partially-filled object authz = core.Authorization{ Identifier: identifier, RegistrationID: regID, Status: core.StatusPending, Combinations: combinations, Challenges: challenges, } // Get a pending Auth first so we can get our ID back, then update with challenges authz, err = ra.SA.NewPendingAuthorization(authz) if err != nil { // InternalServerError since the user-data was validated before being // passed to the SA. err = core.InternalServerError(fmt.Sprintf("Invalid authorization request: %s", err)) return authz, err } // Construct all the challenge URIs for i := range authz.Challenges { // Ignoring these errors because we construct the URLs to be correct challengeURI, _ := core.ParseAcmeURL(ra.AuthzBase + authz.ID + "?challenge=" + strconv.Itoa(i)) authz.Challenges[i].URI = challengeURI // Add the account key used to generate the challenge authz.Challenges[i].AccountKey = ®.Key if !authz.Challenges[i].IsSane(false) { // InternalServerError because we generated these challenges, they should // be OK. err = core.InternalServerError(fmt.Sprintf("Challenge didn't pass sanity check: %+v", authz.Challenges[i])) return authz, err } } // Store the authorization object, then return it err = ra.SA.UpdatePendingAuthorization(authz) if err != nil { // InternalServerError because we created the authorization just above, // and adding Sane challenges should not break it. err = core.InternalServerError(err.Error()) } return authz, err }
// GoodKeyECDSA determines if an ECDSA pubkey meets our requirements func (policy *KeyPolicy) goodKeyECDSA(key ecdsa.PublicKey) (err error) { // Check the curve. // // The validity of the curve is an assumption for all following tests. err = policy.goodCurve(key.Curve) if err != nil { return err } // Key validation routine adapted from NIST SP800-56A § 5.6.2.3.2. // <http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Ar2.pdf> // // Assuming a prime field since a) we are only allowing such curves and b) // crypto/elliptic only supports prime curves. Where this assumption // simplifies the code below, it is explicitly stated and explained. If ever // adapting this code to support non-prime curves, refer to NIST SP800-56A § // 5.6.2.3.2 and adapt this code appropriately. params := key.Params() // SP800-56A § 5.6.2.3.2 Step 1. // Partial check of the public key for an invalid range in the EC group: // Verify that key is not the point at infinity O. // This code assumes that the point at infinity is (0,0), which is the // case for all supported curves. if isPointAtInfinityNISTP(key.X, key.Y) { return core.MalformedRequestError("Key x, y must not be the point at infinity") } // SP800-56A § 5.6.2.3.2 Step 2. // "Verify that x_Q and y_Q are integers in the interval [0,p-1] in the // case that q is an odd prime p, or that x_Q and y_Q are bit strings // of length m bits in the case that q = 2**m." // // Prove prime field: ASSUMED. // Prove q != 2: ASSUMED. (Curve parameter. No supported curve has q == 2.) // Prime field && q != 2 => q is an odd prime p // Therefore "verify that x, y are in [0, p-1]" satisfies step 2. // // Therefore verify that both x and y of the public key point have the unique // correct representation of an element in the underlying field by verifying // that x and y are integers in [0, p-1]. if key.X.Sign() < 0 || key.Y.Sign() < 0 { return core.MalformedRequestError("Key x, y must not be negative") } if key.X.Cmp(params.P) >= 0 || key.Y.Cmp(params.P) >= 0 { return core.MalformedRequestError("Key x, y must not exceed P-1") } // SP800-56A § 5.6.2.3.2 Step 3. // "If q is an odd prime p, verify that (y_Q)**2 === (x_Q)***3 + a*x_Q + b (mod p). // If q = 2**m, verify that (y_Q)**2 + (x_Q)*(y_Q) == (x_Q)**3 + a*(x_Q)*2 + b in // the finite field of size 2**m. // (Ensures that the public key is on the correct elliptic curve.)" // // q is an odd prime p: proven/assumed above. // a = -3 for all supported curves. // // Therefore step 3 is satisfied simply by showing that // y**2 === x**3 - 3*x + B (mod P). // // This proves that the public key is on the correct elliptic curve. // But in practice, this test is provided by crypto/elliptic, so use that. if !key.Curve.IsOnCurve(key.X, key.Y) { return core.MalformedRequestError("Key point is not on the curve") } // SP800-56A § 5.6.2.3.2 Step 4. // "Verify that n*Q == O. // (Ensures that the public key has the correct order. Along with check 1, // ensures that the public key is in the correct range in the correct EC // subgroup, that is, it is in the correct EC subgroup and is not the // identity element.)" // // Ensure that public key has the correct order: // verify that n*Q = O. // // n*Q = O iff n*Q is the point at infinity (see step 1). ox, oy := key.Curve.ScalarMult(key.X, key.Y, params.N.Bytes()) if !isPointAtInfinityNISTP(ox, oy) { return core.MalformedRequestError("Public key does not have correct order") } // End of SP800-56A § 5.6.2.3.2 Public Key Validation Routine. // Key is valid. return nil }
func (wfe *WebFrontEndImpl) verifyPOST(request *http.Request, regCheck bool, resource core.AcmeResource) ([]byte, *jose.JsonWebKey, core.Registration, error) { var err error var reg core.Registration // 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 } key := parsedJws.Signatures[0].Header.JsonWebKey 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 } reg, err = wfe.SA.GetRegistrationByKey(*key) if err != nil { // If we are requiring a valid registration, any failure to look up the // registration is an overall failure to verify. if regCheck { return nil, nil, reg, err } // Otherwise we just return an empty registration. The caller is expected // to use the returned key instead. reg = core.Registration{} } // 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 }
// NewCertificate requests the issuance of a certificate. func (ra *RegistrationAuthorityImpl) NewCertificate(req core.CertificateRequest, regID int64) (cert core.Certificate, err error) { emptyCert := core.Certificate{} var logEventResult string // Assume the worst logEventResult = "error" // Construct the log event logEvent := certificateRequestEvent{ ID: core.NewToken(), Requester: regID, RequestMethod: "online", RequestTime: ra.clk.Now(), } // No matter what, log the request defer func() { // AUDIT[ Certificate Requests ] 11917fa4-10ef-4e0d-9105-bacbe7836a3c ra.log.AuditObject(fmt.Sprintf("Certificate request - %s", logEventResult), logEvent) }() if regID <= 0 { err = core.MalformedRequestError(fmt.Sprintf("Invalid registration ID: %d", regID)) return emptyCert, err } registration, err := ra.SA.GetRegistration(regID) if err != nil { logEvent.Error = err.Error() return emptyCert, err } // Verify the CSR csr := req.CSR if err = core.VerifyCSR(csr); err != nil { logEvent.Error = err.Error() err = core.UnauthorizedError("Invalid signature on CSR") return emptyCert, err } logEvent.CommonName = csr.Subject.CommonName logEvent.Names = csr.DNSNames // Validate that authorization key is authorized for all domains names := make([]string, len(csr.DNSNames)) copy(names, csr.DNSNames) if len(csr.Subject.CommonName) > 0 { names = append(names, csr.Subject.CommonName) } if len(names) == 0 { err = core.UnauthorizedError("CSR has no names in it") logEvent.Error = err.Error() return emptyCert, err } csrPreviousDenied, err := ra.SA.AlreadyDeniedCSR(names) if err != nil { logEvent.Error = err.Error() return emptyCert, err } if csrPreviousDenied { err = core.UnauthorizedError("CSR has already been revoked/denied") logEvent.Error = err.Error() return emptyCert, err } if core.KeyDigestEquals(csr.PublicKey, registration.Key) { err = core.MalformedRequestError("Certificate public key must be different than account key") return emptyCert, err } // Check rate limits before checking authorizations. If someone is unable to // issue a cert due to rate limiting, we don't want to tell them to go get the // necessary authorizations, only to later fail the rate limit check. err = ra.checkLimits(names, registration.ID) if err != nil { logEvent.Error = err.Error() return emptyCert, err } err = ra.checkAuthorizations(names, ®istration) if err != nil { logEvent.Error = err.Error() return emptyCert, err } // Mark that we verified the CN and SANs logEvent.VerifiedFields = []string{"subject.commonName", "subjectAltName"} // Create the certificate and log the result if cert, err = ra.CA.IssueCertificate(*csr, regID); err != nil { logEvent.Error = err.Error() return emptyCert, err } err = ra.MatchesCSR(cert, csr) if err != nil { logEvent.Error = err.Error() return emptyCert, err } parsedCertificate, err := x509.ParseCertificate([]byte(cert.DER)) if err != nil { // InternalServerError because the certificate from the CA should be // parseable. err = core.InternalServerError(err.Error()) logEvent.Error = err.Error() return emptyCert, err } logEvent.SerialNumber = core.SerialToString(parsedCertificate.SerialNumber) logEvent.CommonName = parsedCertificate.Subject.CommonName logEvent.NotBefore = parsedCertificate.NotBefore logEvent.NotAfter = parsedCertificate.NotAfter logEvent.ResponseTime = ra.clk.Now() logEventResult = "successful" ra.stats.Inc("RA.NewCertificates", 1, 1.0) return cert, nil }