diff options
author | Robert Newson <rnewson@apache.org> | 2017-05-10 18:06:13 +0100 |
---|---|---|
committer | Robert Newson <rnewson@apache.org> | 2017-05-10 18:06:13 +0100 |
commit | bf7a2edac9024696f6ba4d0092e45cf071815e71 (patch) | |
tree | 86e8fe3c2f5d45f911f929cef3153e00a16051f9 | |
parent | acbaa3731b7a1131b1116df5cb1cd3d86ddc2534 (diff) | |
download | couchdb-bf7a2edac9024696f6ba4d0092e45cf071815e71.tar.gz |
expand algorithm support
-rw-r--r-- | src/jwks.erl | 50 | ||||
-rw-r--r-- | src/jwtf.erl | 54 |
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; _ -> |