>From 53b41eddfdd72b4297816d9402f93c6a511915f1 Mon Sep 17 00:00:00 2001
From: Abhishek Koneru <akoneru@redhat.com>
Date: Thu, 24 Jul 2014 11:20:12 -0400
Subject: [PATCH] Generate asymmetric keys in the DRM.

Adds methods to key client to generate asymmetric keys using
algorithms RSA and DSA for a valid key sizes of 512, 1024, 2048,4096.
The generated keys are archived in the database.
Uisng the CLI, the public key(base64 encoded) can be retrieved by using
the key-show command.
The private key(base64 encoded) can be retrieved using the key-retrieve
command.

Ticket #1023
---
 base/common/python/pki/key.py                      | 114 +++++++++--
 .../com/netscape/certsrv/base/ResourceMessage.java |   8 +-
 .../certsrv/key/AsymKeyGenerationRequest.java      | 115 +++++++++++
 .../src/com/netscape/certsrv/key/KeyClient.java    |  76 +++++++-
 .../netscape/certsrv/key/KeyGenerationRequest.java | 125 ++++++++++++
 .../src/com/netscape/certsrv/key/KeyInfo.java      |  11 ++
 .../netscape/certsrv/key/KeyRequestResource.java   |   9 +-
 .../certsrv/key/SymKeyGenerationRequest.java       |  83 +-------
 .../src/com/netscape/certsrv/request/IRequest.java |  12 +-
 .../src/com/netscape/cmstools/key/KeyCLI.java      |  12 ++
 .../com/netscape/cmstools/key/KeyGenerateCLI.java  |  47 ++++-
 base/kra/functional/drmtest.py                     |  28 ++-
 .../src/com/netscape/cms/servlet/test/DRMTest.java | 102 +++++++++-
 base/kra/shared/conf/CS.cfg.in                     |   3 +
 .../src/com/netscape/kra/AsymKeyGenService.java    | 216 +++++++++++++++++++++
 base/kra/src/com/netscape/kra/EncryptionUnit.java  |  16 +-
 .../src/com/netscape/kra/EnrollmentService.java    |   4 +-
 base/kra/src/com/netscape/kra/KRAService.java      |   2 +
 .../netscape/kra/SecurityDataRecoveryService.java  |  79 +++++---
 .../src/com/netscape/kra/SecurityDataService.java  |   2 +-
 .../kra/src/com/netscape/kra/SymKeyGenService.java |   9 +-
 .../server/kra/rest/KeyRequestService.java         |  44 ++++-
 .../org/dogtagpki/server/kra/rest/KeyService.java  |  15 +-
 .../netscape/cms/servlet/key/KeyRequestDAO.java    | 116 +++++++++--
 base/server/cmsbundle/src/LogMessages.properties   |   9 +
 25 files changed, 1083 insertions(+), 174 deletions(-)
 create mode 100644 base/common/src/com/netscape/certsrv/key/AsymKeyGenerationRequest.java
 create mode 100644 base/common/src/com/netscape/certsrv/key/KeyGenerationRequest.java
 create mode 100644 base/kra/src/com/netscape/kra/AsymKeyGenService.java

diff --git a/base/common/python/pki/key.py b/base/common/python/pki/key.py
index af34a7ff42ffe288f9b1f2767989bfc2b383343d..8d52fc454588b3c40c5ecc153d4d21b6b50044b5 100644
--- a/base/common/python/pki/key.py
+++ b/base/common/python/pki/key.py
@@ -105,7 +105,7 @@ class KeyInfo(object):
 
     json_attribute_names = {
         'clientKeyID': 'client_key_id', 'keyURL': 'key_url',
-        'ownerName': 'owner_name'
+        'ownerName': 'owner_name', 'publicKey': 'public_key'
     }
 
     # pylint: disable-msg=C0103
@@ -117,6 +117,7 @@ class KeyInfo(object):
         self.status = None
         self.owner_name = None
         self.size = None
+        self.public_key = None
 
     @classmethod
     def from_json(cls, attr_list):
@@ -339,7 +340,7 @@ class KeyRecoveryRequest(pki.ResourceMessage):
 class SymKeyGenerationRequest(pki.ResourceMessage):
     """
     Class representing the data sent to the DRM when generating and archiving
-    a symmetric key on the DRM.
+    a symmetric key in the DRM.
     """
 
     UNWRAP_USAGE = "unwrap"
@@ -363,6 +364,36 @@ class SymKeyGenerationRequest(pki.ResourceMessage):
         self.add_attribute("transWrappedSessionKey", trans_wrapped_session_key)
 
 
+class AsymKeyGenerationRequest(pki.ResourceMessage):
+
+    """
+    Class representing the data sent to the DRM when generating and archiving
+    asymmetric keys in the DRM.
+    """
+    UNWRAP_USAGE = "unwrap"
+    WRAP_USAGE = "wrap"
+    VERIFY_USAGE = "verify"
+    VERIFY_RECOVER_USAGE = "verify_recover"
+    SIGN_USAGE = "sign"
+    SIGN_RECOVER_USAGE = "sign_recover"
+    DECRYPT_USAGE = "decrypt"
+    ENCRYPT_USAGE = "encrypt"
+    DERIVE_USAGE = "derive"
+
+    def __init__(self, client_key_id=None, key_size=None, key_algorithm=None,
+                 key_usages=None, trans_wrapped_session_key=None):
+        """ Constructor """
+        pki.ResourceMessage.__init__(
+            self,
+            "com.netscape.certsrv.key.AsymKeyGenerationRequest")
+        key_usages = key_usages or []
+        self.add_attribute("clientKeyID", client_key_id)
+        self.add_attribute("keySize", key_size)
+        self.add_attribute("keyAlgorithm", key_algorithm)
+        self.add_attribute("keyUsage", ','.join(key_usages))
+        self.add_attribute("transWrappedSessionKey", trans_wrapped_session_key)
+
+
 class KeyClient(object):
     """
     Class that encapsulates and mirrors the functions in the KeyResource
@@ -383,6 +414,10 @@ class KeyClient(object):
     RC4_ALGORITHM = "RC4"
     AES_ALGORITHM = "AES"
 
+    # Asymmetric Key Algorithms
+    RSA_ALGORITHM = "RSA"
+    DSA_ALGORITHM = "DSA"
+
     #default session key wrapping algorithm
     DES_EDE3_CBC_OID = "{1 2 840 113549 3 7}"
 
@@ -509,12 +544,13 @@ class KeyClient(object):
         self.connection.post(url, None, self.headers)
 
     @pki.handle_exceptions()
-    def create_request(self, request):
+    def submit_request(self, request):
         """ Submit an archival, recovery or key generation request
             to the DRM.
 
             @param request - is either a KeyArchivalRequest,
