erasmus-without-paper / ewp-specs-sec-srvauth-httpsig

MIT License
1 stars 2 forks source link

Authenticating Servers with HTTP Signature

This document describes how EWP server authentication can be accomplished with signatures included in HTTP responses.

Introduction

This authentication method makes use of:

Note, that - in many cases - TLS Server Certificate Authentication is enough to provide sufficient authentication security. However, HTTP Signatures provide much easier non-repudiation support. See Security Considerations section below for more information.

Implementing a server

Meet all "inherited" requirements

This server authentication method extends the standard TLS Server Certificate Authentication method. The servers are REQUIRED to meet all the requirements listed here.

In particular, it is RECOMMENDED for servers to declare their support for TLS Server Certificate Authentication. For example, if they use sec:HttpSecurityOptions datatype to describe their security requirements, then they should have TLS Server Certificate Authentication listed among their <sec:server-auth-methods> elements. This will allow clients which do not support HTTP Signature Server Authentication to connect to your endpoints in a backward-compatible way.

Generate a key-pair

You need to generate an RSA key-pair for your server. You MAY use the same key-pair you use for your TLS communication if you want to.

Publish your key

Each partner declares (in his Manifest file) a list of public keys which its servers can use for signing their responses. This list is later fetched by registry, and the keys (and/or their fingerprints) are served to all other partners see (see Registry API for details).

Usually (but not necessarily always) you will bind a single public key to all endpoints you serve. Once the client confirms that the server is in possession of the matching private key, it is then able to identify (with the help of the Registry again) if this key-pair has been listed as one with which server authentication at this endpoint can be performed.

Note, that the Registry will verify if your keys meet certain security standards (i.e. their length). These standards MAY change in time. Remember to include <admin-email> elements in your manifest file if you want to be notified about such changes.

Check if you need to sign (optional)

