openxpki
openxpki copied to clipboard
Rework encrypted datapool functionality (replace with TransparentEncryption)
The Datapool API supports encrypted storage of data in the datapool. Although this works fine it would be nice to provide a transparent encryption mechanism to the core system that could replace both VolatileVault and the dedicated Datapool encryption.
Sample implementation of base class at https://github.com/mbartosch/TransparentEncryption
Possible start for adding this to the server context (untested):
diff --git a/trunk/perl-modules/core/trunk/OpenXPKI/Server/Context.pm b/trunk/perl-modules/core/trunk/OpenXPKI/Server/Context.pm
index d15ad8a..1999918 100644
--- a/trunk/perl-modules/core/trunk/OpenXPKI/Server/Context.pm
+++ b/trunk/perl-modules/core/trunk/OpenXPKI/Server/Context.pm
@@ -29,6 +29,7 @@ my $context = {
pki_realm => undef,
pki_realm_by_cfg => undef,
volatile_vault => undef,
+ transparent_encryption => undef,
log => undef,
dbi_backend => undef,
dbi_workflow => undef,
@@ -231,6 +232,8 @@ by calling CTX('...') once create() has been called:
=item * volatile_vault
+=item * transparent_encryption
+
=item * log
=item * dbi_backend
diff --git a/trunk/perl-modules/core/trunk/OpenXPKI/Server/Init.pm b/trunk/perl-modules/core/trunk/OpenXPKI/Server/Init.pm
index 3619e57..9425f59 100644
--- a/trunk/perl-modules/core/trunk/OpenXPKI/Server/Init.pm
+++ b/trunk/perl-modules/core/trunk/OpenXPKI/Server/Init.pm
@@ -67,6 +67,7 @@ my @init_tasks = qw(
crypto_layer
pki_realm
volatile_vault
+ transparent_encryption
acl
api
pki_realm_by_cfg
@@ -402,6 +403,214 @@ sub __do_init_volatile_vault {
});
}
+sub __do_init_transparent_encryption {
+ ##! 1: "init transparent encryption"
+
+ # FIXME: get rekeying policy from configuration?
+ my $key_management_policy = 'CERT';
+ my $tenc = OpenXPKI::Crypto::KeyManagement::TransparentEncryption->new(
+ {
+ KEYMANAGEMENT => $key_management_policy,
+ NAMEPACE_KEY_STORAGE => 'sys.datapool.keys',
+ NAMEPACE_KEY_MAPPING => 'sys.datapool.pwsafe',
+ });
+
+ # delegate implementations for accessing the datapool and for asymmetric
+ # encryption
+ $tenc->delegate(
+ {
+ GET_CURRENT_ASYMMETRIC_KEY_ID => {
+ ##! 1: 'start'
+ my $realm = CTX('session')->get_pki_realm();
+ my $cfg_id = CTX('api')->get_current_config_id();
+
+ my @possible_safes = ();
+ my $pki_realm_cfg = CTX('pki_realm_by_cfg')->{$cfg_id}->{$realm}->{'password_safe'}->{'id'};
+ if (! defined $pki_realm_cfg || ref $pki_realm_cfg ne 'HASH') {
+ OpenXPKI::Exception->throw(
+ message => 'I18N_OPENXPKI_SERVER_API_OBJECT_GET_CURRENT_SAFE_ID_MISSING_PKI_REALM_CONFIG',
+ params => {
+ CONFIG_ID => $cfg_id,
+ REALM => $realm,
+ },
+ log => {
+ logger => CTX('log'),
+ priority => 'error',
+ facility => [ 'system', ],
+ },
+ );
+ }
+
+ foreach my $key (keys %{ $pki_realm_cfg }) {
+ ##! 64: 'key: ' . $key
+ push @possible_safes, {
+ 'id' => $key,
+ 'notbefore' => $pki_realm_cfg->{$key}->{notbefore},
+ 'notafter' => $pki_realm_cfg->{$key}->{notafter},
+ };
+ }
+ ##! 16: 'possible safes: ' . Dumper \@possible_safes
+ # sort safes by notbefore date (latest earliest)
+ my @sorted_safes = sort { DateTime->compare($b->{notbefore}, $a->{notbefore}) } @possible_safes;
+ ##! 16: 'sorted safes: ' . Dumper \@sorted_safes
+
+ # find the topmost one that is available /now/
+ my $now = DateTime->now();
+
+ ##! 16: 'now: ' . Dumper $now
+ my $current_safe = first
+ { DateTime->compare($now, $_->{notbefore}) >= 0
+ && DateTime->compare($_->{notafter}, $now) > 0 } @sorted_safes;
+ if (! defined $current_safe) {
+ OpenXPKI::Exception->throw(
+ message => 'I18N_OPENXPKI_SERVER_INIT_CALLBACK_GET_CURRENT_SAFE_ID_NO_SAFE_AVAILABLE',
+ log => {
+ logger => CTX('log'),
+ priority => 'error',
+ facility => [ 'system', ],
+ },
+ );
+ }
+ ##! 16: 'current safe: ' . Dumper $current_safe
+
+ return $current_safe->{id};
+ },
+
+ ENCRYPT_ASYMMETRICALLY => {
+ my $arg_ref = shift;
+
+ my $keyid = $arg_ref->{KEYID};
+ my $data = $arg_ref->{DATA};
+
+ my $cfg_id = CTX('api')->get_current_config_id();
+ my $realm = CTX('session')->get_pki_realm();
+
+ my $cert = CTX('pki_realm_by_cfg')->{$cfg_id}->{$realm}->{password_safe}->{id}->{$keyid}->{certificate};
+
+ ##! 16: 'cert: ' . $cert
+ if (! defined $cert) {
+ OpenXPKI::Exception->throw(
+ message => 'I18N_OPENXPKI_SERVER_INIT_CALLBACK_ENCRYPT_ASYMMETRICALLY_CERT_NOT_AVAILABLE',
+ params => {
+ PKI_REALM => $realm,
+ KEY_ID => $key,
+ CONFIG_ID => $cfg_id,
+ },
+ log => {
+ logger => CTX('log'),
+ priority => 'error',
+ facility => [ 'system', ],
+ },
+ );
+ }
+
+ ##! 16: 'asymmetric encryption via passwordsafe ' . $current_password_safe
+ my $token = CTX('pki_realm_by_cfg')->{$cfg_id}->{$realm}->{crypto}->{default};
+ $value = $token->command(
+ {
+ COMMAND => 'pkcs7_encrypt',
+ CERT => $cert,
+ CONTENT => $data,
+ });
+ return $value;
+ },
+
+ DECRYPT_ASYMMETRICALLY => {
+ my $arg_ref = shift;
+
+ my $keyid = $arg_ref->{KEYID};
+ my $data = $arg_ref->{DATA};
+
+ my $cfg_id = CTX('api')->get_current_config_id();
+ my $realm = CTX('session')->get_pki_realm();
+
+ my $safe_token = CTX('pki_realm_by_cfg')->{$cfg_id}->{$realm}->{password_safe}->{id}->{$keyid}->{crypto};
+ if (! defined $safe_token) {
+ OpenXPKI::Exception->throw(
+ message => 'I18N_OPENXPKI_SERVER_INIT_CALLBACK_DECRYPT_ASYMMETRICALLY_TOKEN_NOT_AVAILABLE',
+ params => {
+ PKI_REALM => $realm,
+ KEY_ID => $keyid,
+ CONFIG_ID => $cfg_id,
+ },
+ log => {
+ logger => CTX('log'),
+ priority => 'error',
+ facility => [ 'system', ],
+ },
+ );
+ }
+ ##! 16: 'asymmetric decryption via passwordsafe ' . $safe_id
+ eval {
+ $value = $safe_token->command(
+ {
+ COMMAND => 'pkcs7_decrypt',
+ PKCS7 => $value,
+ });
+ };
+ if (my $exc = OpenXPKI::Exception->caught()) {
+ if ($exc->message()
+ eq 'I18N_OPENXPKI_TOOLKIT_COMMAND_FAILED') {
+
+ OpenXPKI::Exception->throw(
+ message => 'I18N_OPENXPKI_SERVER_INIT_CALLBACK_DECRYPT_ASYMMETRICALLY_ENCRYPTION_KEY_UNAVAILABLE',
+ params => {
+ PKI_REALM => $realm,
+ KEY_ID => $keyid,
+ CONFIG_ID => $cfg_id,
+ },
+ log => {
+ logger => CTX('log'),
+ priority => 'error',
+ facility => [ 'system', ],
+ },
+ );
+ }
+
+ $exc->rethrow();
+ }
+ return $value;
+ },
+ STORE_TUPLE => {
+ my $arg_ref = shift;
+
+ my $namespace = $arg_ref->{NAMESPACE};
+ my $key = $arg_ref->{KEY};
+ my $data = $arg_ref->{VALUE};
+
+ my $realm = CTX('session')->get_pki_realm();
+ return CTX('api')->set_data_pool_entry(
+ {
+ PKI_REALM => $realm,
+ NAMESPACE => $namespace,
+ KEY => $key,
+ VALUE => $data,
+ });
+ },
+ RETRIEVE_TUPLE => {
+ my $arg_ref = shift;
+
+ my $namespace = $arg_ref->{NAMESPACE};
+ my $key = $arg_ref->{KEY};
+
+ my $realm = CTX('session')->get_pki_realm();
+ my $result = CTX('api')->get_data_pool_entry(
+ {
+ PKI_REALM => $realm,
+ NAMESPACE => $namespace,
+ KEY => $key,
+ });
+ return unless defined $result;
+ return $result->{VALUE};
+ },
+ });
+
+ OpenXPKI::Server::Context::setcontext(
+ {
+ transparent_encryption => $tenc,
+ });
+}
+
sub __do_init_dbi_backend {
### init backend dbi...
my $dbi = get_dbi(