Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RESTification #48

Merged
merged 10 commits into from
Jan 29, 2015
Merged

RESTification #48

merged 10 commits into from
Jan 29, 2015

Conversation

bifurcation
Copy link
Contributor

This PR closes #23. It updates the overall flow of the protocol to make better use of HTTP. There are no changes to the validation challenges. In case it helps, there's a side-by-side comparison of protocol messages here:

http://www.ipv.sx/tmp/restification.html

@pde
Copy link
Contributor

pde commented Dec 22, 2014

We're planning to do a line-by-line review of this PR this week.


<!-- NOTE: This flow assumes that the authorization state is stored on the server. It would also be possible for the server to pass a token back to the client that encodes the state. -->
For example, if the client requests a domain name, the server might challenge the client to provision a record in the DNS under that name, or to provision a file on a web server reference by an A or AAAA record under that name. The server would then query the DNS for the record in question, or send an HTTP request for the file. If the client provisioned the DNS or the web server as expected, then the server considers the client authorized for the domain name.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/reference by an A/referenced by an A/

@martinthomson martinthomson mentioned this pull request Dec 22, 2014
~~~~~~~~~~

signature-input = nonce || content
To begin the key authorization process, the client sends a POST request to the server's new-authorization resource. The body of the POST request MUST contain a JWS object, whose payload MUST be an initial authorization object. This JWS object MUST contain the "identifier" field, so that the server knows what identifier is being authorized. The client MAY provide contact information in the "contact" field in this or any subsequent request.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you clarify here what an 'initial' authorization object means, versus a regular authorization object?

@jsha
Copy link
Collaborator

jsha commented Jan 15, 2015

All done with my review. The two big items that I think need fixing are:

  • GET requests cannot be signed using our current JWS scheme. We should do one of:
    1. Define all GET resources as fully public and deal with what that means for the protocol, or
    2. Define a way for GET requests to be signed by an account key, or
    3. Turn any non-public GET resources back into POSTs, even if it is a slight divergence from REST.
  • Using JSON merge patch from the client to modify a security-critical data structure is inherently risky. We should go back to an explicit ChallengeResponse object.

@pde
Copy link
Contributor

pde commented Jan 15, 2015

@jsha on GET requests, I'd vote for option iii. It's both cleanest and safest to wrap everything in JWS signatures.

@martinthomson
Copy link
Contributor

Are there any resources that are confidential and need to respond to a GET? My preference would be to try to find a place where all the GET resources don't need confidentiality: i.e., the first option.

I don't think that a capability URL is bad for information that is not especially sensitive, like whether domain X has a valid authorization. For those resources that need GET, is there a case in the threat model that supports the need for any confidentiality protection (i.e., authorization based on account key)?

@jsha
Copy link
Collaborator

jsha commented Jan 20, 2015

@martinthomson: It seems like the authorization resource is currently in an in-between state. It was designed as an resource that would be confidential by the nature of the protocol. This branch makes it non-confidential because that approach fits the REST model better, but I think has not fully updated the model to reflect that. For instance, as you pointed out, it currently includes a 'contact' field, which should be confidential.

I think it will be much easier to analyze the security of the system if we adopt clear security boundaries, i.e.:

  • authenticated / unauthenticated
  • confidential / public

I think introducing a new authentication type (capability URLs) and a new confidentiality level (not especially sensitive) is going to make our jobs a lot harder, and potentially lead to implementation mistakes.

As far as I can tell, the main reason to introduce the new authentication type for Authorization resources is to allow them to be fetched via GET during polling, and therefore match REST semantics better. I like the REST model, but when it increases complexity rather than reducing it, I think we should modify the model a little bit.

So I prefer item (iii) in my previous comment. It also happens to be the smallest departure from the existing spec, which will help us with the schedule.

