Verifying the signature of an Alexa request - digital-signature

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==
Excerpt from the Alexa documentation:
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!

Related

Verifying the signature of 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).
Various info:
certificate chain file:https://s3.amazonaws.com/echo.api/echo-api-cert-5.pem
Original received signature for the above example signature:
LqhhuCKwBRVucGS1MHS2yf3jKMmpm10cuImDnK0bC8lQHLfCbMukdHhvulWH4SAypXqgAk3y81G0CRS4NIG+oLnTB3PfeHb70yS8WdSFflKd/NlTc/2Rr1c5pCdpZ9C1LtNmsa/pSafTbSt4RDhmQ8XtKVCw6twhTsebS6om6/ggom95z3m1Zi4k4SkLKRQGvq18+sJHcsADKHrLO735FQ3CNrIVfS76UMXkROlJ9oSEBa9KpqSONffdVe7DDBGTGF4CLjfoSDDBjQ1nCQ0THxljUdTZ2kp4cYn1qkXJfCPoLB2+75O6Cndf+BMP9+gWd20Rl5GV44KLY9ezwEmYpA==
Excerpt from the Alexa documentation:
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
Then I used the verify method in class SkillRequestSignatureVerifier provided by Alexa SDK, but it didn't work.
Which decoding way should I use to realize what it says:
Use the public key extracted from the signing certificate to decrypt
the encrypted signature to produce the asserted hash value.
And he say :
Generate a SHA-1 hash value from the full HTTPS request body to
produce the derived hash value.
But I don't find it. Please help me to solve this problem!

Does NodeJS crypto module fail verification if the RSA cert is expired?

If 'key' in the following code is an expired cert, will res always be false regardless of the signature's validity?
var verifier = crypto.createVerify("RSA-SHA1")
verifier.update(str)
var res = verifier.verify(key, signatureValue, 'base64')
In other words, does the NodeJS crypto module care about a certificate's expiration when validating a signature. This is all in the context of validating a signed XML document.
No, the expiration is not validated using the code above. If you directly use the public key instead of the signature then the algorithm doesn't even receive the end-of-validity date.
If the key in your code is not a key but a certificate then the signature verification does normally not fail either. The test to see if the certificate is valid should be performed before the signature over the data is verified.
The certificate verification and validation procedures in other words should contain the check that the certificate is in its validity period - among all the other checks. Signature verification should only take place after that.

use X509Certificate field in SAML assertion or an external cert file.

As Identity Provider we send a SAML assertion request to Service Provider and then they validate our signature in assertion using our certificate. SAML assertion contains an optional field called X509Certificate which is certificate of assertion issuer. (our certificate). My question is that from a security perspective is it better Service Provider use this field in each assertion for validating signature or use an external certificate file.
It's a very bad idea for them to only trust the public key value that is included in a signed message. Who's to say that someone couldn't just forge your EntityID and send them random SAMLResponses with some user data? The signature of the message would be valid, and they are using the key included in the message to validate the signature, right?
The benefits of offline key exchange are well known: Your SP has securely stored your public key and will always use to it validate the signature of your messages unless you instruct them otherwise (key rollover/update). If you include your certificate in the message, the SP will compare the two certificates first to ensure they match and then they should use the copy they have stored previously (assuming they match). Otherwise the message is rejected.
However, if you want an SP to trust the public key you include in your messages, the SP must be able to ensure that it is YOUR certificate that is being used. There are some smart folks at Ping Identity who have thought about this SP DSig Validation Use Case -- you can find a description of how they do this in their "Anchored Certificate" model for DSig Validation.
https://documentation.pingidentity.com/pingfederate/pf80/index.shtml#concept_digitalSigningPolicyCoordination.html
I don't really get the 11/19 answer. If you send your BinarySecurityToken (BST) in the Assertion for signature validation, and the receiver has an entry in his trust store with this public certificate, you should be good. In order for this to work:
1) The receiver must require that the assertion is signed
2) The receiver must check the signature verifying certificate in the assertion against a trust store.
3) DO NOT just trust the dn/issuer of the signer instead of using a trust store; that can be faked in a signing certificate.
If these things are followed, you have verified that the message is signed by the holder of the private key and that the assertion has not changed in flight. You then trust that holder, therefore you can proceed.
If the receiver doesn't require that an assertion is signed, anyone can send anything to the receiver.
If the receiver doesn't check a trust store for the verifying certificate, anyone can send a signed anything to the receiver.
The advantage of sending the BST in the message is that when your IdP certificate expires and you have to get a new one, the client only has to add your new certificate to his trust store instead of changing the configuration of his application.

