From 5c3190542792f6653b1104e65268130c96b7e0c8 Mon Sep 17 00:00:00 2001 From: jvelilla Date: Wed, 21 Jun 2017 18:34:07 -0300 Subject: [PATCH 01/16] Updated EWF http_network, websocket, httpd to use the latest EiffelNet SSL version. --- .../src/ssl/http_stream_secure_socket.e | 15 ++++++++------- .../websocket/client/src/ssl/web_socket_client.e | 4 +--- .../httpd/configuration/httpd_configuration_i.e | 9 +-------- library/server/httpd/ssl/httpd_configuration.e | 8 +------- 4 files changed, 11 insertions(+), 25 deletions(-) diff --git a/library/network/http_network/src/ssl/http_stream_secure_socket.e b/library/network/http_network/src/ssl/http_stream_secure_socket.e index bb49cd19..c14aec4f 100644 --- a/library/network/http_network/src/ssl/http_stream_secure_socket.e +++ b/library/network/http_network/src/ssl/http_stream_secure_socket.e @@ -54,12 +54,6 @@ feature -- Secure connection Helpers set_tls_protocol (v) end - set_secure_protocol_to_ssl_2_or_3 - -- Set `ssl_protocol' with `Ssl_23'. - do - set_secure_protocol ({SSL_PROTOCOL}.Ssl_23) - end - set_secure_protocol_to_tls_1_0 -- Set `ssl_protocol' with `Tls_1_0'. do @@ -176,7 +170,14 @@ feature -- Output end note - copyright: "2011-2013, Javier Velilla, Jocelyn Fiat and others" + copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" end diff --git a/library/network/websocket/client/src/ssl/web_socket_client.e b/library/network/websocket/client/src/ssl/web_socket_client.e index 12dae408..d0639a62 100644 --- a/library/network/websocket/client/src/ssl/web_socket_client.e +++ b/library/network/websocket/client/src/ssl/web_socket_client.e @@ -26,9 +26,7 @@ feature -- Factory create l_secure.make_client_by_port (a_port, a_host) Result := l_secure if attached secure_protocol as l_prot then - if l_prot.is_case_insensitive_equal ("ssl_2_3") then - l_secure.set_secure_protocol_to_ssl_2_or_3 - elseif l_prot.is_case_insensitive_equal ("tls_1_0") then + if l_prot.is_case_insensitive_equal ("tls_1_0") then l_secure.set_secure_protocol_to_tls_1_0 elseif l_prot.is_case_insensitive_equal ("tls_1_1") then l_secure.set_secure_protocol_to_tls_1_1 diff --git a/library/server/httpd/configuration/httpd_configuration_i.e b/library/server/httpd/configuration/httpd_configuration_i.e index 74503928..61e702a9 100644 --- a/library/server/httpd/configuration/httpd_configuration_i.e +++ b/library/server/httpd/configuration/httpd_configuration_i.e @@ -297,9 +297,7 @@ feature -- Element change set_secure_protocol_from_string (a_ssl_version: READABLE_STRING_GENERAL) -- Set `secure_protocol' with `a_ssl_version' do - if a_ssl_version.is_case_insensitive_equal ("ssl_2_3") then - set_secure_protocol_to_ssl_2_or_3 - elseif a_ssl_version.is_case_insensitive_equal ("tls_1_0") then + if a_ssl_version.is_case_insensitive_equal ("tls_1_0") then set_secure_protocol_to_tls_1_0 elseif a_ssl_version.is_case_insensitive_equal ("tls_1_1") then set_secure_protocol_to_tls_1_1 @@ -314,11 +312,6 @@ feature -- Element change feature -- SSL Helpers - set_secure_protocol_to_ssl_2_or_3 - -- Set `secure_protocol' with `Ssl_23'. - deferred - end - set_secure_protocol_to_tls_1_0 -- Set `secure_protocol' with `Tls_1_0'. deferred diff --git a/library/server/httpd/ssl/httpd_configuration.e b/library/server/httpd/ssl/httpd_configuration.e index 1a5d1961..e0901a1a 100644 --- a/library/server/httpd/ssl/httpd_configuration.e +++ b/library/server/httpd/ssl/httpd_configuration.e @@ -35,12 +35,6 @@ feature -- Access feature -- SSL Helpers - set_secure_protocol_to_ssl_2_or_3 - -- Set `secure_protocol' with `Ssl_23'. - do - set_secure_protocol ({SSL_PROTOCOL}.Ssl_23) - end - set_secure_protocol_to_tls_1_0 -- Set `secure_protocol' with `Tls_1_0'. do @@ -67,7 +61,7 @@ feature -- SSL Helpers note - copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" + copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software From dbf5e76047f40288afd3f27600afb8cb265cc4bf Mon Sep 17 00:00:00 2001 From: jvelilla Date: Thu, 22 Jun 2017 10:23:56 -0300 Subject: [PATCH 02/16] Updated EWF network and httpd libraries. Updated features using ssl_2 and ssl_3 as obsolete and raise a developer exception. --- .../src/ssl/http_stream_secure_socket.e | 15 ++++++++++- .../client/src/ssl/web_socket_client.e | 4 ++- .../configuration/httpd_configuration_i.e | 25 +++++++++++++------ .../server/httpd/ssl/httpd_configuration.e | 13 ++++++++++ 4 files changed, 47 insertions(+), 10 deletions(-) diff --git a/library/network/http_network/src/ssl/http_stream_secure_socket.e b/library/network/http_network/src/ssl/http_stream_secure_socket.e index c14aec4f..9ada51f8 100644 --- a/library/network/http_network/src/ssl/http_stream_secure_socket.e +++ b/library/network/http_network/src/ssl/http_stream_secure_socket.e @@ -54,7 +54,20 @@ feature -- Secure connection Helpers set_tls_protocol (v) end - set_secure_protocol_to_tls_1_0 + set_secure_protocol_to_ssl_2_or_3 + -- Set `ssl_protocol' with `Ssl_23'. + -- Protocol not supported anymore. + obsolete + "Use set_secure_protocol_to_tls_1_2 [2017-11-30]." + local + err: DEVELOPER_EXCEPTION + do + create err + err.set_description ("SSL_2 or SSL_3 are not supported anymore, upgrate to TLS set_secure_protocol_to_tls_1_2") + err.raise + end + + set_secure_protocol_to_tls_1_0 -- Set `ssl_protocol' with `Tls_1_0'. do set_secure_protocol ({SSL_PROTOCOL}.Tls_1_0) diff --git a/library/network/websocket/client/src/ssl/web_socket_client.e b/library/network/websocket/client/src/ssl/web_socket_client.e index d0639a62..2ae681e2 100644 --- a/library/network/websocket/client/src/ssl/web_socket_client.e +++ b/library/network/websocket/client/src/ssl/web_socket_client.e @@ -26,7 +26,9 @@ feature -- Factory create l_secure.make_client_by_port (a_port, a_host) Result := l_secure if attached secure_protocol as l_prot then - if l_prot.is_case_insensitive_equal ("tls_1_0") then + if l_prot.is_case_insensitive_equal ("ssl_2_3") then + l_secure.set_secure_protocol_to_ssl_2_or_3 + elseif l_prot.is_case_insensitive_equal ("tls_1_0") then l_secure.set_secure_protocol_to_tls_1_0 elseif l_prot.is_case_insensitive_equal ("tls_1_1") then l_secure.set_secure_protocol_to_tls_1_1 diff --git a/library/server/httpd/configuration/httpd_configuration_i.e b/library/server/httpd/configuration/httpd_configuration_i.e index 61e702a9..403d8cfc 100644 --- a/library/server/httpd/configuration/httpd_configuration_i.e +++ b/library/server/httpd/configuration/httpd_configuration_i.e @@ -167,7 +167,7 @@ feature -- Element change end set_socket_timeout (a_nb_seconds: like socket_timeout) - -- Set `socket_timeout' with `a_nb_seconds' + -- Set `socket_timeout' with `a_nb_seconds'. do socket_timeout := a_nb_seconds ensure @@ -175,7 +175,7 @@ feature -- Element change end set_socket_recv_timeout (a_nb_seconds: like socket_recv_timeout) - -- Set `socket_recv_timeout' with `a_nb_seconds' + -- Set `socket_recv_timeout' with `a_nb_seconds'. do socket_recv_timeout := a_nb_seconds ensure @@ -183,7 +183,7 @@ feature -- Element change end set_keep_alive_timeout (a_seconds: like keep_alive_timeout) - -- Set `keep_alive_timeout' with `a_seconds' + -- Set `keep_alive_timeout' with `a_seconds'. do keep_alive_timeout := a_seconds ensure @@ -191,7 +191,7 @@ feature -- Element change end set_max_keep_alive_requests (nb: like max_keep_alive_requests) - -- Set `max_keep_alive_requests' with `nb' + -- Set `max_keep_alive_requests' with `nb'. do max_keep_alive_requests := nb ensure @@ -254,7 +254,7 @@ feature -- Element change end mark_secure - -- Set is_secure in True + -- Set is_secure in True. do set_is_secure (True) ensure @@ -287,7 +287,7 @@ feature -- Element change end set_secure_protocol (a_version: NATURAL) - -- Set `secure_protocol' with `a_version' + -- Set `secure_protocol' with `a_version'. do secure_protocol := a_version ensure @@ -295,9 +295,11 @@ feature -- Element change end set_secure_protocol_from_string (a_ssl_version: READABLE_STRING_GENERAL) - -- Set `secure_protocol' with `a_ssl_version' + -- Set `secure_protocol' with `a_ssl_version'. do - if a_ssl_version.is_case_insensitive_equal ("tls_1_0") then + if a_ssl_version.is_case_insensitive_equal ("ssl_2_3") then + set_secure_protocol_to_ssl_2_or_3 + elseif a_ssl_version.is_case_insensitive_equal ("tls_1_0") then set_secure_protocol_to_tls_1_0 elseif a_ssl_version.is_case_insensitive_equal ("tls_1_1") then set_secure_protocol_to_tls_1_1 @@ -312,6 +314,13 @@ feature -- Element change feature -- SSL Helpers + set_secure_protocol_to_ssl_2_or_3 + -- Set `secure_protocol' with `Ssl_23'. + obsolete + "Use set_secure_protocol_to_tls_1_0 [2017-11-30]." + deferred + end + set_secure_protocol_to_tls_1_0 -- Set `secure_protocol' with `Tls_1_0'. deferred diff --git a/library/server/httpd/ssl/httpd_configuration.e b/library/server/httpd/ssl/httpd_configuration.e index e0901a1a..1e5dc7e3 100644 --- a/library/server/httpd/ssl/httpd_configuration.e +++ b/library/server/httpd/ssl/httpd_configuration.e @@ -35,6 +35,19 @@ feature -- Access feature -- SSL Helpers + set_secure_protocol_to_ssl_2_or_3 + -- Set `ssl_protocol' with `Ssl_23'. + -- Protocol not supported anymore. + obsolete + "Use set_secure_protocol_to_tls_1_2 [2017-11-30]." + local + err: DEVELOPER_EXCEPTION + do + create err + err.set_description ("SSL_2 or SSL_3 are not supported anymore, upgrate to TLS set_secure_protocol_to_tls_1_2") + err.raise + end + set_secure_protocol_to_tls_1_0 -- Set `secure_protocol' with `Tls_1_0'. do From 02383810b492c9294e3f3217269dff74c1452c8e Mon Sep 17 00:00:00 2001 From: jvelilla Date: Fri, 23 Jun 2017 09:51:59 -0300 Subject: [PATCH 03/16] Fixed bad identation Updated date to current date in obsolte message. --- .../src/ssl/http_stream_secure_socket.e | 8 +++---- .../client/src/ssl/web_socket_client.e | 4 ++-- .../configuration/httpd_configuration_i.e | 6 ++--- .../server/httpd/ssl/httpd_configuration.e | 22 +++++++++---------- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/library/network/http_network/src/ssl/http_stream_secure_socket.e b/library/network/http_network/src/ssl/http_stream_secure_socket.e index 9ada51f8..4b78bc7a 100644 --- a/library/network/http_network/src/ssl/http_stream_secure_socket.e +++ b/library/network/http_network/src/ssl/http_stream_secure_socket.e @@ -57,14 +57,14 @@ feature -- Secure connection Helpers set_secure_protocol_to_ssl_2_or_3 -- Set `ssl_protocol' with `Ssl_23'. -- Protocol not supported anymore. - obsolete - "Use set_secure_protocol_to_tls_1_2 [2017-11-30]." + obsolete + "Use set_secure_protocol_to_tls_1_2 [2017-06-23]." local err: DEVELOPER_EXCEPTION do create err - err.set_description ("SSL_2 or SSL_3 are not supported anymore, upgrate to TLS set_secure_protocol_to_tls_1_2") - err.raise + err.set_description ("SSL_2 or SSL_3 are not supported anymore, upgrate to TLS set_secure_protocol_to_tls_1_2") + err.raise end set_secure_protocol_to_tls_1_0 diff --git a/library/network/websocket/client/src/ssl/web_socket_client.e b/library/network/websocket/client/src/ssl/web_socket_client.e index 2ae681e2..12dae408 100644 --- a/library/network/websocket/client/src/ssl/web_socket_client.e +++ b/library/network/websocket/client/src/ssl/web_socket_client.e @@ -27,8 +27,8 @@ feature -- Factory Result := l_secure if attached secure_protocol as l_prot then if l_prot.is_case_insensitive_equal ("ssl_2_3") then - l_secure.set_secure_protocol_to_ssl_2_or_3 - elseif l_prot.is_case_insensitive_equal ("tls_1_0") then + l_secure.set_secure_protocol_to_ssl_2_or_3 + elseif l_prot.is_case_insensitive_equal ("tls_1_0") then l_secure.set_secure_protocol_to_tls_1_0 elseif l_prot.is_case_insensitive_equal ("tls_1_1") then l_secure.set_secure_protocol_to_tls_1_1 diff --git a/library/server/httpd/configuration/httpd_configuration_i.e b/library/server/httpd/configuration/httpd_configuration_i.e index 403d8cfc..f02c35e6 100644 --- a/library/server/httpd/configuration/httpd_configuration_i.e +++ b/library/server/httpd/configuration/httpd_configuration_i.e @@ -298,8 +298,8 @@ feature -- Element change -- Set `secure_protocol' with `a_ssl_version'. do if a_ssl_version.is_case_insensitive_equal ("ssl_2_3") then - set_secure_protocol_to_ssl_2_or_3 - elseif a_ssl_version.is_case_insensitive_equal ("tls_1_0") then + set_secure_protocol_to_ssl_2_or_3 + elseif a_ssl_version.is_case_insensitive_equal ("tls_1_0") then set_secure_protocol_to_tls_1_0 elseif a_ssl_version.is_case_insensitive_equal ("tls_1_1") then set_secure_protocol_to_tls_1_1 @@ -317,7 +317,7 @@ feature -- SSL Helpers set_secure_protocol_to_ssl_2_or_3 -- Set `secure_protocol' with `Ssl_23'. obsolete - "Use set_secure_protocol_to_tls_1_0 [2017-11-30]." + "Use set_secure_protocol_to_tls_1_2 [2017-06-23]." deferred end diff --git a/library/server/httpd/ssl/httpd_configuration.e b/library/server/httpd/ssl/httpd_configuration.e index 1e5dc7e3..2b088fc1 100644 --- a/library/server/httpd/ssl/httpd_configuration.e +++ b/library/server/httpd/ssl/httpd_configuration.e @@ -36,17 +36,17 @@ feature -- Access feature -- SSL Helpers set_secure_protocol_to_ssl_2_or_3 - -- Set `ssl_protocol' with `Ssl_23'. - -- Protocol not supported anymore. - obsolete - "Use set_secure_protocol_to_tls_1_2 [2017-11-30]." - local - err: DEVELOPER_EXCEPTION - do - create err - err.set_description ("SSL_2 or SSL_3 are not supported anymore, upgrate to TLS set_secure_protocol_to_tls_1_2") - err.raise - end + -- Set `ssl_protocol' with `Ssl_23'. + -- Protocol not supported anymore. + obsolete + "Use set_secure_protocol_to_tls_1_2 [2017-06-23]." + local + err: DEVELOPER_EXCEPTION + do + create err + err.set_description ("SSL_2 or SSL_3 are not supported anymore, upgrate to TLS set_secure_protocol_to_tls_1_2") + err.raise + end set_secure_protocol_to_tls_1_0 -- Set `secure_protocol' with `Tls_1_0'. From 27ee20f99b8a980700ef4a7217e2839fe3ab3db7 Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Tue, 11 Jul 2017 23:29:42 +0200 Subject: [PATCH 04/16] Added convenient `get` and `custom` functions on HTTP_CLIENT directly. --- library/network/http_client/src/http_client.e | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/library/network/http_client/src/http_client.e b/library/network/http_client/src/http_client.e index 2b3ba358..a75a9620 100644 --- a/library/network/http_client/src/http_client.e +++ b/library/network/http_client/src/http_client.e @@ -16,8 +16,19 @@ feature -- Access deferred end + get (a_url: READABLE_STRING_8; ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT): HTTP_CLIENT_RESPONSE + do + Result := new_session (a_url).get ("", ctx) + end + + custom (a_method: READABLE_STRING_8; a_url: READABLE_STRING_8; ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT): HTTP_CLIENT_RESPONSE + -- Response for `a_method' request based on `a_url' and optional `ctx'. + do + Result := new_session (a_url).custom (a_method, "", ctx) + end + note - copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" + copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software From 2748e1d9eebfde2c9eb3bd37f597bac08b728442 Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Tue, 11 Jul 2017 23:32:11 +0200 Subject: [PATCH 05/16] Now JWT_LOADER takes the alg as argument, to avoid security issue where the lib is taking alg from the header (which may be a bad security weakness). --- .../jwt/src/errors/jwt_mismatched_alg_error.e | 36 ++++++++++++ library/security/jwt/src/jwt.e | 5 ++ library/security/jwt/src/jwt_loader.e | 31 +++++++---- library/security/jwt/testing/test_jwt.e | 55 +++++++++++++++---- 4 files changed, 105 insertions(+), 22 deletions(-) create mode 100644 library/security/jwt/src/errors/jwt_mismatched_alg_error.e diff --git a/library/security/jwt/src/errors/jwt_mismatched_alg_error.e b/library/security/jwt/src/errors/jwt_mismatched_alg_error.e new file mode 100644 index 00000000..4e9ba1c3 --- /dev/null +++ b/library/security/jwt/src/errors/jwt_mismatched_alg_error.e @@ -0,0 +1,36 @@ +note + description: "Summary description for {JWT_MISMATCHED_ALG_ERROR}." + date: "$Date$" + revision: "$Revision$" + +class + JWT_MISMATCHED_ALG_ERROR + +inherit + JWT_ERROR + +create + make + +feature {NONE} -- Initialization + + make (a_alg, a_header_alg: READABLE_STRING_8) + do + alg := a_alg + header_alg := a_header_alg + end + +feature -- Access + + alg: READABLE_STRING_8 + + header_alg: READABLE_STRING_8 + + id: STRING = "ALG_MISMATCH" + + message: READABLE_STRING_8 + do + Result := "Header alg [" + header_alg + "] does not match given alg [" + alg + "]!" + end + +end diff --git a/library/security/jwt/src/jwt.e b/library/security/jwt/src/jwt.e index 381afc9f..f23091fb 100644 --- a/library/security/jwt/src/jwt.e +++ b/library/security/jwt/src/jwt.e @@ -118,6 +118,11 @@ feature {JWT_UTILITIES} -- Error reporting l_errors.extend (err) end + report_mismatched_alg_error (alg, a_header_alg: READABLE_STRING_8) + do + report_error (create {JWT_MISMATCHED_ALG_ERROR}.make (alg, a_header_alg)) + end + report_unsupported_alg_error (alg: READABLE_STRING_8) do report_error (create {JWT_UNSUPPORTED_ALG_ERROR}.make (alg)) diff --git a/library/security/jwt/src/jwt_loader.e b/library/security/jwt/src/jwt_loader.e index 69df2beb..e6466585 100644 --- a/library/security/jwt/src/jwt_loader.e +++ b/library/security/jwt/src/jwt_loader.e @@ -1,8 +1,8 @@ note - description: "Summary description for {JWT_LOADER}." - author: "" + description: "Loader and verifier to JWT token." date: "$Date$" revision: "$Revision$" + EIS: "name=Known Critical vulnerabilities in JWT libs", "protocol=URI", "src=https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/" class JWT_LOADER @@ -12,9 +12,13 @@ inherit feature -- Access - token (a_token_input: READABLE_STRING_8; a_secret: READABLE_STRING_8; ctx: detachable JWT_CONTEXT): detachable JWT - -- Decoded token from `a_token_input` given the secret `a_secret`, and optional context `ctx` + token (a_token_input: READABLE_STRING_8; a_alg: detachable READABLE_STRING_8; a_verification_key: READABLE_STRING_8; ctx: detachable JWT_CONTEXT): detachable JWT + -- Decoded token from `a_token_input` given the verification key `a_verification_key` and optional (but recommended) signature algorithm `a_alg`, and optional context `ctx` -- used to specify eventual issuer and various parameters. + -- WARNING: passing Void for `a_alg` is not safe, as the server should know which alg he used for tokens, + -- leaving the possibility to use the header alg is dangerous as client may use "none" and then bypass verification! + require + a_valid_alg: a_alg /= Void implies is_supporting_signature_algorithm (a_alg) local jws: JWS i,j,n: INTEGER @@ -29,20 +33,27 @@ feature -- Access l_enc_payload := a_token_input.substring (i + 1, j - 1) l_signature := a_token_input.substring (j + 1, n) create jws.make_with_json_payload (base64url_decode (l_enc_payload)) - alg := signature_algorithm_from_encoded_header (l_enc_header) - jws.set_algorithm (alg) - if alg = Void then - -- Use default - alg := alg_hs256 + if a_alg /= Void then + if alg /= Void and then not alg.is_case_insensitive_equal_general (a_alg) then + jws.report_mismatched_alg_error (a_alg, alg) + else + alg := a_alg + end + else + if alg = Void then + -- Use default + alg := alg_hs256 + end end + jws.set_algorithm (alg) check alg_set: alg /= Void end if ctx = Void or else not ctx.validation_ignored then if not is_supporting_signature_algorithm (alg) then jws.report_unsupported_alg_error (alg) alg := alg_hs256 end - if not l_signature.same_string (signature (l_enc_header, l_enc_payload, a_secret, alg)) then + if not l_signature.same_string (signature (l_enc_header, l_enc_payload, a_verification_key, alg)) then jws.report_unverified_token_error end if diff --git a/library/security/jwt/testing/test_jwt.e b/library/security/jwt/testing/test_jwt.e index 4642458b..9e4dcac8 100644 --- a/library/security/jwt/testing/test_jwt.e +++ b/library/security/jwt/testing/test_jwt.e @@ -54,7 +54,14 @@ feature -- Test create jwt_loader - if attached jwt_loader.token (tok, "secret", Void) as l_tok then + -- Use header alg! + if attached jwt_loader.token (tok, Void, "secret", Void) as l_tok then + assert ("no error", not l_tok.has_error) + assert ("same payload", l_tok.claimset.string.same_string (payload)) + end + + -- Use given alg! + if attached jwt_loader.token (tok, jwt.algorithm, "secret", Void) as l_tok then assert ("no error", not l_tok.has_error) assert ("same payload", l_tok.claimset.string.same_string (payload)) end @@ -96,21 +103,21 @@ feature -- Test create jwt_loader -- Test with validation + exp - if attached jwt_loader.token (tok, "secret", Void) as l_tok then + if attached jwt_loader.token (tok, jwt.algorithm, "secret", Void) as l_tok then assert ("no error", not l_tok.has_error) assert ("same payload", l_tok.claimset.string.same_string (payload)) end create ctx ctx.set_time (now) - if attached jwt_loader.token (tok, "secret", ctx) as l_tok then + if attached jwt_loader.token (tok, jwt.algorithm, "secret", ctx) as l_tok then assert ("no error", not l_tok.has_error) end dt := duplicated_time (now) dt.hour_add (5) ctx.set_time (dt) - if attached jwt_loader.token (tok, "secret", ctx) as l_tok then + if attached jwt_loader.token (tok, jwt.algorithm, "secret", ctx) as l_tok then assert ("exp error", l_tok.has_error) end @@ -122,7 +129,7 @@ feature -- Test tok := jwt.encoded_string ("secret") ctx.set_time (now) - if attached jwt_loader.token (tok, "secret", ctx) as l_tok then + if attached jwt_loader.token (tok, jwt.algorithm, "secret", ctx) as l_tok then assert ("has nbf error", l_tok.has_error) end @@ -130,7 +137,7 @@ feature -- Test dt.second_add (15) ctx.set_time (dt) - if attached jwt_loader.token (tok, "secret", ctx) as l_tok then + if attached jwt_loader.token (tok, jwt.algorithm, "secret", ctx) as l_tok then assert ("has nbf error", l_tok.has_error) end @@ -138,31 +145,51 @@ feature -- Test dt.minute_add (45) ctx.set_time (dt) - if attached jwt_loader.token (tok, "secret", ctx) as l_tok then + if attached jwt_loader.token (tok, jwt.algorithm, "secret", ctx) as l_tok then assert ("no error", not l_tok.has_error) end -- Test Issuer ctx.set_issuer ("urn:foobar") - if attached jwt_loader.token (tok, "secret", ctx) as l_tok then + if attached jwt_loader.token (tok, jwt.algorithm, "secret", ctx) as l_tok then assert ("has iss error", l_tok.has_error) end ctx.set_issuer ("urn:foo") - if attached jwt_loader.token (tok, "secret", ctx) as l_tok then + if attached jwt_loader.token (tok, jwt.algorithm, "secret", ctx) as l_tok then assert ("no error", not l_tok.has_error) end -- Test Audience ctx.set_audience ("urn:foobar") - if attached jwt_loader.token (tok, "secret", ctx) as l_tok then + if attached jwt_loader.token (tok, jwt.algorithm, "secret", ctx) as l_tok then assert ("has aud error", l_tok.has_error) end ctx.set_audience ("urn:foo") - if attached jwt_loader.token (tok, "secret", ctx) as l_tok then + if attached jwt_loader.token (tok, jwt.algorithm, "secret", ctx) as l_tok then assert ("no error", not l_tok.has_error) end end + test_mismatched_alg_jwt + local + jwt: JWS + payload: STRING + tok: STRING + do + payload := "[ + {"iss":"joe","exp":1300819380,"http://example.com/is_root":true} + ]" + + create jwt.make_with_json_payload (payload) + jwt.set_algorithm ("none") + tok := jwt.encoded_string ("secret") + + if attached (create {JWT_LOADER}).token (tok, "HS256", "secret", Void) as l_tok then + assert ("no error", not jwt.has_error) + assert ("same payload", l_tok.claimset.string.same_string (payload)) + end + end + test_unsecured_jwt local jwt: JWS @@ -177,7 +204,11 @@ feature -- Test jwt.set_algorithm ("none") tok := jwt.encoded_string ("secret") - if attached (create {JWT_LOADER}).token (tok, "secret", Void) as l_tok then + if attached (create {JWT_LOADER}).token (tok, "none", "secret", Void) as l_tok then + assert ("no error", not jwt.has_error) + assert ("same payload", l_tok.claimset.string.same_string (payload)) + end + if attached (create {JWT_LOADER}).token (tok, Void, "secret", Void) as l_tok then assert ("no error", not jwt.has_error) assert ("same payload", l_tok.claimset.string.same_string (payload)) end From 16d5076fe513cbd46421bc2f7a1ff46146cc5e99 Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Tue, 8 Aug 2017 14:03:39 +0200 Subject: [PATCH 06/16] Added Travis CI support with 17.05. --- .travis.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/.travis.yml b/.travis.yml index e69de29b..6d4cf64d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -0,0 +1,18 @@ +language: eiffel +before_script: + - export current_dir=$PWD ; echo current_dir=$current_dir ; cd .. + - export ISE_VERSION=17.05; export ISE_BUILD=100416 + - curl -sSL http://downloads.sourceforge.net/eiffelstudio/Eiffel_${ISE_VERSION}_gpl_${ISE_BUILD}-linux-x86-64.tar.bz2 | tar -x --bzip2 + - export ISE_EIFFEL=$PWD/Eiffel_${ISE_VERSION} ; export ISE_PLATFORM=linux-x86-64 + - export PATH=$PATH:$ISE_EIFFEL/studio/spec/$ISE_PLATFORM/bin:$PATH:$ISE_EIFFEL/tools/spec/$ISE_PLATFORM/bin + - echo `ec -version` + - cd $current_dir + +branches: + only: + - master + - v1 + +script: compile_all -ecb -melt -list_failures -log_verbose -clean -options dotnet=false +group: stable +os: linux From dac50b490de20019aa8fa6b00f8ba9cdb6e2674c Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Tue, 8 Aug 2017 14:10:12 +0200 Subject: [PATCH 07/16] Added output for the travis CI job. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 6d4cf64d..1da72194 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,7 @@ before_script: - export PATH=$PATH:$ISE_EIFFEL/studio/spec/$ISE_PLATFORM/bin:$PATH:$ISE_EIFFEL/tools/spec/$ISE_PLATFORM/bin - echo `ec -version` - cd $current_dir + - echo Check projects compilation status... branches: only: From 818c3fb46085de9f2f933f260de2ec737c027fc8 Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Tue, 8 Aug 2017 15:54:21 +0200 Subject: [PATCH 08/16] Made compilable with EiffelStudio 17.05 and probably before as well. --- library/security/jwt/src/jwt_encoder.e | 7 +++--- library/security/jwt/src/jwt_utilities.e | 28 +++++++++++++++++++++++- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/library/security/jwt/src/jwt_encoder.e b/library/security/jwt/src/jwt_encoder.e index 0dffce81..9c81ece3 100644 --- a/library/security/jwt/src/jwt_encoder.e +++ b/library/security/jwt/src/jwt_encoder.e @@ -266,11 +266,10 @@ feature {NONE} -- Implementation base64_hmacsha256 (s: READABLE_STRING_8; a_secret: READABLE_STRING_8): STRING_8 local - hs256: HMAC_SHA256 + ut: JWT_UTILITIES do - create hs256.make_ascii_key (a_secret) - hs256.update_from_string (s) - Result := hs256.base64_digest --lowercase_hexadecimal_string_digest + create ut + Result := ut.base64_hmacsha256 (s, a_secret) end end diff --git a/library/security/jwt/src/jwt_utilities.e b/library/security/jwt/src/jwt_utilities.e index e7bf4547..24eb5cc9 100644 --- a/library/security/jwt/src/jwt_utilities.e +++ b/library/security/jwt/src/jwt_utilities.e @@ -61,7 +61,33 @@ feature -- Encoding do create hs256.make_ascii_key (a_secret) hs256.update_from_string (s) - Result := hs256.base64_digest --lowercase_hexadecimal_string_digest + -- if Version >= EiffelStudio 17.11 then + -- Result := hs256.base64_digest --lowercase_hexadecimal_string_digest + -- else + Result := base64_bytes_encoded_string (hs256.digest) + -- end + end + +feature {NONE} -- Implementation + + base64_bytes_encoded_string (a_bytes: SPECIAL [NATURAL_8]): STRING_8 + -- Base64 string from `a_bytes`. + --| Note: to be removed when 17.11 is not latest release anymore. + local + s: STRING + i,n: INTEGER + do + from + i := 1 + n := a_bytes.count + create s.make (n) + until + i > n + loop + s.append_code (a_bytes[i - 1]) + i := i + 1 + end + Result := (create {BASE64}).encoded_string (s) end feature -- Decoding From 64254820701b74a4c88a703756f5c5cdd5c5af08 Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Tue, 8 Aug 2017 15:55:52 +0200 Subject: [PATCH 09/16] Fixed ecf by removing the override declaration. --- tests/dev/hello-safe.ecf | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/dev/hello-safe.ecf b/tests/dev/hello-safe.ecf index ca09845f..b6211f2a 100644 --- a/tests/dev/hello-safe.ecf +++ b/tests/dev/hello-safe.ecf @@ -24,7 +24,6 @@ - From c2764e25ff72c22dab9b210bc17ea8891fcf721d Mon Sep 17 00:00:00 2001 From: jvelilla Date: Thu, 14 Sep 2017 10:21:32 -0300 Subject: [PATCH 10/16] Update HTTP Client cURL implementation: Added the option to set cipher list used to negotiate security settings (SSL handshake) --- .../http_client/src/http_client_session.e | 16 ++++++++++++++++ .../spec/libcurl/libcurl_http_client_request.e | 5 +++++ 2 files changed, 21 insertions(+) diff --git a/library/network/http_client/src/http_client_session.e b/library/network/http_client/src/http_client_session.e index 5272173e..b2021cc0 100644 --- a/library/network/http_client/src/http_client_session.e +++ b/library/network/http_client/src/http_client_session.e @@ -272,6 +272,15 @@ feature -- Authentication -- Associated optional credentials value. -- Computed as `username':`password'. + cipher_list: detachable READABLE_STRING_32 + -- SSL cipher preference lists + -- examples: DEFAULT, ALL, TLSv1 + -- check https://www.openssl.org/docs/man1.1.0/apps/ciphers.html + --! At the moment only used for LIB_CURL_HTTP_CLIENT + --! Net implementation set all the ciphers using the OpenSSL at + --! initialization time. + + feature -- Status setting set_is_debug (b: BOOLEAN) @@ -401,6 +410,13 @@ feature -- Element change chunk_size := a_size end + set_cipher_list (a_list: READABLE_STRING_GENERAL) + do + create {STRING_32} cipher_list.make_from_string_general (a_list) + ensure + cipher_list_set: attached cipher_list as c_list and then c_list.same_string_general (a_list) + end + note copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" diff --git a/library/network/http_client/src/spec/libcurl/libcurl_http_client_request.e b/library/network/http_client/src/spec/libcurl/libcurl_http_client_request.e index 13e44bbb..b0091e80 100644 --- a/library/network/http_client/src/spec/libcurl/libcurl_http_client_request.e +++ b/library/network/http_client/src/spec/libcurl/libcurl_http_client_request.e @@ -372,6 +372,11 @@ feature -- Execution curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_ssl_verifypeer, 0) end + --| Cipher List + if attached session.cipher_list as c_list then + curl_easy.setopt_string (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_ssl_cipher_list, c_list ) + end + --| Request method if request_method.is_case_insensitive_equal ("GET") then curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_httpget, 1) From bb334aef80f820082ef76615a27bba387d3418c6 Mon Sep 17 00:00:00 2001 From: jvelilla Date: Thu, 14 Sep 2017 11:58:43 -0300 Subject: [PATCH 11/16] Updated HTTP client cURL implementation. Refactor rename cipher_list by ciphers_settings and description. Updated ciphers_settings representation to STIRNG_8 Refactor rename set_cipher_list by set_ciphers. --- .../network/http_client/src/http_client_session.e | 14 +++++++------- .../src/spec/libcurl/libcurl_http_client_request.e | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/library/network/http_client/src/http_client_session.e b/library/network/http_client/src/http_client_session.e index b2021cc0..78f8323a 100644 --- a/library/network/http_client/src/http_client_session.e +++ b/library/network/http_client/src/http_client_session.e @@ -272,13 +272,13 @@ feature -- Authentication -- Associated optional credentials value. -- Computed as `username':`password'. - cipher_list: detachable READABLE_STRING_32 + ciphers_settings: detachable READABLE_STRING_8 -- SSL cipher preference lists -- examples: DEFAULT, ALL, TLSv1 -- check https://www.openssl.org/docs/man1.1.0/apps/ciphers.html - --! At the moment only used for LIB_CURL_HTTP_CLIENT - --! Net implementation set all the ciphers using the OpenSSL at - --! initialization time. + --Warning At the moment only used for LIB_CURL_HTTP_CLIENT + --Warning Net implementation set all the ciphers using the OpenSSL at + --Warning initialization time. feature -- Status setting @@ -410,11 +410,11 @@ feature -- Element change chunk_size := a_size end - set_cipher_list (a_list: READABLE_STRING_GENERAL) + set_ciphers (a_list: READABLE_STRING_8) do - create {STRING_32} cipher_list.make_from_string_general (a_list) + create {STRING_8} ciphers_settings.make_from_string (a_list) ensure - cipher_list_set: attached cipher_list as c_list and then c_list.same_string_general (a_list) + cipher_settings_set: attached ciphers_settings as c_list and then c_list.same_string (a_list) end note diff --git a/library/network/http_client/src/spec/libcurl/libcurl_http_client_request.e b/library/network/http_client/src/spec/libcurl/libcurl_http_client_request.e index b0091e80..5fda6c06 100644 --- a/library/network/http_client/src/spec/libcurl/libcurl_http_client_request.e +++ b/library/network/http_client/src/spec/libcurl/libcurl_http_client_request.e @@ -373,7 +373,7 @@ feature -- Execution end --| Cipher List - if attached session.cipher_list as c_list then + if attached session.ciphers_settings as c_list then curl_easy.setopt_string (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_ssl_cipher_list, c_list ) end From 6ed91699b8034f7f60e5768372f66d4856fe45aa Mon Sep 17 00:00:00 2001 From: jvelilla Date: Tue, 19 Sep 2017 10:32:17 -0300 Subject: [PATCH 12/16] Renamed feature 'set_ciphers' to 'set_ciphers_settings' and added description. --- library/network/http_client/src/http_client_session.e | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/library/network/http_client/src/http_client_session.e b/library/network/http_client/src/http_client_session.e index 78f8323a..ae9177f6 100644 --- a/library/network/http_client/src/http_client_session.e +++ b/library/network/http_client/src/http_client_session.e @@ -410,11 +410,12 @@ feature -- Element change chunk_size := a_size end - set_ciphers (a_list: READABLE_STRING_8) + set_ciphers_settings (a_ciphers_settings: READABLE_STRING_8) + -- Set 'ciphers_settings' with 'a_ciphers_settings'. do - create {STRING_8} ciphers_settings.make_from_string (a_list) + create {STRING_8} ciphers_settings.make_from_string (a_ciphers_settings) ensure - cipher_settings_set: attached ciphers_settings as c_list and then c_list.same_string (a_list) + cipher_settings_set: attached ciphers_settings as c_settings and then c_settings.same_string (a_ciphers_settings) end note From 20a90db2e3da118d13ef800f4ae12bc3985c3408 Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Thu, 21 Sep 2017 10:45:08 +0200 Subject: [PATCH 13/16] If url is relative, use session.url (...) to get valid url. It could happen with relative url in `Location: ...` header (for redirection). --- library/network/http_client/src/http_client_request.e | 6 +++++- .../http_client/src/spec/net/net_http_client_request.e | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/library/network/http_client/src/http_client_request.e b/library/network/http_client/src/http_client_request.e index 087484d9..3f282249 100644 --- a/library/network/http_client/src/http_client_request.e +++ b/library/network/http_client/src/http_client_request.e @@ -31,7 +31,11 @@ feature {NONE} -- Initialization -- This can be used to reset/reinitialize Current with new url -- in the case of redirection. do - url := a_url + if a_url.starts_with ("http://") or a_url.starts_with ("http://") then + url := a_url + else + url := session.url (a_url, Void) + end headers := session.headers.twin if ctx /= Void then context := ctx diff --git a/library/network/http_client/src/spec/net/net_http_client_request.e b/library/network/http_client/src/spec/net/net_http_client_request.e index 3c00f138..cbc457c0 100644 --- a/library/network/http_client/src/spec/net/net_http_client_request.e +++ b/library/network/http_client/src/spec/net/net_http_client_request.e @@ -113,6 +113,7 @@ feature -- Access -- Get URL data l_is_https := url.starts_with_general ("https://") create l_uri.make_from_string (url) + check valid_url: l_uri.is_valid end l_port := l_uri.port if l_port = 0 then if l_is_https then From ab507d543af74afe61ba5483667266712a98741c Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Thu, 21 Sep 2017 10:45:40 +0200 Subject: [PATCH 14/16] Now HTTP_AUTHORIZATION acceps READABLE_STRING_GENERAL for username and password argument. --- .../src/http_authorization.e | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/library/server/authentication/http_authorization/src/http_authorization.e b/library/server/authentication/http_authorization/src/http_authorization.e index abc9a83c..ac93520e 100644 --- a/library/server/authentication/http_authorization/src/http_authorization.e +++ b/library/server/authentication/http_authorization/src/http_authorization.e @@ -76,13 +76,13 @@ feature -- Initialization a_http_authorization /= Void implies http_authorization /= Void end - make_basic_auth (u: READABLE_STRING_32; p: READABLE_STRING_32) + make_basic_auth (u: READABLE_STRING_GENERAL; p: READABLE_STRING_GENERAL) -- Create a Basic authentication. do make_custom_auth (u, p, Basic_auth_type) end - make_custom_auth (u: READABLE_STRING_32; p: READABLE_STRING_32; a_type: READABLE_STRING_8) + make_custom_auth (u: READABLE_STRING_GENERAL; p: READABLE_STRING_GENERAL; a_type: READABLE_STRING_8) -- Create a custom `a_type' authentication. require a_type_accepted: a_type.is_case_insensitive_equal (Basic_auth_type) @@ -90,15 +90,20 @@ feature -- Initialization local t: STRING_8 utf: UTF_CONVERTER + s: STRING_32 do - login := u - password := p + create login.make_from_string_general (u) + create password.make_from_string_general (p) create t.make_from_string (a_type) t.left_adjust; t.right_adjust type := t if t.is_case_insensitive_equal (Basic_auth_type) then type := Basic_auth_type - create http_authorization.make_from_string ("Basic " + (create {BASE64}).encoded_string (utf.string_32_to_utf_8_string_8 (u + {STRING_32} ":" + p))) + create s.make_from_string_general (u) + s.extend (':') + s.append_string_general (p) + create http_authorization.make_from_string ("Basic " + (create {BASE64}).encoded_string (utf.string_32_to_utf_8_string_8 (s))) + elseif t.is_case_insensitive_equal (Digest_auth_type) then type := Digest_auth_type to_implement ("HTTP Authorization %""+ t +"%", not yet implemented") @@ -115,9 +120,9 @@ feature -- Access type: READABLE_STRING_8 - login: detachable READABLE_STRING_32 + login: detachable IMMUTABLE_STRING_32 - password: detachable READABLE_STRING_32 + password: detachable IMMUTABLE_STRING_32 feature -- Status report From 498e4a6ec24d2cd7e59f23a075ffd371a6a3f81b Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Thu, 21 Sep 2017 10:46:08 +0200 Subject: [PATCH 15/16] Fixed validation of iss and aud when issuer and audience are not set. --- library/security/jwt/src/jwt.e | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/security/jwt/src/jwt.e b/library/security/jwt/src/jwt.e index f23091fb..acf1e3e0 100644 --- a/library/security/jwt/src/jwt.e +++ b/library/security/jwt/src/jwt.e @@ -59,6 +59,8 @@ feature -- Status report do if attached claimset.issuer as iss then Result := a_issuer = Void or else a_issuer.same_string (iss) + else + Result := a_issuer = Void end end @@ -66,6 +68,8 @@ feature -- Status report do if attached claimset.audience as aud then Result := a_audience = Void or else a_audience.same_string (aud) + else + Result := a_audience = Void end end From 85c8a46c892908d9bee4a17c40b94ec0661c194d Mon Sep 17 00:00:00 2001 From: jvelilla Date: Thu, 21 Sep 2017 08:07:11 -0300 Subject: [PATCH 16/16] Update Readme.md with a note about ciphers implementation. --- library/network/http_client/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/network/http_client/README.md b/library/network/http_client/README.md index 288ad58d..6a995c8c 100644 --- a/library/network/http_client/README.md +++ b/library/network/http_client/README.md @@ -10,6 +10,9 @@ It provides simple routine to perform http requests, and get response. - Eiffel Net library - and optionally Eiffel NetSSL library to support `https://...` +* Note: set ciphers settings is supported only with libcurl implementation for now, net implementation +set all the ciphers as part of the OpenSSL initialization. + This means on Windows, do not forget to copy the libcurl.dll (and related) either in the same directory of the executable, or ensure the .dll are in the PATH environment. It is possible to exclude the libcurl implementation xor the Eiffel Net implementation: