in managementnode/lib/VCL/Module/OS/Linux/ManagementNode.pm [880:979]
sub decrypt_cryptsecret {
my $self = shift;
if (ref($self) !~ /VCL::Module/i) {
notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
return;
}
my ($secret_id, $encrypted_string, $recreate_key) = @_;
if (!defined($secret_id)) {
notify($ERRORS{'WARNING'}, 0, "secret ID argument was not supplied");
return;
}
if (!defined($encrypted_string)) {
notify($ERRORS{'WARNING'}, 0, "encrypted string argument was not supplied");
return;
}
my $management_node_id = $self->data->get_management_node_id() || return;
my $management_node_short_name = $self->data->get_management_node_short_name() || return;
my $private_key_file_path = $self->get_private_key_file_path();
if ($recreate_key) {
notify($ERRORS{'DEBUG'}, 0, "previous attempt to decrypt cryptsecret failed, attempting to regenerate private key and cryptsecret entries");
if (!$self->generate_private_key_file({force => 1})) {
notify($ERRORS{'WARNING'}, 0, "unable to decrypt secret ID $secret_id, failed to verify private key stored in file on management node is valid and its public key matches the cryptkey.pubkey value in the database");
return;
}
}
# Pass opposite of $recreate_key as $suppress_warning argument
my $cryptsecret = get_management_node_cryptsecret_value($management_node_id, $secret_id, !$recreate_key);
if (!$cryptsecret) {
#notify($ERRORS{'WARNING'}, 0, "unable to decrypt secret ID $secret_id, failed to retrieve cryptsecret.cryptsecret value for management node ID $management_node_id");
$recreate_key ? return : return $self->decrypt_cryptsecret($secret_id, $encrypted_string, 1);
}
# The encrypted string (addomain.password, etc) and cryptsecret.cryptsecret should ALWAYS be base64 encoded
# They must be decoded to binary before being passed to decrypt functions
my $encrypted_string_decoded = decode_base64($encrypted_string);
my $cryptsecret_decoded = decode_base64($cryptsecret);
my $rsa_private = $self->_get_private_key_object_from_file();
if (!$rsa_private) {
#notify($ERRORS{'WARNING'}, 0, "unable to decrypt secret ID $secret_id, failed to create RSA object based on management node's private key");
$recreate_key ? return : return $self->decrypt_cryptsecret($secret_id, $encrypted_string, 1);
}
# Override the die handler
local $SIG{__DIE__} = sub{};
my $key;
eval {
$key = $rsa_private->decrypt($cryptsecret_decoded);
};
if ($EVAL_ERROR || !$key) {
# Wrong key error:
# RSA.xs:202: OpenSSL error: oaep decoding error
notify($ERRORS{'WARNING'}, 0, "unable to decrypt secret ID $secret_id, failed to decrypt cryptsecret using RSA object based on management node's private key file: $private_key_file_path" . ($EVAL_ERROR ? ", error:\n" . $EVAL_ERROR : ''));
$recreate_key ? return : return $self->decrypt_cryptsecret($secret_id, $encrypted_string, 1);
}
my $encrypted_string_length = length($encrypted_string_decoded);
if ($encrypted_string_length < 32) {
# This should always be at least 32 bytes
# If less than 16, the next 2 substr commands may fail with 'substr outside of string' errors
notify($ERRORS{'WARNING'}, 0, "unable to decrypt secret ID $secret_id, encrypted string length: $encrypted_string_length bytes, it must be 32 bytes or more:\n$encrypted_string\n\n" . decode_base64($encrypted_string));
return;
}
my $iv = substr($encrypted_string_decoded, 0, 16);
my $ciphered_string = substr($encrypted_string_decoded, 16);
my $cipher;
eval {
$cipher = Crypt::CBC->new(
{
'key' => $key,
'cipher' => 'Crypt::Rijndael',
'iv' => $iv,
'header' => 'none',
'literal_key' => 1,
}
);
};
if (!$cipher || $EVAL_ERROR) {
notify($ERRORS{'WARNING'}, 0, "unable to decrypt secret ID $secret_id, failed to create Crypt::CBC object" . ($EVAL_ERROR ? ", error:\n" . $EVAL_ERROR : ''));
return;
}
my $decrypted_string = $cipher->decrypt($ciphered_string);
if (defined($decrypted_string)) {
notify($ERRORS{'OK'}, 0, "decrypted secret ID $secret_id");
return $decrypted_string;
}
else {
notify($ERRORS{'WARNING'}, 0, "failed to decrypt secret ID $secret_id");
$recreate_key ? return : return $self->decrypt_cryptsecret($secret_id, $encrypted_string, 1);
}
}