From a19e5cbb85b591ce3289b06c467b8ab21cbba85e Mon Sep 17 00:00:00 2001 From: Jay Mundrawala Date: Mon, 16 Nov 2015 14:03:19 -0800 Subject: Added signature verification for signing version 1.3 --- lib/mixlib/authentication/signatureverification.rb | 11 ++- .../authentication/mixlib_authentication_spec.rb | 109 ++++++++++++++++++++- 2 files changed, 116 insertions(+), 4 deletions(-) diff --git a/lib/mixlib/authentication/signatureverification.rb b/lib/mixlib/authentication/signatureverification.rb index d73b16c..ff43664 100644 --- a/lib/mixlib/authentication/signatureverification.rb +++ b/lib/mixlib/authentication/signatureverification.rb @@ -138,8 +138,15 @@ module Mixlib def verify_signature(algorithm, version) candidate_block = canonicalize_request(algorithm, version) - request_decrypted_block = @user_secret.public_decrypt(Base64.decode64(request_signature)) - @valid_signature = (request_decrypted_block == candidate_block) + signature = Base64.decode64(request_signature) + @valid_signature = case version + when '1.3' + digest = validate_sign_version_digest!(version, algorithm) + @user_secret.verify(digest.new, signature, candidate_block) + else + request_decrypted_block = @user_secret.public_decrypt(signature) + (request_decrypted_block == candidate_block) + end # Keep the debug messages lined up so it's easy to scan them Mixlib::Authentication::Log.debug("Verifying request signature:") diff --git a/spec/mixlib/authentication/mixlib_authentication_spec.rb b/spec/mixlib/authentication/mixlib_authentication_spec.rb index 1a18faa..abc5503 100644 --- a/spec/mixlib/authentication/mixlib_authentication_spec.rb +++ b/spec/mixlib/authentication/mixlib_authentication_spec.rb @@ -150,7 +150,7 @@ describe "Mixlib::Authentication::SignatureVerification" do @user_private_key = PRIVATE_KEY end - it "should authenticate a File-containing request - Merb" do + it "should authenticate a File-containing request V1.1 - Merb" do request_params = MERB_REQUEST_PARAMS.clone request_params["file"] = { "size"=>MockFile.length, "content_type"=>"application/octet-stream", "filename"=>"zsh.tar.gz", "tempfile"=>MockFile.new } @@ -163,6 +163,32 @@ describe "Mixlib::Authentication::SignatureVerification" do expect(res).not_to be_nil end + it "should authenticate a File-containing request V1.3 SHA1 - Merb" do + request_params = MERB_REQUEST_PARAMS.clone + request_params["file"] = + { "size"=>MockFile.length, "content_type"=>"application/octet-stream", "filename"=>"zsh.tar.gz", "tempfile"=>MockFile.new } + + mock_request = MockRequest.new(PATH, request_params, MERB_HEADERS_V1_3_SHA1, "") + expect(Time).to receive(:now).at_least(:once).and_return(TIMESTAMP_OBJ) + + service = Mixlib::Authentication::SignatureVerification.new + res = service.authenticate_user_request(mock_request, @user_private_key) + expect(res).not_to be_nil + end + + it "should authenticate a File-containing request V1.3 SHA256 - Merb" do + request_params = MERB_REQUEST_PARAMS.clone + request_params["file"] = + { "size"=>MockFile.length, "content_type"=>"application/octet-stream", "filename"=>"zsh.tar.gz", "tempfile"=>MockFile.new } + + mock_request = MockRequest.new(PATH, request_params, MERB_HEADERS_V1_3_SHA256, "") + expect(Time).to receive(:now).at_least(:once).and_return(TIMESTAMP_OBJ) + + service = Mixlib::Authentication::SignatureVerification.new + res = service.authenticate_user_request(mock_request, @user_private_key) + expect(res).not_to be_nil + end + it "should authenticate a File-containing request from a v1.0 client - Passenger" do request_params = PASSENGER_REQUEST_PARAMS.clone request_params["tarball"] = MockFile.new @@ -175,7 +201,25 @@ describe "Mixlib::Authentication::SignatureVerification" do expect(res).not_to be_nil end - it "should authenticate a normal (post body) request - Merb" do + it "should authenticate a normal (post body) request v1.3 SHA1 - Merb" do + mock_request = MockRequest.new(PATH, MERB_REQUEST_PARAMS, MERB_HEADERS_V1_3_SHA1, BODY) + expect(Time).to receive(:now).at_least(:once).and_return(TIMESTAMP_OBJ) + + service = Mixlib::Authentication::SignatureVerification.new + res = service.authenticate_user_request(mock_request, @user_private_key) + expect(res).not_to be_nil + end + + it "should authenticate a normal (post body) request v1.3 SHA256 - Merb" do + mock_request = MockRequest.new(PATH, MERB_REQUEST_PARAMS, MERB_HEADERS_V1_3_SHA1, BODY) + expect(Time).to receive(:now).at_least(:once).and_return(TIMESTAMP_OBJ) + + service = Mixlib::Authentication::SignatureVerification.new + res = service.authenticate_user_request(mock_request, @user_private_key) + expect(res).not_to be_nil + end + + it "should authenticate a normal (post body) request v1.1 - Merb" do mock_request = MockRequest.new(PATH, MERB_REQUEST_PARAMS, MERB_HEADERS_V1_1, BODY) expect(Time).to receive(:now).at_least(:once).and_return(TIMESTAMP_OBJ) @@ -256,6 +300,35 @@ describe "Mixlib::Authentication::SignatureVerification" do expect(auth_req).to be_a_valid_content_hash end + it "shouldn't authenticate if the signature is wrong for v1.3 SHA1" do + headers = MERB_HEADERS_V1_3_SHA1.dup + headers["HTTP_X_OPS_AUTHORIZATION_1"] = "epicfail" + mock_request = MockRequest.new(PATH, MERB_REQUEST_PARAMS, headers, BODY) + expect(Time).to receive(:now).at_least(:once).and_return(TIMESTAMP_OBJ) + + auth_req = Mixlib::Authentication::SignatureVerification.new + res = auth_req.authenticate_user_request(mock_request, @user_private_key) + expect(res).to be_nil + expect(auth_req).not_to be_a_valid_request + expect(auth_req).not_to be_a_valid_signature + expect(auth_req).to be_a_valid_timestamp + expect(auth_req).to be_a_valid_content_hash + end + + it "shouldn't authenticate if the signature is wrong for v1.3 SHA256" do + headers = MERB_HEADERS_V1_3_SHA256.dup + headers["HTTP_X_OPS_AUTHORIZATION_1"] = "epicfail" + mock_request = MockRequest.new(PATH, MERB_REQUEST_PARAMS, headers, BODY) + expect(Time).to receive(:now).at_least(:once).and_return(TIMESTAMP_OBJ) + + auth_req = Mixlib::Authentication::SignatureVerification.new + res = auth_req.authenticate_user_request(mock_request, @user_private_key) + expect(res).to be_nil + expect(auth_req).not_to be_a_valid_request + expect(auth_req).not_to be_a_valid_signature + expect(auth_req).to be_a_valid_timestamp + expect(auth_req).to be_a_valid_content_hash + end end USER_ID = "spec-user" @@ -432,6 +505,38 @@ MERB_REQUEST_PARAMS = { "organization_id"=>"local-test-org", "requesting_actor_id"=>REQUESTING_ACTOR_ID, } +MERB_HEADERS_V1_3_SHA1 = { + # These are used by signatureverification. + "HTTP_HOST"=>"127.0.0.1", + "HTTP_X_OPS_SIGN"=>"algorithm=sha1;version=1.3;", + "HTTP_X_OPS_REQUESTID"=>"127.0.0.1 1258566194.85386", + "HTTP_X_OPS_TIMESTAMP"=>TIMESTAMP_ISO8601, + "HTTP_X_OPS_CONTENT_HASH"=>X_OPS_CONTENT_HASH, + "HTTP_X_OPS_USERID"=>USER_ID, + "HTTP_X_OPS_AUTHORIZATION_1"=>X_OPS_AUTHORIZATION_LINES_V1_3_SHA1[0], + "HTTP_X_OPS_AUTHORIZATION_2"=>X_OPS_AUTHORIZATION_LINES_V1_3_SHA1[1], + "HTTP_X_OPS_AUTHORIZATION_3"=>X_OPS_AUTHORIZATION_LINES_V1_3_SHA1[2], + "HTTP_X_OPS_AUTHORIZATION_4"=>X_OPS_AUTHORIZATION_LINES_V1_3_SHA1[3], + "HTTP_X_OPS_AUTHORIZATION_5"=>X_OPS_AUTHORIZATION_LINES_V1_3_SHA1[4], + "HTTP_X_OPS_AUTHORIZATION_6"=>X_OPS_AUTHORIZATION_LINES_V1_3_SHA1[5], +}.merge(OTHER_HEADERS) + +MERB_HEADERS_V1_3_SHA256 = { + # These are used by signatureverification. + "HTTP_HOST"=>"127.0.0.1", + "HTTP_X_OPS_SIGN"=>"algorithm=sha256;version=1.3;", + "HTTP_X_OPS_REQUESTID"=>"127.0.0.1 1258566194.85386", + "HTTP_X_OPS_TIMESTAMP"=>TIMESTAMP_ISO8601, + "HTTP_X_OPS_CONTENT_HASH"=>X_OPS_CONTENT_HASH_SHA256, + "HTTP_X_OPS_USERID"=>USER_ID, + "HTTP_X_OPS_AUTHORIZATION_1"=>X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[0], + "HTTP_X_OPS_AUTHORIZATION_2"=>X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[1], + "HTTP_X_OPS_AUTHORIZATION_3"=>X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[2], + "HTTP_X_OPS_AUTHORIZATION_4"=>X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[3], + "HTTP_X_OPS_AUTHORIZATION_5"=>X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[4], + "HTTP_X_OPS_AUTHORIZATION_6"=>X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[5], +}.merge(OTHER_HEADERS) + # Tis is what will be in request.env for the Merb case. MERB_HEADERS_V1_1 = { # These are used by signatureverification. -- cgit v1.2.1