From 04597e4f9dd25ee912135c4ee9c614c345e1e444 Mon Sep 17 00:00:00 2001
From: Matthew Harmsen <mharmsen@redhat.com>
Date: Thu, 21 May 2015 16:56:27 -0600
Subject: [PATCH] disable backup keys and share master keys when using an HSM

- PKI TRAC Ticket #1371 - pkispawn: need to disable backup_keys when using an
  HSM (and provide recommendation); allow clones to share keys
---
 .../dogtagpki/server/rest/SystemConfigService.java |  6 +++++
 .../python/pki/server/deployment/pkihelper.py      | 30 +++++++++++++++++-----
 .../python/pki/server/deployment/pkimessages.py    |  9 +++++++
 3 files changed, 39 insertions(+), 6 deletions(-)

diff --git a/base/server/cms/src/org/dogtagpki/server/rest/SystemConfigService.java b/base/server/cms/src/org/dogtagpki/server/rest/SystemConfigService.java
index c341d14..bbbeaba 100644
--- a/base/server/cms/src/org/dogtagpki/server/rest/SystemConfigService.java
+++ b/base/server/cms/src/org/dogtagpki/server/rest/SystemConfigService.java
@@ -1116,6 +1116,8 @@ public class SystemConfigService extends PKIService implements SystemConfigResou
                 if (data.getP12Password() == null) {
                     throw new BadRequestException("P12 password not provided");
                 }
