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:
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
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!