>From 6554b96e53956a64ca7a7dad4c361e7277fd12ad Mon Sep 17 00:00:00 2001
From: Ade Lee <alee@redhat.com>
Date: Mon, 24 Feb 2014 11:33:38 -0500
Subject: [PATCH 204/205] Make generate_symmetric_key more generic.

Added a method generate_session_key() which should be used when
wrapping secrets for the drm.  For now, this has to be a 168-bit
3DES symmetric key.
---
 base/common/python/pki/cryptoutil.py | 27 +++++++++++++++++++++++----
 base/common/python/pki/key.py        |  8 ++++----
 base/kra/functional/drmtest.py       |  2 +-
 3 files changed, 28 insertions(+), 9 deletions(-)

diff --git a/base/common/python/pki/cryptoutil.py b/base/common/python/pki/cryptoutil.py
index b5d5fdc1368b51de302ebe2f35110d36cadc22cf..b39259dd543134a9e48d1eedeeb42ee7ce380fb6 100644
--- a/base/common/python/pki/cryptoutil.py
+++ b/base/common/python/pki/cryptoutil.py
@@ -46,11 +46,17 @@ class CryptoUtil(object):
         pass
 
     @abc.abstractmethod
-    def generate_symmetric_key(self, mechanism=None):
+    def generate_symmetric_key(self, mechanism=None, size=0):
         ''' Generate and return a symmetric key '''
         pass
 
     @abc.abstractmethod
+    def generate_session_key(self):
+        ''' Generate a session key to be used for wrapping data to the DRM
+        This must return a 3DES 168 bit key '''
+        pass
+
+    @abc.abstractmethod
     def symmetric_wrap(self, data, wrapping_key, mechanism=None, nonce_iv=None):
         ''' encrypt data using a symmetric key (wrapping key)'''
         pass
@@ -166,10 +172,23 @@ class NSSCryptoUtil(CryptoUtil):
 
         return encoding_ctx, decoding_ctx
 
-    def generate_symmetric_key(self, mechanism=nss.CKM_DES3_CBC_PAD):
-        ''' Returns a symmetric key.'''
+    def generate_symmetric_key(self, mechanism=nss.CKM_DES3_CBC_PAD, size=0):
+        ''' Returns a symmetric key.
+
+        Note that for fixed length keys, this length should be 0.  If no length
+        is provided, then the function will either use 0 (for fixed length keys)
+        or the maximaum available length for that algorithm and the token.
+        '''
         slot = nss.get_best_slot(mechanism)
-        return slot.key_gen(mechanism, None, slot.get_best_key_length(mechanism))
+        if size == 0:
+            size = slot.get_best_key_length(mechanism)
+        return slot.key_gen(mechanism, None, size)
+
+    def generate_session_key(self):
+        ''' Returns a session key to be used when wrapping secrets for the DRM
+        This will return a 168 bit 3DES key.
+        '''
+        return self.generate_symmetric_key(mechanism=nss.CKM_DES3_CBC_PAD)
 
     def symmetric_wrap(self, data, wrapping_key, mechanism=nss.CKM_DES3_CBC_PAD, nonce_iv=None):
         '''
diff --git a/base/common/python/pki/key.py b/base/common/python/pki/key.py
index 3fa5952dbf37acaf898c16914f5b16030c2d741a..b4158fed6a750cc00fdd01237629caf0ee40e801 100644
--- a/base/common/python/pki/key.py
+++ b/base/common/python/pki/key.py
@@ -433,7 +433,7 @@ class KeyClient(object):
         if secret is None:
             raise ValueError("secret must be specified")
 
-        session_key = self.crypto.generate_symmetric_key()
+        session_key = self.crypto.generate_session_key()
         trans_wrapped_session_key = self.crypto.asymmetric_wrap(session_key, self.transport_cert)
         wrapped_secret = self.crypto.symmetric_wrap(secret, session_key)
 
@@ -591,7 +591,7 @@ class KeyClient(object):
         to authorize the recovery.
 
         To ensure data security in transit, the data will be returned encrypted by a session
-        key (56 bit DES3 symmetric key) - which is first wrapped (encrypted) by the public
+        key (168 bit 3DES symmetric key) - which is first wrapped (encrypted) by the public
         key of the DRM transport certificate before being sent to the DRM.  The
         parameter trans_wrapped_session_key refers to this wrapped session key.
 
@@ -616,7 +616,7 @@ class KeyClient(object):
         key_provided = True
         if trans_wrapped_session_key is None:
             key_provided = False
-            session_key = self.crypto.generate_symmetric_key()
+            session_key = self.crypto.generate_session_key()
             trans_wrapped_session_key = self.crypto.asymmetric_wrap(session_key,
                                                                     self.transport_cert)
 
@@ -660,7 +660,7 @@ class KeyClient(object):
         In this case, CryptoUtil methods will be called to create the data to securely send the
         passphrase to the DRM.  Basically, three pieces of data will be sent:
 
-        - the passphrase wrapped by a 56 bit DES3 symmetric key (the session key).  This
+        - the passphrase wrapped by a 168 bit 3DES symmetric key (the session key).  This
           is referred to as the parameter session_wrapped_passphrase above.
 
         - the session key wrapped with the public key in the DRM transport certificate.  This
diff --git a/base/kra/functional/drmtest.py b/base/kra/functional/drmtest.py
index b53c5569a227bf72048a6cf754fef2357afa3d6a..dd7abbf53e37e720c002d991cd097cc02e5b8ebf 100644
--- a/base/kra/functional/drmtest.py
+++ b/base/kra/functional/drmtest.py
@@ -130,7 +130,7 @@ def main():
         print "Failure - key_ids for generation do not match!"
 
     # Test 6: Barbican_decode() - Retrieve while providing trans_wrapped_session_key
-    session_key = crypto.generate_symmetric_key()
+    session_key = crypto.generate_session_key()
     wrapped_session_key = crypto.asymmetric_wrap(session_key, keyclient.transport_cert)
     key_data, _unwrapped_key = keyclient.retrieve_key(key_id, trans_wrapped_session_key=wrapped_session_key)
     print_key_data(key_data)
-- 
1.8.4.2

