cgraham

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

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

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

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. :slight_smile:

Where Next?

Popular in Questions Top

9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
chrisalley
ExUnit now has describe blocks which is a welcome addition coming from RSpec. In the docs, it states that nested hierarchies of describe ...
New
JeremM34
Hello, how can I check the Phoenix version ? Thanks !
New
mgjohns61585
Could someone help me? I’m making my first elixir program, number guessing game. I can’t figure out how to convert the user’s guess from ...
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod – where is this set? Thanks.
New
fireproofsocks
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? Ecto.Repo — Ecto v3.14.0 has exampl...
New
joeerl
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
aalberti333
As the title describes, I’m trying to run Enum.map() over a list of key/value pairs, where the value is a map. My data looks like this: ...
New
JDanielMartinez
Hi! May someone helps me, please! I have two apps into an umbrella project: the first one is Database, which manages queries, and the se...
New

Other popular topics Top

New
fireproofsocks
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? Ecto.Repo — Ecto v3.14.0 has exampl...
New
aalberti333
As the title describes, I’m trying to run Enum.map() over a list of key/value pairs, where the value is a map. My data looks like this: ...
New
grych
Hi folks, Few months ago I have announced the proof-of-concept of the library to manipulate the browsers DOM objects directly from Elixi...
639 52341 488
New
AstonJ
Please see the new poll here: Which code editor or IDE do you use? (Poll) (2022 Edition) It’s been a while since we first asked this, I...
208 31142 143
New
saif
Hello everyone, Long time lurker first time poster here. I’ve recently begun working on Elixir full-time again! :raised_hands: It’s been...
New
boundedvariable
I am going through the kafka architecture. All the features what the kafka is providing are already in Erlang. I would like hear your opi...
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 records...
New
dogweather
I wrote this comment on r/haskell, and it’s not popular there. :wink: But I think I’m on to something… Haskell reminds me of Java, and e...
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New

Latest on Elixir Forum

We're in Beta

About us Mission Statement