{
"type": "simpleHttps",
"challenges": {
"simpleHttps": {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This data structure change makes it difficult to issue challenges of the same type. This isn't a problem given the current challenges and as ACME's goal is DV. However, if there is a challenge someday where different parameters to the challenge prove different components of the authorization we will be stuck with a hack (some form of compound challenge or defining multiple challenges of the same type with different names). This probably doesn't justify the complication involved with using a list and indices, but is something to keep in mind.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good point. For instance, in the future we will want to issue wildcard certificates. You can imagine wanting to do two different SimpleHTTPS challenges to two different random subdomains, to verify full control of the domain.

Both this and the previous list/indices approach also introduce an awkward non-locality in evaluating the data structure. Proposal: Snap the pointers. Instead of challenges, and combinations, have a single field challengeSets, which is an array of arrays of challenges. This may mean a small amount of duplication, but I think it simplifies the structure.

@bifurcation
Copy link
Contributor Author

We had a call about this (me, martinthomson, jsha, pde, jdkasten, et al.). Besides the obvious typo fixes, our resolutions came to the following major changes:

  • Sensitive information from Authorizations is moved to Registration objects, and a separate registration transaction updates them.
  • Challenges will be their own resources, to which responses will be POSTed.

There are also some more minor structural changes to authorizations, and I'm also planning to add more link relations to tie things together.


All requests for a given ACME server are sent to the same HTTPS URI. It is assumed that clients are configured with this URI out of band. ACME requests MUST use the POST method, and since they carry JSON payloads, SHOULD set the Content-Type header field to "application/json". ACME responses MUST be carried in HTTP responses with the status code 200. ACME clients SHOULD follow HTTP redirects (301 or 302 responses), in case an ACME server is relocated.
The following diagram illustrates the relations between resources on an ACME server. The solid lines indicate link relations, and the dotted lines correspond to relationships expressed in other ways, e.g., the Location header in a 201 (Created) response.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirming my understanding: Link relations are expressed in headers, so they can't be JWS-signed, right? But responses from the server are never JWS signed and are secured instead by HTTPS?

Also, we should probably add the constraint: "All link relations must be specified relative to the current scheme, host, and port. The client MUST reject responses that include a link relation that specifies a scheme, host, or port."

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that Richard needs to clean this up. A link relation is a link in the 5988 sense. It doesn't matter where it appears, it can still be a link relation. The header field vs. body distinction doesn't read on the subject.

@jsha
Copy link
Collaborator

jsha commented Jan 27, 2015

Done with today's round of reviews. I think we're pretty close to merging.

@martinthomson, as a separate task, can you document the decision to go with a REST architecture? It was made before I started dedicating a lot of time to the project, and it deeply shapes a lot of our architectural decisions reflected in this doc, so it would be great to have a section in the doc describing why we use it.

@martinthomson
Copy link
Contributor

@jsha, that's @bifurcation's doing entirely.

All I ever said was: "If you are using HTTP, might as well do it properly". I just noted a few points where some of the basic principles seem to fit. Like how having different identifiers for each of the "things" helps. If you wanted to go all out, there's plenty more to do, though at some point you realize that you're off the reservation. Usually at the point where you are delving into signatures over HTTP messages.

It seems to me that this is an improvement, and not just because it's had a lot more attention paid to it. Do you have specific architectural concerns that this redesign doesn't address? Or concerns that it raises? I think that we covered the confidentiality concerns.

@jsha
Copy link
Collaborator

jsha commented Jan 27, 2015

@martinthomson: My main concern was, as you mentioned, the confidentiality issue. I agree that we've resolved them, but there are a couple of additional places they popped up in my latest review (registration resources, refresh certificate resources). We also wound up resolving those. But I still don't 100% understand why we switched some requests from POSTs to GETs in the first place. I'm not requesting that we revise that aspect of the spec further at this late date, but I think documenting the choice would be very helpful to future reviewers.

@martinthomson
Copy link
Contributor

GET has robustness advantages over POST. If the GET fails, any layer of the stack can automatically retry it. In this specific case, it also makes it easier to distribute certificates using a CDN. Many CDNs won't handle "application logic", but all of them are happy to take a GET request.


ACME messaging is based on HTTPS {{RFC2818}} and JSON {{RFC7159}}. Since JSON is a text-based format, binary fields are Base64-encoded. For Base64 encoding, we use the variant defined in {{I-D.ietf-jose-json-web-signature}}. The important features of this encoding are (1) that it uses the URL-safe character set, and (2) that "=" padding characters are stripped.

Some HTTPS bodies in ACME are authenticated and integrity-protected by being encapsulated in a JSON Web Signature (JWS) object {{I-D.ietf-jose-json-web-signature}}. ACME uses a profile of JWS, with the following restrictions:

* The JWS MUST use the Flattened JSON Serialization

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why? What is the reason behind this?

I consider this to be an unreasonable imposition, for the following reason:

Suppose a certain JOSE library serialises a JWS with a single signature
using the General JWS JSON Serialization Syntax. That library cannot
be used with ACME.

According to the JWS draft there is no requirement or recommendation for an implementation
to serialise a single-signature JWS using the Flattened syntax, nor is there
a requirement or recommendation to provide users a knob to control how to deal with this
ambiguous case.

So if there is no important reason to have this requirement in ACME,
please remove it.

bifurcation added a commit that referenced this pull request Jan 29, 2015
Moving to a more RESTful architecture
@bifurcation bifurcation merged commit 170929c into letsencrypt:master Jan 29, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

HTTP usage
7 participants