Sample code for 30+ languages & platforms
Tcl

Verify Signature of Alexa Custom Skill Request

See more HTTP Misc Examples

This example verifies the signature of an Alexa Custom Skill Request.

Chilkat Tcl Downloads

Tcl

load ./chilkat.dll

set success 0

# This example assumes you have a web service that will receive requests from Alexa.
# A sample request sent by Alexa will look like the following:

# Connection: Keep-Alive
# Content-Length: 2583
# Content-Type: application/json; charset=utf-8
# Accept: application/json
# Accept-Charset: utf-8
# Host: your.web.server.com
# User-Agent: Apache-HttpClient/4.5.x (Java/1.8.0_172)
# Signature: dSUmPwxc9...aKAf8mpEXg==
# SignatureCertChainUrl: https://s3.amazonaws.com/echo.api/echo-api-cert-6-ats.pem
# 
# {"version":"1.0","session":{"new":true,"sessionId":"amzn1.echo-api.session.433 ... }}

# First, assume we've written code to get the 3 pieces of data we need:
set signature "dSUmPwxc9...aKAf8mpEXg=="
set certChainUrl "https://s3.amazonaws.com/echo.api/echo-api-cert-6-ats.pem"
set jsonBody "{\"version\":\"1.0\",\"session\":{\"new\":true,\"sessionId\":\"amzn1.echo-api.session.433 ... }}"

# To validate the signature, we do the following:

# First, download the PEM-encoded X.509 certificate chain that Alexa used to sign the message 
set http [new_CkHttp]

set sbPem [new_CkStringBuilder]

set success [CkHttp_QuickGetSb $http $certChainUrl $sbPem]
if {$success == 0} then {
    puts [CkHttp_lastErrorText $http]
    delete_CkHttp $http
    delete_CkStringBuilder $sbPem
    exit
}

set pem [new_CkPem]

set success [CkPem_LoadPem $pem [CkStringBuilder_getAsString $sbPem] "passwordNotUsed"]
if {$success == 0} then {
    puts [CkPem_lastErrorText $pem]
    delete_CkHttp $http
    delete_CkStringBuilder $sbPem
    delete_CkPem $pem
    exit
}

# The 1st certificate should be the signing certificate.
# cert is a CkCert
set cert [CkPem_GetCert $pem 0]
if {[CkPem_get_LastMethodSuccess $pem] == 0} then {
    puts [CkPem_lastErrorText $pem]
    delete_CkHttp $http
    delete_CkStringBuilder $sbPem
    delete_CkPem $pem
    exit
}

# Get the public key from the cert.
set pubKey [new_CkPublicKey]

CkCert_GetPublicKey $cert $pubKey

delete_CkCert $cert

# Use the public key extracted from the signing certificate to decrypt the encrypted signature to produce the asserted hash value.
set rsa [new_CkRsa]

set success [CkRsa_UsePublicKey $rsa $pubKey]
if {$success == 0} then {
    puts [CkCert_lastErrorText $cert]
    delete_CkHttp $http
    delete_CkStringBuilder $sbPem
    delete_CkPem $pem
    delete_CkPublicKey $pubKey
    delete_CkRsa $rsa
    exit
}

# RSA "decrypt" the signature.
# (Amazon's documentation is confusing, because we're simply verifiying the signature against the SHA-1 hash
# of the request body.  This happens in a single call to VerifyStringENC...)
CkRsa_put_EncodingMode $rsa "base64"
set bVerified [CkRsa_VerifyStringENC $rsa $jsonBody "sha1" $signature]
if {$bVerified == 1} then {
    puts "The signature is verified against the JSON body of the request. Yay!"
} else {
    puts "Sorry, not verified.  Crud!"
}


delete_CkHttp $http
delete_CkStringBuilder $sbPem
delete_CkPem $pem
delete_CkPublicKey $pubKey
delete_CkRsa $rsa