Skip to content

Commit 503bb3f

Browse files
authored
Catch CipherError and TypeError in run_cipher and raise EncryptorError (#4365)
* Catch CipherError and TypeError in run_cipher and raise EncryptorError Wraps OpenSSL::Cipher::CipherError and TypeError in a custom EncryptorError to allow centralized handling in ApplicationController. This enables consistent 500 error responses with clearer messages like "Error while processing encrypted data".
1 parent 699ae14 commit 503bb3f

File tree

10 files changed

+25
-11
lines changed

10 files changed

+25
-11
lines changed

app/controllers/v3/application_controller.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ class ApplicationController < ActionController::Base
9393
rescue_from CloudController::Errors::CompoundError, with: :handle_compound_error
9494
rescue_from ActionDispatch::Http::Parameters::ParseError, with: :handle_invalid_request_body
9595
rescue_from Sequel::DatabaseConnectionError, Sequel::DatabaseDisconnectError, with: :handle_db_connection_error
96-
rescue_from OpenSSL::Cipher::CipherError, with: :handle_key_derivation_error
96+
rescue_from VCAP::CloudController::Encryptor::EncryptorError, with: :handle_key_derivation_error
9797

9898
def configuration
9999
Config.config

errors/v3.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
http_code: 429
1919
message: "The UAA is currently rate limited. Please try again later"
2020

21-
10001:
21+
10081:
2222
name: InternalServerError
2323
http_code: 500
2424
message: "%s"

lib/cloud_controller/encryptor.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ module VCAP::CloudController
99
module Encryptor
1010
ENCRYPTION_ITERATIONS = 2048
1111

12+
class EncryptorError < StandardError; end
13+
1214
class << self
1315
ALGORITHM = 'AES-128-CBC'.freeze
1416

@@ -87,6 +89,8 @@ def run_cipher(cipher, input, salt, key, iterations:)
8789
cipher.iv = salt
8890
end
8991
cipher.update(input) << cipher.final
92+
rescue OpenSSL::Cipher::CipherError, TypeError => e
93+
raise EncryptorError.new("Encryption/Decryption failed: #{e.message}")
9094
end
9195

9296
def deprecated_short_salt?(salt)

lib/cloud_controller/validate_database_keys.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ def validate_encryption_key_values_unchanged!(config)
5656
iterations: sentinel_model.encryption_iterations
5757
)
5858
# A failed decryption occasionally results in a CipherError: bad decrypt instead of a garbled string
59-
rescue OpenSSL::Cipher::CipherError
59+
# This is now caught inside Encryptor and re-raised as EncryptorError
60+
rescue VCAP::CloudController::Encryptor::EncryptorError
6061
labels_with_changed_keys << label_string
6162
next
6263
end

spec/request/apps_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3406,7 +3406,7 @@
34063406

34073407
it 'fails to decrypt the environment variables and returns a 500 error' do
34083408
app_model # ensure that app model is created before run_cipher is mocked to throw an error
3409-
allow(VCAP::CloudController::Encryptor).to receive(:run_cipher).and_raise(OpenSSL::Cipher::CipherError)
3409+
allow(VCAP::CloudController::Encryptor).to receive(:run_cipher).and_raise(VCAP::CloudController::Encryptor::EncryptorError)
34103410
api_call.call(admin_headers)
34113411

34123412
expect(last_response).to have_status_code(500)

spec/request/service_brokers_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -920,7 +920,7 @@ def expect_empty_list(user_headers)
920920

921921
it 'fails to decrypt the broker data and returns a 500 error' do
922922
broker # ensure the broker is created before run_cipher is mocked to throw an error
923-
allow(VCAP::CloudController::Encryptor).to receive(:run_cipher).and_raise(OpenSSL::Cipher::CipherError)
923+
allow(VCAP::CloudController::Encryptor).to receive(:run_cipher).and_raise(VCAP::CloudController::Encryptor::EncryptorError)
924924
api_call.call(admin_headers)
925925

926926
expect(last_response).to have_status_code(500)

spec/request/service_credential_bindings_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -631,7 +631,7 @@ def check_filtered_bindings(*bindings)
631631

632632
it 'fails to decrypt the credentials and returns a 500 error' do
633633
app_binding # ensure that binding is created before run_cipher is mocked to throw an error
634-
allow(VCAP::CloudController::Encryptor).to receive(:run_cipher).and_raise(OpenSSL::Cipher::CipherError)
634+
allow(VCAP::CloudController::Encryptor).to receive(:run_cipher).and_raise(VCAP::CloudController::Encryptor::EncryptorError)
635635
api_call.call(admin_headers)
636636

637637
expect(last_response).to have_status_code(500)

spec/support/shared_examples/models/encrypted_attribute.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ def last_row
5353

5454
begin
5555
decrypted_value = Encryptor.decrypt(saved_attribute, model.send(attr_salt), label: model.encryption_key_label, iterations: model.encryption_iterations)
56-
rescue OpenSSL::Cipher::CipherError
56+
rescue VCAP::CloudController::Encryptor::EncryptorError
5757
errored = true
5858
end
5959

spec/unit/controllers/v3/application_controller_spec.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ def not_found
3939
end
4040

4141
def key_derivation_error
42-
raise OpenSSL::Cipher::CipherError
42+
raise VCAP::CloudController::Encryptor::EncryptorError
4343
end
4444

4545
def db_disconnect_error
@@ -334,7 +334,7 @@ def warnings_incorrect_type
334334
end
335335
end
336336

337-
it 'rescues from OpenSSL::Cipher::CipherError and renders an error presenter' do
337+
it 'rescues from EncryptorError and renders an error presenter' do
338338
get :key_derivation_error
339339
expect(response).to have_http_status(:internal_server_error)
340340
expect(response).to have_error_message(/Error while processing encrypted data/)

spec/unit/lib/cloud_controller/encryptor_spec.rb

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ module VCAP::CloudController
155155

156156
result = begin
157157
Encryptor.decrypt(encrypted_string, salt, iterations: encryption_iterations)
158-
rescue OpenSSL::Cipher::CipherError => e
158+
rescue VCAP::CloudController::Encryptor::EncryptorError => e
159159
e.message
160160
end
161161

@@ -169,12 +169,21 @@ module VCAP::CloudController
169169

170170
result = begin
171171
Encryptor.decrypt(encrypted_string, salt, label: 'death', iterations: encryption_iterations)
172-
rescue OpenSSL::Cipher::CipherError => e
172+
rescue VCAP::CloudController::Encryptor::EncryptorError => e
173173
e.message
174174
end
175175

176176
expect(result).not_to eq(unencrypted_string)
177177
end
178+
179+
it 'raises an EncryptorError' do
180+
allow(Encryptor).to receive(:current_encryption_key_label).and_return('foo')
181+
encrypted_string = Encryptor.encrypt(unencrypted_string, salt)
182+
183+
expect do
184+
Encryptor.decrypt(encrypted_string, salt, label: 'bar', iterations: encryption_iterations)
185+
end.to raise_error(VCAP::CloudController::Encryptor::EncryptorError, %r{Encryption/Decryption failed: })
186+
end
178187
end
179188
end
180189
end

0 commit comments

Comments
 (0)