URL: https://github.com/freeipa/freeipa/pull/510
Author: tiran
 Title: #510: Vault: port key wrapping to python-cryptography
Action: opened

PR body:
"""
https://fedorahosted.org/freeipa/ticket/6650

Signed-off-by: Christian Heimes <chei...@redhat.com>
"""

To pull the PR as Git branch:
git remote add ghfreeipa https://github.com/freeipa/freeipa
git fetch ghfreeipa pull/510/head:pr510
git checkout pr510
From 9ec7548f1181f4b5baa2386833a1c3d1732eda87 Mon Sep 17 00:00:00 2001
From: Christian Heimes <chei...@redhat.com>
Date: Sat, 25 Feb 2017 13:09:11 +0100
Subject: [PATCH] Vault: port key wrapping to python-cryptography

https://fedorahosted.org/freeipa/ticket/6650

Signed-off-by: Christian Heimes <chei...@redhat.com>
---
 ipaclient/plugins/vault.py | 102 ++++++++++++++++++---------------------------
 1 file changed, 41 insertions(+), 61 deletions(-)

diff --git a/ipaclient/plugins/vault.py b/ipaclient/plugins/vault.py
index 9efb1f1..073d3b5 100644
--- a/ipaclient/plugins/vault.py
+++ b/ipaclient/plugins/vault.py
@@ -31,10 +31,11 @@
 from cryptography.hazmat.primitives import hashes
 from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
 from cryptography.hazmat.primitives.asymmetric import padding
-from cryptography.hazmat.primitives.serialization import load_pem_public_key,\
-    load_pem_private_key
-
-import nss.nss as nss
+from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
+from cryptography.hazmat.primitives.padding import PKCS7
+from cryptography.hazmat.primitives.serialization import (
+    load_pem_public_key, load_pem_private_key)
+from cryptography.x509 import load_der_x509_certificate
 
 from ipaclient.frontend import MethodOverride
 from ipalib.frontend import Local, Method, Object
@@ -762,32 +763,25 @@ def forward(self, *args, **options):
                 name='vault_type',
                 error=_('Invalid vault type'))
 
-        # initialize NSS database
-        nss.nss_init(api.env.nss_dir)
-
         # retrieve transport certificate
         config = self.api.Command.vaultconfig_show()['result']
         transport_cert_der = config['transport_cert']
-        nss_transport_cert = nss.Certificate(transport_cert_der)
+        transport_cert = load_der_x509_certificate(
+            transport_cert_der, default_backend())
+        public_key = transport_cert.public_key()
 
         # generate session key
