コード例 #1
0
ファイル: ra.go プロジェクト: andrewrothstein/boulder
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
}
コード例 #2
0
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
}
コード例 #3
0
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
}
コード例 #4
0
// 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
}
コード例 #5
0
// 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
}
コード例 #6
0
ファイル: amqp-rpc.go プロジェクト: jcjones/boulder
// 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
}
コード例 #7
0
ファイル: amqp-rpc.go プロジェクト: jfrazelle/boulder
// 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
}
コード例 #8
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()))
	}
	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
}
コード例 #9
0
ファイル: amqp-rpc.go プロジェクト: JoeHorn/boulder
// 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
}
コード例 #10
0
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
}
コード例 #11
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
}
コード例 #12
0
ファイル: bcodes.go プロジェクト: jfrazelle/boulder
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
	}
}
コード例 #13
0
ファイル: amqp-rpc_test.go プロジェクト: bretthoerner/boulder
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)
		}

	}
}
コード例 #14
0
ファイル: ra.go プロジェクト: jfrazelle/boulder
// 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
}
コード例 #15
0
ファイル: ra.go プロジェクト: jfrazelle/boulder
// 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
}
コード例 #16
0
ファイル: good_key.go プロジェクト: jfrazelle/boulder
// 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))
	}
}
コード例 #17
0
ファイル: ra.go プロジェクト: jfrazelle/boulder
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
}
コード例 #18
0
// 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)))
	}
}
コード例 #19
0
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
}
コード例 #20
0
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
}
コード例 #21
0
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
}
コード例 #22
0
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
}
コード例 #23
0
ファイル: bcodes_test.go プロジェクト: jfrazelle/boulder
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))
	}
}
コード例 #24
0
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")
	}
}
コード例 #25
0
// 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
}
コード例 #26
0
// 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
}
コード例 #27
0
// 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 = &reg.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
}
コード例 #28
0
// 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
}
コード例 #29
0
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
}
コード例 #30
0
// 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, &registration)
	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
}