diff --git a/kmip/services/server/config.py b/kmip/services/server/config.py index 6230c480..3a1b1eaa 100644 --- a/kmip/services/server/config.py +++ b/kmip/services/server/config.py @@ -50,7 +50,9 @@ def __init__(self): 'policy_path', 'enable_tls_client_auth', 'tls_cipher_suites', - 'logging_level' + 'logging_level', + 'tpm_srk_pswd', + 'enable_tpm' ] def set_setting(self, setting, value): @@ -92,6 +94,10 @@ def set_setting(self, setting, value): self._set_enable_tls_client_auth(value) elif setting == 'tls_cipher_suites': self._set_tls_cipher_suites(value) + elif setting == 'enable_tpm': + self._set_enable_tpm(value) + elif setting == 'tpm_srk_pswd': + self._set_tpm_srk_pswd(value) else: self._set_logging_level(value) @@ -164,6 +170,10 @@ def _parse_settings(self, parser): self._set_enable_tls_client_auth( parser.getboolean('server', 'enable_tls_client_auth') ) + if parser.has_option('server', 'enable_tpm'): + self._set_enable_tpm(parser.getboolean('server', 'enable_tpm')) + if parser.has_option('server', 'tpm_srk_pswd'): + self._set_tpm_srk_pswd(paser.get('server', 'tpm_srk_pswd')) if parser.has_option('server', 'tls_cipher_suites'): self._set_tls_cipher_suites( parser.get('server', 'tls_cipher_suites') @@ -278,6 +288,26 @@ def _set_enable_tls_client_auth(self, value): "must be a boolean." ) + def _set_enable_tpm(self, value): + if value is None: + self.settings['enable_tpm'] = False + elif isinstance(value, bool): + self.settings['enable_tpm'] = value + else: + raise exceptions.ConfigurationError( + "The flag enabling the TPM must be a boolean" + ) + + def _set_tpm_srk_pswd(self, value): + if not value: + self.settings['tpm_srk_pswd'] = '0'*20 + elif isinstance(value, six.string_types): + self.settings['tpm_srk_pswd'] = value + else: + raise exceptions.ConfigurationError( + "The tpm srk password, if specified, must be a valid string" + ) + def _set_tls_cipher_suites(self, value): if not value: self.settings['tls_cipher_suites'] = [] diff --git a/kmip/services/server/crypto/engine.py b/kmip/services/server/crypto/engine.py index 232f3847..abf2b723 100644 --- a/kmip/services/server/crypto/engine.py +++ b/kmip/services/server/crypto/engine.py @@ -12,10 +12,13 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. - +import base64 import logging import os +import subprocess +import tempfile + from cryptography import exceptions as errors from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import serialization, hashes, hmac, cmac @@ -1439,3 +1442,22 @@ def verify_signature(self, "The signing algorithm '{0}' is not supported for " "signature verification.".format(signing_algorithm) ) + + def tpm_encrypt_key(self, plain_key): + p = subprocess.Popen(['tpm_sealdata', '--well-known'], + stdin=subprocess.PIPE, stdout=subprocess.PIPE) + encrypted = p.communicate(plain_key)[0] + return base64.b64encode(encrypted) + + def tpm_decrypt_key(self, encrypted_key): + encrypted_key = base64.b64decode(encrypted_key) + (encfile, encpath) = tempfile.mkstemp() + encfile = open(encpath, 'w') + encfile.write(encrypted_key) + encfile.close() + p = subprocess.Popen(['tpm_unsealdata', '--srk-well-known', + '-i', encpath], + stdin=subprocess.PIPE, stdout=subprocess.PIPE) + plain_key = p.communicate()[0] + os.remove(encpath) + return plain_key diff --git a/kmip/services/server/engine.py b/kmip/services/server/engine.py index 805f1e2e..b76297d3 100644 --- a/kmip/services/server/engine.py +++ b/kmip/services/server/engine.py @@ -77,7 +77,7 @@ class KmipEngine(object): * Cryptographic usage mask enforcement per object type """ - def __init__(self, policy_path=None): + def __init__(self, policy_path=None, enable_tpm=None): """ Create a KmipEngine. @@ -126,7 +126,7 @@ def __init__(self, policy_path=None): self._attribute_policy = policy.AttributePolicy(self._protocol_version) self._operation_policies = copy.deepcopy(operation_policy.policies) self._load_operation_policies(policy_path) - + self._enable_tpm = enable_tpm self._client_identity = None def _load_operation_policies(self, policy_path): @@ -1230,8 +1230,12 @@ def _process_create_key_pair(self, payload): private_key._owner = self._client_identity private_key.initial_date = public_key.initial_date - self._data_session.add(public_key) - self._data_session.add(private_key) + if self._enable_tpm: + self._data_session.add(self._cryptography_engine.tpm_encrypt_key(public_key)) + self._data_session.add(self._cryptography_engine.tpm_encrypt_key(private_key)) + else: + self._data_session.add(public_key) + self._data_session.add(private_key) # NOTE (peterhamilton) SQLAlchemy will *not* assign an ID until # commit is called. This makes future support for UNDO problematic. @@ -1575,6 +1579,8 @@ def _process_get(self, payload): unique_identifier, enums.Operation.GET ) + if self._enable_tpm: + managed_object = self._cryptography_engine.tpm_decrypt_key(managed_object) if key_format_type: if not hasattr(managed_object, 'key_format_type'): diff --git a/kmip/services/server/server.py b/kmip/services/server/server.py index a020db37..704a5f80 100644 --- a/kmip/services/server/server.py +++ b/kmip/services/server/server.py @@ -52,6 +52,7 @@ def __init__( log_path='/var/log/pykmip/server.log', policy_path=None, enable_tls_client_auth=None, + enable_tpm=None, tls_cipher_suites=None, logging_level=None ): @@ -128,6 +129,7 @@ def __init__( auth_suite, policy_path, enable_tls_client_auth, + enable_tpm, tls_cipher_suites, logging_level ) @@ -141,7 +143,8 @@ def __init__( self.auth_suite = auth.BasicAuthenticationSuite(cipher_suites) self._engine = engine.KmipEngine( - self.config.settings.get('policy_path') + self.config.settings.get('policy_path'), + self.config.settings.get('enable_tpm') ) self._session_id = 1 self._is_serving = False @@ -178,6 +181,7 @@ def _setup_configuration( auth_suite=None, policy_path=None, enable_tls_client_auth=None, + enable_tpm=None, tls_cipher_suites=None, logging_level=None ): @@ -203,6 +207,8 @@ def _setup_configuration( 'enable_tls_client_auth', enable_tls_client_auth ) + if enable_tpm: + self.config.set_setting('enable_tpm', enable_tpm) if tls_cipher_suites: self.config.set_setting( 'tls_cipher_suites',