Signing of HTTP Messages¶
Abstract¶
When communicating with version 2 and later of DAX REST API using the HTTP protocol you will need to sign all requests with a private key. DAX has the public key on record and will verify the signature with the callers public key.
This is how it works …
Signature¶
All transactions with DAX are considered high security and having an additional signature in the HTTP header allows the server to ensure that even if the transport channel has been compromised the content of the message from a client has not been compromised and/or tampered with.
Components of the signature (signature parameters)¶
There are a number of different parameters of the signature header that are needed - here we will detail those parameters. The order of the parameters are not important.
A complete signature header can look like this:
Example signature header:
realm="dax" algorithm="sha256withrsa" headers="(request-target) cache-control date content-length" signature="zYLDJ9pBayO5QpFkYo1b1r5h0j9sK/Sy8lzAwz2hTdwQy..."
realm¶
REQUIRED. The realm
parameter signals the server which realm is being used. A realm is used to group together a set of users, credentials and roles. In DAX the realm to use is dax
.
Example:
realm="dax"
signature¶
REQUIRED. This is the base 64 encoded signature generated by the client. The client uses the algorithm
and headers
signature parameters to form a signing string and this string is later signed with the private key associated with the calling client using the specified algorithm
. The signature
parameter is then set to the base 64 encoding of the signature.
Example:
signature="zYLDJ9pBayO5QpFkYo1b1r5h0j9sK/Sy8lzAwz2hTdwQyXj6ZrjgCAdc..."
headers¶
REQUIRED. The headers
parameter is used to specify the ordered list of HTTP headers that has been used when generating the signature. The headers should be lowercased with surround quotes and if multiple headers are used they should be separated by a single space character. If there are duplicate headers the last header will be used.
Mandatory headers when communicating with DAX are date
and the special (request-target)
(more on that later).
If a header is in the list but not available in the request, the request will be denied.
Example:
headers="(request-target) date content-type"
algorithm¶
REQUIRED. The algorithm
parameter is used to specifiy the digital signature algorithm that was used when generating the signature. DAX supports a single algorithm, sha256 hashed and signed with RSA, SHA256withRSA
.
Example:
algorithm="sha256withrsa"
Signature string construction¶
In order to generate the string that is signed with a key, the client MUST use the values of each HTTP header field in the headers
signature parameter, in the order they appear in the headers
signature parameter. It’s also important to note that the enforced encoding is utf-8
and that information needs to be included either as a Content-Type
header or as an Accept-Charset
header. And of course, all necessary strings must be calculated and hashed using utf-8.
- The special
(request-target)
header is used to specify the HTTP request’s target. To put it together you use the lowercased request method (i.e. get, post, put, delete etc.), a single space character and then the request’s target path. Lowercasing is only used for the request method and not the target path. - Create the
headers
field by joining the lowercased header field name followed by a colon (:
), a single space and the header field value. Always trim the value before adding it. If there are multiple instances of the header being used it should be concatenated to the previous header separated with a single comma (,
). - All values in the string should end with a newline
\n
character.
Example GET request¶
GET /api/v2/DaxEndPoint HTTP/1.1
Host: dax.amido.se
Date: 2020-05-17T14:44:30+02:00
X-Example: Example header
with some whitespace.
Cache-Control: max-age=60
Cache-Control: must-revalidate
The following example illustrates how the signature would be constructed if the headers
part of the signature looked like this:
headers="(request-target) host date cache-control
Example signing string:
(request-target): get /api/v2/DaxEndPoint\n
host: dax.amido.se\n
date: 2020-05-17T14:44:30+02:00\n
cache-control: max-age=60,must-revalidate\n
Example POST request¶
When DAX gets a request with a body the body MUST be included in the signing string.
POST /api/v2/DaxEndPoint HTTP/1.1
Host: dax.amido.se
Date: 2020-05-17T14:44:30+02:00
X-Example: Example header
with some whitespace.
Cache-Control: max-age=60
Cache-Control: must-revalidate
Content-Length: 18
{"hello": "world"}
The following example illustrates how the signature would be constructed if the headers
part of the signature looked like this:
headers="(request-target) host date cache-control content-length
Example signing string:
(request-target): post /api/v2/DaxEndPoint\n
host: dax.amido.se\n
date: 2020-05-17T14:44:30+02:00\n
cache-control: max-age=60,must-revalidate\n
content-length: 18\n
{"hello": "world"}
DAX mandatory headers¶
The following headers are mandatory to use when calling DAX:
(request-target)
date
(as an ISO-8601 timestamp with timezone information, see examples above)
Creating the actual signature¶
In order to create a signature, a client must use the contents of the HTTP message, the headers
value, and the signature string construction algorithm to create the signature string
.
The algorithm
must then be used to generate a digital signature on the signature string.
The signature
is then generated by base 64 encoding the output of the digital signature algorithm.
For example, assume that the algorithm
value was SHA256withRSA
. This would signal to the server that the data has been signed with an RSA Private Key and that the signature string hashing function is SHA-256. The signature should be a byte[] which is then base 64 encoded and placed in the signature
value.
Complete request example with signature:
GET /api/v2/DaxEndPoint HTTP/1.1
Host: dax.amido.se
Signature: realm="dax" algorithm="sha256withrsa" headers="(request-target) cache-control date" signature="zYLDJ9pBayO5QpFkYo1b1r5h0j9sK/Sy8lzAwz2hTdwQy..."
Date: 2020-05-17T14:44:30+02:00
X-Example: Example header
with some whitespace.
Cache-Control: max-age=60
Cache-Control: must-revalidate
The signature string using algorithm sha256withrsa
could conceptually be described as:
base64encode(rsasign(sha256(byte-array-from-utf8(signingstring))))
.
Final words¶
If you’re using .net core we have .net standard SDK available upon request that takes care of all complexities during REST API requests. The code for this SDK will be published at a later date.