-            KeyRecoverRequest or SymKeyGenerationRequest.
+            KeyRecoverRequest, SymKeyGenerationRequest or
+            AsymKeyGenerationRequest.
 
             returns a KeyRequestResponse object.
         """
@@ -558,7 +594,57 @@ class KeyClient(object):
                 key_size=size,
                 key_algorithm=algorithm,
                 key_usages=usages)
-        return self.create_request(request)
+        return self.submit_request(request)
+
+    @pki.handle_exceptions()
+    def generate_asymmetric_key(self, client_key_id, algorithm=None,
+                                key_size=None, usages=None,
+                                trans_wrapped_session_key=None):
+        """ Generate and archive asymmetric keys in the DRM.
+            Supports algorithms RSA and DSA.
+            Valid key size for RSA = 256 + (16 * n), where n: 0-496
+            Valid key size for DSA = 512, 768, 1024. p,q,g params are not
+            supported.
+
+            Return a KeyRequestResponse which contains a KeyRequestInfo
+            object that describes the URL for the request and generated keys.
+
+        """
+        if client_key_id is None:
+            raise TypeError("Must specify Client Key ID")
+
+        if str(algorithm).upper() not in \
+                [self.RSA_ALGORITHM, self.DSA_ALGORITHM]:
+            raise TypeError("Only RSA and DSA algorithms are supported.")
+
+        # For generating keys using the RSA algorithm, the valid range of key
+        # sizes is:
+        #         256 + 16 * n, where 0 <= n <= 1008
+        # When using DSA, the current supported values are 512, 768, 1024
+
+        if algorithm == self.RSA_ALGORITHM:
+            if key_size < 256:
+                raise ValueError("Invalid key size specified.")
+            if ((key_size-256) % 16) != 0:
+                raise ValueError("Invalid key size specified.")
+        if algorithm == self.DSA_ALGORITHM:
+            if key_size not in [512, 768, 1024]:
+                raise ValueError("Invalid key size specified.")
+
+        if trans_wrapped_session_key is not None:
+            raise NotImplementedError(
+                "Returning the asymmetric keys in the same call is not yet "
+                "implemented.")
+
+        request = AsymKeyGenerationRequest(
+            client_key_id=client_key_id,
+            key_size=key_size,
+            key_algorithm=algorithm,
+            key_usages=usages,
+            trans_wrapped_session_key=trans_wrapped_session_key
+        )
+
+        return self.submit_request(request)
 
     @pki.handle_exceptions()
     def archive_key(self, client_key_id, data_type, private_data,
@@ -666,7 +752,7 @@ class KeyClient(object):
                                      key_algorithm=key_algorithm,
                                      key_size=key_size)
 
-        return self.create_request(request)
+        return self.submit_request(request)
 
     @pki.handle_exceptions()
     def archive_pki_options(self, client_key_id, data_type, pki_archive_options,
@@ -701,7 +787,7 @@ class KeyClient(object):
                                      pki_archive_options=data,
                                      key_algorithm=key_algorithm,
                                      key_size=key_size)
-        return self.create_request(request)
+        return self.submit_request(request)
 
     @pki.handle_exceptions()
     def recover_key(self, key_id, request_id=None,
@@ -729,7 +815,7 @@ class KeyClient(object):
             session_wrapped_passphrase=session_wrapped_passphrase,
             certificate=b64certificate,
             nonce_data=nonce_data)
-        return self.create_request(request)
+        return self.submit_request(request)
 
     @pki.handle_exceptions()
     def retrieve_key_data(self, data):
@@ -770,9 +856,10 @@ class KeyClient(object):
 
         1) trans_wrapped_session_key is not provided by caller.
 
-        In this case, the function will call CryptoProvider methods to generate and
-        wrap the session key.  The function will return the KeyData object with
-        a private_data attribute which stores the unwrapped key information.
+        In this case, the function will call CryptoProvider methods to generate
+        and wrap the session key.  The function will return the KeyData object
+        with a private_data attribute which stores the unwrapped key
+        information.
 
         2)  The trans_wrapped_session_key is provided by the caller.
 
@@ -833,8 +920,8 @@ class KeyClient(object):
 
         1) A passphrase is provided by the caller.
 
-        In this case, CryptoProvider methods will be called to create the data to
-        securely send the passphrase to the DRM.  Basically, three pieces of
+        In this case, CryptoProvider 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 168 bit 3DES symmetric key (the session
@@ -894,6 +981,7 @@ encoder.NOTYPES['KeyArchivalRequest'] = KeyArchivalRequest
 encoder.NOTYPES['KeyRecoveryRequest'] = KeyRecoveryRequest
 encoder.NOTYPES['ResourceMessage'] = pki.ResourceMessage
 encoder.NOTYPES['SymKeyGenerationRequest'] = SymKeyGenerationRequest
+encoder.NOTYPES['AsymKeyGenerationRequest'] = AsymKeyGenerationRequest
 
 
 def main():
diff --git a/base/common/src/com/netscape/certsrv/base/ResourceMessage.java b/base/common/src/com/netscape/certsrv/base/ResourceMessage.java
index 34d7c2b11dc70efea03a96dac00bab02e48f580a..1214b45fbf59341f4c515116071361835c59a119 100644
--- a/base/common/src/com/netscape/certsrv/base/ResourceMessage.java
+++ b/base/common/src/com/netscape/certsrv/base/ResourceMessage.java
@@ -26,6 +26,7 @@ import javax.xml.bind.annotation.XmlValue;
 import javax.xml.bind.annotation.adapters.XmlAdapter;
 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
 
+import com.netscape.certsrv.key.AsymKeyGenerationRequest;
 import com.netscape.certsrv.key.KeyArchivalRequest;
 import com.netscape.certsrv.key.KeyRecoveryRequest;
 import com.netscape.certsrv.key.SymKeyGenerationRequest;
@@ -33,8 +34,9 @@ import com.netscape.certsrv.key.SymKeyGenerationRequest;
 /**
  * @author Ade Lee
  */
-@XmlRootElement(name="ResourceMessage")
-@XmlSeeAlso({KeyArchivalRequest.class, KeyRecoveryRequest.class, SymKeyGenerationRequest.class, PKIException.Data.class})
+@XmlRootElement(name = "ResourceMessage")
+@XmlSeeAlso({ KeyArchivalRequest.class, KeyRecoveryRequest.class, SymKeyGenerationRequest.class,
+        PKIException.Data.class, AsymKeyGenerationRequest.class })
 @XmlAccessorType(XmlAccessType.NONE)
 public class ResourceMessage {
 
@@ -46,7 +48,7 @@ public class ResourceMessage {
     }
 
     public ResourceMessage(MultivaluedMap<String, String> form) {
-        for (Map.Entry<String, List<String>> entry: form.entrySet()) {
+        for (Map.Entry<String, List<String>> entry : form.entrySet()) {
             attributes.put(entry.getKey(), entry.getValue().get(0));
         }
     }
diff --git a/base/common/src/com/netscape/certsrv/key/AsymKeyGenerationRequest.java b/base/common/src/com/netscape/certsrv/key/AsymKeyGenerationRequest.java
new file mode 100644
index 0000000000000000000000000000000000000000..867c06acf64dda91f97bddec24cc17ffe4dd5f07
--- /dev/null
+++ b/base/common/src/com/netscape/certsrv/key/AsymKeyGenerationRequest.java
@@ -0,0 +1,115 @@
+//--- BEGIN COPYRIGHT BLOCK ---
+//This program is free software; you can redistribute it and/or modify
+//it under the terms of the GNU General Public License as published by
+//the Free Software Foundation; version 2 of the License.
+//
+//This program is distributed in the hope that it will be useful,
+//but WITHOUT ANY WARRANTY; without even the implied warranty of
+//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//GNU General Public License for more details.
+//
+//You should have received a copy of the GNU General Public License along
+//with this program; if not, write to the Free Software Foundation, Inc.,
+//51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+//(C) 2014 Red Hat, Inc.
+//All rights reserved.
+//--- END COPYRIGHT BLOCK ---
+package com.netscape.certsrv.key;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.ws.rs.core.MultivaluedMap;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.apache.commons.lang.StringUtils;
+
+import com.netscape.certsrv.base.ResourceMessage;
+
+@XmlRootElement(name = "AsymKeyGenerationRequest")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class AsymKeyGenerationRequest extends KeyGenerationRequest {
+
+    // Asymmetric Key Usages
+    public static final String ENCRYPT = "encrypt";
+    public static final String DECRYPT = "decrypt";
+    public static final String SIGN = "sign";
+    public static final String SIGN_RECOVER = "sign_recover";
+    public static final String VERIFY = "verify";
+    public static final String VERIFY_RECOVER = "verify_recover";
+    public static final String WRAP = "wrap";
+    public static final String UNWRAP = "unwrap";
+    public static final String DERIVE = "derive";
+
+    public AsymKeyGenerationRequest() {
+        // required for JAXB (defaults)
+        setClassName(getClass().getName());
+    }
+
+    public AsymKeyGenerationRequest(MultivaluedMap<String, String> form) {
+        attributes.put(CLIENT_KEY_ID, form.getFirst(CLIENT_KEY_ID));
+        attributes.put(KEY_SIZE, form.getFirst(KEY_SIZE));
+        attributes.put(KEY_ALGORITHM, form.getFirst(KEY_ALGORITHM));
+        attributes.put(KEY_USAGE, form.getFirst(KEY_USAGE));
+        attributes.put(TRANS_WRAPPED_SESSION_KEY, form.getFirst(TRANS_WRAPPED_SESSION_KEY));
+
+        String usageString = attributes.get(KEY_USAGE);
+        if (!StringUtils.isBlank(usageString)) {
+            setUsages(new ArrayList<String>(Arrays.asList(usageString.split(","))));
+        }
+        setClassName(getClass().getName());
+    }
+
+    public AsymKeyGenerationRequest(ResourceMessage data) {
+        attributes.putAll(data.getAttributes());
+        setClassName(getClass().getName());
+    }
+
+    public String toString() {
+        try {
+            return ResourceMessage.marshal(this, AsymKeyGenerationRequest.class);
+        } catch (Exception e) {
+            return super.toString();
+        }
+    }
+
+    public static AsymKeyGenerationRequest valueOf(String string) throws Exception {
+        try {
+            return ResourceMessage.unmarshal(string, AsymKeyGenerationRequest.class);
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    public static List<String> getValidUsagesList() {
+        List<String> list = new ArrayList<String>();
+        list.add(DERIVE);
+        list.add(SIGN);
+        list.add(DECRYPT);
+        list.add(ENCRYPT);
+        list.add(WRAP);
+        list.add(UNWRAP);
+        list.add(SIGN_RECOVER);
+        list.add(VERIFY);
+        list.add(VERIFY_RECOVER);
+
+        return list;
+    }
+
+    public static void main(String[] args) {
+        AsymKeyGenerationRequest request = new AsymKeyGenerationRequest();
+        request.setKeyAlgorithm(KeyRequestResource.RSA_ALGORITHM);
+        request.setKeySize(1024);
+        request.setClientKeyId("vek12345");
+        List<String> usages = new ArrayList<String>();
+        usages.add(AsymKeyGenerationRequest.ENCRYPT);
+        usages.add(AsymKeyGenerationRequest.DECRYPT);
+        request.setUsages(usages);
+
+        System.out.println(request.toString());
+    }
+}
diff --git a/base/common/src/com/netscape/certsrv/key/KeyClient.java b/base/common/src/com/netscape/certsrv/key/KeyClient.java
index 9363a6a8cfe121d4e80496bbd762ecfd866bea91..262a33d8f0274723c04b6188821b12cb0fd6a596 100644
--- a/base/common/src/com/netscape/certsrv/key/KeyClient.java
+++ b/base/common/src/com/netscape/certsrv/key/KeyClient.java
@@ -249,11 +249,11 @@ public class KeyClient extends Client {
      * @param data -- A KeyArchivalRequest/KeyRecoveryRequest/SymKeyGenerationRequest object
      * @return A KeyRequestResponse object
      */
-    private KeyRequestResponse createRequest(ResourceMessage request) {
+    private KeyRequestResponse submitRequest(ResourceMessage request) {
         if (request == null) {
             throw new IllegalArgumentException("A Request object must be specified.");
         }
-        Response response = keyRequestClient.createRequest(request);
+        Response response = keyRequestClient.submitRequest(request);
         return client.getEntity(response, KeyRequestResponse.class);
     }
 
@@ -296,7 +296,7 @@ public class KeyClient extends Client {
             data.setCertificate(b64Certificate);
         }
 
-        return createRequest(data);
+        return submitRequest(data);
     }
 
     /**
@@ -612,7 +612,7 @@ public class KeyClient extends Client {
         data.setWrappedPrivateData(req1);
         data.setTransWrappedSessionKey(Utils.base64encode(transWrappedSessionKey));
 
-        return createRequest(data);
+        return submitRequest(data);
     }
 
     /**
@@ -653,15 +653,15 @@ public class KeyClient extends Client {
         String options = Utils.base64encode(pkiArchiveOptions);
         data.setPKIArchiveOptions(options);
 
-        return createRequest(data);
+        return submitRequest(data);
     }
 
     /**
-     * Generate and archive a symmetric key on the DRM.
+     * Generate and archive a symmetric key in the DRM.
      *
      * @param clientKeyId -- Client Key Identifier
      * @param keyAlgorithm -- Algorithm to be used to generate the key
-     * @param keySize -- Strength of the algorithm
+     * @param keySize -- Strength of the keys
      * @param usages -- Usages of the generated key.
      * @return a KeyRequestResponse which contains a KeyRequestInfo
      *         object that describes the URL for the request and generated key.
@@ -687,6 +687,66 @@ public class KeyClient extends Client {
         data.setUsages(usages);
         data.setTransWrappedSessionKey(transWrappedSessionKey);
 
-        return createRequest(data);
+        return submitRequest(data);
+    }
+
+    /**
+     * Generate and archive an asymmetric keys in the DRM
+     *
+     * @param clientKeyId -- Client Key Identifier
+     * @param keyAlgorithm -- Algorithm to be used to generate the asymmetric keys
+     * @param keySize -- Strength of the keys
+     * @param usages
+     * @param transWrappedSessionKey
+     * @return
+     */
+    public KeyRequestResponse generateAsymmetricKey(String clientKeyId, String keyAlgorithm, int keySize,
+            List<String> usages, byte[] transWrappedSessionKey) {
+
+        if (clientKeyId == null) {
+            throw new IllegalArgumentException("Client Key Identifier must be specified.");
+        }
+
+        //Validate the usages list
+        List<String> validUsages = AsymKeyGenerationRequest.getValidUsagesList();
+        if (usages != null) {
+            for (String usage : usages) {
+                if (!validUsages.contains(usage)) {
+                    throw new IllegalArgumentException("Invalid usage \"" + usage + "\" specified.");
+                }
+            }
+        }
+        if (!(keyAlgorithm.equals(KeyRequestResource.RSA_ALGORITHM) || keyAlgorithm
+                .equals(KeyRequestResource.DSA_ALGORITHM))) {
+            throw new IllegalArgumentException("Unsupported algorithm specified.");
+        }
+
+        /*
+         * For RSA, JSS accepts key sizes that fall in this set of values:
+         * {256 + (16 * n), where 0 <= n <= 1008
+         *
+         * For DSA, JSS accepts key sizes 512, 768, 1024 only when there are no p,q,g params specified.
+         */
+        if (keyAlgorithm.equals(KeyRequestResource.RSA_ALGORITHM)) {
+            if (keySize >= 256) {
+                if ((keySize - 256) % 16 != 0) {
+                    throw new IllegalArgumentException("Invalid key size specified.");
+                }
+            } else {
+                throw new IllegalArgumentException("Invalid key size specified.");
+            }
+        } else if (keyAlgorithm.equals(KeyRequestResource.DSA_ALGORITHM)) {
+            if (keySize != 512 && keySize != 768 && keySize != 1024) {
+                throw new IllegalArgumentException("Invalid key size specified.");
+            }
+        }
+        AsymKeyGenerationRequest data = new AsymKeyGenerationRequest();
+        data.setClientKeyId(clientKeyId);
+        data.setKeyAlgorithm(keyAlgorithm);
+        data.setKeySize(keySize);
+        data.setUsages(usages);
+        data.setTransWrappedSessionKey(Utils.base64encode(transWrappedSessionKey));
+
+        return submitRequest(data);
     }
 }
diff --git a/base/common/src/com/netscape/certsrv/key/KeyGenerationRequest.java b/base/common/src/com/netscape/certsrv/key/KeyGenerationRequest.java
new file mode 100644
index 0000000000000000000000000000000000000000..ed36b6d9dbfdece3922d9ca6647a06fb4cc56d8c
--- /dev/null
+++ b/base/common/src/com/netscape/certsrv/key/KeyGenerationRequest.java
@@ -0,0 +1,125 @@
+//--- BEGIN COPYRIGHT BLOCK ---
+//This program is free software; you can redistribute it and/or modify
+//it under the terms of the GNU General Public License as published by
+//the Free Software Foundation; version 2 of the License.
+//
+//This program is distributed in the hope that it will be useful,
+//but WITHOUT ANY WARRANTY; without even the implied warranty of
+//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//GNU General Public License for more details.
+//
+//You should have received a copy of the GNU General Public License along
+//with this program; if not, write to the Free Software Foundation, Inc.,
+//51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+//(C) 2014 Red Hat, Inc.
+//All rights reserved.
+//--- END COPYRIGHT BLOCK ---
+package com.netscape.certsrv.key;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.commons.lang.StringUtils;
+
+import com.netscape.certsrv.base.ResourceMessage;
+
+/**
+ * Class to define the common attributes and methods used by
+ * SymKeyGenerationRequest and AsymKeyGenerationRequest
+ * @author akoneru
+ *
+ */
+public class KeyGenerationRequest extends ResourceMessage{
+
+    protected static final String CLIENT_KEY_ID = "clientKeyID";
+    protected static final String KEY_SIZE = "keySize";
+    protected static final String KEY_ALGORITHM = "keyAlgorithm";
+    protected static final String KEY_USAGE = "keyUsage";
+    protected static final String TRANS_WRAPPED_SESSION_KEY = "transWrappedSessionKey";
+
+
+    public List<String> getUsages() {
+        String usageString = attributes.get(KEY_USAGE);
+        if (!StringUtils.isBlank(usageString)) {
+            return new ArrayList<String>(Arrays.asList(usageString.split(",")));
+        }
+        return new ArrayList<String>();
+    }
+
+    public void setUsages(List<String> usages) {
+        attributes.put(KEY_USAGE, StringUtils.join(usages, ","));
+    }
+
+    public void addUsage(String usage) {
+        List<String> usages = getUsages();
+        for (String u : usages) {
+            if (u.equals(usage))
+                return;
+        }
+        usages.add(usage);
+        setUsages(usages);
+    }
+
+    /**
+     * @return the clientKeyId
+     */
+    public String getClientKeyId() {
+        return attributes.get(CLIENT_KEY_ID);
+    }
+
+    /**
+     * @param clientKeyId the clientKeyId to set
+     */
+    public void setClientKeyId(String clientKeyId) {
+        attributes.put(CLIENT_KEY_ID, clientKeyId);
+    }
+
+    /**
+     * @return the keySize
+     */
+    public Integer getKeySize() {
+        try {
+            return new Integer(attributes.get(KEY_SIZE));
+        } catch (NumberFormatException e) {
+            return null;
+        }
+    }
+
+    /**
+     * @param keySize the key size to set
+     */
+    public void setKeySize(Integer keySize) {
+        attributes.put(KEY_SIZE, keySize.toString());
+    }
+
+    /**
+     * @return the keyAlgorithm
+     */
+    public String getKeyAlgorithm() {
+        return attributes.get(KEY_ALGORITHM);
+    }
+
+    /**
+     * @param keyAlgorithm the key algorithm to set
+     */
+    public void setKeyAlgorithm(String keyAlgorithm) {
+        attributes.put(KEY_ALGORITHM, keyAlgorithm);
+    }
+
+    /**
+     * @return the transWrappedSessionKey
+     */
+    public String getTransWrappedSessionKey() {
+        return attributes.get(TRANS_WRAPPED_SESSION_KEY);
+    }
+
+    /**
+     * @param transWrappedSessionKey the wrapped seesion key to set
+     */
+    public void setTransWrappedSessionKey(String transWrappedSessionKey) {
+        attributes.put(TRANS_WRAPPED_SESSION_KEY, transWrappedSessionKey);
+    }
+
+}
diff --git a/base/common/src/com/netscape/certsrv/key/KeyInfo.java b/base/common/src/com/netscape/certsrv/key/KeyInfo.java
index 10da545d8a9bf421f27f6886fc0140073ecadd0b..71a858e6b3350f5e9891602a47464e027481198c 100644
--- a/base/common/src/com/netscape/certsrv/key/KeyInfo.java
+++ b/base/common/src/com/netscape/certsrv/key/KeyInfo.java
@@ -54,6 +54,9 @@ public class KeyInfo {
     @XmlElement
     protected String ownerName;
 
+    @XmlElement
+    protected String publicKey;
+
     public KeyInfo() {
         // required for JAXB (defaults)
     }
@@ -125,4 +128,12 @@ public class KeyInfo {
     public void setOwnerName(String ownerName) {
         this.ownerName = ownerName;
     }
+
+    public String getPublicKey() {
+        return publicKey;
+    }
+
+    public void setPublicKey(String publicKey) {
+        this.publicKey = publicKey;
+    }
 }
diff --git a/base/common/src/com/netscape/certsrv/key/KeyRequestResource.java b/base/common/src/com/netscape/certsrv/key/KeyRequestResource.java
index fb82afe19bbe7bf774f45f96da7c1c8b0dc3cc89..768127e42eb0b96b0c199d03ba3013b0510136cd 100644
--- a/base/common/src/com/netscape/certsrv/key/KeyRequestResource.java
+++ b/base/common/src/com/netscape/certsrv/key/KeyRequestResource.java
@@ -35,6 +35,11 @@ public interface KeyRequestResource {
     public static final String RC4_ALGORITHM = "RC4";
     public static final String AES_ALGORITHM = "AES";
 
+    // Asymmetric Key algorithms
+    public final static String RSA_ALGORITHM = "RSA";
+    public final static String DSA_ALGORITHM = "DSA";
+    public final static String EC_ALGORITHM = "EC"; // Not supported yet.
+
     /**
      * Used to generate list of key requests based on the search parameters
      */
@@ -51,11 +56,11 @@ public interface KeyRequestResource {
     @POST
     @ClientResponseType(entityType=KeyRequestResponse.class)
     @Consumes({ MediaType.APPLICATION_FORM_URLENCODED})
-    public Response createRequest(MultivaluedMap<String, String> form);
+    public Response submitRequest(MultivaluedMap<String, String> form);
 
     @POST
     @ClientResponseType(entityType=KeyRequestResponse.class)
-    public Response createRequest(ResourceMessage data);
+    public Response submitRequest(ResourceMessage data);
 
     /**
      * Used to retrieve key request info for a specific request
diff --git a/base/common/src/com/netscape/certsrv/key/SymKeyGenerationRequest.java b/base/common/src/com/netscape/certsrv/key/SymKeyGenerationRequest.java
index a2440d7cbab7038628133f91426d5df4f650b1d1..7f65d0e59c1f8facf1e270ca12d1fe56adc9e063 100644
--- a/base/common/src/com/netscape/certsrv/key/SymKeyGenerationRequest.java
+++ b/base/common/src/com/netscape/certsrv/key/SymKeyGenerationRequest.java
@@ -19,13 +19,7 @@ import com.netscape.certsrv.base.ResourceMessage;
  */
 @XmlRootElement(name = "SymKeyGenerationRequest")
 @XmlAccessorType(XmlAccessType.FIELD)
-public class SymKeyGenerationRequest extends ResourceMessage {
-
-    private static final String CLIENT_KEY_ID = "clientKeyID";
-    private static final String KEY_SIZE = "keySize";
-    private static final String KEY_ALGORITHM = "keyAlgorithm";
-    private static final String KEY_USAGE = "keyUsage";
-    private static final String TRANS_WRAPPED_SESSION_KEY = "transWrappedSessionKey";
+public class SymKeyGenerationRequest extends KeyGenerationRequest {
 
     /* Symmetric Key usages */
     public static final String UWRAP_USAGE = "unwrap";
@@ -35,28 +29,6 @@ public class SymKeyGenerationRequest extends ResourceMessage {
     public static final String DECRYPT_USAGE = "decrypt";
     public static final String ENCRYPT_USAGE = "encrypt";
 
-    public List<String> getUsages() {
-        String usageString = attributes.get(KEY_USAGE);
-        if (!StringUtils.isBlank(usageString)) {
-            return new ArrayList<String>(Arrays.asList(usageString.split(",")));
-        }
-        return new ArrayList<String>();
-    }
-
-    public void setUsages(List<String> usages) {
-        attributes.put(KEY_USAGE, StringUtils.join(usages, ","));
-    }
-
-    public void addUsage(String usage) {
-        List<String> usages = getUsages();
-        for (String u : usages) {
-            if (u.equals(usage))
-                return;
-        }
-        usages.add(usage);
-        setUsages(usages);
-    }
-
     public SymKeyGenerationRequest() {
         // required for JAXB (defaults)
         setClassName(getClass().getName());
@@ -82,59 +54,6 @@ public class SymKeyGenerationRequest extends ResourceMessage {
     }
 
     /**
-     * @return the clientKeyId
-     */
-    public String getClientKeyId() {
-        return attributes.get(CLIENT_KEY_ID);
-    }
-
-    /**
-     * @param clientKeyId the clientKeyId to set
-     */
-    public void setClientKeyId(String clientKeyId) {
-        attributes.put(CLIENT_KEY_ID, clientKeyId);
-    }
-
-    /**
-     * @return the keySize
-     */
-    public Integer getKeySize() {
-        try {
-            return new Integer(attributes.get(KEY_SIZE));
-        } catch (NumberFormatException e) {
-            return null;
-        }
-    }
-
-    /**
-     * @param keySize the key size to set
-     */
-    public void setKeySize(Integer keySize) {
-        attributes.put(KEY_SIZE, keySize.toString());
-    }
-
-    /**
-     * @return the keyAlgorithm
-     */
-    public String getKeyAlgorithm() {
-        return attributes.get(KEY_ALGORITHM);
-    }
-
-    /**
-     * @param keyAlgorithm the key algorithm to set
-     */
-    public void setKeyAlgorithm(String keyAlgorithm) {
-        attributes.put(KEY_ALGORITHM, keyAlgorithm);
-    }
-
-    /**
-     * @return the transWrappedSessionKey
-     */
-    public String getTransWrappedSessionKey() {
-        return attributes.get(TRANS_WRAPPED_SESSION_KEY);
-    }
-
-    /**
      * @param transWrappedSessionKey the wrapped seesion key to set
      */
     public void setTransWrappedSessionKey(String transWrappedSessionKey) {
diff --git a/base/common/src/com/netscape/certsrv/request/IRequest.java b/base/common/src/com/netscape/certsrv/request/IRequest.java
index 885cb72a60b8b276973bddcfc347e1dd06f97beb..8d4ec98fbd8f8703b4792668530d530bd00f072c 100644
--- a/base/common/src/com/netscape/certsrv/request/IRequest.java
+++ b/base/common/src/com/netscape/certsrv/request/IRequest.java
@@ -169,12 +169,14 @@ public interface IRequest extends Serializable {
     public static final String SECURITY_DATA_SESS_WRAPPED_DATA = "sessWrappedSecData";
     public static final String SECURITY_DATA_PASS_WRAPPED_DATA = "passPhraseWrappedData";
 
-    // symkey generation request attributes
+    // key generation request attributes
+    public static final String ASYMKEY_GENERATION_REQUEST = "asymkeyGenRequest";
     public static final String SYMKEY_GENERATION_REQUEST = "symkeyGenRequest";
-    public static final String SYMKEY_GEN_ALGORITHM = "symkeyGenAlgorithm";
-    public static final String SYMKEY_GEN_SIZE = "symkeyGenSize";
-    public static final String SYMKEY_GEN_USAGES = "symkeyGenUsages";
-    public static final String SYMKEY_TRANS_WRAPPED_SESSION_KEY = "transWrappedSessionKey";
+
+    public static final String KEY_GEN_ALGORITHM = "keyGenAlgorithm";
+    public static final String KEY_GEN_SIZE = "keyGenSize";
+    public static final String KEY_GEN_USAGES = "keyGenUsages";
+    public static final String KEY_GEN_TRANS_WRAPPED_SESSION_KEY = "transWrappedSessionKey";
 
     // requestor type values.
     public static final String REQUESTOR_EE = "EE";
diff --git a/base/java-tools/src/com/netscape/cmstools/key/KeyCLI.java b/base/java-tools/src/com/netscape/cmstools/key/KeyCLI.java
index 1b8ae64b552a22072c1c39a37c77afcbacdb97da..82235d278236a30485325bab766e33e6ca2a309d 100644
--- a/base/java-tools/src/com/netscape/cmstools/key/KeyCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/key/KeyCLI.java
@@ -93,6 +93,18 @@ public class KeyCLI extends CLI {
         if (info.getAlgorithm() != null) System.out.println("  Algorithm: "+info.getAlgorithm());
         if (info.getSize() != null) System.out.println("  Size: "+info.getSize());
         if (info.getOwnerName() != null) System.out.println("  Owner: "+info.getOwnerName());
+        if (info.getPublicKey() != null) {
+            // Print out the Base64 encoded public key in the form of a blob,
+            // where the max line length is 64.
+            System.out.println("  Public Key: \n");
+            String publicKey = info.getPublicKey();
+            int i = 0;
+            for(i=0;i<publicKey.length()/64;i++){
+                System.out.println(publicKey.substring(i*64, i*64 + 64));
+            }
+            System.out.println(publicKey.substring(i*64));
+            System.out.println();
+        }
     }
 
     public static void printKeyRequestInfo(KeyRequestInfo info) {
diff --git a/base/java-tools/src/com/netscape/cmstools/key/KeyGenerateCLI.java b/base/java-tools/src/com/netscape/cmstools/key/KeyGenerateCLI.java
index a551d61f3f1248b9cb79a009f23af0cf89746cce..c8608731e7c6bef66174f5fb0012df9fd89cf82b 100644
--- a/base/java-tools/src/com/netscape/cmstools/key/KeyGenerateCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/key/KeyGenerateCLI.java
@@ -28,7 +28,7 @@ public class KeyGenerateCLI extends CLI {
 
     public void createOptions() {
         Option option = new Option(null, "key-algorithm", true,
-                "Algorithm to be used to create a key.\nValid values: AES, DES, DES3, RC2, RC4, DESede.");
+                "Algorithm to be used to create a key.\nValid values: AES, DES, DES3, RC2, RC4, DESede, RSA, DSA");
         option.setArgName("algorithm");
         option.setRequired(true);
         options.addOption(option);
@@ -38,12 +38,14 @@ public class KeyGenerateCLI extends CLI {
                 "key-size",
                 true,
                 "Size of the key to be generated.\nThis is required for AES, RC2 and RC4.\n"
-                        + "Valid values for AES: 128, 192. 256.\nValid values for RC2: 8-128.\n Valid values for RC4: Any positive integer.");
+                        + "Valid values for AES: 128, 192. 256.\nValid values for RC2: 8-128.\n Valid values for RC4: Any positive integer."
+                        + "\n Valid values for DSA: 512, 768, 1024.\nValid values for RSA: 256 + (16*n), n= [0-496]");
         option.setArgName("size");
         options.addOption(option);
 
         option = new Option(null, "usages", true, "Comma separated list of usages."
-                + "\nValid values: wrap, unwrap, sign, verify, encrypt, decrypt.");
+                + "\nValid values: wrap, unwrap, sign, verify, encrypt, decrypt."
+                + "\nAdditional usages for RSA and DSA type keys: derive, sign_recover, verify_recover.");
         option.setArgName("list of usages");
         options.addOption(option);
     }
@@ -91,6 +93,8 @@ public class KeyGenerateCLI extends CLI {
             case KeyRequestResource.RC4_ALGORITHM:
             case KeyRequestResource.AES_ALGORITHM:
             case KeyRequestResource.RC2_ALGORITHM:
+            case KeyRequestResource.RSA_ALGORITHM:
+            case KeyRequestResource.DSA_ALGORITHM:
                 System.err.println("Error: Key size must be specified for the algorithm used.");
                 printHelp();
                 System.exit(-1);
@@ -100,16 +104,45 @@ public class KeyGenerateCLI extends CLI {
                 System.exit(-1);
             }
         }
+
+        int size = 0;
+        try {
+            size = Integer.parseInt(keySize);
+        } catch (NumberFormatException e) {
+            System.err.println("Error: Key size must be an integer.");
+            printHelp();
+            System.exit(-1);
+        }
         List<String> usages = null;
         String givenUsages = cmd.getOptionValue("usages");
         if (givenUsages != null) {
             usages = Arrays.asList(givenUsages.split(","));
         }
-        KeyRequestResponse response = keyCLI.keyClient.generateSymmetricKey(clientKeyId, keyAlgorithm,
-                Integer.parseInt(keySize),
-                usages, null);
-
+        KeyRequestResponse response = null;
+        switch (keyAlgorithm) {
+        case KeyRequestResource.DES3_ALGORITHM:
+        case KeyRequestResource.DESEDE_ALGORITHM:
+        case KeyRequestResource.DES_ALGORITHM:
+        case KeyRequestResource.RC4_ALGORITHM:
+        case KeyRequestResource.AES_ALGORITHM:
+        case KeyRequestResource.RC2_ALGORITHM:
+            response = keyCLI.keyClient.generateSymmetricKey(clientKeyId, keyAlgorithm,
+                    size,
+                    usages, null);
+            break;
+        case KeyRequestResource.RSA_ALGORITHM:
+        case KeyRequestResource.DSA_ALGORITHM:
+            response = keyCLI.keyClient.generateAsymmetricKey(clientKeyId, keyAlgorithm,
+                    size,
+                    usages, null);
+            break;
+        default:
+            System.err.println("Error: Algorithm not supported.");
+            printHelp();
+            System.exit(-1);
+        }
         MainCLI.printMessage("Key generation request info");
         KeyCLI.printKeyRequestInfo(response.getRequestInfo());
     }
+
 }
diff --git a/base/kra/functional/drmtest.py b/base/kra/functional/drmtest.py
index b309ce09faa5d5df4e9e759c449b7a5f589780cb..4d65955f9f109281ed0efc95e12f046bd4d3ec3f 100644
--- a/base/kra/functional/drmtest.py
+++ b/base/kra/functional/drmtest.py
@@ -57,6 +57,12 @@ def print_key_info(key_info):
     print "Status: " + str(key_info.status)
     print "Owner Name: " + str(key_info.owner_name)
     print "Size: " + str(key_info.size)
+    if key_info.public_key is not None:
+        print "Public key: "
+        print
+        pub_key = str(key_info.public_key)
+        for i in range(0, len(pub_key), 64):
+            print pub_key[i:i+64]
 
 
 def print_key_data(key_data):
@@ -81,7 +87,7 @@ def main():
     certdb_dir = "/tmp/drmtest-certdb"
     certdb_password = "redhat123"
     pki.crypto.NSSCryptoProvider.setup_database(certdb_dir, certdb_password,
-                                            over_write=True)
+                                                over_write=True)
 
     #create kraclient
     crypto = pki.crypto.NSSCryptoProvider(certdb_dir, certdb_password)
@@ -260,6 +266,26 @@ def main():
         print "Success: archived and recovered keys match"
     else:
         print "Error: archived and recovered keys do not match"
+    print
+
+    #Test 20: Generating asymmetric keys
+    print "Generating asymmetric keys"
+    try:
+        response = keyclient.generate_asymmetric_key(
+            "Vek #5" + time.strftime('%c'),
+            algorithm="RSA",
+            key_size=1024,
+            usages=None
+        )
+        print_key_request(response.request_info)
+    except pki.BadRequestException as exc:
+        print "BadRequestException thrown - Code:" + exc.code +\
+              " Message: " + exc.message
+
+    #Test 21: Get key information of the newly generated asymmetric keys
+    print "Retrieving key information"
+    key_info = keyclient.get_key_info(response.request_info.get_key_id())
+    print_key_info(key_info)
 
 if __name__ == "__main__":
     main()
diff --git a/base/kra/functional/src/com/netscape/cms/servlet/test/DRMTest.java b/base/kra/functional/src/com/netscape/cms/servlet/test/DRMTest.java
index cb80039b76d642586b0f14bcd3c756ebf67cd44c..1b96c1809101275385604df42cb18e9751ff57f8 100644
--- a/base/kra/functional/src/com/netscape/cms/servlet/test/DRMTest.java
+++ b/base/kra/functional/src/com/netscape/cms/servlet/test/DRMTest.java
@@ -17,6 +17,17 @@
 // --- END COPYRIGHT BLOCK ---
 package com.netscape.cms.servlet.test;
 
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
 import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.Iterator;
@@ -40,6 +51,7 @@ import com.netscape.certsrv.cert.CertData;
 import com.netscape.certsrv.client.ClientConfig;
 import com.netscape.certsrv.client.PKIClient;
 import com.netscape.certsrv.dbs.keydb.KeyId;
+import com.netscape.certsrv.key.AsymKeyGenerationRequest;
 import com.netscape.certsrv.key.Key;
 import com.netscape.certsrv.key.KeyClient;
 import com.netscape.certsrv.key.KeyInfo;
@@ -66,7 +78,8 @@ public class DRMTest {
         System.exit(1);
     }
 
-    public static void main(String args[]) {
+    public static void main(String args[]) throws InvalidKeyException, NoSuchAlgorithmException,
+            InvalidKeySpecException, SignatureException, IOException {
         String host = null;
         String port = null;
         String token_pwd = null;
@@ -648,6 +661,84 @@ public class DRMTest {
         } catch (ResourceNotFoundException e) {
             log("Success: ResourceNotFound exception thrown: " + e);
         }
+
+        // Test asymmetric key generation.
+
+        String[] algs = { "RSA", "DSA" };
+        for (int i = 0; i < algs.length; i++) {
+            // Test 30: Generate Asymmetric keys - RSA key
+            System.out.println("\nTesting asymmetric key generation for algorithm " + algs[i]);
+            clientKeyId = "AsymKey #" + Calendar.getInstance().getTimeInMillis();
+            usages.clear();
+            usages.add(AsymKeyGenerationRequest.SIGN);
+            usages.add(AsymKeyGenerationRequest.VERIFY);
+            KeyRequestResponse response = keyClient.generateAsymmetricKey(clientKeyId, algs[i], 1024, usages, null);
+            printRequestInfo(response.getRequestInfo());
+            System.out.println();
+
+            // Test 31: Get information of the newly generated asymmetric keys
+            System.out.println("Fetch information of the newly generated asymmetric keys.");
+            System.out.println();
+            KeyInfo info = keyClient.getKeyInfo(response.getKeyId());
+            printKeyInfo(info);
+            System.out.println();
+
+            // Test 32: Retrieve private key data
+            System.out.println("Retrieving and verifying the generated private key.");
+            try {
+                keyData = keyClient.retrieveKey(response.getKeyId());
+            } catch (Exception e) {
+                log("Exception retrieving the private key data.");
+                e.printStackTrace();
+            }
+
+            // Test 33: Verify the generated key pair.
+            if (isKeyPairValid(algs[i], keyData.getData(), Utils.base64decode(info.getPublicKey()))) {
+                log("The key pair generated using " + algs[i] + " algorithm is valid.");
+            } else {
+                log("The key pair generated using " + algs[i] + " algorithm is invalid.");
+            }
+            System.out.println();
+        }
+
+        // Test 34:
+    }
+
+    /**
+     * Verify the generated asymmetric key pair.
+     *
+     * @param keyAlgorithm - Algorithm used to generate keys.
+     * @param privateKey - binary data of the private key.
+     * @param publicKey - binary data of he public key.
+     * @return
+     * @throws NoSuchAlgorithmException
+     * @throws InvalidKeySpecException
+     * @throws InvalidKeyException
+     * @throws SignatureException
+     * @throws IOException
+     */
+    public static boolean isKeyPairValid(String keyAlgorithm, byte[] privateKey, byte[] publicKey)
+            throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, SignatureException,
+            IOException {
+        String algorithm = keyAlgorithm.toUpperCase();
+        String signingAlgorithm = "SHA1with" + algorithm;
+        KeyFactory factory = KeyFactory.getInstance(algorithm);
+        PrivateKey priKey = factory.generatePrivate(new PKCS8EncodedKeySpec(privateKey));
+        PublicKey pubKey = factory.generatePublic(new X509EncodedKeySpec(publicKey));
+        Signature sig = Signature.getInstance(signingAlgorithm);
+        sig.initSign(priKey);
+        String s = "Data to test asymmetric keys.";
+        sig.update(s.getBytes());
+
+        // Sign the data with the private key.
+        byte[] realSig = sig.sign();
+
+        Signature sig2 = Signature.getInstance(signingAlgorithm);
+        sig2.initVerify(pubKey);
+
+        sig2.update(s.getBytes());
+        // Verify the signature with the public key.
+        return sig2.verify(realSig);
     }
 
     private static void printKeyInfo(KeyInfo keyInfo) {
@@ -657,6 +748,15 @@ public class DRMTest {
         log("Algorithm: " + keyInfo.getAlgorithm());
         log("Strength:  " + keyInfo.getSize());
         log("Status:    " + keyInfo.getStatus());
+        if (keyInfo.getPublicKey() != null) {
+            log("Public Key: ");
+            String publicKey = keyInfo.getPublicKey();
+            int i = 0;
+            for (i = 0; i < publicKey.length() / 64; i++) {
+                log(publicKey.substring(i * 64, i * 64 + 64));
+            }
+            log(publicKey.substring(i * 64));
+        }
     }
 
     private static void log(String string) {
diff --git a/base/kra/shared/conf/CS.cfg.in b/base/kra/shared/conf/CS.cfg.in
index 5febae83984d44ed884fe051320513177d1fdaa3..a3cf7918ead1ff5d777d3027b977385da80907a3 100644
--- a/base/kra/shared/conf/CS.cfg.in
+++ b/base/kra/shared/conf/CS.cfg.in
@@ -213,6 +213,9 @@ keys.ecc.curve.list=nistp256,nistp384,nistp521,sect163k1,nistk163,sect163r1,sect
 keys.ecc.curve.display.list=nistp256 (secp256r1),nistp384 (secp384r1),nistp521 (secp521r1),nistk163 (sect163k1),sect163r1,nistb163 (sect163r2),sect193r1,sect193r2,nistk233 (sect233k1),nistb233 (sect233r1),sect239k1,nistk283 (sect283k1),nistb283 (sect283r1),nistk409 (sect409k1),nistb409 (sect409r1),nistk571 (sect571k1),nistb571 (sect571r1),secp160k1,secp160r1,secp160r2,secp192k1,nistp192 (secp192r1, prime192v1),secp224k1,nistp224 (secp224r1),secp256k1,prime192v2,prime192v3,prime239v1,prime239v2,prime239v3,c2pnb163v1,c2pnb163v2,c2pnb163v3,c2pnb176v1,c2tnb191v1,c2tnb191v2,c2tnb191v3,c2pnb208w1,c2tnb239v1,c2tnb239v2,c2tnb239v3,c2pnb272w1,c2pnb304w1,c2tnb359w1,c2pnb368w1,c2tnb431r1,secp112r1,secp112r2,secp128r1,secp128r2,sect113r1,sect113r2,sect131r1,sect131r2
 keys.ecc.curve.default=nistp256
 keys.rsa.keysize.default=2048
+keys.rsa.min.size=256
+keys.rsa.max.size=8192
+keys.dsa.list=512,768,1024
 internaldb._000=##
 internaldb._001=## Internal Database
 internaldb._002=##
diff --git a/base/kra/src/com/netscape/kra/AsymKeyGenService.java b/base/kra/src/com/netscape/kra/AsymKeyGenService.java
new file mode 100644
index 0000000000000000000000000000000000000000..1bd743c09335b7806b5cc1ba6161fc02dd25d5ae
--- /dev/null
+++ b/base/kra/src/com/netscape/kra/AsymKeyGenService.java
@@ -0,0 +1,216 @@
+//--- BEGIN COPYRIGHT BLOCK ---
+//This program is free software; you can redistribute it and/or modify
+//it under the terms of the GNU General Public License as published by
+//the Free Software Foundation; version 2 of the License.
+//
+//This program is distributed in the hope that it will be useful,
+//but WITHOUT ANY WARRANTY; without even the implied warranty of
+//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//GNU General Public License for more details.
+//
+//You should have received a copy of the GNU General Public License along
+//with this program; if not, write to the Free Software Foundation, Inc.,
+//51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+//(C) 2014 Red Hat, Inc.
+//All rights reserved.
+//--- END COPYRIGHT BLOCK ---
+package com.netscape.kra;
+
+import java.math.BigInteger;
+import java.security.KeyPair;
+import java.security.NoSuchAlgorithmException;
+
+import org.mozilla.jss.crypto.CryptoToken;
+import org.mozilla.jss.crypto.KeyPairAlgorithm;
+import org.mozilla.jss.crypto.KeyPairGenerator;
+import org.mozilla.jss.crypto.KeyPairGeneratorSpi;
+import org.mozilla.jss.crypto.PrivateKey;
+import org.mozilla.jss.crypto.TokenException;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.dbs.keydb.IKeyRecord;
+import com.netscape.certsrv.dbs.keydb.IKeyRepository;
+import com.netscape.certsrv.key.AsymKeyGenerationRequest;
+import com.netscape.certsrv.key.KeyRequestResource;
+import com.netscape.certsrv.kra.IKeyRecoveryAuthority;
+import com.netscape.certsrv.logging.ILogger;
+import com.netscape.certsrv.request.IRequest;
+import com.netscape.certsrv.request.IService;
+import com.netscape.certsrv.request.RequestId;
+import com.netscape.certsrv.security.IStorageKeyUnit;
+import com.netscape.cms.servlet.key.KeyRequestDAO;
+import com.netscape.cmscore.dbs.KeyRecord;
+
+/**
+ * Service class to handle asymmetric key generation requests.
+ * A new asymmetric key is generated and archived the database as a key record.
+ * The private key is wrapped with the storage key and stored in the privateKeyData attribute of the
+ * ldap record.
+ * The public key is stored in the publicKeyData attribute of the record.
+ *
+ * @author akoneru
+ *
+ */
+public class AsymKeyGenService implements IService {
+
+    private static final String ATTR_KEY_RECORD = "keyRecord";
+    private static final String STATUS_ACTIVE = "active";
+
+    private IKeyRecoveryAuthority kra = null;
+    private IStorageKeyUnit storageUnit = null;
+    private ILogger signedAuditLogger = CMS.getSignedAuditLogger();
+    private final static String LOGGING_SIGNED_AUDIT_ASYMKEY_GEN_REQUEST_PROCESSED =
+            "LOGGING_SIGNED_AUDIT_ASYMKEY_GEN_REQUEST_PROCESSED_6";
+
+    public AsymKeyGenService(IKeyRecoveryAuthority kra) {
+        this.kra = kra;
+        this.storageUnit = kra.getStorageKeyUnit();
+    }
+
+    @Override
+    public boolean serviceRequest(IRequest request) throws EBaseException {
+
+        String clientKeyId = request.getExtDataInString(IRequest.SECURITY_DATA_CLIENT_KEY_ID);
+        String algorithm = request.getExtDataInString(IRequest.KEY_GEN_ALGORITHM);
+
+        String keySizeStr = request.getExtDataInString(IRequest.KEY_GEN_SIZE);
+        int keySize = Integer.valueOf(keySizeStr);
+
+        KeyPairGeneratorSpi.Usage[] usageList = null;
+        String usageStr = request.getExtDataInString(IRequest.KEY_GEN_USAGES);
+        if (usageStr != null) {
+            String[] usages = usageStr.split(",");
+
+            if (usages.length > 0) {
+                usageList = new KeyPairGeneratorSpi.Usage[usages.length];
+                for (int i = 0; i < usages.length; i++) {
+                    switch (usages[i]) {
+                    case AsymKeyGenerationRequest.DECRYPT:
+                        usageList[i] = KeyPairGeneratorSpi.Usage.DECRYPT;
+                        break;
+                    case AsymKeyGenerationRequest.ENCRYPT:
+                        usageList[i] = KeyPairGeneratorSpi.Usage.ENCRYPT;
+                        break;
+                    case AsymKeyGenerationRequest.WRAP:
+                        usageList[i] = KeyPairGeneratorSpi.Usage.WRAP;
+                        break;
+                    case AsymKeyGenerationRequest.UNWRAP:
+                        usageList[i] = KeyPairGeneratorSpi.Usage.UNWRAP;
+                        break;
+                    case AsymKeyGenerationRequest.DERIVE:
+                        usageList[i] = KeyPairGeneratorSpi.Usage.DERIVE;
+                        break;
+                    case AsymKeyGenerationRequest.SIGN:
+                        usageList[i] = KeyPairGeneratorSpi.Usage.SIGN;
+                        break;
+                    case AsymKeyGenerationRequest.SIGN_RECOVER:
+                        usageList[i] = KeyPairGeneratorSpi.Usage.SIGN_RECOVER;
+                        break;
+                    case AsymKeyGenerationRequest.VERIFY:
+                        usageList[i] = KeyPairGeneratorSpi.Usage.VERIFY;
+                        break;
+                    case AsymKeyGenerationRequest.VERIFY_RECOVER:
+                        usageList[i] = KeyPairGeneratorSpi.Usage.VERIFY_RECOVER;
+                        break;
+                    }
+                }
+            } else {
+                usageList = new KeyPairGeneratorSpi.Usage[2];
+                usageList[0] = KeyPairGeneratorSpi.Usage.DECRYPT;
+                usageList[1] = KeyPairGeneratorSpi.Usage.ENCRYPT;
+            }
+        }
+
+        CMS.debug("AsymKeyGenService.serviceRequest. Request id: " + request.getRequestId());
+        CMS.debug("AsymKeyGenService.serviceRequest algorithm: " + algorithm);
+
+        KeyPairAlgorithm keyPairAlgorithm = KeyRequestDAO.ASYMKEY_GEN_ALGORITHMS.get(algorithm.toUpperCase());
+
+        String owner = request.getExtDataInString(IRequest.ATTR_REQUEST_OWNER);
+        String auditSubjectID = owner;
+
+        // Get the token
+        CryptoToken token = kra.getKeygenToken();
+
+        // Generating the asymmetric keys
+        KeyPairGenerator keyPairGen = null;
+        KeyPair kp = null;
+
+        try {
+            keyPairGen = token.getKeyPairGenerator(keyPairAlgorithm);
+            keyPairGen.initialize(keySize);
+            if (usageList != null)
+                keyPairGen.setKeyPairUsages(usageList, usageList);
+            kp = keyPairGen.genKeyPair();
+        } catch (NoSuchAlgorithmException | TokenException e) {
+            CMS.debugStackTrace();
+            auditAsymKeyGenRequestProcessed(auditSubjectID, ILogger.FAILURE, request.getRequestId(),
+                    clientKeyId, null, "Failed to generate Asymmetric key");
+            throw new EBaseException("Errors in generating Asymmetric key: " + e);
+        }
+
+        if (kp == null) {
+            auditAsymKeyGenRequestProcessed(auditSubjectID, ILogger.FAILURE, request.getRequestId(),
+                    clientKeyId, null, "Failed to generate Asymmetric key");
+            throw new EBaseException("Errors in generating Asymmetric key");
+        }
+
+        KeyRecord record = new KeyRecord(null, kp.getPublic().getEncoded(), storageUnit.wrap((PrivateKey) kp
+                .getPrivate()), owner, algorithm, owner);
+
+        IKeyRepository storage = kra.getKeyRepository();
+        BigInteger serialNo = storage.getNextSerialNumber();
+
+        if (serialNo == null) {
+            kra.log(ILogger.LL_FAILURE,
+                    CMS.getLogMessage("CMSCORE_KRA_GET_NEXT_SERIAL"));
+            auditAsymKeyGenRequestProcessed(auditSubjectID, ILogger.FAILURE, request.getRequestId(),
+                    clientKeyId, null, "Failed to get next Key ID");
+            throw new EBaseException(CMS.getUserMessage("CMS_KRA_INVALID_STATE"));
+        }
+
+        // Storing the public key and private key.
+        record.set(IKeyRecord.ATTR_CLIENT_ID, clientKeyId);
+        record.setSerialNumber(serialNo);
+        record.set(KeyRecord.ATTR_ID, serialNo);
+        record.set(KeyRecord.ATTR_DATA_TYPE, KeyRequestResource.ASYMMETRIC_KEY_TYPE);
+        record.set(KeyRecord.ATTR_STATUS, STATUS_ACTIVE);
+        record.set(KeyRecord.ATTR_KEY_SIZE, keySize);
+        request.setExtData(ATTR_KEY_RECORD, serialNo);
+
+        storage.addKeyRecord(record);
+
+        auditAsymKeyGenRequestProcessed(auditSubjectID, ILogger.SUCCESS, request.getRequestId(),
+                clientKeyId, serialNo.toString(), "None");
+        request.setExtData(IRequest.RESULT, IRequest.RES_SUCCESS);
+        kra.getRequestQueue().updateRequest(request);
+        return true;
+    }
+
+    private void audit(String msg) {
+        if (signedAuditLogger == null)
+            return;
+
+        signedAuditLogger.log(ILogger.EV_SIGNED_AUDIT,
+                null,
+                ILogger.S_SIGNED_AUDIT,
+                ILogger.LL_SECURITY,
+                msg);
+    }
+
+    private void auditAsymKeyGenRequestProcessed(String subjectID, String status, RequestId requestID,
+            String clientKeyID,
+            String keyID, String reason) {
+        String auditMessage = CMS.getLogMessage(
+                LOGGING_SIGNED_AUDIT_ASYMKEY_GEN_REQUEST_PROCESSED,
+                subjectID,
+                status,
+                requestID.toString(),
+                clientKeyID,
+                keyID != null ? keyID : "None",
+                reason);
+        audit(auditMessage);
+    }
+}
diff --git a/base/kra/src/com/netscape/kra/EncryptionUnit.java b/base/kra/src/com/netscape/kra/EncryptionUnit.java
index 71bd1d7816a9842753a9154c0285109ada85b314..8eabe05ae322198e9ba997624981964807c17d2c 100644
--- a/base/kra/src/com/netscape/kra/EncryptionUnit.java
+++ b/base/kra/src/com/netscape/kra/EncryptionUnit.java
@@ -43,6 +43,7 @@ import org.mozilla.jss.crypto.TokenException;
 
 import com.netscape.certsrv.apps.CMS;
 import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.key.KeyRequestResource;
 import com.netscape.certsrv.logging.ILogger;
 import com.netscape.certsrv.security.IEncryptionUnit;
 import com.netscape.cmscore.util.Debug;
@@ -600,6 +601,7 @@ public abstract class EncryptionUnit implements IEncryptionUnit {
                                pubKey, boolean temporary)
             throws EBaseException {
         try {
+
             DerValue val = new DerValue(wrappedKeyData);
             // val.tag == DerValue.tag_Sequence
             DerInputStream in = val.data;
@@ -623,13 +625,23 @@ public abstract class EncryptionUnit implements IEncryptionUnit {
 
             wrapper.initUnwrap(sk, IV);
 
+            // Get the key type for unwrapping the private key.
+            PrivateKey.Type keyType = null;
+            if (pubKey.getAlgorithm().equalsIgnoreCase(KeyRequestResource.RSA_ALGORITHM)) {
+                keyType = PrivateKey.RSA;
+            } else if (pubKey.getAlgorithm().equalsIgnoreCase(KeyRequestResource.DSA_ALGORITHM)) {
+                keyType = PrivateKey.DSA;
+            } else if (pubKey.getAlgorithm().equalsIgnoreCase(KeyRequestResource.EC_ALGORITHM)) {
+                keyType = PrivateKey.EC;
+            }
+
             PrivateKey pk = null;
             if (temporary) {
                 pk = wrapper.unwrapTemporaryPrivate(pri,
-                        PrivateKey.RSA, pubKey);
+                        keyType, pubKey);
             } else {
                 pk = wrapper.unwrapPrivate(pri,
-                        PrivateKey.RSA, pubKey);
+                        keyType, pubKey);
             }
             return pk;
         } catch (TokenException e) {
diff --git a/base/kra/src/com/netscape/kra/EnrollmentService.java b/base/kra/src/com/netscape/kra/EnrollmentService.java
index 3ce37d6aeef20c2cdca0ca345fd45ad1040889a3..d1b716cf87072142dde0022c2b6f21ecf2840a49 100644
--- a/base/kra/src/com/netscape/kra/EnrollmentService.java
+++ b/base/kra/src/com/netscape/kra/EnrollmentService.java
@@ -272,7 +272,7 @@ public class EnrollmentService implements IService {
           }
              */
 
-            // retrieve pubic key
+            // retrieve public key
             X509Key publicKey = getPublicKey(request, aOpts[i].mReqPos);
             byte publicKeyData[] = publicKey.getEncoded();
 
@@ -458,7 +458,7 @@ public class EnrollmentService implements IService {
                 rec.setKeySize(-1);
             }
 
-            // if record alreay has a serial number, yell out.
+            // if record already has a serial number, yell out.
             if (rec.getSerialNumber() != null) {
                 mKRA.log(ILogger.LL_FAILURE,
                         CMS.getLogMessage("CMSCORE_KRA_INVALID_SERIAL_NUMBER",
diff --git a/base/kra/src/com/netscape/kra/KRAService.java b/base/kra/src/com/netscape/kra/KRAService.java
index f4768bd00f76f1462332108de9ef6ed9721ef4e0..06c8ce1d5297309e49ef9ee657e928c1c29b0e33 100644
--- a/base/kra/src/com/netscape/kra/KRAService.java
+++ b/base/kra/src/com/netscape/kra/KRAService.java
@@ -50,6 +50,7 @@ public class KRAService implements IService {
     public final static String SECURITY_DATA_ENROLLMENT = IRequest.SECURITY_DATA_ENROLLMENT_REQUEST;
     public final static String SECURITY_DATA_RECOVERY = IRequest.SECURITY_DATA_RECOVERY_REQUEST;
     public final static String SYMKEY_GENERATION = IRequest.SYMKEY_GENERATION_REQUEST;
+    public final static String ASYMKEY_GENERATION = IRequest.ASYMKEY_GENERATION_REQUEST;
 
 
     // private variables
@@ -68,6 +69,7 @@ public class KRAService implements IService {
         mServices.put(SECURITY_DATA_ENROLLMENT, new SecurityDataService(kra));
         mServices.put(SECURITY_DATA_RECOVERY, new SecurityDataRecoveryService(kra));
         mServices.put(SYMKEY_GENERATION, new SymKeyGenService(kra));
+        mServices.put(ASYMKEY_GENERATION, new AsymKeyGenService(kra));
     }
 
     /**
diff --git a/base/kra/src/com/netscape/kra/SecurityDataRecoveryService.java b/base/kra/src/com/netscape/kra/SecurityDataRecoveryService.java
index a2d587318efb59f0e1e7ebff0a3533468b558d10..4198fc5e010cbced36910bf40ca0471f6ceab1aa 100644
--- a/base/kra/src/com/netscape/kra/SecurityDataRecoveryService.java
+++ b/base/kra/src/com/netscape/kra/SecurityDataRecoveryService.java
@@ -30,6 +30,9 @@ import java.util.Random;
 
 import javax.crypto.spec.RC2ParameterSpec;
 
+import netscape.security.util.DerValue;
+import netscape.security.x509.X509Key;
+
 import org.dogtagpki.server.kra.rest.KeyRequestService;
 import org.mozilla.jss.CryptoManager;
 import org.mozilla.jss.asn1.OCTET_STRING;
@@ -42,6 +45,7 @@ import org.mozilla.jss.crypto.KeyWrapAlgorithm;
 import org.mozilla.jss.crypto.KeyWrapper;
 import org.mozilla.jss.crypto.PBEAlgorithm;
 import org.mozilla.jss.crypto.PBEKeyGenParams;
+import org.mozilla.jss.crypto.PrivateKey;
 import org.mozilla.jss.crypto.SymmetricKey;
 import org.mozilla.jss.crypto.TokenException;
 import org.mozilla.jss.pkcs12.PasswordConverter;
@@ -123,36 +127,29 @@ public class SecurityDataRecoveryService implements IService {
 
         Hashtable<String, Object> params = mKRA.getVolatileRequest(
                 request.getRequestId());
-
         BigInteger serialno = request.getExtDataInBigInteger(ATTR_SERIALNO);
         request.setExtData(ATTR_KEY_RECORD, serialno);
         RequestId requestID = request.getRequestId();
-
         if (params == null) {
             CMS.debug("Can't get volatile params.");
             auditRecoveryRequestProcessed(auditSubjectID, ILogger.FAILURE, requestID, serialno.toString(),
                     "cannot get volatile params");
             throw new EBaseException("Can't obtain volatile params!");
         }
-
         byte[] wrappedPassPhrase = null;
         byte[] wrappedSessKey = null;
-
         String transWrappedSessKeyStr = (String) params.get(IRequest.SECURITY_DATA_TRANS_SESS_KEY);
         if (transWrappedSessKeyStr != null) {
             wrappedSessKey = Utils.base64decode(transWrappedSessKeyStr);
         }
-
         String sessWrappedPassPhraseStr = (String) params.get(IRequest.SECURITY_DATA_SESS_PASS_PHRASE);
         if (sessWrappedPassPhraseStr != null) {
             wrappedPassPhrase = Utils.base64decode(sessWrappedPassPhraseStr);
         }
-
         String ivInStr = (String) params.get(IRequest.SECURITY_DATA_IV_STRING_IN);
         if (ivInStr != null) {
             iv_in = Utils.base64decode(ivInStr);
         }
-
         if (transWrappedSessKeyStr == null && sessWrappedPassPhraseStr == null) {
             //We may be in recovery case where no params were initially submitted.
             return false;
@@ -167,46 +164,57 @@ public class SecurityDataRecoveryService implements IService {
         } catch (Exception e) {
             iv = iv_default;
         }
-
         String ivStr = Utils.base64encode(iv);
 
         KeyRecord keyRecord = (KeyRecord) mStorage.readKeyRecord(serialno);
 
         SymmetricKey unwrappedSess = null;
-
         String dataType = (String) keyRecord.get(IKeyRecord.ATTR_DATA_TYPE);
         SymmetricKey symKey = null;
         byte[] unwrappedSecData = null;
+        PrivateKey privateKey = null;
         if (dataType.equals(KeyRequestResource.SYMMETRIC_KEY_TYPE)) {
             symKey = recoverSymKey(keyRecord);
+
         } else if (dataType.equals(KeyRequestResource.PASS_PHRASE_TYPE)) {
             unwrappedSecData = recoverSecurityData(keyRecord);
+        } else if (dataType.equals(KeyRequestResource.ASYMMETRIC_KEY_TYPE)) {
+            try {
+                privateKey = mStorageUnit.unwrap(keyRecord.getPrivateKeyData(),
+                        X509Key.parsePublicKey(new DerValue(keyRecord.getPublicKeyData())));
+            } catch (IOException e) {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+                CMS.debug("Cannot unwrap stored private key.");
+                throw new EBaseException("Cannot fetch the private key from the database.");
+            }
+        } else {
+            throw new EBaseException("Invalid data type stored in the database.");
         }
-
         CryptoToken ct = mTransportUnit.getToken();
 
         byte[] key_data = null;
         String pbeWrappedData = null;
-
         if (sessWrappedPassPhraseStr != null) { //We have a trans wrapped pass phrase, we will be doing PBE packaging
             byte[] unwrappedPass = null;
             Password pass = null;
-
             try {
                 unwrappedSess = mTransportUnit.unwrap_sym(wrappedSessKey, SymmetricKey.Usage.DECRYPT);
                 Cipher decryptor = ct.getCipherContext(EncryptionAlgorithm.DES3_CBC_PAD);
                 decryptor.initDecrypt(unwrappedSess, new IVParameterSpec(iv_in));
                 unwrappedPass = decryptor.doFinal(wrappedPassPhrase);
                 String passStr = new String(unwrappedPass, "UTF-8");
-
                 pass = new Password(passStr.toCharArray());
                 passStr = null;
 
                 if (dataType.equals(KeyRequestResource.SYMMETRIC_KEY_TYPE)) {
-                    pbeWrappedData = createEncryptedContentInfo(ct, symKey, null,
+                    pbeWrappedData = createEncryptedContentInfo(ct, symKey, null, null,
                             pass);
-                } else if (dataType.equals(KeyRequestResource.PASS_PHRASE_TYPE)) {
-                    pbeWrappedData = createEncryptedContentInfo(ct, null, unwrappedSecData,
+                } else if (dataType.equals(KeyRequestResource.PASS_PHRASE_TYPE)){
+                    pbeWrappedData = createEncryptedContentInfo(ct, null, unwrappedSecData, null,
+                            pass);
+                } else if (dataType.equals(KeyRequestResource.ASYMMETRIC_KEY_TYPE)) {
+                    pbeWrappedData = createEncryptedContentInfo(ct, null, null, privateKey,
                             pass);
                 }
 
@@ -258,6 +266,19 @@ public class SecurityDataRecoveryService implements IService {
                             serialno.toString(), "Cannot wrap pass phrase");
                     throw new EBaseException("Can't wrap pass phrase!");
                 }
+
+            } else if (dataType.equals(KeyRequestResource.ASYMMETRIC_KEY_TYPE)) {
+                CMS.debug("Wrapping the private key with the session key");
+                try {
+                    unwrappedSess = mTransportUnit.unwrap_sym(wrappedSessKey, SymmetricKey.Usage.WRAP);
+                    KeyWrapper wrapper = ct.getKeyWrapper(KeyWrapAlgorithm.DES3_CBC_PAD);
+                    wrapper.initWrap(unwrappedSess, new IVParameterSpec(iv));
+                    key_data = wrapper.wrap(privateKey);
+                } catch (Exception e) {
+                    auditRecoveryRequestProcessed(auditSubjectID, ILogger.FAILURE, requestID, serialno.toString(),
+                            "Cannot wrap private key");
+                    throw new EBaseException("Cannot wrap private key - " + e.toString());
+                }
             }
 
             String wrappedKeyData = Utils.base64encode(key_data);
@@ -319,10 +340,10 @@ public class SecurityDataRecoveryService implements IService {
 
     //ToDo: This might fit in JSS.
     private static EncryptedContentInfo
-            createEncryptedContentInfoPBEOfSymmKey(PBEAlgorithm keyGenAlg, Password password, byte[] salt,
+            createEncryptedContentInfoPBEOfKey(PBEAlgorithm keyGenAlg, Password password, byte[] salt,
                     int iterationCount,
                     KeyGenerator.CharToByteConverter charToByteConverter,
-                    SymmetricKey symKey, CryptoToken token)
+                    SymmetricKey symKey, PrivateKey privateKey, CryptoToken token)
                     throws CryptoManager.NotInitializedException, NoSuchAlgorithmException,
                     InvalidKeyException, InvalidAlgorithmParameterException, TokenException,
                     CharConversionException {
@@ -354,8 +375,15 @@ public class SecurityDataRecoveryService implements IService {
         KeyWrapper wrapper = token.getKeyWrapper(
                 KeyWrapAlgorithm.DES3_CBC_PAD);
         wrapper.initWrap(key, params);
-        byte encrypted[] = wrapper.wrap(symKey);
-
+        byte[] encrypted = null;
+        if (symKey != null) {
+            encrypted = wrapper.wrap(symKey);
+        } else if (privateKey != null) {
+            encrypted = wrapper.wrap(privateKey);
+        }
+        if (encrypted == null) {
+            //TODO - think about the exception to be thrown
+        }
         PBEParameter pbeParam = new PBEParameter(salt, iterationCount);
         AlgorithmIdentifier encAlgID = new AlgorithmIdentifier(
                 keyGenAlg.toOID(), pbeParam);
@@ -369,7 +397,7 @@ public class SecurityDataRecoveryService implements IService {
 
     }
 
-    private static String createEncryptedContentInfo(CryptoToken ct, SymmetricKey symKey, byte[] securityData,
+    private static String createEncryptedContentInfo(CryptoToken ct, SymmetricKey symKey, byte[] securityData, PrivateKey privateKey,
             Password password)
             throws EBaseException {
 
@@ -384,14 +412,19 @@ public class SecurityDataRecoveryService implements IService {
             byte salt[] = { 0x01, 0x01, 0x01, 0x01 };
             if (symKey != null) {
 
-                cInfo = createEncryptedContentInfoPBEOfSymmKey(keyGenAlg, password, salt,
+                cInfo = createEncryptedContentInfoPBEOfKey(keyGenAlg, password, salt,
                         1,
                         passConverter,
-                        symKey, ct);
+                        symKey, null, ct);
 
             } else if (securityData != null) {
 
                 cInfo = EncryptedContentInfo.createPBE(keyGenAlg, password, salt, 1, passConverter, securityData);
+            } else if (privateKey != null) {
+                cInfo = createEncryptedContentInfoPBEOfKey(keyGenAlg, password, salt,
+                        1,
+                        passConverter,
+                        null, privateKey, ct);
             }
 
             if(cInfo == null) {
diff --git a/base/kra/src/com/netscape/kra/SecurityDataService.java b/base/kra/src/com/netscape/kra/SecurityDataService.java
index 4a2ebef34fcf871fae19dbb53d13306255dbd1d8..73e1ec6fc8d28a76d0e7f6288087bf36ca2b6738 100644
--- a/base/kra/src/com/netscape/kra/SecurityDataService.java
+++ b/base/kra/src/com/netscape/kra/SecurityDataService.java
@@ -184,7 +184,7 @@ public class SecurityDataService implements IService {
         // because the archival request is made by the agent.
         KeyRecord rec = new KeyRecord(null, publicKey,
                 privateSecurityData, owner,
-                algStr, owner);
+                null, owner);
 
         rec.set(IKeyRecord.ATTR_CLIENT_ID, clientKeyId);
 
diff --git a/base/kra/src/com/netscape/kra/SymKeyGenService.java b/base/kra/src/com/netscape/kra/SymKeyGenService.java
index 46c8265f0e25334c72c221c5f7c398ac7935301c..d308345d74014689b347e5fae29b5881908dc025 100644
--- a/base/kra/src/com/netscape/kra/SymKeyGenService.java
+++ b/base/kra/src/com/netscape/kra/SymKeyGenService.java
@@ -88,13 +88,13 @@ public class SymKeyGenService implements IService {
             throws EBaseException {
         String id = request.getRequestId().toString();
         String clientKeyId = request.getExtDataInString(IRequest.SECURITY_DATA_CLIENT_KEY_ID);
-        String algorithm = request.getExtDataInString(IRequest.SYMKEY_GEN_ALGORITHM);
+        String algorithm = request.getExtDataInString(IRequest.KEY_GEN_ALGORITHM);
 
-        String usageStr = request.getExtDataInString(IRequest.SYMKEY_GEN_USAGES);
+        String usageStr = request.getExtDataInString(IRequest.KEY_GEN_USAGES);
         List<String> usages = new ArrayList<String>(
                 Arrays.asList(StringUtils.split(usageStr, ",")));
 
-        String keySizeStr = request.getExtDataInString(IRequest.SYMKEY_GEN_SIZE);
+        String keySizeStr = request.getExtDataInString(IRequest.KEY_GEN_SIZE);
         int keySize = Integer.parseInt(keySizeStr);
 
         CMS.debug("SymKeyGenService.serviceRequest. Request id: " + id);
@@ -111,7 +111,7 @@ public class SymKeyGenService implements IService {
         }
 
         CryptoToken token = mStorageUnit.getToken();
-        KeyGenAlgorithm kgAlg = KeyRequestDAO.KEYGEN_ALGORITHMS.get(algorithm);
+        KeyGenAlgorithm kgAlg = KeyRequestDAO.SYMKEY_GEN_ALGORITHMS.get(algorithm);
         if (kgAlg == null) {
             throw new EBaseException("Invalid algorithm");
         }
@@ -209,7 +209,6 @@ public class SymKeyGenService implements IService {
         rec.set(KeyRecord.ATTR_ID, serialNo);
         rec.set(KeyRecord.ATTR_DATA_TYPE, KeyRequestResource.SYMMETRIC_KEY_TYPE);
         rec.set(KeyRecord.ATTR_STATUS, STATUS_ACTIVE);
-        rec.set(KeyRecord.ATTR_ALGORITHM, algorithm);
         rec.set(KeyRecord.ATTR_KEY_SIZE, keySize);
         request.setExtData(ATTR_KEY_RECORD, serialNo);
 
diff --git a/base/kra/src/org/dogtagpki/server/kra/rest/KeyRequestService.java b/base/kra/src/org/dogtagpki/server/kra/rest/KeyRequestService.java
index c538e016b2c89d5d3d28d3cb5db9d837873fac35..04dd3253f93fd7a6da0a7aa72330d53d10b95d48 100644
--- a/base/kra/src/org/dogtagpki/server/kra/rest/KeyRequestService.java
+++ b/base/kra/src/org/dogtagpki/server/kra/rest/KeyRequestService.java
@@ -45,6 +45,7 @@ import com.netscape.certsrv.base.PKIException;
 import com.netscape.certsrv.base.ResourceMessage;
 import com.netscape.certsrv.base.UnauthorizedException;
 import com.netscape.certsrv.dbs.keydb.KeyId;
+import com.netscape.certsrv.key.AsymKeyGenerationRequest;
 import com.netscape.certsrv.key.KeyArchivalRequest;
 import com.netscape.certsrv.key.KeyRecoveryRequest;
 import com.netscape.certsrv.key.KeyRequestInfo;
@@ -88,6 +89,9 @@ public class KeyRequestService extends PKIService implements KeyRequestResource
     private static final String LOGGING_SIGNED_AUDIT_SYMKEY_GENERATION_REQUEST =
             "LOGGING_SIGNED_AUDIT_SYMKEY_GENERATION_REQUEST_4";
 
+    private static final String LOGGING_SIGNED_AUDIT_ASYMKEY_GENERATION_REQUEST =
+            "LOGGING_SIGNED_AUDIT_ASYMKEY_GENERATION_REQUEST_4";
+
     private static final String LOGGING_SIGNED_AUDIT_SECURITY_DATA_RECOVERY_REQUEST =
             "LOGGING_SIGNED_AUDIT_SECURITY_DATA_RECOVERY_REQUEST_4";
 
@@ -412,14 +416,24 @@ public class KeyRequestService extends PKIService implements KeyRequestResource
         auditor.log(msg);
     }
 
+    public void auditAsymKeyGenRequestMade(RequestId requestId, String status, String clientKeyID) {
+        String msg = CMS.getLogMessage(
+                LOGGING_SIGNED_AUDIT_ASYMKEY_GENERATION_REQUEST,
+                servletRequest.getUserPrincipal().getName(),
+                status,
+                requestId != null ? requestId.toString() : "null",
+                clientKeyID);
+        auditor.log(msg);
+    }
+
     @Override
-    public Response createRequest(MultivaluedMap<String, String> form) {
+    public Response submitRequest(MultivaluedMap<String, String> form) {
         ResourceMessage data = new ResourceMessage(form);
-        return createRequest(data);
+        return submitRequest(data);
     }
 
     @Override
-    public Response createRequest(ResourceMessage data) {
+    public Response submitRequest(ResourceMessage data) {
         Object request = null;
         try {
             Class<?> requestClazz = Class.forName(data.getClassName());
@@ -435,6 +449,8 @@ public class KeyRequestService extends PKIService implements KeyRequestResource
             return recoverKey(new KeyRecoveryRequest(data));
         } else if (request instanceof SymKeyGenerationRequest) {
             return generateSymKey(new SymKeyGenerationRequest(data));
+        } else if (request instanceof AsymKeyGenerationRequest) {
+            return generateAsymKey(new AsymKeyGenerationRequest(data));
         } else {
             throw new BadRequestException("Invalid request class.");
         }
@@ -464,4 +480,26 @@ public class KeyRequestService extends PKIService implements KeyRequestResource
             throw new PKIException(e.toString());
         }
     }
+
+    public Response generateAsymKey(AsymKeyGenerationRequest data) {
+        if (data == null) {
+            throw new BadRequestException("Invalid key generation request.");
+        }
+
+        KeyRequestDAO dao = new KeyRequestDAO();
+        KeyRequestResponse response;
+        try {
+            String owner = servletRequest.getUserPrincipal().getName();
+            response = dao.submitRequest(data, uriInfo, owner);
+            auditAsymKeyGenRequestMade(response.getRequestInfo().getRequestId(), ILogger.SUCCESS,
+                    data.getClientKeyId());
+
+            return createCreatedResponse(response, new URI(response.getRequestInfo().getRequestURL()));
+
+        } catch (EBaseException | URISyntaxException e) {
+            e.printStackTrace();
+            auditArchivalRequestMade(null, ILogger.FAILURE, data.getClientKeyId());
+            throw new PKIException(e.toString());
+        }
+    }
 }
diff --git a/base/kra/src/org/dogtagpki/server/kra/rest/KeyService.java b/base/kra/src/org/dogtagpki/server/kra/rest/KeyService.java
index 9f33b1ba7d910f94d8abcce2d05a59f48212f165..ecf3b0398d8b231dd0803a8aaab80f832c82a4d3 100644
--- a/base/kra/src/org/dogtagpki/server/kra/rest/KeyService.java
+++ b/base/kra/src/org/dogtagpki/server/kra/rest/KeyService.java
@@ -19,6 +19,7 @@
 package org.dogtagpki.server.kra.rest;
 
 
+import java.io.IOException;
 import java.math.BigInteger;
 import java.net.URI;
 import java.util.ArrayList;
@@ -69,6 +70,7 @@ import com.netscape.certsrv.request.RequestId;
 import com.netscape.certsrv.request.RequestStatus;
 import com.netscape.cms.servlet.base.PKIService;
 import com.netscape.cms.servlet.key.KeyRequestDAO;
+import com.netscape.cmsutil.crypto.CryptoUtil;
 import com.netscape.cmsutil.ldap.LDAPUtil;
 import com.netscape.cmsutil.util.Utils;
 
@@ -376,7 +378,7 @@ public class KeyService extends PKIService implements KeyResource {
             while (e.hasMoreElements()) {
                 IKeyRecord rec = e.nextElement();
                 if (rec == null) continue;
-                results.add(createKeyDataInfo(rec));
+                results.add(createKeyDataInfo(rec, false));
             }
 
             int total = results.size();
@@ -431,13 +433,20 @@ public class KeyService extends PKIService implements KeyResource {
         throw new ResourceNotFoundException("Key not found.");
     }
 
-    public KeyInfo createKeyDataInfo(IKeyRecord rec) throws EBaseException {
+    public KeyInfo createKeyDataInfo(IKeyRecord rec, boolean getPublicKey) throws EBaseException {
         KeyInfo ret = new KeyInfo();
         ret.setClientKeyID(rec.getClientId());
         ret.setStatus(rec.getKeyStatus());
         ret.setAlgorithm(rec.getAlgorithm());
         ret.setSize(rec.getKeySize());
         ret.setOwnerName(rec.getOwnerName());
+        if(rec.getPublicKeyData() != null && getPublicKey){
+            try {
+                ret.setPublicKey(CryptoUtil.base64Encode(rec.getPublicKeyData()));
+            } catch (IOException e) {
+                throw new EBaseException(e.getMessage());
+            }
+        }
 
         Path keyPath = KeyResource.class.getAnnotation(Path.class);
         BigInteger serial = rec.getSerialNumber();
@@ -539,7 +548,7 @@ public class KeyService extends PKIService implements KeyResource {
         IKeyRecord rec = null;
         try {
             rec = repo.readKeyRecord(keyId.toBigInteger());
-            KeyInfo info = createKeyDataInfo(rec);
+            KeyInfo info = createKeyDataInfo(rec, true);
 
             return createOKResponse(info);
         } catch (EDBRecordNotFoundException e) {
diff --git a/base/server/cms/src/com/netscape/cms/servlet/key/KeyRequestDAO.java b/base/server/cms/src/com/netscape/cms/servlet/key/KeyRequestDAO.java
index dd0393aab5164fe7537d3ed2183d26ebc3132b53..8c014b02df0335a83368fe37391a1f3d72320b79 100644
--- a/base/server/cms/src/com/netscape/cms/servlet/key/KeyRequestDAO.java
+++ b/base/server/cms/src/com/netscape/cms/servlet/key/KeyRequestDAO.java
@@ -17,6 +17,7 @@
 // --- END COPYRIGHT BLOCK ---
 package com.netscape.cms.servlet.key;
 
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Enumeration;
 import java.util.HashMap;
@@ -30,14 +31,17 @@ import javax.ws.rs.core.UriInfo;
 
 import org.apache.commons.lang.StringUtils;
 import org.mozilla.jss.crypto.KeyGenAlgorithm;
+import org.mozilla.jss.crypto.KeyPairAlgorithm;
 
 import com.netscape.certsrv.apps.CMS;
 import com.netscape.certsrv.base.BadRequestException;
 import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.base.PKIException;
 import com.netscape.certsrv.dbs.EDBRecordNotFoundException;
 import com.netscape.certsrv.dbs.keydb.IKeyRecord;
 import com.netscape.certsrv.dbs.keydb.IKeyRepository;
 import com.netscape.certsrv.dbs.keydb.KeyId;
+import com.netscape.certsrv.key.AsymKeyGenerationRequest;
 import com.netscape.certsrv.key.KeyArchivalRequest;
 import com.netscape.certsrv.key.KeyData;
 import com.netscape.certsrv.key.KeyNotFoundException;
@@ -63,16 +67,21 @@ import com.netscape.cms.servlet.request.CMSRequestDAO;
  */
 public class KeyRequestDAO extends CMSRequestDAO {
 
-    public static final Map<String, KeyGenAlgorithm> KEYGEN_ALGORITHMS;
+    public static final Map<String, KeyGenAlgorithm> SYMKEY_GEN_ALGORITHMS;
+    public static final Map<String, KeyPairAlgorithm> ASYMKEY_GEN_ALGORITHMS;
 
     static {
-        KEYGEN_ALGORITHMS = new HashMap<String, KeyGenAlgorithm>();
-        KEYGEN_ALGORITHMS.put(KeyRequestResource.DES_ALGORITHM, KeyGenAlgorithm.DES);
-        KEYGEN_ALGORITHMS.put(KeyRequestResource.DESEDE_ALGORITHM, KeyGenAlgorithm.DESede);
-        KEYGEN_ALGORITHMS.put(KeyRequestResource.DES3_ALGORITHM, KeyGenAlgorithm.DES3);
-        KEYGEN_ALGORITHMS.put(KeyRequestResource.RC2_ALGORITHM, KeyGenAlgorithm.RC2);
-        KEYGEN_ALGORITHMS.put(KeyRequestResource.RC4_ALGORITHM, KeyGenAlgorithm.RC4);
-        KEYGEN_ALGORITHMS.put(KeyRequestResource.AES_ALGORITHM, KeyGenAlgorithm.AES);
+        SYMKEY_GEN_ALGORITHMS = new HashMap<String, KeyGenAlgorithm>();
+        SYMKEY_GEN_ALGORITHMS.put(KeyRequestResource.DES_ALGORITHM, KeyGenAlgorithm.DES);
+        SYMKEY_GEN_ALGORITHMS.put(KeyRequestResource.DESEDE_ALGORITHM, KeyGenAlgorithm.DESede);
+        SYMKEY_GEN_ALGORITHMS.put(KeyRequestResource.DES3_ALGORITHM, KeyGenAlgorithm.DES3);
+        SYMKEY_GEN_ALGORITHMS.put(KeyRequestResource.RC2_ALGORITHM, KeyGenAlgorithm.RC2);
+        SYMKEY_GEN_ALGORITHMS.put(KeyRequestResource.RC4_ALGORITHM, KeyGenAlgorithm.RC4);
+        SYMKEY_GEN_ALGORITHMS.put(KeyRequestResource.AES_ALGORITHM, KeyGenAlgorithm.AES);
+
+        ASYMKEY_GEN_ALGORITHMS = new HashMap<String, KeyPairAlgorithm>();
+        ASYMKEY_GEN_ALGORITHMS.put(KeyRequestResource.RSA_ALGORITHM, KeyPairAlgorithm.RSA);
+        ASYMKEY_GEN_ALGORITHMS.put(KeyRequestResource.DSA_ALGORITHM, KeyPairAlgorithm.DSA);
     }
 
     private static String REQUEST_ARCHIVE_OPTIONS = IEnrollProfile.REQUEST_ARCHIVE_OPTIONS;
@@ -288,7 +297,7 @@ public class KeyRequestDAO extends CMSRequestDAO {
             keySize = new Integer(128);
         }
 
-        KeyGenAlgorithm alg = KEYGEN_ALGORITHMS.get(algName);
+        KeyGenAlgorithm alg = SYMKEY_GEN_ALGORITHMS.get(algName);
         if (alg == null) {
             throw new BadRequestException("Invalid Algorithm");
         }
@@ -299,17 +308,98 @@ public class KeyRequestDAO extends CMSRequestDAO {
 
         IRequest request = queue.newRequest(IRequest.SYMKEY_GENERATION_REQUEST);
 
-        request.setExtData(IRequest.SYMKEY_GEN_ALGORITHM, algName);
-        request.setExtData(IRequest.SYMKEY_GEN_SIZE, keySize);
+        request.setExtData(IRequest.KEY_GEN_ALGORITHM, algName);
+        request.setExtData(IRequest.KEY_GEN_SIZE, keySize);
         request.setExtData(IRequest.SECURITY_DATA_STRENGTH, keySize);
         request.setExtData(IRequest.SECURITY_DATA_ALGORITHM, algName);
 
-        request.setExtData(IRequest.SYMKEY_GEN_USAGES, StringUtils.join(usages, ","));
+        request.setExtData(IRequest.KEY_GEN_USAGES, StringUtils.join(usages, ","));
         request.setExtData(IRequest.SECURITY_DATA_CLIENT_KEY_ID, clientKeyId);
         request.setExtData(IRequest.ATTR_REQUEST_OWNER, owner);
 
         if (transWrappedSessionKey != null) {
-            request.setExtData(IRequest.SYMKEY_TRANS_WRAPPED_SESSION_KEY,
+            request.setExtData(IRequest.KEY_GEN_TRANS_WRAPPED_SESSION_KEY,
+                    transWrappedSessionKey);
+        }
+
+        queue.processRequest(request);
+        queue.markAsServiced(request);
+
+        return createKeyRequestResponse(request, uriInfo);
+    }
+
+    public KeyRequestResponse submitRequest(AsymKeyGenerationRequest data, UriInfo uriInfo, String owner)
+            throws EBaseException {
+        String clientKeyId = data.getClientKeyId();
+        String algName = data.getKeyAlgorithm();
+        Integer keySize = data.getKeySize();
+        List<String> usages = data.getUsages();
+        String transWrappedSessionKey = data.getTransWrappedSessionKey();
+
+        if (StringUtils.isBlank(clientKeyId)) {
+            throw new BadRequestException("Invalid key generation request. Missing client ID");
+        }
+
+        boolean keyExists = doesKeyExist(clientKeyId, "active");
+        if (keyExists == true) {
+            throw new BadRequestException("Cannot archive already active existing key!");
+        }
+
+        if (StringUtils.isBlank(algName)) {
+            if (keySize.intValue() != 0) {
+                throw new BadRequestException(
+                        "Invalid request.  Must specify key algorithm if size is specified");
+            }
+        }
+
+        KeyPairAlgorithm alg = ASYMKEY_GEN_ALGORITHMS.get(algName);
+        if (alg == null) {
+            throw new BadRequestException("Unsupported algorithm specified.");
+        }
+
+        if (keySize == null) {
+            if (algName.equalsIgnoreCase(KeyRequestResource.RSA_ALGORITHM)
+                    || algName.equalsIgnoreCase(KeyRequestResource.DSA_ALGORITHM)) {
+                throw new BadRequestException("Key size must be specified.");
+            }
+        } else {
+            //Validate key size
+            if (algName.equalsIgnoreCase(KeyRequestResource.RSA_ALGORITHM)) {
+                int size = Integer.valueOf(keySize);
+                int minSize = Integer.valueOf(CMS.getConfigStore().getInteger("keys.rsa.min.size", 256));
+                int maxSize = Integer.valueOf(CMS.getConfigStore().getInteger("keys.rsa.max.size", 8192));
+                if (minSize > maxSize) {
+                    throw new PKIException("Incorrect size parameters stored in config file.");
+                }
+                if (size < minSize || size > maxSize) {
+                    throw new BadRequestException("Key size out of supported range - " + minSize + " - " + maxSize);
+                }
+                //JSS supports key sizes that are of the form 256 + (16*n), where n = 0-1008, for RSA
+                if (((size - 256) % 16) != 0) {
+                    throw new BadRequestException("Invalid key size specified.");
+                }
+            } else if (algName.equalsIgnoreCase(KeyRequestResource.DSA_ALGORITHM)) {
+                // Without the PQGParams, JSS can create DSA keys of size 512, 768, 1024 only.
+                String[] sizes = CMS.getConfigStore().getString("keys.dsa.list", "512,768,1024").split(",");
+                if (!Arrays.asList(sizes).contains(String.valueOf(keySize))) {
+                    throw new BadRequestException("Invalid key size specified.");
+                }
+            }
+        }
+
+        IRequest request = queue.newRequest(IRequest.ASYMKEY_GENERATION_REQUEST);
+
+        request.setExtData(IRequest.KEY_GEN_ALGORITHM, algName);
+        request.setExtData(IRequest.KEY_GEN_SIZE, keySize);
+        request.setExtData(IRequest.SECURITY_DATA_STRENGTH, keySize);
+        request.setExtData(IRequest.SECURITY_DATA_ALGORITHM, algName);
+
+        request.setExtData(IRequest.KEY_GEN_USAGES, StringUtils.join(usages, ","));
+        request.setExtData(IRequest.SECURITY_DATA_CLIENT_KEY_ID, clientKeyId);
+        request.setExtData(IRequest.ATTR_REQUEST_OWNER, owner);
+
+        if (transWrappedSessionKey != null) {
+            request.setExtData(IRequest.KEY_GEN_TRANS_WRAPPED_SESSION_KEY,
                     transWrappedSessionKey);
         }
 
diff --git a/base/server/cmsbundle/src/LogMessages.properties b/base/server/cmsbundle/src/LogMessages.properties
index f1485deecb5d61fe5b4d4147de2d2ddb10d2f6c2..dfa23c15b58e613880503293cf1442e512bcedfa 100644
--- a/base/server/cmsbundle/src/LogMessages.properties
+++ b/base/server/cmsbundle/src/LogMessages.properties
@@ -2448,6 +2448,15 @@ LOGGING_SIGNED_AUDIT_SYMKEY_GEN_REQUEST_PROCESSED_6=<type=SYMKEY_GENERATION_REQU
 #
 LOGGING_SIGNED_AUDIT_SYMKEY_GENERATION_REQUEST_4=<type=SYMKEY_GENERATION_REQUEST>:[AuditEvent=SYMKEY_GENERATION_REQUEST][SubjectID={0}][Outcome={1}][GenerationRequestID={2}][ClientKeyID={3}] symkey generation request made
 #
+# LOGGING_SIGNED_AUDIT_ASYMKEY_GENERATION_REQUEST
+# - used when asymmetric key generation request is made
+LOGGING_SIGNED_AUDIT_ASYMKEY_GENERATION_REQUEST_4=<type=ASYMKEY_GENERATION_REQUEST>:[AuditEvent=ASYMKEY_GENERATION_REQUEST][SubjectID={0}][Outcome={1}][GenerationRequestID={2}][ClientKeyID={3}] Asymkey generation request made
+#
+# LOGGING_SIGNED_AUDIT_ASYMKEY_GEN_REQUEST_PROCESSED
+# - used when a request to generate asymmetric keys received by the DRM
+#   is processed.
+LOGGING_SIGNED_AUDIT_ASYMKEY_GEN_REQUEST_PROCESSED_6=<type=ASYMKEY_GENERATION_REQUEST_PROCESSED>:[AuditEvent=ASYMKEY_GENERATION_REQUEST_PROCESSED][SubjectID={0}][Outcome={1}][GenerationRequestID={2}][ClientKeyID={3}][KeyID={4}][FailureReason={5}] Asymkey generation request processed
+#
 # LOGGING_SIGNED_AUDIT_TOKEN_CERT_ENROLLMENT
 # - used for TPS when token certificate enrollment request is made
 #
-- 
1.8.5.3