-        mechanism = nss.CKM_DES3_CBC_PAD
-        slot = nss.get_best_slot(mechanism)
-        key_length = slot.get_best_key_length(mechanism)
-        session_key = slot.key_gen(mechanism, None, key_length)
+        key_length = max(algorithms.TripleDES.key_sizes)
+        algo = algorithms.TripleDES(os.urandom(key_length // 8))
+        nonce = os.urandom(algo.block_size // 8)
 
         # wrap session key with transport certificate
-        # pylint: disable=no-member
-        public_key = nss_transport_cert.subject_public_key_info.public_key
-        # pylint: enable=no-member
-        wrapped_session_key = nss.pub_wrap_sym_key(mechanism,
-                                                   public_key,
-                                                   session_key)
-
-        options['session_key'] = wrapped_session_key.data
+        wrapped_session_key = public_key.encrypt(
+            algo.key,
+            padding.PKCS1v15()
+        )
 
-        nonce_length = nss.get_iv_length(mechanism)
-        nonce = nss.generate_random(nonce_length)
+        options['session_key'] = wrapped_session_key
         options['nonce'] = nonce
 
         vault_data = {}
@@ -797,19 +791,16 @@ def forward(self, *args, **options):
             vault_data[u'encrypted_key'] = base64.b64encode(encrypted_key)\
                 .decode('utf-8')
 
-        json_vault_data = json.dumps(vault_data)
+        json_vault_data = json.dumps(vault_data).encode('utf-8')
 
         # wrap vault_data with session key
-        iv_si = nss.SecItem(nonce)
-        iv_param = nss.param_from_iv(mechanism, iv_si)
-
-        encoding_ctx = nss.create_context_by_sym_key(mechanism,
-                                                     nss.CKA_ENCRYPT,
-                                                     session_key,
-                                                     iv_param)
+        padder = PKCS7(algo.block_size).padder()
+        padded_data = padder.update(json_vault_data)
+        padded_data += padder.finalize()
 
-        wrapped_vault_data = encoding_ctx.cipher_op(json_vault_data)\
-            + encoding_ctx.digest_final()
+        cipher = Cipher(algo, modes.CBC(nonce), backend=default_backend())
+        encryptor = cipher.encryptor()
+        wrapped_vault_data = encryptor.update(padded_data) + encryptor.finalize()
 
         options['vault_data'] = wrapped_vault_data
 
@@ -925,49 +916,38 @@ def forward(self, *args, **options):
 
         vault_type = vault['ipavaulttype'][0]
 
-        # initialize NSS database
-        nss.nss_init(api.env.nss_dir)
-
         # retrieve transport certificate
         config = self.api.Command.vaultconfig_show()['result']
         transport_cert_der = config['transport_cert']
-        nss_transport_cert = nss.Certificate(transport_cert_der)
+        transport_cert = load_der_x509_certificate(
+            transport_cert_der, default_backend())
+        public_key = transport_cert.public_key()
 
         # generate session key
-        mechanism = nss.CKM_DES3_CBC_PAD
-        slot = nss.get_best_slot(mechanism)
-        key_length = slot.get_best_key_length(mechanism)
-        session_key = slot.key_gen(mechanism, None, key_length)
+        key_length = max(algorithms.TripleDES.key_sizes)
+        algo = algorithms.TripleDES(os.urandom(key_length // 8))
 
         # wrap session key with transport certificate
-        # pylint: disable=no-member
-        public_key = nss_transport_cert.subject_public_key_info.public_key
-        # pylint: enable=no-member
-        wrapped_session_key = nss.pub_wrap_sym_key(mechanism,
-                                                   public_key,
-                                                   session_key)
+        wrapped_session_key = public_key.encrypt(
+            algo.key,
+            padding.PKCS1v15()
+        )
 
         # send retrieval request to server
-        options['session_key'] = wrapped_session_key.data
-
+        options['session_key'] = wrapped_session_key
         response = self.api.Command.vault_retrieve_internal(*args, **options)
-
         result = response['result']
         nonce = result['nonce']
 
         # unwrap data with session key
-        wrapped_vault_data = result['vault_data']
-
-        iv_si = nss.SecItem(nonce)
-        iv_param = nss.param_from_iv(mechanism, iv_si)
-
-        decoding_ctx = nss.create_context_by_sym_key(mechanism,
-                                                     nss.CKA_DECRYPT,
-                                                     session_key,
-                                                     iv_param)
-
-        json_vault_data = decoding_ctx.cipher_op(wrapped_vault_data)\
-            + decoding_ctx.digest_final()
+        cipher = Cipher(algo, modes.CBC(nonce), backend=default_backend())
+        decryptor = cipher.decryptor()
+        padded_data = decryptor.update(result['vault_data'])
+        padded_data += decryptor.finalize()
+
+        unpadder = PKCS7(algo.block_size).unpadder()
+        json_vault_data = unpadder.update(padded_data)
+        json_vault_data += unpadder.finalize()
 
         vault_data = json.loads(json_vault_data.decode('utf-8'))
         data = base64.b64decode(vault_data[u'data'].encode('utf-8'))
-- 
Manage your subscription for the Freeipa-devel mailing list:
https://www.redhat.com/mailman/listinfo/freeipa-devel
Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code

Reply via email to