>From a21185b391a4ccd12638977b56227a75d83a12ba Mon Sep 17 00:00:00 2001
From: Ade Lee <alee@redhat.com>
Date: Tue, 4 Mar 2014 14:19:22 -0500
Subject: [PATCH] Get archival working for python key client

---
 base/common/python/pki/cryptoutil.py | 26 +++++++++++++++++++++-----
 base/common/python/pki/key.py        | 28 +++++++++++-----------------
 base/kra/functional/drmtest.py       | 24 ++++++++++++++++++------
 3 files changed, 50 insertions(+), 28 deletions(-)

diff --git a/base/common/python/pki/cryptoutil.py b/base/common/python/pki/cryptoutil.py
index d7cd1670c1136c5b9e729d8085d3ad8e80d98c5e..b0db776805ffadcaf0674360eedf8d0634cfee53 100644
--- a/base/common/python/pki/cryptoutil.py
+++ b/base/common/python/pki/cryptoutil.py
@@ -45,6 +45,12 @@ class CryptoUtil(object):
         ''' Initialization code '''
         pass
 
+    @staticmethod
+    @abc.abstractmethod
+    def generate_nonce_iv(mechanism):
+        ''' Create a random initialization vector '''
+        pass
+
     @abc.abstractmethod
     def generate_symmetric_key(self, mechanism=None, size=0):
         ''' Generate and return a symmetric key '''
@@ -141,6 +147,16 @@ class NSSCryptoUtil(CryptoUtil):
             subprocess.check_call(command)
 
     @staticmethod
+    def generate_nonce_iv(mechanism=nss.CKM_DES3_CBC_PAD):
+        ''' Create a random initialization vector '''
+        iv_length = nss.get_iv_length(mechanism)
+        if iv_length > 0:
+            iv_data = nss.generate_random(iv_length)
+            return iv_data
+        else:
+            return None
+
+    @staticmethod
     def setup_contexts(mechanism, sym_key, nonce_iv):
         ''' Set up contexts to do wrapping/unwrapping by symmetric keys. '''
         # Get a PK11 slot based on the cipher
@@ -151,8 +167,7 @@ class NSSCryptoUtil(CryptoUtil):
 
         # If initialization vector was supplied use it, otherwise set it to None
         if nonce_iv:
-            iv_data = nss.read_hex(nonce_iv)
-            iv_si = nss.SecItem(iv_data)
+            iv_si = nss.SecItem(nonce_iv)
             iv_param = nss.param_from_iv(mechanism, iv_si)
         else:
             iv_length = nss.get_iv_length(mechanism)
@@ -198,6 +213,9 @@ class NSSCryptoUtil(CryptoUtil):
 
         Wrap (encrypt) data using the supplied symmetric key
         '''
+        if nonce_iv is None:
+            nonce_iv = nss.read_hex(self.nonce_iv)
+
         encoding_ctx, _decoding_ctx = self.setup_contexts(mechanism, wrapping_key, nonce_iv)
         wrapped_data = encoding_ctx.cipher_op(data) + encoding_ctx.digest_final()
         return wrapped_data
@@ -211,9 +229,7 @@ class NSSCryptoUtil(CryptoUtil):
         Unwrap (decrypt) data using the supplied symmetric key
         '''
         if nonce_iv is None:
-            nonce_iv = self.nonce_iv
-        else:
-            nonce_iv = nss.data_to_hex(nonce_iv)
+            nonce_iv = nss.read_hex(self.nonce_iv)
 
         _encoding_ctx, decoding_ctx = self.setup_contexts(mechanism, wrapping_key, nonce_iv)
         unwrapped_data = decoding_ctx.cipher_op(data) \
