Skip to content

Commit

Permalink
Adds RejectedIdentifierError on Blacklisted error. (letsencrypt#1944)
Browse files Browse the repository at this point in the history
Boulder uses MalformedRequestError as a universal error. This pull request adds the RejectedIdentifierError and use it on a blacklist error.

For a client implementation, it is easier and cleaner to use an exception than parse the error message.

https://github.com/letsencrypt/boulder/blob/1336c428130cba866768b766b51b421176ad14ef/policy/pa.go#L131

Fixes letsencrypt#1938

PR in acme : ietf-wg-acme/acme#142
  • Loading branch information
maxboisvert authored and rolandshoemaker committed Jun 29, 2016
1 parent c4f7fb5 commit 821d572
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 26 deletions.
29 changes: 15 additions & 14 deletions policy/pa.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (

"github.com/letsencrypt/boulder/core"
blog "github.com/letsencrypt/boulder/log"
"github.com/letsencrypt/boulder/probs"
"github.com/letsencrypt/boulder/reloader"
"github.com/letsencrypt/net/publicsuffix"
)
Expand Down Expand Up @@ -121,20 +122,20 @@ func suffixMatch(labels []string, suffixSet map[string]bool, properSuffix bool)
}

var (
errInvalidIdentifier = core.MalformedRequestError("Invalid identifier type")
errNonPublic = core.MalformedRequestError("Name does not end in a public suffix")
errICANNTLD = core.MalformedRequestError("Name is an ICANN TLD")
errBlacklisted = core.MalformedRequestError("Policy forbids issuing for name")
errNotWhitelisted = core.MalformedRequestError("Name is not whitelisted")
errInvalidDNSCharacter = core.MalformedRequestError("Invalid character in DNS name")
errNameTooLong = core.MalformedRequestError("DNS name too long")
errIPAddress = core.MalformedRequestError("Issuance for IP addresses not supported")
errTooManyLabels = core.MalformedRequestError("DNS name has too many labels")
errEmptyName = core.MalformedRequestError("DNS name was empty")
errTooFewLabels = core.MalformedRequestError("DNS name does not have enough labels")
errLabelTooShort = core.MalformedRequestError("DNS label is too short")
errLabelTooLong = core.MalformedRequestError("DNS label is too long")
errIDNNotSupported = core.MalformedRequestError("Internationalized domain names (starting with xn--) not yet supported")
errInvalidIdentifier = probs.Malformed("Invalid identifier type")
errNonPublic = probs.Malformed("Name does not end in a public suffix")
errICANNTLD = probs.Malformed("Name is an ICANN TLD")
errBlacklisted = probs.RejectedIdentifier("Policy forbids issuing for name")
errNotWhitelisted = probs.Malformed("Name is not whitelisted")
errInvalidDNSCharacter = probs.Malformed("Invalid character in DNS name")
errNameTooLong = probs.Malformed("DNS name too long")
errIPAddress = probs.Malformed("Issuance for IP addresses not supported")
errTooManyLabels = probs.Malformed("DNS name has too many labels")
errEmptyName = probs.Malformed("DNS name was empty")
errTooFewLabels = probs.Malformed("DNS name does not have enough labels")
errLabelTooShort = probs.Malformed("DNS label is too short")
errLabelTooLong = probs.Malformed("DNS label is too long")
errIDNNotSupported = probs.UnsupportedIdentifier("Internationalized domain names (starting with xn--) not yet supported")
)

