>From 3ad3bb08353cf4e01ba4a1c292920ea686ccaa19 Mon Sep 17 00:00:00 2001
From: "Endi S. Dewata" <edewata@redhat.com>
Date: Tue, 15 Nov 2016 21:32:53 +0100
Subject: [PATCH] Fixed problem installing subordinate CA with HSM in FIPS
 mode.

Due to certutil issue (bug #1393668) the installation code has
been modified to import certificates into the NSS database in
two steps. This workaround is needed to install subordinate CA
with HSM in FIPS mode.

First, the certificate will be imported into the HSM using the
HSM password without the trust attributes. Then, the certificate
will be imported into the internal token using the internal token
password with the trust attributes.

https://fedorahosted.org/pki/ticket/2543
---
 base/common/python/pki/nssdb.py           | 51 ++++++++++++++++++++++++-------
 base/server/python/pki/server/__init__.py |  3 +-
 2 files changed, 42 insertions(+), 12 deletions(-)

diff --git a/base/common/python/pki/nssdb.py b/base/common/python/pki/nssdb.py
index c044ba1fba069a5b5e560319fe7a4c91a62934c5..430cacd83ee7eb6edd4f965e18d941ddb141251c 100644
--- a/base/common/python/pki/nssdb.py
+++ b/base/common/python/pki/nssdb.py
@@ -99,7 +99,8 @@ def get_file_type(filename):
 
 class NSSDatabase(object):
 
-    def __init__(self, directory=None, token=None, password=None, password_file=None):
+    def __init__(self, directory=None, token=None, password=None, password_file=None,
+                 internal_password=None, internal_password_file=None):
 
         if not directory:
             directory = os.path.join(os.path.expanduser("~"), '.dogtag', 'nssdb')
@@ -124,25 +125,53 @@ class NSSDatabase(object):
         else:
             raise Exception('Missing NSS database password')
 
+        if internal_password:
+            # Store the specified internal token into password file.
+            self.internal_password_file = os.path.join(self.tmpdir, 'internal_password.txt')
+            with open(self.internal_password_file, 'w') as f:
+                f.write(internal_password)
+
+        elif internal_password_file:
+            # Use the specified internal token password file.
+            self.internal_password_file = internal_password_file
+
+        else:
+            # By default use the same password for both internal token and HSM.
+            self.internal_password_file = self.password_file
+
     def close(self):
         shutil.rmtree(self.tmpdir)
 
     def add_cert(self, nickname, cert_file, trust_attributes=',,'):
+
+        # Add cert in two steps due to bug #1393668.
+
+        # First, import cert into HSM without trust attributes.
+        if self.token:
+            cmd = [
+                'certutil',
+                '-A',
+                '-d', self.directory,
+                '-h', self.token,
+                '-f', self.password_file,
+                '-n', nickname,
+                '-i', cert_file,
+                '-t', ''
+            ]
+
+            # Ignore return code due to bug #1393668.
+            subprocess.call(cmd)
+
+        # Then, import cert into internal token with trust attributes.
         cmd = [
             'certutil',
             '-A',
-            '-d', self.directory
-        ]
-
-        if self.token:
-            cmd.extend(['-h', self.token])
-
-        cmd.extend([
-            '-f', self.password_file,
+            '-d', self.directory,
+            '-f', self.internal_password_file,
             '-n', nickname,
             '-i', cert_file,
             '-t', trust_attributes
-        ])
+        ]
 
         subprocess.check_call(cmd)
 
@@ -584,7 +613,7 @@ class NSSDatabase(object):
                 else:
                     n = '%s #%d' % (nickname, counter)
 
-                self.add_cert(n, cert_file, trust_attributes)
+                self.add_cert(n, cert_file, trust_attributes=trust_attributes)
                 nicks.append(n)
 
                 counter += 1
diff --git a/base/server/python/pki/server/__init__.py b/base/server/python/pki/server/__init__.py
index 13b3258580e6536cea2b99ad9955ae8ff2e32de5..d556312a7c0f87cfeda025abd9d6841939d220f1 100644
--- a/base/server/python/pki/server/__init__.py
+++ b/base/server/python/pki/server/__init__.py
@@ -654,7 +654,8 @@ class PKIInstance(object):
         return pki.nssdb.NSSDatabase(
             directory=self.nssdb_dir,
             token=token,
-            password=self.get_token_password(token))
+            password=self.get_token_password(token),
+            internal_password=self.get_token_password())
 
     def external_cert_exists(self, nickname, token):
         for cert in self.external_certs:
-- 
2.5.5

