Skip to main content
Version: v2

HTTP Request signing

To verify that requests have been made by a trusted source and have not been altered by third parties, requests shall be signed. This page explains how request shall be signed.

The following standard is applied: https://tools.ietf.org/html/draft-cavage-http-signatures-10

The certificate

The certificate that shall be used for certification, is generated by Invers B.V. and shall be sent as a part of the onboarding procedure. Only the public certificate is registered in Invers' system to validate signatures.

Headers

To sign a request, following headers are required:

  • ApiKey
  • X-Request-ID
  • Date
  • Digest
  • Signature

ApiKey

The ApiKey sent by Invers B.V. during onboarding.


ApiKey header example
ApiKey: cEZrSmVPLTN1XzVDM09nVDhEanlZaUJwYzRXTldpVUc=

X-Request-ID

X-Request-ID shall be a Guid. Note that the Guid must be unique for each request.


X-Request-ID header example
X-Request-ID: f1b8d9bd-0118-47ff-bdb7-5e2956ad0e9f

Date

Request date and shall contain the current date, in HTTP Date (RFC 2616).

DateTime.Now.ToUniversalTime().ToString("r");

Date header example
Date: Wed, 25 Sep 2019 07:45:19 GMT

Digest

Contains a hash of the requestbody, more information on this can be found below.


Digest header example
Digest: sha-512=z4PhNX7vuL3xVChQ1m2AB9Yg5AULVxXcg/SpIdNs6c5H0NE8XYXysP+DGNKHfuwvY7kxvUdBeoGlODJ6+SfaPg==

Signature

Contains the signature and signature info, more information on generating a signature header can be found below.


Signature header example
Signature: keyId="cEZrSmVPLTN1XzVDM09nVDhEanlZaUJwYzRXTldpVUc=",algorithm="rsa-sha512",headers="date digest x-request-id",signature="lvJxQyr9JTBZGj5zIss4lPRDntClh9wdYRdcq1MQYd0sdav/ccPR3tyEWklpgGc9vLNLETLUnAXl4LtmSEW6Zu4ZHxlJ82Y7hzzjDYDnyj1OSZa97ArlY9N5aLKKG1rICPTeWPN4hxID/taThTh8Ab2TCCNrpYRiIYTkxHWvjrQF8HPerbFalqjLn1WfNyhCIGkO6u6I2H9hOsLaFJG3k+Ui5i3IxmaT1yLSWYgHxo32xRHaGr6KqrspkbQmoCVbI78SkCkajOuBhVUXqAw213GuOxjLaOFFnoLAo3cfrMxvPtL/2JMpTjYUPdTZJ3EsuXXnvx7bwmrvooJtuNRgFw=="

Generating a digest

The digest is a Base64 (RFC 4648) encoded hash of the request body: Base64(SHA512(body))

  • The value that should be hashed is the request body, if said body is empty then the empty string must be hashed.
  • Both SHA-512 and SHA-256 can be used as hashing algorithm
  • The output must be Base64 (RFC 4648) encoded.
  • The value must be added to the digest-header.

A few examples:

Digest: sha-256=47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=
Digest: sha-512=z4PhNX7vuL3xVChQ1m2AB9Yg5AULVxXcg/SpIdNs6c5H0NE8XYXysP+DGNKHfuwvY7kxvUdBeoGlODJ6+SfaPg==

C# Example code for generating the digest
private string CalculateDigest(byte[] body, HashAlgorithmName hashAlgorithm)
{
byte[] hash = null;
using (var algorithm = HashAlgorithm.Create(hashAlgorithm.Name))
{
hash = algorithm.ComputeHash(body);
}
return Convert.ToBase64String(hash);
}

Generating the Signing String

  • The order of the headers in the signing string is important.
  • The names of the headers must be lowercase.
  • Note: date format: In C# this will be: DateTime.Now.ToUniversalTime().ToSTring("r").
  • Expected header: date, digest and x-request-id.