// WillingToIssue determines whether the CA is willing to issue for the provided
Expand Down
42 changes: 32 additions & 10 deletions probs/probs.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,17 @@ import (

// Error types that can be used in ACME payloads
const (
ConnectionProblem = ProblemType("urn:acme:error:connection")
MalformedProblem = ProblemType("urn:acme:error:malformed")
ServerInternalProblem = ProblemType("urn:acme:error:serverInternal")
TLSProblem = ProblemType("urn:acme:error:tls")
UnauthorizedProblem = ProblemType("urn:acme:error:unauthorized")
UnknownHostProblem = ProblemType("urn:acme:error:unknownHost")
RateLimitedProblem = ProblemType("urn:acme:error:rateLimited")
BadNonceProblem = ProblemType("urn:acme:error:badNonce")
InvalidEmailProblem = ProblemType("urn:acme:error:invalidEmail")
ConnectionProblem = ProblemType("urn:acme:error:connection")
MalformedProblem = ProblemType("urn:acme:error:malformed")
ServerInternalProblem = ProblemType("urn:acme:error:serverInternal")
TLSProblem = ProblemType("urn:acme:error:tls")
UnauthorizedProblem = ProblemType("urn:acme:error:unauthorized")
UnknownHostProblem = ProblemType("urn:acme:error:unknownHost")
RateLimitedProblem = ProblemType("urn:acme:error:rateLimited")
BadNonceProblem = ProblemType("urn:acme:error:badNonce")
InvalidEmailProblem = ProblemType("urn:acme:error:invalidEmail")
RejectedIdentifierProblem = ProblemType("urn:acme:error:rejectedIdentifier")
UnsupportedIdentifierProblem = ProblemType("urn:acme:error:unsupportedIdentifier")
)

// ProblemType defines the error types in the ACME protocol
Expand Down Expand Up @@ -47,7 +49,7 @@ func ProblemDetailsToStatusCode(prob *ProblemDetails) int {
return prob.HTTPStatus
}
switch prob.Type {
case ConnectionProblem, MalformedProblem, TLSProblem, UnknownHostProblem, BadNonceProblem, InvalidEmailProblem:
case ConnectionProblem, MalformedProblem, TLSProblem, UnknownHostProblem, BadNonceProblem, InvalidEmailProblem, RejectedIdentifierProblem, UnsupportedIdentifierProblem:
return http.StatusBadRequest
case ServerInternalProblem:
return http.StatusInternalServerError
Expand All @@ -70,6 +72,26 @@ func BadNonce(detail string) *ProblemDetails {
}
}

// RejectedIdentifier returns a ProblemDetails with a RejectedIdentifierProblem and a 400 Bad
// Request status code.
func RejectedIdentifier(detail string) *ProblemDetails {
return &ProblemDetails{
Type: RejectedIdentifierProblem,
Detail: detail,
HTTPStatus: http.StatusBadRequest,
}
}

// UnsupportedIdentifier returns a ProblemDetails with a UnsupportedIdentifierProblem and a 400 Bad
// Request status code.
func UnsupportedIdentifier(detail string) *ProblemDetails {
return &ProblemDetails{
Type: UnsupportedIdentifierProblem,
Detail: detail,
HTTPStatus: http.StatusBadRequest,
}
}

// Conflict returns a ProblemDetails with a MalformedProblem and a 409 Conflict
// status code.
func Conflict(detail string) *ProblemDetails {
Expand Down
2 changes: 2 additions & 0 deletions probs/probs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ func TestProblemDetailsConvenience(t *testing.T) {
{RateLimited("rate limited detail"), RateLimitedProblem, statusTooManyRequests, "rate limited detail"},
{BadNonce("bad nonce detail"), BadNonceProblem, http.StatusBadRequest, "bad nonce detail"},
{TLSError("TLS error detail"), TLSProblem, http.StatusBadRequest, "TLS error detail"},
{RejectedIdentifier("rejected identifier detail"), RejectedIdentifierProblem, http.StatusBadRequest, "rejected identifier detail"},
{UnsupportedIdentifier("unsupported identifier detail"), UnsupportedIdentifierProblem, http.StatusBadRequest, "unsupported identifier detail"},
}

for _, c := range testCases {
Expand Down
7 changes: 5 additions & 2 deletions ra/ra_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -604,8 +604,11 @@ func TestNewAuthorizationInvalidName(t *testing.T) {
if err == nil {
t.Fatalf("NewAuthorization succeeded for 127.0.0.1, should have failed")
}
if _, ok := err.(core.MalformedRequestError); !ok {
t.Errorf("Wrong type for NewAuthorization error: expected core.MalformedRequestError, got %T", err)
if _, ok := err.(*probs.ProblemDetails); !ok {
t.Errorf("Wrong type for NewAuthorization error: expected *probs.ProblemDetails, got %T", err)
}
if err.(*probs.ProblemDetails).Type != probs.MalformedProblem {
t.Errorf("Incorrect problem type. Expected %s got %s", probs.MalformedProblem, err.(*probs.ProblemDetails).Type)
}
}

Expand Down

0 comments on commit 821d572

Please sign in to comment.