This document describes how EWP server authentication can be accomplished with signatures included in HTTP responses.
This authentication method makes use of:
Digest
header, specified in RFC 3230.SHA-256
Digest Algorithm, specified in RFC 5843.Signature
header, specified in
draft-cavage-http-signatures-07 (presumably,
soon to become RFC),
along with its rsa-sha256
signature algorithm.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.
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.
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.
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.
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:
If the request contains the Accept-Signature
header (case insensitive),
with one of the comma-separated values equal to rsa-sha256
(case
insensitive again), then you MUST sign your response.
Note, that this header MAY contain multiple algorithms. You are required to
support only rsa-sha256
.
If the request contains the Accept-Signature
header, but you don't support
any of the algorithms requested there, then you SHOULD ignore such signature
request. It is RECOMMENDED to proceed as if the client didn't send any
Accept-Signature
header.
If the request doesn't contain the Accept-Signature
header (or you don't
support any of the requested algorithms), then you are NOT REQUIRED to sign
your response (and you don't need to follow the rest of the steps below).
This simply means that the client won't verify your signature, so you don't
need to bother and sign it (but you MAY, if you wish).
Note, that you SHOULD NOT force your client to send the Accept-Signature
header. You SHOULD allow your client to not include the Accept-Signature
header, and therefore "fall back" to the regular TLS Server Certificate
Authentication.
You MUST include either the Date
or Original-Date
header in your response. You MAY include both of them. The format of the
Original-Date
header, if included, MUST match the "regular" format of the
Date
header, as defined in RFC 2616. You MUST make sure
that your clock is synchronized (otherwise the client may reject your
response).
You MUST include the Digest
header in your response, as explained
here. If the client sent you a Want-Digest
header, then you
MAY take it into account when choosing your digest algorithm, but you are
REQUIRED to support only one digest algorithm - SHA-256
.
If the client didn't send a Want-Digest
header, then you still MUST
include the digest (in the SHA-256
algorithm).
Also note, that your Digest
header MAY contain many digests, in different
algorithms.
If the client's request contained the X-Request-Id
header, then you MUST
include the X-Request-Id
header with the same contents in your response.
If HTTP Signature method has been used for client
authentication, then you MUST include the X-Request-Signature
header in
your response, with the value copied from the signature
parameter used in
the request's Authorization
header.
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:
date
or original-date
(it MUST contain at least one of those, it also
MAY contain both),digest
,x-request-id
, but only when you actually include this header in your
response,x-request-signature
, but only when you actually include this header in
your response.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.
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.
This server authentication method extends the "standard" TLS Server Certificate Authentication method. The clients are REQUIRED to meet all the requirements listed here.
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
Accept-Signature
headerYou 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.
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.
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.
Make sure that:
The server's response contains the Signature
header.
The algorithm
parameter of the Signature
header is equal to
rsa-sha256
. You MAY support other algorithms too, but rsa-sha256
is
(currently) the only one required.
The headers
parameter of the Signature
header contains at least
the following values:
date
or original-date
(it MUST contain at
least one of those, it also MAY contain both),digest
,x-request-id
, but only if you actually included this header in your
request,x-request-signature
, but only if you used HTTP Signature Client
Authentication in your request.If some of these conditions are not met, then you MUST reject the server's response.
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:
The date cannot be parsed.
The date does not match your clock within a certain threshold of time.
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).
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.
You MUST verify the request's signature, as explained here.
If the signature is invalid, then you MUST reject the server's response.
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.
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).
Original-Date
headerWhile 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.
The format of the Original-Date
header, if included, MUST match the "regular" format of the Date
header,
as defined in RFC 2616.
It is RECOMMENDED to use the Original-Date
header in signed
payloads.
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:
Including a signed Date
or Original-Date
header
in the response serves as a proof, that the response has indeed been
generated by a particular server in a particular time.
Including a signed X-Request-Id
in the response serves as a proof, that
the response is indeed correlated to the given request.
Including a signed X-Request-Signature
in the response serves as a proof,
that the request has indeed been sent by the particular client, and received
by the particular server.
Note, that the client needs to archive all requests and responses (along with their headers) in order for this proofs to work. He also needs to use HTTP Signature for client authentication.
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.