summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--components/authorize/src/authorize_keys.erl38
-rw-r--r--components/authorize/src/authorize_rpc.erl13
-rw-r--r--components/authorize/src/authorize_sig.erl46
-rw-r--r--components/rvi_common/src/rvi_common.erl1
-rw-r--r--rebar.config3
-rw-r--r--rvi_backend.config4
-rw-r--r--test_keys/jlr_com.pem27
7 files changed, 125 insertions, 7 deletions
diff --git a/components/authorize/src/authorize_keys.erl b/components/authorize/src/authorize_keys.erl
new file mode 100644
index 0000000..99f6847
--- /dev/null
+++ b/components/authorize/src/authorize_keys.erl
@@ -0,0 +1,38 @@
+-module(authorize_keys).
+
+-export([get_key_pair/0]).
+
+-include_lib("lager/include/log.hrl").
+-include_lib("public_key/include/public_key.hrl").
+
+get_key_pair() ->
+ case application:get_env(rvi, key_pair, undefined) of
+ undefined ->
+ {undefined, undefined};
+ {openssl_pem, Pem} ->
+ get_key_pair_from_pem(openssl, Pem)
+ end.
+
+get_key_pair_from_pem(openssl, Pem) ->
+ case file:read_file(Pem) of
+ {ok, Bin} ->
+ case public_key:pem_decode(Bin) of
+ [Entry] ->
+ case public_key:pem_entry_decode(Entry) of
+ #'RSAPrivateKey'{modulus = Mod,
+ publicExponent = PE} = Priv ->
+ Pub = #'RSAPublicKey'{modulus = Mod,
+ publicExponent = PE},
+ {Priv, Pub};
+ _ ->
+ ?debug("Unknown PEM entry (~p)~n", [Pem]),
+ {undefined, undefined}
+ end;
+ _ ->
+ ?debug("Unsupported PEM file (~p)~n", [Pem]),
+ {undefined, undefined}
+ end;
+ Error ->
+ ?debug("Cannot read PEM file (~p): ~p~n", [Pem, Error]),
+ {undefined, undefined}
+ end.
diff --git a/components/authorize/src/authorize_rpc.erl b/components/authorize/src/authorize_rpc.erl
index a37ecc1..f380783 100644
--- a/components/authorize/src/authorize_rpc.erl
+++ b/components/authorize/src/authorize_rpc.erl
@@ -28,7 +28,9 @@
-record(st, {
next_transaction_id = 1, %% Sequentially incremented transaction id.
services_tid = undefined, %% Known services.
- cs = #component_spec{}
+ cs = #component_spec{},
+ private_key = undefined,
+ public_key = undefined
}).
start_link() ->
@@ -36,7 +38,10 @@ start_link() ->
init([]) ->
?debug("authorize_rpc:init(): called."),
- {ok, #st { cs = rvi_common:get_component_specification() } }.
+ {Priv, Pub} = authorize_keys:get_key_pair(),
+ {ok, #st { cs = rvi_common:get_component_specification(),
+ private_key = Priv,
+ public_key = Pub} }.
start_json_server() ->
?debug("authorize_rpc:start_json_server(): called"),
@@ -106,7 +111,7 @@ authorize_local_message(CompSpec, Service) ->
?debug("authorize_rpc:authorize_local_msg(): service: ~p ~n", [Service]),
rvi_common:request(authorize, ?MODULE,authorize_local_message,
[{ service, Service }],
- [staus, signature, certificate], CompSpec).
+ [status, signature, certificate], CompSpec).
@@ -118,7 +123,7 @@ authorize_remote_message(CompSpec, Service, Signature, Certificate) ->
[{ service, Service},
{ signature, Signature },
{ certificate, Certificate }],
- [staus], CompSpec).
+ [status], CompSpec).
diff --git a/components/authorize/src/authorize_sig.erl b/components/authorize/src/authorize_sig.erl
new file mode 100644
index 0000000..8fb2353
--- /dev/null
+++ b/components/authorize/src/authorize_sig.erl
@@ -0,0 +1,46 @@
+-module(authorize_sig).
+
+-compile(export_all).
+
+-define(DIGEST_TYPE, sha).
+
+%% Inspired by
+%% http://blog.differentpla.net/blog/2015/04/19/jwt-rs256-erlang/
+decode_jwt(JWT, PubKey) ->
+ [H, P, S] = binary:split(JWT, <<".">>, [global]),
+ Header = decode_json(base64url:decode(H)),
+ Payload = decode_json(base64url:decode(P)),
+ Signature = base64url:decode(S),
+ case public_key:verify(P, ?DIGEST_TYPE, Signature, PubKey) of
+ false ->
+ invalid;
+ true ->
+ {Header, Payload}
+ end.
+
+encode_jwt(JSON, PrivKey) ->
+ encode_jwt(JSON, header(), PrivKey).
+
+encode_jwt(Payload0, Header0, PrivKey) ->
+ Header = base64url:encode(ensure_json(Header0)),
+ Payload = base64url:encode(ensure_json(Payload0)),
+ Signature = base64url:encode(
+ public_key:sign(Payload, ?DIGEST_TYPE, PrivKey)),
+ <<Header/binary, ".", Payload/binary, ".", Signature/binary>>.
+
+header() ->
+ "{\"alg\": \"RS256\"}".
+
+ensure_json("{" ++ _ = JSON) ->
+ list_to_binary(JSON);
+ensure_json(<<"{", _/binary>> = JSON) ->
+ JSON;
+ensure_json({struct, _} = JSON) ->
+ list_to_binary(exo_json:encode(JSON)).
+
+decode_json("{" ++ _ = JSON) ->
+ {ok, Res} = exo_json:decode_string(JSON),
+ Res;
+decode_json(<<"{", _/binary>> = JSON) ->
+ {ok, Res} = exo_json:decode_string(binary_to_list(JSON)),
+ Res.
diff --git a/components/rvi_common/src/rvi_common.erl b/components/rvi_common/src/rvi_common.erl
index 2c16b40..95dff51 100644
--- a/components/rvi_common/src/rvi_common.erl
+++ b/components/rvi_common/src/rvi_common.erl
@@ -651,4 +651,3 @@ start_json_rpc_server(Component, Module, Supervisor) ->
[ Component, Module ]),
Err
end.
-
diff --git a/rebar.config b/rebar.config
index 96de275..07bd053 100644
--- a/rebar.config
+++ b/rebar.config
@@ -31,5 +31,6 @@
{dthread, ".*", {git, "git://github.com/tonyrog/dthread.git", "HEAD"}},
{uart, ".*", {git, "git://github.com/tonyrog/uart.git", "HEAD"}},
{gsms, ".*", {git, "git://github.com/tonyrog/gsms.git", "HEAD"}},
- {wse, ".*", {git, "git://github.com/tonyrog/wse.git", "HEAD"}}
+ {wse, ".*", {git, "git://github.com/tonyrog/wse.git", "HEAD"}},
+ {base64url, ".*", {git, "git://github.com/dvv/base64url.git", "HEAD"}}
]}.
diff --git a/rvi_backend.config b/rvi_backend.config
index 9ca9392..6a2ea52 100644
--- a/rvi_backend.config
+++ b/rvi_backend.config
@@ -68,7 +68,9 @@
]
}
]
- },
+ },
+
+ {key_pair, {openssl_pem, "test_keys/jlr_com.pem"}},
{ components,
[
diff --git a/test_keys/jlr_com.pem b/test_keys/jlr_com.pem
new file mode 100644
index 0000000..1c25795
--- /dev/null
+++ b/test_keys/jlr_com.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEA5atdLLEj9QQdPLNS3EeiKMqvU8O2luLgNrPu/3NZyazIHOj0
+XsyIfrrUH7M696yLPeon5RyTt9YS8G9mvvoEdWCs9QQxYCUj3cDWAAfSPaeCtzsc
+sJPEkIxb/DN37SWiyEMD+X96YDi5QAbNbS4D3bVlCvdQCJHCYxwnWltH66jCbyYj
+mmDSc4ECrFbsvqAt4Cj4WsrhrOOar8t3eEYQwJ7wtTUJ4ZWKiwOGjNspMXsiR/W8
+on/nI5tJjb4ie5i9wi5nScrcE0bkrERJAb8geVLvxv6UJ6KDhgHkYJ+N55whgZtm
+xWK+Hyx2x16y+utyXA1w1KWtVgNuEXTumm/BgwIDAQABAoIBAQCqlNCrdRYj0V51
+yyrr+Thz27bFHEPtZazqdFI64U37AJ3Q+yUlk/x9Q/5xXQmbE0iIP/ZJsSP2EsYW
+VmeVyNSu6ZMMmISjyHIPLj7D3wtER7pKpVj1vYrtYZKgiwmz1ZRF8aBuG0SlWvwc
+lfDV+qtcbHIT5wRGmRwryKlh7xJH8LOxCn95859lqUO2/nao1FiToGg6L7GOjKnc
+kyoHzMXc57Ju18iOf0ef+Rpjz3gYU8+jqhMVYc02ceXcTGUmKyFlUgLo5oTgswkv
+ihQSvESdL4Wjy9N70CZ3LmbX4sQtbGmB//+TUhtLRz3QZ24UHyZftmPqmofxKl0u
++V9MPZZhAoGBAPrz9PUVh1qhB6h3o3zsaMqwghv+LGJP9e+pAfRrxOlsl9D+oXJ9
+RqtYZ1TSkG4zh7zjUtbAwBpOnhDwNmoWggdzAVQqY0dZkFWcIKMFwgJ2bdIctnqP
+gb+5mdHIAFr2mMGkCakYah58rBFHTwscB+DJo1nQkeeAtZZVhjKNZWglAoGBAOpJ
+0+EvMPmilxdu0JtEM0yCIgiWztzx8Xk/Dk94rvFL1hGlpqzWb1zrSmkn0nZJOMwp
+czaqwPGKVVKga+FyG/Ph5EOjzeq6o6L4updhXVK4+FQyYjtW76Gd45d0SEtoFHDv
+VnNACE2wKYy8eRn6YL8/1wWSK3J3Bl4R2wLKQ56HAoGAUZ50ph15Z1WGSxmWN7Qg
+JQQhXP9e6h69i1P5ichfQ9gIzHV0husNx/65pNHTHbRuylVZBPWtxSCaskGeQQTP
+B6M05G3g2jzb/6wGxV7DCdAAydyC0PvJpFS2HY+h5fPcHObAKZoCMaY0xG3f3Goi
+ec667SQzwAqRhLKOMfTg7W0CgYAqH4H3v6tXhrMRpHvfHqD2hYMm9i5VLS7UNNEW
+2sThX1gqrhTMiHVXSHqFc4J0f++1TVKIpqSwCMYUaAFddE2wSJHo01+nb00SdRPf
+OcM0p0sGoFRnBNdqwF92EJMa86iRMYbii8WyahTeV9iSIiEY4ZqARuqG1v2PFjjB
+RKppqwKBgDIxg44mmqYruXUIeJ7Z85Q4vbTwaQN/cWCTRU/RKI/WvwJVUZI77aDH
+a4kKzRwB6yUxVsjCo6Pdv1nXLK4UpgXMkpObhni/5TfWxNlczbgVqtWwGGu2xlx6
+vKUuq8oFetWkDhIsaIdw20FKzSwFpQ7xFZU2iD1Nd5/etAIi7zxp
+-----END RSA PRIVATE KEY-----