summaryrefslogtreecommitdiffstats
path: root/base
diff options
context:
space:
mode:
Diffstat (limited to 'base')
-rw-r--r--base/common/python/pki/key.py116
-rw-r--r--base/common/src/com/netscape/certsrv/base/ResourceMessage.java8
-rw-r--r--base/common/src/com/netscape/certsrv/key/AsymKeyGenerationRequest.java115
-rw-r--r--base/common/src/com/netscape/certsrv/key/KeyClient.java76
-rw-r--r--base/common/src/com/netscape/certsrv/key/KeyGenerationRequest.java125
-rw-r--r--base/common/src/com/netscape/certsrv/key/KeyInfo.java11
-rw-r--r--base/common/src/com/netscape/certsrv/key/KeyRequestResource.java9
-rw-r--r--base/common/src/com/netscape/certsrv/key/SymKeyGenerationRequest.java83
-rw-r--r--base/common/src/com/netscape/certsrv/request/IRequest.java12
-rw-r--r--base/java-tools/src/com/netscape/cmstools/key/KeyCLI.java12
-rw-r--r--base/java-tools/src/com/netscape/cmstools/key/KeyGenerateCLI.java47
-rw-r--r--base/kra/functional/drmtest.py28
-rw-r--r--base/kra/functional/src/com/netscape/cms/servlet/test/DRMTest.java102
-rw-r--r--base/kra/shared/conf/CS.cfg.in3
-rw-r--r--base/kra/src/com/netscape/kra/AsymKeyGenService.java210
-rw-r--r--base/kra/src/com/netscape/kra/EncryptionUnit.java16
-rw-r--r--base/kra/src/com/netscape/kra/EnrollmentService.java4
-rw-r--r--base/kra/src/com/netscape/kra/KRAService.java2
-rw-r--r--base/kra/src/com/netscape/kra/SecurityDataRecoveryService.java78
-rw-r--r--base/kra/src/com/netscape/kra/SecurityDataService.java5
-rw-r--r--base/kra/src/com/netscape/kra/SymKeyGenService.java9
-rw-r--r--base/kra/src/org/dogtagpki/server/kra/rest/KeyRequestService.java44
-rw-r--r--base/kra/src/org/dogtagpki/server/kra/rest/KeyService.java15
-rw-r--r--base/server/cms/src/com/netscape/cms/servlet/key/KeyRequestDAO.java116
-rw-r--r--base/server/cmsbundle/src/LogMessages.properties9
25 files changed, 1081 insertions, 174 deletions
diff --git a/base/common/python/pki/key.py b/base/common/python/pki/key.py
index af34a7ff4..0be438a28 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):
@@ -127,6 +128,8 @@ class KeyInfo(object):
setattr(key_info, KeyInfo.json_attribute_names[k], v)
else:
setattr(key_info, k, v)
+ if key_info.public_key is not None:
+ key_info.public_key = base64.decodestring(key_info.public_key)
return key_info
def get_key_id(self):
@@ -339,7 +342,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 +366,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 +416,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 +546,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 +596,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 +754,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 +789,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 +817,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 +858,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 +922,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 +983,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 34d7c2b11..1214b45fb 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 000000000..867c06acf
--- /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 9363a6a8c..262a33d8f 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 000000000..ed36b6d9d
--- /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 10da545d8..71a858e6b 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 fb82afe19..768127e42 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 a2440d7cb..7f65d0e59 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 885cb72a6..8d4ec98fb 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 1b8ae64b5..82235d278 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 a551d61f3..c8608731e 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 b309ce09f..4d65955f9 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 cb80039b7..1b96c1809 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 5febae839..a3cf7918e 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 000000000..f4f68ea01
--- /dev/null
+++ b/base/kra/src/com/netscape/kra/AsymKeyGenService.java
@@ -0,0 +1,210 @@
+//--- 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);
+ }
+
+ 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 71bd1d781..8eabe05ae 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 3ce37d6ae..d1b716cf8 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 f4768bd00..06c8ce1d5 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 a2d587318..752c8dff5 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,56 @@ 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) {
+ 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, null,
pass);
- } else if (dataType.equals(KeyRequestResource.PASS_PHRASE_TYPE)) {
- pbeWrappedData = createEncryptedContentInfo(ct, null, unwrappedSecData,
+ } else if (dataType.equals(KeyRequestResource.ASYMMETRIC_KEY_TYPE)) {
+ pbeWrappedData = createEncryptedContentInfo(ct, null, null, privateKey,
pass);
}
@@ -258,6 +265,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 +339,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 +374,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 +396,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 +411,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 4a2ebef34..25bb240e1 100644
--- a/base/kra/src/com/netscape/kra/SecurityDataService.java
+++ b/base/kra/src/com/netscape/kra/SecurityDataService.java
@@ -182,9 +182,12 @@ public class SecurityDataService implements IService {
// create key record
// Note that in this case the owner is the same as the approving agent
// because the archival request is made by the agent.
+ // The algorithm used to generate the symmetric key (being stored as the secret)
+ // is set in later in this method. (which is different from the algStr variable
+ // which is the algorithm used for encrypting the secret.)
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 46c8265f0..d308345d7 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 c538e016b..04dd3253f 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 9f33b1ba7..ecf3b0398 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 dd0393aab..8c014b02d 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 f1485deec..dfa23c15b 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
#