summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Newson <rnewson@apache.org>2017-05-10 18:06:13 +0100
committerRobert Newson <rnewson@apache.org>2017-05-10 18:06:13 +0100
commitbf7a2edac9024696f6ba4d0092e45cf071815e71 (patch)
tree86e8fe3c2f5d45f911f929cef3153e00a16051f9
parentacbaa3731b7a1131b1116df5cb1cd3d86ddc2534 (diff)
downloadcouchdb-bf7a2edac9024696f6ba4d0092e45cf071815e71.tar.gz
expand algorithm support
-rw-r--r--src/jwks.erl50
-rw-r--r--src/jwtf.erl54
2 files changed, 86 insertions, 18 deletions
diff --git a/src/jwks.erl b/src/jwks.erl
index 1820ab669..8b72ac85c 100644
--- a/src/jwks.erl
+++ b/src/jwks.erl
@@ -19,6 +19,8 @@
get_keyset/1
]).
+-include_lib("public_key/include/public_key.hrl").
+
get_keyset(Url) ->
ReqHeaders = [],
case ibrowse:send_req(Url, ReqHeaders, get) of
@@ -32,16 +34,23 @@ get_keyset(Url) ->
parse_keyset(Body) ->
{Props} = jiffy:decode(Body),
Keys = proplists:get_value(<<"keys">>, Props),
- [parse_key(Key) || Key <- Keys].
+ lists:flatmap(fun parse_key/1, Keys).
parse_key({Props}) ->
- <<"RS256">> = proplists:get_value(<<"alg">>, Props),
- <<"RSA">> = proplists:get_value(<<"kty">>, Props),
+ Alg = proplists:get_value(<<"alg">>, Props),
+ Kty = proplists:get_value(<<"kty">>, Props),
Kid = proplists:get_value(<<"kid">>, Props),
- E = proplists:get_value(<<"e">>, Props),
- N = proplists:get_value(<<"n">>, Props),
- {Kid, {'RSAPublicKey', decode_number(N), decode_number(E)}}.
+ case {Alg, Kty} of
+ {<<"RS256">>, <<"RSA">>} ->
+ E = proplists:get_value(<<"e">>, Props),
+ N = proplists:get_value(<<"n">>, Props),
+ [{{Kty, Kid}, #'RSAPublicKey'{
+ modulus = decode_number(N),
+ publicExponent = decode_number(E)}}];
+ _ ->
+ []
+ end.
decode_number(Base64) ->
@@ -55,4 +64,33 @@ jwks_test() ->
application:ensure_all_started(ibrowse),
?assertMatch({ok, _}, get_keyset("https://iam.eu-gb.bluemix.net/oidc/keys")).
+rs_test() ->
+ Ejson = {[
+ {<<"kty">>, <<"RSA">>},
+ {<<"n">>, <<"0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx"
+ "4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMs"
+ "tn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2"
+ "QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbI"
+ "SD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqb"
+ "w0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw">>},
+ {<<"e">>, <<"AQAB">>},
+ {<<"alg">>, <<"RS256">>},
+ {<<"kid">>, <<"2011-04-29">>}
+ ]},
+ ?assertMatch([{{<<"RSA">>, <<"2011-04-29">>}, {'RSAPublicKey', _, 65537}}],
+ parse_key(Ejson)).
+
+
+ec_test() ->
+ Ejson = {[
+ {<<"kty">>, <<"EC">>},
+ {<<"crv">>, <<"P-256">>},
+ {<<"x">>, <<"MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4">>},
+ {<<"y">>, <<"4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM">>},
+ {<<"alg">>, <<"ES256">>},
+ {<<"kid">>, <<"1">>}
+ ]},
+ %% TODO figure out how to convert x,y to an ECPoint.
+ ?assertMatch([], parse_key(Ejson)).
+
-endif.
diff --git a/src/jwtf.erl b/src/jwtf.erl
index b03fa91c4..18f84deb7 100644
--- a/src/jwtf.erl
+++ b/src/jwtf.erl
@@ -70,17 +70,31 @@ validate_typ(Props, Checks) ->
validate_alg(Props, Checks) ->
Required = prop(alg, Checks),
Alg = prop(<<"alg">>, Props),
+ Valid = [
+ <<"RS256">>,
+ <<"RS384">>,
+ <<"RS512">>,
+
+ <<"HS256">>,
+ <<"HS384">>,
+ <<"HS512">>,
+
+ <<"ES384">>,
+ <<"ES512">>,
+ <<"ES512">>
+ ],
case {Required, Alg} of
{undefined, _} ->
ok;
{true, undefined} ->
throw({error, missing_alg});
- {true, <<"RS256">>} ->
- ok;
- {true, <<"HS256">>} ->
- ok;
- _ ->
- throw({error, invalid_alg})
+ {true, Alg} ->
+ case lists:member(Alg, Valid) of
+ true ->
+ ok;
+ false ->
+ throw({error, invalid_alg})
+ end
end.
@@ -167,14 +181,30 @@ verify(Alg, Header, Payload, Signature0, Key) ->
Signature1 = b64url:decode(Signature0),
case Alg of
<<"RS256">> ->
- rs256_verify(Message, Signature1, Key);
+ public_key_verify(sha256, Message, Signature1, Key);
+ <<"RS384">> ->
+ public_key_verify(sha384, Message, Signature1, Key);
+ <<"RS512">> ->
+ public_key_verify(sha512, Message, Signature1, Key);
+
+ <<"ES256">> ->
+ public_key_verify(sha256, Message, Signature1, Key);
+ <<"ES384">> ->
+ public_key_verify(sha384, Message, Signature1, Key);
+ <<"ES512">> ->
+ public_key_verify(sha512, Message, Signature1, Key);
+
<<"HS256">> ->
- hs256_verify(Message, Signature1, Key)
+ hmac_verify(sha256, Message, Signature1, Key);
+ <<"HS384">> ->
+ hmac_verify(sha384, Message, Signature1, Key);
+ <<"HS512">> ->
+ hmac_verify(sha512, Message, Signature1, Key)
end.
-rs256_verify(Message, Signature, PublicKey) ->
- case public_key:verify(Message, sha256, Signature, PublicKey) of
+public_key_verify(Alg, Message, Signature, PublicKey) ->
+ case public_key:verify(Message, Alg, Signature, PublicKey) of
true ->
ok;
false ->
@@ -182,8 +212,8 @@ rs256_verify(Message, Signature, PublicKey) ->
end.
-hs256_verify(Message, HMAC, SecretKey) ->
- case crypto:hmac(sha256, SecretKey, Message) of
+hmac_verify(Alg, Message, HMAC, SecretKey) ->
+ case crypto:hmac(Alg, SecretKey, Message) of
HMAC ->
ok;
_ ->