Signing string example:

date: Wed, 25 Sep 2019 07:45:19 GMT
digest: sha-512=z4PhNX7vuL3xVChQ1m2AB9Yg5AULVxXcg/SpIdNs6c5H0NE8XYXysP+DGNKHfuwvY7kxvUdBeoGlODJ6+SfaPg==
x-request-id: 23bfabd8-3ffa-4e41-a851-2395f15a889e

C# example of the construction of a signing string
private string CalculateSigningString(string requestDate, string requestDigest, string requestId)
{
var s = string.Format("date: {0}\ndigest: {1}\nx-request-id: {2}", requestDate, requestDigest, requestId);
return s;
}

Generating the signature

The signature is the signature string and signed using the certificate: Base64(RSA-SHA512(signing_string))

  • As algorithm RSA-SHA512 must be used
  • The private key of the certificate shall be used
  • The output shall be Base64 (RFC 4648) encoded.

An example of a signature:

lvJxQyr9JTBZGj5zIss4lPRDntClh9wdYRdcq1MQYd0sdav/ccPR3tyEWklpgGc9vLNLETLUnAXl4LtmSEW6Zu4ZHxlJ82Y7hzzjDYDnyj1OSZa97ArlY9N5aLKKG1rICPTeWPN4hxID/taThTh8Ab2TCCNrpYRiIYTkxHWvjrQF8HPerbFalqjLn1WfNyhCIGkO6u6I2H9hOsLaFJG3k+Ui5i3IxmaT1yLSWYgHxo32xRHaGr6KqrspkbQmoCVbI78SkCkajOuBhVUXqAw213GuOxjLaOFFnoLAo3cfrMxvPtL/2JMpTjYUPdTZJ3EsuXXnvx7bwmrvooJtuNRgFw==

C# Example of generating a signature using the signing string
    private string CalculateSignature(string signingString)
{
if (_certificate != null)
{
byte[] bytesData = Encoding.ASCII.GetBytes(signingString);
byte[] bytesEncrypted = _certificate.GetRSAPrivateKey().SignData(bytesData, HashAlgorithmName.SHA512, RSASignaturePadding.Pkcs1);
return Convert.ToBase64String(bytesEncrypted);
}
else
{
_logger.LogError("No certificate loaded for calculating signature");
}

return String.Empty;
}

Constructing the Signature header

The signature header contains the following sections:

  • keyId - ApiKey.
  • algorithm - The value of the algorithm, this shall be rsa-sha512.
  • headers - Lowercase list of the headers that have been used in the signature. The value shall be date digest x-request-id
  • signature - The value calculated in the previous section.
keyId="cEZrSmVPLTN1XzVDM09nVDhEanlZaUJwYzRXTldpVUc=",algorithm="rsa-sha512",headers="date digest x-request-id",signature="lvJxQyr9JTBZGj5zIss4lPRDntClh9wdYRdcq1MQYd0sdav/ccPR3tyEWklpgGc9vLNLETLUnAXl4LtmSEW6Zu4ZHxlJ82Y7hzzjDYDnyj1OSZa97ArlY9N5aLKKG1rICPTeWPN4hxID/taThTh8Ab2TCCNrpYRiIYTkxHWvjrQF8HPerbFalqjLn1WfNyhCIGkO6u6I2H9hOsLaFJG3k+Ui5i3IxmaT1yLSWYgHxo32xRHaGr6KqrspkbQmoCVbI78SkCkajOuBhVUXqAw213GuOxjLaOFFnoLAo3cfrMxvPtL/2JMpTjYUPdTZJ3EsuXXnvx7bwmrvooJtuNRgFw=="

C# example of generating a signature header
private string GenerateSignatureHeader(string apiKey, string requestSignature)
{
return string.Format("keyId=\"{0}\",algorithm=\"rsa-sha512\",headers=\"date digest x-request-id\",signature=\"{1}\"", apiKey, requestSignature);
}