This step is RECOMMENDED, but not required. If you decide not to implement it, then you need to sign all your responses (even if the client doesn't want you to).

A single server endpoint MAY support multiple server authentication methods. For this reason, the client notifies the server which of these methods it wants to use.

For example, if your endpoint supports both <tlscert/> and <httpsig/>, then the client might be okay with using <tlscert/> and you are NOT REQUIRED to sign your response in this case.

How does the client notify you if it wants your signature? Since we couldn't find any standard header for expressing that, we have invented our own:

Include all required headers

Sign your response

You MUST include the Signature header in your response, as explained here. You MUST support the rsa-sha256 signature algorithm. You MAY use a different algorithm, if the client listed this algorithm in its Accept-Signature header. You MUST include at least the following values in your headers parameter:

If it is important for the client to recognize any other of your headers, then you MUST sign all these headers too. The headers mentioned above are important for handling authentication, non-repudiation and security described in this document, but other headers can also be very important in your case.

The keyId parameter of the Signature header MUST contain a lower-case HEX-encoded SHA-256 fingerprint of the binary public key part of the kay-pair which you have used to sign your response. It MUST match one of the keys you previously published in your manifest file.

Take care to not modify it again

Many frameworks or proxies might try to automatically modify your response after you sign it. For example, they may try to add additional gzip coding to your response's Content-Encodings if they detect that the client supports it. In many cases, this would be a good thing, but in this case, such changes could break your HTTP Signature (because we sign the content after it has been encoded). Make sure that you disable such automatic modifications when you use HTTP Signatures for signing.

On this topic, also read the chapter about the Original-Date header below.

Implementing a client

Meet all "inherited" requirements

This server authentication method extends the "standard" TLS Server Certificate Authentication method. The clients are REQUIRED to meet all the requirements listed here.

Include Want-Digest header (optional)

You MAY include the Want-Digest header in your request, as explained here. If included, then one of the digest algorithms included SHOULD be SHA-256 (because it's currently the only algorithm required by the servers to support).

If you don't include this header, servers will assume it's equal to:

Want-Digest: SHA-256

Include Accept-Signature header

You MUST include the Accept-Signature header in your request. This header informs the server that you want it to sign its responses with HTTP Signatures. The value contains a comma-separated list of signature algorithms, ordered by client's preference. One of these algorithms SHOULD be rsa-sha256.

Currently, rsa-sha256 is the only algorithm required to be implemented by servers. If you don't include it in your Accept-Signature list, then the server MAY not sign the response at all.

Consider signing yourself

This method of authentication works best when both parties use it. Consider using HTTP Signature Client Authentication (if the server supports it). If you do, then the server will include additional headers in the response which will enhance non-repudiation.

If you don't want to use HTTP Signature Client Authentication (or you can't use it because the server doesn't support it), then it is still RECOMMENDED to include X-Request-Id header (as described here) for request-response correlation. See Security Considerations section below.

Verify X-Request-Id

If you have included X-Request-Id in your request, then you SHOULD verify if the value returned in the response's X-Request-Id header matches the value use sent along in your request. If it doesn't, then you MUST reject the server's response.

Verify signature parameters

Make sure that:

If some of these conditions are not met, then you MUST reject the server's response.

Verify the date(s)

You need to parse and verify the values of the Date and Original-Date headers, if they are included in the response (at least one of them MUST be). In particular, you MUST verify at least the ones which have been listed in the response's Signature header, but it is RECOMMENDED to verify both (if both are included in the response).

Verification process consists of parsing the date, and matching it against the date reported by your own clock. The verification fails if:

If the verification fails, then you MUST reject the server's response.

Also note, that you MUST make sure that your clock is synchronized (otherwise your verification process will fail constantly).

Look up the key

Extract the keyId from the response's Signature header.

It is supposed to contain a lower-case HEX-encoded SHA-256 fingerprint of the RSA binary public key published by the server in the Registry. If it doesn't, then you MUST reject the server's response.

Verify the signature

You MUST verify the request's signature, as explained here.

If the signature is invalid, then you MUST reject the server's response.

Verify the digest

Calculate the Base64-encoded SHA-256 digest of the response's body, according to RFC 3230 and RFC 5843. Compare it to the Digest header which MUST be present in the response. The values MUST match. If they don't, then you MUST reject the server's response.

Remember, that the Digest header MAY contain many digests, in different algorithms. You MUST parse the header and extract the SHA-256 algorithm from this list.

Ignore unsigned headers

Clients MUST ignore all response headers which hadn't been signed by the server. They might have been added by the attacker in transport. This is important especially in cases when TLS is not used in some parts of the transport, or when you don't fully trust the partner's TLS implementation.

The safest way to properly ignore such headers is to modify your Response object now (during the authentication and authorization process), by either removing the suspicious headers, or at least changing their name (e.g. prepending it with Unsigned-). Then, pass the modified Response along as the result of your verification, so that the actual client you are implementing believes that the server didn't supply these headers at all. This approach is much safer than trusting yourself to remember to verify this every time before you access every header in every single ones of your underlying clients (and some clients might be dependent on response's headers).

About the Original-Date header

While testing EWP HTTP Signature specifications (both of them), some developers reported that the values of their Date headers got replaced by proxies, thus invalidating their signatures. In practice, no reliable way to prevent this from happening was found. The Original-Date has been introduced in this specification as a measure to circumvent this problem.

Security considerations

Non-repudiation

The Signature header proves that the response has been generated by a particular server, but it doesn't say anything about the requester and request for which the response has been produced. The Date (Original-Date), X-Request-Id and X-Request-Signature headers are required in order to enhance non-repudiation in request-response correlation:

Main security questions

The Authentication and Security document recommends that each server authentication method specification explicitly answers the following questions:

How the client's request must look like? How can the server know, that the client wants the server to use this particular method of authentication?

The server knows that this method is used, when the request contains the Accept-Signature header.

How can the client verify the server's identity?

Since this method builds on TLS, the client uses regular HTTPS server certificate validation to make sure that it is communicating with the proper domain and URL.

Additionally, the client also verifies the key with which HTTP headers were signed. The key-HEI relationship is retrieved securely from the Registry.

How can the client verify that the response has not been tampered with? Can it also verify that it was indeed generated for this particular request?

TLS prevents communication to be tampered with during the transport. Additionally, HTTP Signature prevents it from being tampered behind the TLS terminator (useful in cases when the server's internal network is not secure).

If the client includes a random X-Request-Id header in his requests, then it also gets the proof that the response has been generated for this particular request.

Does it provide non-repudiation? Can a client provide a solid proof later on, that the server sent a particular response (in response to a particular client's request)?

Yes. See Non-repudiation section above.