>From 7cfac6a6259c9008755f8c9dbc13aeb56ab75e71 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                      |  58 +++++++-
 .../com/netscape/certsrv/base/ResourceMessage.java |   3 +-
 .../certsrv/key/AsymKeyGenerationRequest.java      |  76 +++++++++++
 .../src/com/netscape/certsrv/key/KeyClient.java    |  32 ++++-
 .../netscape/certsrv/key/KeyGenerationRequest.java | 108 +++++++++++++++
 .../src/com/netscape/certsrv/key/KeyInfo.java      |  11 ++
 .../netscape/certsrv/key/KeyRequestResource.java   |   5 +
 .../certsrv/key/SymKeyGenerationRequest.java       |  83 +-----------
 .../src/com/netscape/certsrv/request/IRequest.java |  12 +-
 .../src/com/netscape/cmstools/key/KeyCLI.java      |  11 ++
 .../com/netscape/cmstools/key/KeyGenerateCLI.java  |  21 ++-
 base/kra/functional/drmtest.py                     |  17 +++
 .../src/com/netscape/kra/AsymKeyGenService.java    | 146 +++++++++++++++++++++
 .../src/com/netscape/kra/EnrollmentService.java    |   4 +-
 base/kra/src/com/netscape/kra/KRAService.java      |   2 +
 .../netscape/kra/SecurityDataRecoveryService.java  |   4 +-
 .../src/com/netscape/kra/SecurityDataService.java  |   2 +-
 .../kra/src/com/netscape/kra/SymKeyGenService.java |   9 +-
 .../server/kra/rest/KeyRequestService.java         |  41 ++++++
 .../org/dogtagpki/server/kra/rest/KeyService.java  |  15 ++-
 .../netscape/cms/servlet/key/KeyRequestDAO.java    |  98 ++++++++++++--
 base/server/cmsbundle/src/LogMessages.properties   |   9 ++
 22 files changed, 644 insertions(+), 123 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..0a4d47e034fe78ae9fda3a27cd534cc3cfa49936 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', 'b64PublicKey': 'b64_public_key'
     }
 
     # pylint: disable-msg=C0103
@@ -117,6 +117,7 @@ class KeyInfo(object):
         self.status = None
         self.owner_name = None
         self.size = None
+        self.b64_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"
@@ -362,6 +363,25 @@ class SymKeyGenerationRequest(pki.ResourceMessage):
         self.add_attribute("keyUsage", ','.join(key_usages))
         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.
+    """
+    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):
     """
@@ -561,6 +581,39 @@ class KeyClient(object):
         return self.create_request(request)
 
     @pki.handle_exceptions()
+    def generate_asymmetric_key(self, client_key_id, algorithm=None, size=None,
+                               usages=None,
+                               trans_wrapped_session_key=None):
+        """ Generate and archive asymmetric keys in the DRM.
+
+            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 trans_wrapped_session_key is not None:
+            twsk = base64.encodestring(trans_wrapped_session_key)
+            # noinspection PyUnusedLocal
+            request = AsymKeyGenerationRequest(
+                client_key_id=client_key_id,
+                key_size=size,
+                key_algorithm=algorithm,
+                key_usages=usages,
+                trans_wrapped_session_key=twsk)
+            raise NotImplementedError(
+                "Returning the asymmetric keys in the same call is not yet "
+                "implemented.")
+        else:
+            request = AsymKeyGenerationRequest(
+                client_key_id=client_key_id,
+                key_size=size,
+                key_algorithm=algorithm,
+                key_usages=usages)
+        return self.create_request(request)
+
+    @pki.handle_exceptions()
     def archive_key(self, client_key_id, data_type, private_data,
                     key_algorithm=None, key_size=None):
         """ Archive a secret (symmetric key or passphrase) on the DRM.
@@ -894,6 +947,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..f2db7710608a165f174f1d34276db9181d80f04d 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;
@@ -34,7 +35,7 @@ import com.netscape.certsrv.key.SymKeyGenerationRequest;
  * @author Ade Lee
  */
 @XmlRootElement(name="ResourceMessage")