Certificate & Hash checking?

I'm asking this question in order for be 100% sure.
link
To validate the certificate to ensure it contains the information
digitally signed by the certificate authority, the web browser
verifies the digital signature. Because the digital signature is an
encrypted hash value that was computed based on the contents of the
certificate, the web browser needs to compare hash values. The web
browser computes a hash value based on the contents of the certificate
it received. It then decrypts the digital signature to determine the
hash value that the certificate authority computed. If the two hash
values match, the web browser is assured that the certificate contains
the information that the certificate authority verified and digitally
signed.
questions :
The web browser computes a hash value based on the contents of the
certificate it received
The browser knows in which digest algorithm the certificate was used inside , so he uses it also to calculate a hash - based on the certificate content.
It then decrypts the digital signature to determine the hash value
that the certificate authority computed
The browser knows which CA created the certificate , so he takes the public key from the appropriate computer store location and apply it on the encrypted hash value . the result is the decrypted hash value.
It then see if both the same.
Am I right ?
(You may be interested in this question on Security.SE.)
This is the structure of an X.509 certificate:
Certificate ::= SEQUENCE {
tbsCertificate TBSCertificate,
signatureAlgorithm AlgorithmIdentifier,
signatureValue BIT STRING }
TBSCertificate ::= SEQUENCE {
version [0] EXPLICIT Version DEFAULT v1,
serialNumber CertificateSerialNumber,
signature AlgorithmIdentifier,
issuer Name,
validity Validity,
subject Name,
subjectPublicKeyInfo SubjectPublicKeyInfo,
issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
-- If present, version MUST be v2 or v3
subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
-- If present, version MUST be v2 or v3
extensions [3] EXPLICIT Extensions OPTIONAL
-- If present, version MUST be v3
}
When presented with the certificate, the browser gets the signature algorithm from the certificate itself. Typically, this is something like RSAwithSHA1.
In this case, it can indeed recalculate the SHA-1 digest of the TBSCertificate (the actual content of the certificate).
In addition, from the TBSCertificate, it can find the issuer name: this is what's used to find a trust anchor from the known CA certificates (the issuer name must match the subject of the CA certificate). When it has found the CA certificate with the right name in the list it already trusts, it can get the public RSA key from that CA certificate.
Having both the SHA-1 digest and the RSA public key, it can verify that the signatureValue matches.
the digital signature is an encrypted hash value
That's not strictly true, although it's commonly said. Digital signatures are digital signatures, not encryption.
The problem is that RSA uses the same maths to encrypt and sign: encryption with the public key and signature with the private key. Often, one is confused with the other (even in the OpenSSL API). It doesn't make sense to "encrypt" with a private key, since "encrypting" implies hiding (and you're not hiding anything if you're giving the public key away so the it can "decrypt" the signature).
This subtly about hash and encryption with digital signatures wouldn't work with some other algorithms such as DSA, which are for signatures only.
This is why a number of digital signature APIs combine the hash and key usage into a single "sign" or "verify" operation. This is what the Java Signature API does, for example: you tell it to use RSAwithSHA1 or DSAwithSHA1, give it the key and the message, and tell it to sign or verify, you don't have to do the digest or "encryption" manually.
For the purpose of certificate verification: the browser gets the issuer from the cert and find the corresponding public key (from trusted CA certs), it also gets the signature algorithm from the cert, and then verifies the signature with that public key and the TBSCertificate content, according to what the signature algorithm dictates.

X509Data element appearing twice in signature

I am trying to decrypt (and later encrypt) an email message (ebXML). The message contains a Signature element that contains child elements to specify the SignedInfo, SignatureValue and KeyInfo. Also, the message contains an encrypted attachment.
The KeyInfo element contains two X509Data elements. Each of these specify a X509Certificate. Why are there two certificates? Is it one certificate for the message itself and one certificate for the attachment?
Most likely it's an end-entity certificate and it's CA certificate. You can check this by obtaining those certificates and comparing their Issuer and Subject properties.

Resources