diff --git a/base/common/python/pki/key.py b/base/common/python/pki/key.py
index cdcc7380fce3f6b92a3ba5c7e8c7aecf1ac4fe9d..d9113cd3fac4d079f6beaa3345c8a8c3ca71990f 100644
--- a/base/common/python/pki/key.py
+++ b/base/common/python/pki/key.py
@@ -327,6 +327,9 @@ class KeyClient(object):
     RC4_ALGORITHM = "RC4"
     AES_ALGORITHM = "AES"
 
+    #default session key wrapping algorithm
+    DES_EDE3_CBC_OID = "{1 2 840 113549 3 7}"
+
     def __init__(self, connection, crypto, transport_cert_nick=None):
         ''' Constructor '''
         self.connection = connection
@@ -526,28 +529,19 @@ class KeyClient(object):
         if private_data is None:
             raise TypeError("No data provided to be archived")
 
+        nonce_iv = self.crypto.generate_nonce_iv()
         session_key = self.crypto.generate_session_key()
         trans_wrapped_session_key = \
             self.crypto.asymmetric_wrap(session_key, self.transport_cert)
-        wrapped_private_data = self.crypto.symmetric_wrap(private_data, session_key)
+        wrapped_private_data = self.crypto.symmetric_wrap(private_data, session_key, nonce_iv=nonce_iv)
 
-        twsk = base64.encodestring(trans_wrapped_session_key)
-        data = base64.encodestring(wrapped_private_data)
+        algorithm_oid = self.DES_EDE3_CBC_OID
+        symkey_params = base64.encodestring(nonce_iv)
 
-        # TODO - generate_algorithm_oid here
-        # generate symkey_params here
-        algorithm_oid = "todo - fix me"
-        symkey_params = "todo - fix me"
-
-        request = KeyArchivalRequest(client_key_id=client_key_id,
-                         data_type=data_type,
-                         wrapped_private_data=data,
-                         trans_wrapped_session_key=twsk,
-                         algorithm_oid=algorithm_oid,
-                         symkey_params=symkey_params,
-                         key_algorithm=key_algorithm,
-                         key_size=key_size)
-        return self.create_request(request)
+        return self.archive_wrapped_data(client_key_id, data_type, wrapped_private_data,
+                                         trans_wrapped_session_key, algorithm_oid,
+                                         symkey_params, key_algorithm=key_algorithm,
+                                         key_size=key_size)
 
     @pki.handle_exceptions()
     def archive_wrapped_data(self, client_key_id, data_type,
diff --git a/base/kra/functional/drmtest.py b/base/kra/functional/drmtest.py
index 169a7879fab4cda61fc915d3ca2652039c3c5929..f2e866ed056786c9136a26cc2fe3168d262982a9 100644
--- a/base/kra/functional/drmtest.py
+++ b/base/kra/functional/drmtest.py
@@ -216,12 +216,24 @@ def main():
     print "key to archive: " + key1
     client_key_id = "Vek #4" + time.strftime('%c')
 
-    # this test is not quite working yet
-    #response = keyclient.archive_key(client_key_id, keyclient.SYMMETRIC_KEY_TYPE,
-    #                                base64.decodestring(key1),
-    #                                key_algorithm=keyclient.AES_ALGORITHM,
-    #                                key_size=128)
-    #print_key_request(response.requestInfo)
+    response = keyclient.archive_key(client_key_id, keyclient.SYMMETRIC_KEY_TYPE,
+                                    base64.decodestring(key1),
+                                    key_algorithm=keyclient.AES_ALGORITHM,
+                                    key_size=128)
+    print_key_request(response.requestInfo)
+
+    # Test 20: Lets get it back
+    key_info = keyclient.get_active_key_info(client_key_id)
+    print_key_info(key_info)
+
+    key_data, unwrapped_key = keyclient.retrieve_key(key_id)
+    print_key_data(key_data)
+    key2 = base64.encodestring(unwrapped_key)
+
+    if key1 == key2:
+        print "Success: archived and recovered keys match"
+    else:
+        print "Error: archived and recovered keys do not match"
 
 if __name__ == "__main__":
     main()
-- 
1.8.4.2