-@XmlSeeAlso({KeyArchivalRequest.class, KeyRecoveryRequest.class, SymKeyGenerationRequest.class, PKIException.Data.class})
+@XmlSeeAlso({KeyArchivalRequest.class, KeyRecoveryRequest.class, SymKeyGenerationRequest.class, PKIException.Data.class, AsymKeyGenerationRequest.class})
 @XmlAccessorType(XmlAccessType.NONE)
 public class ResourceMessage {
 
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..e43d00d69b27c6f095ccec19f8287d0b9e03bbac
--- /dev/null
+++ b/base/common/src/com/netscape/certsrv/key/AsymKeyGenerationRequest.java
@@ -0,0 +1,76 @@
+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{
+    /* EC Key usages */
+    public static final String DERIVE_USAGE = "derive";
+    public static final String SIGN_USAGE = "sign";
+
+    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_USAGE);
+        list.add(SIGN_USAGE);
+
+        return list;
+    }
+
+    public static boolean validateKeySizes(int keySize){
+        if (keySize == 512 || keySize == 1024 || keySize == 2048 || keySize == 4096)
+            return true;
+        return false;
+    }
+}
diff --git a/base/common/src/com/netscape/certsrv/key/KeyClient.java b/base/common/src/com/netscape/certsrv/key/KeyClient.java
index 9363a6a8cfe121d4e80496bbd762ecfd866bea91..90d4d01704315957352dcdcaf9e285e971898bf4 100644
--- a/base/common/src/com/netscape/certsrv/key/KeyClient.java
+++ b/base/common/src/com/netscape/certsrv/key/KeyClient.java
@@ -657,11 +657,11 @@ public class KeyClient extends Client {
     }
 
     /**
-     * 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.
@@ -689,4 +689,32 @@ public class KeyClient extends Client {
 
         return createRequest(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 -- Not being used now. NULL value is permitted.
+     * @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.");
+        }
+        if (!AsymKeyGenerationRequest.validateKeySizes(keySize)){
+            throw new IllegalArgumentException("Invalid key size specified.");
+        }
+        AsymKeyGenerationRequest data = new AsymKeyGenerationRequest();
+        data.setClientKeyId(clientKeyId);
+        data.setKeyAlgorithm(keyAlgorithm);
+        data.setKeySize(1024);
+        data.setUsages(usages);
+        data.setTransWrappedSessionKey(Utils.base64encode(transWrappedSessionKey));
+
+        return createRequest(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..02c019ce4e4ccfd556507648555835d61ca3d245
--- /dev/null
+++ b/base/common/src/com/netscape/certsrv/key/KeyGenerationRequest.java
@@ -0,0 +1,108 @@
+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..5b23b975ebaaca7c146249cbbd85a8527f8cbecf 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 b64PublicKey;
+
     public KeyInfo() {
         // required for JAXB (defaults)
     }
@@ -125,4 +128,12 @@ public class KeyInfo {
     public void setOwnerName(String ownerName) {
         this.ownerName = ownerName;
     }
+
+    public String getB64PublicKey() {
+        return b64PublicKey;
+    }
+
+    public void setB64PublicKey(String b64PublicKey) {
+        this.b64PublicKey = b64PublicKey;
+    }
 }
diff --git a/base/common/src/com/netscape/certsrv/key/KeyRequestResource.java b/base/common/src/com/netscape/certsrv/key/KeyRequestResource.java
index fb82afe19bbe7bf774f45f96da7c1c8b0dc3cc89..409d7b3c87a3778108bfb4dacd2d5f67e7419cf4 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";
 
+    // AsymmetricKey algorithms
+    public final static String RSA_ALGORITHM = "RSA";
+    public final static String DSA_ALGORITHM = "DSA";
+    public final static String EC_ALGORITHM = "EC";
+
     /**
      * Used to generate list of key requests based on the search parameters
      */
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..bafe65203d40fce99a30d82987685c5fbac73ae0 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,17 @@ 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.getB64PublicKey() != 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 \n");
+            String publicKey = info.getB64PublicKey();
+            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));
+        }
     }
 
     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..f099770cfaf8a09df263b89dc4632b259dfd7dd9 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,7 +38,8 @@ 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 RSA and DSA: 512, 1024, 2048, 4096");
         option.setArgName("size");
         options.addOption(option);
 
