openxpki icon indicating copy to clipboard operation
openxpki copied to clipboard

Rework encrypted datapool functionality (replace with TransparentEncryption)

Open mbartosch opened this issue 11 years ago • 0 comments

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(

mbartosch avatar Jun 12 '13 15:06 mbartosch