+            } else {
+                throw new BadRequestException("HSM clones must share their HSM master's private keys");
             }
         } else {
             data.setClone("false");
@@ -1177,6 +1179,10 @@ public class SystemConfigService extends PKIService implements SystemConfigResou
         }
 
         if ((data.getBackupKeys() != null) && data.getBackupKeys().equals("true")) {
+            if (! data.getToken().equals(ConfigurationRequest.TOKEN_DEFAULT)) {
+                throw new BadRequestException("HSMs cannot publish private keys to PKCS #12 files");
+            }
+
             if ((data.getBackupFile() == null) || (data.getBackupFile().length()<=0)) {
                 //TODO: also check for valid path, perhaps by touching file there
                 throw new BadRequestException("Invalid key backup file name");
diff --git a/base/server/python/pki/server/deployment/pkihelper.py b/base/server/python/pki/server/deployment/pkihelper.py
index 4f1c136..a53751c 100644
--- a/base/server/python/pki/server/deployment/pkihelper.py
+++ b/base/server/python/pki/server/deployment/pkihelper.py
@@ -559,6 +559,13 @@ class ConfigurationFile:
         # Verify existence of Admin Password (except for Clones)
         if not self.clone:
             self.confirm_data_exists("pki_admin_password")
+        if (config.str2bool(self.mdict['pki_hsm_enable']) and
+            config.str2bool(self.mdict['pki_backup_keys'])):
+            config.pki_log.error(
+                log.PKIHELPER_HSM_KEYS_CANNOT_BE_BACKED_UP_TO_PKCS12_FILES,
+                extra=config.PKI_INDENTATION_LEVEL_2)
+            raise Exception(
+                log.PKIHELPER_HSM_KEYS_CANNOT_BE_BACKED_UP_TO_PKCS12_FILES)
         # If required, verify existence of Backup Password
         if config.str2bool(self.mdict['pki_backup_keys']):
             self.confirm_data_exists("pki_backup_password")
@@ -568,8 +575,15 @@ class ConfigurationFile:
             self.confirm_data_exists("pki_client_database_password")
         # Verify existence of Client PKCS #12 Password for Admin Cert
         self.confirm_data_exists("pki_client_pkcs12_password")
-        # Verify existence of PKCS #12 Password (ONLY for Clones)
-        if self.clone:
+        if (config.str2bool(self.mdict['pki_hsm_enable']) and
+            os.path.exists(self.mdict['pki_clone_pkcs12_path'])):
+            config.pki_log.error(
+                log.PKIHELPER_HSM_CLONES_MUST_SHARE_HSM_MASTER_PRIVATE_KEYS,
+                extra=config.PKI_INDENTATION_LEVEL_2)
+            raise Exception(
+                log.PKIHELPER_HSM_CLONES_MUST_SHARE_HSM_MASTER_PRIVATE_KEYS)
+        # Verify existence of PKCS #12 Password (ONLY for non-HSM Clones)
+        if self.clone and not config.str2bool(self.mdict['pki_hsm_enable']):
             self.confirm_data_exists("pki_clone_pkcs12_password")
         # Verify existence of Security Domain Password
         # (ONLY for PKI KRA, PKI OCSP, PKI TKS, PKI TPS, Clones, or
@@ -675,8 +689,10 @@ class ConfigurationFile:
             self.confirm_data_exists("pki_http_port")
             self.confirm_data_exists("pki_https_port")
             self.confirm_data_exists("pki_tomcat_server_port")
-            self.confirm_data_exists("pki_clone_pkcs12_path")
-            self.confirm_file_exists("pki_clone_pkcs12_path")
+            if not config.str2bool(self.mdict['pki_hsm_enable']):
+                # Check clone parameters for non-HSM clone
+                self.confirm_data_exists("pki_clone_pkcs12_path")
+                self.confirm_file_exists("pki_clone_pkcs12_path")
             self.confirm_data_exists("pki_clone_replication_security")
             self.confirm_data_exists("pki_clone_uri")
         elif self.external:
@@ -4120,8 +4136,10 @@ class ConfigClient:
     def set_cloning_parameters(self, data):
         data.isClone = "true"
         data.cloneUri = self.mdict['pki_clone_uri']
-        data.p12File = self.mdict['pki_clone_pkcs12_path']
-        data.p12Password = self.mdict['pki_clone_pkcs12_password']
+        if not config.str2bool(self.mdict['pki_hsm_enable']):
+            # Set these clone parameters for non-HSM clones only
+            data.p12File = self.mdict['pki_clone_pkcs12_path']
+            data.p12Password = self.mdict['pki_clone_pkcs12_password']
         if config.str2bool(self.mdict['pki_clone_replicate_schema']):
             data.replicateSchema = "true"
         else:
diff --git a/base/server/python/pki/server/deployment/pkimessages.py b/base/server/python/pki/server/deployment/pkimessages.py
index 321ea78..0e7d143 100644
--- a/base/server/python/pki/server/deployment/pkimessages.py
+++ b/base/server/python/pki/server/deployment/pkimessages.py
@@ -199,6 +199,15 @@ PKIHELPER_GROUP_ADD_2 = "adding GID '%s' for group '%s' . . ."
 PKIHELPER_GROUP_ADD_DEFAULT_2 = "adding default GID '%s' for group '%s' . . ."
 PKIHELPER_GROUP_ADD_GID_KEYERROR_1 = "KeyError:  pki_gid %s"
 PKIHELPER_GROUP_ADD_KEYERROR_1 = "KeyError:  pki_group %s"
+PKIHELPER_HSM_CLONES_MUST_SHARE_HSM_MASTER_PRIVATE_KEYS = \
+    "Since clones using Hardware Security Modules (HSMs) must share their "\
+    "master's private keys, the 'pki_clone_pkcs12_path' and "\
+    "'pki_clone_pkcs12_password' variables may not be utilized with HSMs."
+PKIHELPER_HSM_KEYS_CANNOT_BE_BACKED_UP_TO_PKCS12_FILES = \
+    "Since Hardware Security Modules (HSMs) do not allow their private keys "\
+    "to be extracted to PKCS #12 files, the 'pki_backup_keys' and "\
+    "'pki_backup_password' variables may not be utilized with HSMs.\n"\
+    "Please contact the HSM vendor regarding their specific backup mechanism."
 PKIHELPER_INVALID_SELINUX_CONTEXT_FOR_PORT = \
     "port %s has invalid selinux context %s"
 PKIHELPER_IS_A_DIRECTORY_1 = "'%s' is a directory"
-- 
1.8.3.1