@@ -91,6 +92,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);
@@ -105,11 +108,19 @@ public class KeyGenerateCLI extends CLI {
         if (givenUsages != null) {
             usages = Arrays.asList(givenUsages.split(","));
         }
-        KeyRequestResponse response = keyCLI.keyClient.generateSymmetricKey(clientKeyId, keyAlgorithm,
-                Integer.parseInt(keySize),
-                usages, null);
 
+        KeyRequestResponse response = null;
+        if (keyAlgorithm.equalsIgnoreCase(KeyRequestResource.RSA_ALGORITHM) || keyAlgorithm.equalsIgnoreCase(KeyRequestResource.DSA_ALGORITHM)) {
+            response = keyCLI.keyClient.generateAsymmetricKey(clientKeyId, keyAlgorithm,
+                    Integer.parseInt(keySize),
+                    usages, null);
+        } else {
+            response = keyCLI.keyClient.generateSymmetricKey(clientKeyId, keyAlgorithm,
+                    Integer.parseInt(keySize),
+                    usages, null);
+        }
         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..f8962a22aed1f3673c75eb8a36cb9c953f54fb09 100644
--- a/base/kra/functional/drmtest.py
+++ b/base/kra/functional/drmtest.py
@@ -261,5 +261,22 @@ def main():
     else:
         print "Error: archived and recovered keys do not match"
 
+        print "Trying to generate a new symkey with the same client ID"
+
+    #Test 20: Generating asymmetric keys
+    try:
+        response = keyclient.generate_asymmetric_key("vek12890",
+                                         algorithm="RSA",
+                                         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
+    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/src/com/netscape/kra/AsymKeyGenService.java b/base/kra/src/com/netscape/kra/AsymKeyGenService.java
new file mode 100644
index 0000000000000000000000000000000000000000..a934b1ae4de09dbab021fb93e4894463151bc0fb
--- /dev/null
+++ b/base/kra/src/com/netscape/kra/AsymKeyGenService.java
@@ -0,0 +1,146 @@
+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.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.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 mKRA = null;
+    private IStorageKeyUnit mStorageUnit = 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){
+        mKRA = kra;
+        mStorageUnit = mKRA.getStorageKeyUnit();
+    }
+
+    @Override
+    public boolean serviceRequest(IRequest request) throws EBaseException {
+
+        String id = request.getRequestId().toString();
+        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.parseInt(keySizeStr);
+
+        CMS.debug("AsymKeyGenService.serviceRequest. Request id: " + id);
+        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;
+
+        CryptoToken token = mKRA.getKeygenToken();
+
+        KeyPairGenerator keyPairGen = null;
+        KeyPair kp = null;
+
+        try {
+            keyPairGen = token.getKeyPairGenerator(keyPairAlgorithm);
+            keyPairGen.initialize(keySize);
+            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(), mStorageUnit.wrap((PrivateKey)kp.getPrivate()), owner, algorithm, owner);
+
+        IKeyRepository storage = mKRA.getKeyRepository();
+        BigInteger serialNo = storage.getNextSerialNumber();
+
+        if (serialNo == null) {
+            mKRA.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);
+        mKRA.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/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..ef353eeab018b9e3cec8f562f25d889892b830dc 100644
--- a/base/kra/src/com/netscape/kra/SecurityDataRecoveryService.java
+++ b/base/kra/src/com/netscape/kra/SecurityDataRecoveryService.java
@@ -179,7 +179,7 @@ public class SecurityDataRecoveryService implements IService {
         byte[] unwrappedSecData = null;
         if (dataType.equals(KeyRequestResource.SYMMETRIC_KEY_TYPE)) {
             symKey = recoverSymKey(keyRecord);
-        } else if (dataType.equals(KeyRequestResource.PASS_PHRASE_TYPE)) {
+        } else {
             unwrappedSecData = recoverSecurityData(keyRecord);
         }
 
@@ -240,7 +240,7 @@ public class SecurityDataRecoveryService implements IService {
                     throw new EBaseException("Can't wrap symmetric key! " + e.toString());
                 }
 
-            } else if (dataType.equals(KeyRequestResource.PASS_PHRASE_TYPE)) {
+            } else {
                 try {
                     unwrappedSess = mTransportUnit.unwrap_sym(wrappedSessKey, SymmetricKey.Usage.ENCRYPT);
                     Cipher encryptor = ct.getCipherContext(EncryptionAlgorithm.DES3_CBC_PAD);
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..a9548345ecea7f1507fe04c8340f4eec679708cf 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,6 +416,16 @@ 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) {
         ResourceMessage data = new ResourceMessage(form);
@@ -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,29 @@ 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();
+            if (owner == null) {
+                throw new UnauthorizedException("Key generation must be performed by an agent");
+            }
+            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..7c4a58ed7cedc09ea836f74fc294e9d0296550d0 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.setB64PublicKey(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..c202f3ec402bc3af9b6e1bf81a9d41273b4c79cb 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
@@ -30,6 +30,7 @@ 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;
@@ -38,6 +39,7 @@ 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 +65,22 @@ 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);
+        ASYMKEY_GEN_ALGORITHMS.put(KeyRequestResource.EC_ALGORITHM, KeyPairAlgorithm.EC);
     }
 
     private static String REQUEST_ARCHIVE_OPTIONS = IEnrollProfile.REQUEST_ARCHIVE_OPTIONS;
@@ -288,7 +296,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 +307,81 @@ 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("Invalid Algorithm");
+        }
+
+        if (keySize == null) {
+            if (algName == KeyRequestResource.RSA_ALGORITHM
+                    || algName == KeyRequestResource.DSA_ALGORITHM) {
+                throw new BadRequestException("Key size must be specified.");
+            }
+        } else {
+            if (algName == KeyRequestResource.RSA_ALGORITHM
+                    || algName == KeyRequestResource.DSA_ALGORITHM) {
+                if (!AsymKeyGenerationRequest.validateKeySizes(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

