Search code examples
digital-signaturealexa-skills-kit

Verifying the signature of an Alexa request


I am currently building a webservice that should handle Alexa voice intents. The HTTP request I get from Alexa must be verified by checking a signature, as described in the documentation (see below for excerpt).

I seem to correctly decrypt the signature sent in the request, and seem to correctly compute the request body's signature. But they differ - but instead of being completely different (which would hint at some error in the computation), the computed signature is a suffix of the sent signature. For example:

Received signature (decoded and decrypted):

3021300906052b0e03021a05000414ca5cc3be233b045be79e94389e47353b7aaec434

Calculated signature of the request body (its sha1 hash):

ca5cc3be233b045be79e94389e47353b7aaec434

What are the extra bytes at the beginning of the received signature? They don't seem to change between requests.

Various info:

  • The current (2016-10-29) certificate chain file
  • Original received signature for the above example signature: M4Xq8WmUHjaR4Fgj9HUheoOUkZf4tkc5koBtkBq/nCmh4X6EiimBXWa7p+kHoMx9noTdytGSUREaxYofTne1CzYOW0wxb9x6Jhor6lMwHAr4cY+aR1AEOkWrjsP94bewRr1/CxYNl7kGcj4+QjbEa/7dL19BNmLiufMLZDdRFsZSzlfXpPaAspsoStqVc/qc26tj5R9wtB0sTS4wbFc4eyCPFaCZocq1gmjfR3YQXupuD7J3slrz54SxukNmL/M1CIoZ8lOXjS82XLkKjsrzXdY5ePk8XsEDjNWkFSLbqzBzGBqzWx4M913uDA6gPx5tFKeoP8FgpV+BHKDf3d4gmQ==

Checking the Signature of the Request

Requests sent by Alexa provide the information you need to verify the signature in the HTTP headers:

  • SignatureCertChainUrl
  • Signature

To validate the signature:

  • Verify the URL specified by the SignatureCertChainUrl header value on the request to ensure that it matches the format used by Amazon. See Verifying the Signature Certificate URL.

  • Download the PEM-encoded X.509 certificate chain that Alexa used to sign the message as specified by the SignatureCertChainUrl header value on the request.

  • This chain is provided at runtime so that the certificate may be updated periodically, so your web service should be resilient to different URLs with different content.

  • This certificate chain is composed of, in order, (1) the Amazon signing certificate and (2) one or more additional certificates that create a chain of trust to a root certificate authority (CA) certificate. To confirm the validity of the signing certificate, perform the following checks:
    • The signing certificate has not expired (examine both the Not Before and Not After dates)
    • The domain echo-api.amazon.com is present in the Subject Alternative Names (SANs) section of the signing certificate
    • All certificates in the chain combine to create a chain of trust to a trusted root CA certificate
  • Once you have determined that the signing certificate is valid, extract the public key from it.
  • Base64-decode the Signature header value on the request to obtain the encrypted signature.
  • Use the public key extracted from the signing certificate to decrypt the encrypted signature to produce the asserted hash value.
  • Generate a SHA-1 hash value from the full HTTPS request body to produce the derived hash value
  • Compare the asserted hash value and derived hash values to ensure that they match

Solution

  • By googleing for the prefix 3021300906052b0e03021a05000414 of the sent signature I found out that the prefix is a constant that indicates the used hash algorithm. Either just cutting it off, or letting OpenSSL do the signature verification solves the problem. Never brew your own crypto!