cgraham
X.509 request Cert chain validation plug for Alexa Skills
Hello,
I am trying to get an alexa skill certified by Amazon. As part of the certification process, they want the server to validate the request has a valid X.509 certificate chain from an Amazon domain. They provide an impl in Java.
(https://github.com/amzn/alexa-skills-kit-java/blob/master/src/com/amazon/speech/speechlet/authentication/SpeechletRequestSignatureVerifier.java)
I am trying to build a version in Phoenix / Elixir. (I have the rest of the system working - just not this.).
Does anyone have a good suggestion as to which libraries/plug-ins I should use to implement these functions (specifically reading and verifying the X.509 certificate chain)?
I am assuming it would work best as a Phoenix Plug but I am open to other suggestions too.
I am also happy to make it open source if we can figure out a solution that works.
Thanks!
Most Liked
cgraham
Yeah - that is my plan! Once I get the functionality working I’ll then have to figure out how to separate it out into a library (Haven’t never done that yet but I am assuming there is good documentation and it is not that hard).
Part of me is wondering if there is a big need for an elixir library that basically has all of the erlang records preloaded so that Elixir members can use Erlang records without needing to find the files and extract them etc…
cgraham
Woo hoo! I got it to verify! Some notes for those of you who may later read this: I did need to base64 decode the message and we did not need to further decode the RSA since the :otp decode did it recursively.
I am attaching a modified version of the PublicKey test that xlphs posted on github that now works with verify. I have a few more easy validations an to add and some cleanup and will then extract this whole thing into a library so that people can just use mix to import it. Thanks again to everyone who helped! I really appreciate it!
defmodule PublicKey do
def verify_fun(_, {:extension, _}, state) do
IO.puts "verify_fun -- extension"
{:unknown, state}
end
def verify_fun(_, {:revoked, _}, state) do
IO.puts "verify_fun -- revoked"
{:fail, state}
end
def verify_fun(cert, event, state) do
IO.puts "verify_fun --"
IO.inspect event
{:unknown, state}
end
def verify do
Application.ensure_all_started :inets
Application.ensure_all_started :ssl
Application.ensure_all_started :public_key
{:ok, resp} = :httpc.request(:get, {'https://s3.amazonaws.com/echo.api/echo-api-cert-4.pem', []}, [], [body_format: :binary])
{_, _headers, certificate_chain_bin} = resp
# alternatively, read from local file
# {:ok, certificate_chain_bin} = :file.read_file("echo-api-cert.pem")
cert_chain = :public_key.pem_decode(certificate_chain_bin)
cert_chain_decoded = Enum.map(cert_chain,
fn {_, bin, _} -> bin
end) |> Enum.reverse
{:ok, resp} = :httpc.request(:get, {'https://www.symantec.com/content/dam/symantec/docs/other-resources/verisign-class-3-public-primary-certification-authority-g5-en.pem', []}, [], [body_format: :binary])
{_, _headers, root_cert_bin} = resp
# {:ok, root_cert_bin} = :file.read_file("auth_root.pem")
[{_, root_cer, _}] = :public_key.pem_decode(root_cert_bin)
case :public_key.pkix_path_validation(root_cer, cert_chain_decoded,
[{:verify_fun, {&PublicKey.verify_fun/3, {}}}]) do
{:ok, {public_key_info, _policy_tree}} ->
IO.inspect public_key_info
{:error, {:bad_cert, reason}} ->
IO.puts "validation failed with bad cert"
IO.inspect reason
end
[{_,first,_}|_tail] = cert_chain
decoded = :public_key.pkix_decode_cert(first,:otp)
public_key_der = decoded |> elem(1) |> elem(7) |> elem(2)
message = "<raw body of alexa request>"
signature = "cHV0IHNpZ25hdHVyZSB2YWx1ZSBpbiByZXF1ZXN0IGhlYWRlciBoZXJl" #signature request header parameter
{:ok, signature} = Base.decode64(signature)
IO.puts ("verified? #{:public_key.verify(message, :sha, signature, public_key_der)}");
end
end
PublicKey.verify()
OvermindDL1
Except that will not include it in a release, instead you want to add it to the (extra) applications list in your mix.exs file, that way it will both be included in release as well as loaded. ![]()
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance









