summaryrefslogtreecommitdiffstats
path: root/pki/base/kra/functional/src/com/netscape/cms/servlet/test/DRMTest.java
diff options
context:
space:
mode:
authorJack Magne <jmagne@redhat.com>2012-01-21 17:39:26 -0800
committerEndi Sukma Dewata <edewata@redhat.com>2012-02-13 15:48:20 -0600
commita9680c7b7097c6b715c57c6581d4f24a5e4ee8b8 (patch)
tree8403b15a424a112f4209cba8e78f358bbbfd271e /pki/base/kra/functional/src/com/netscape/cms/servlet/test/DRMTest.java
parent2181aa4dbc4f04cb58af4dcc0f827d30f1526d4c (diff)
downloadpki-a9680c7b7097c6b715c57c6581d4f24a5e4ee8b8.tar.gz
pki-a9680c7b7097c6b715c57c6581d4f24a5e4ee8b8.tar.xz
pki-a9680c7b7097c6b715c57c6581d4f24a5e4ee8b8.zip
KRA changes for archiving and recovering symmetric keys and passphrases.
Ticket #66 and #68. Add ability to archive and recover symmetric keys and passphrases using rest interface. Enhanced test client to test out new functionality. Provided support to return recovered data either wrapped by symmetric key or wrapped in PBE password based encryption blob. DRM symmetric key support cleanup changes. Consists of suggested cleanup measures based on review comments.
Diffstat (limited to 'pki/base/kra/functional/src/com/netscape/cms/servlet/test/DRMTest.java')
-rw-r--r--pki/base/kra/functional/src/com/netscape/cms/servlet/test/DRMTest.java218
1 files changed, 162 insertions, 56 deletions
diff --git a/pki/base/kra/functional/src/com/netscape/cms/servlet/test/DRMTest.java b/pki/base/kra/functional/src/com/netscape/cms/servlet/test/DRMTest.java
index a8560dc2e..7890b96c8 100644
--- a/pki/base/kra/functional/src/com/netscape/cms/servlet/test/DRMTest.java
+++ b/pki/base/kra/functional/src/com/netscape/cms/servlet/test/DRMTest.java
@@ -17,6 +17,7 @@
// --- END COPYRIGHT BLOCK ---
package com.netscape.cms.servlet.test;
+import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.CharConversionException;
import java.io.IOException;
@@ -27,11 +28,13 @@ import java.security.cert.CertificateEncodingException;
import java.util.Calendar;
import java.util.Collection;
import java.util.Iterator;
+import java.util.Random;
+
import org.mozilla.jss.CryptoManager;
import org.mozilla.jss.asn1.BIT_STRING;
+import org.mozilla.jss.asn1.InvalidBERException;
import org.mozilla.jss.asn1.OBJECT_IDENTIFIER;
import org.mozilla.jss.asn1.OCTET_STRING;
-import org.mozilla.jss.asn1.SEQUENCE;
import org.mozilla.jss.crypto.AlreadyInitializedException;
import org.mozilla.jss.crypto.BadPaddingException;
import org.mozilla.jss.crypto.Cipher;
@@ -43,13 +46,15 @@ import org.mozilla.jss.crypto.KeyGenAlgorithm;
import org.mozilla.jss.crypto.KeyGenerator;
import org.mozilla.jss.crypto.KeyWrapAlgorithm;
import org.mozilla.jss.crypto.KeyWrapper;
+import org.mozilla.jss.crypto.PBEAlgorithm;
import org.mozilla.jss.crypto.SymmetricKey;
import org.mozilla.jss.crypto.TokenException;
import org.mozilla.jss.crypto.X509Certificate;
+import org.mozilla.jss.pkcs12.PasswordConverter;
+import org.mozilla.jss.pkcs7.EncryptedContentInfo;
import org.mozilla.jss.pkix.crmf.EncryptedKey;
import org.mozilla.jss.pkix.crmf.EncryptedValue;
import org.mozilla.jss.pkix.crmf.PKIArchiveOptions;
-import org.mozilla.jss.pkix.primitive.AVA;
import org.mozilla.jss.pkix.primitive.AlgorithmIdentifier;
import org.mozilla.jss.util.Password;
@@ -63,6 +68,7 @@ import org.apache.commons.cli.PosixParser;
import com.netscape.cms.servlet.base.CMSResourceService;
import com.netscape.cms.servlet.key.model.KeyData;
import com.netscape.cms.servlet.key.model.KeyDataInfo;
+import com.netscape.cms.servlet.request.KeyRequestResource;
import com.netscape.cms.servlet.request.model.KeyRequestInfo;
@SuppressWarnings("deprecation")
@@ -123,8 +129,16 @@ public class DRMTest {
// used for crypto operations
byte iv[] = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 };
- IVParameterSpec IV = null;
- IV = new IVParameterSpec(iv);
+ IVParameterSpec ivSpec;
+ IVParameterSpec ivSpecServer;
+
+ try {
+ ivSpec = genIV(8);
+ } catch (Exception e) {
+ log("Can't generate initialization vector use default: " + e);
+ ivSpec = new IVParameterSpec(iv);
+ }
+
CryptoManager manager = null;
CryptoToken token = null;
KeyGenerator kg1 = null;
@@ -196,7 +210,7 @@ public class DRMTest {
// Test 2: Get list of completed key archival requests
log("\n\nList of completed archival requests");
- Collection<KeyRequestInfo> list = client.listRequests("complete", "enrollment");
+ Collection<KeyRequestInfo> list = client.listRequests("complete", "securityDataEnrollment");
if (list == null) {
log("No requests found");
} else {
@@ -209,7 +223,7 @@ public class DRMTest {
// Test 3: Get list of key recovery requests
log("\n\nList of completed recovery requests");
- Collection<KeyRequestInfo> list2 = client.listRequests("complete", "recovery");
+ Collection<KeyRequestInfo> list2 = client.listRequests("complete", "securityDataRecovery");
if (list2 == null) {
log("No requests found");
} else {
@@ -226,9 +240,10 @@ public class DRMTest {
try {
kg1 = token.getKeyGenerator(KeyGenAlgorithm.DES3);
vek = kg1.generate();
- byte[] encoded = createPKIArchiveOptions(manager, token, transportCert, vek, null, kg1);
- KeyRequestInfo info = client.archiveSecurityData(encoded, clientId);
+ byte[] encoded = createPKIArchiveOptions(manager, token, transportCert, vek, null, kg1, ivSpec);
+
+ KeyRequestInfo info = client.archiveSecurityData(encoded, clientId, KeyRequestResource.SYMMETRIC_KEY_TYPE);
log("Archival Results:");
printRequestInfo(info);
keyId = getId(info.getKeyURL());
@@ -238,6 +253,7 @@ public class DRMTest {
}
//Test 5: Get keyId for active key with client ID
+
log("Getting key ID for symmetric key");
keyInfo = client.getKeyData(clientId, "active");
String keyId2 = getId(keyInfo.getKeyURL());
@@ -249,6 +265,8 @@ public class DRMTest {
if (!keyId.equals(keyId2)) {
log("Error: key ids from search and archival do not match");
+ } else {
+ log("Success: keyids from search and archival match.");
}
// Test 6: Submit a recovery request for the symmetric key using a session key
@@ -256,7 +274,7 @@ public class DRMTest {
try {
recoveryKey = kg1.generate();
wrappedRecoveryKey = wrapSymmetricKey(manager, token, transportCert, recoveryKey);
- KeyRequestInfo info = client.requestRecovery(keyId, null, wrappedRecoveryKey);
+ KeyRequestInfo info = client.requestRecovery(keyId, null, wrappedRecoveryKey, ivSpec.getIV());
recoveryRequestId = getId(info.getRequestURL());
} catch (Exception e) {
log("Exception in recovering symmetric key using session key: " + e.getMessage());
@@ -269,10 +287,12 @@ public class DRMTest {
// Test 8: Get key
log("Getting key: " + keyId);
- keyData = client.retrieveKey(keyId, recoveryRequestId, null, wrappedRecoveryKey);
+ keyData = client.retrieveKey(keyId, recoveryRequestId, null, wrappedRecoveryKey, ivSpec.getIV());
wrappedRecoveredKey = keyData.getWrappedPrivateData();
+
+ ivSpecServer = new IVParameterSpec( com.netscape.osutil.OSUtil.AtoB(keyData.getNonceData()));
try {
- recoveredKey = unwrap(token, IV, wrappedRecoveredKey.getBytes("ISO-8859-1"), recoveryKey);
+ recoveredKey = unwrap(token, ivSpecServer,com.netscape.osutil.OSUtil.AtoB(wrappedRecoveredKey), recoveryKey);
} catch (Exception e) {
log("Exception in unwrapping key: " + e.toString());
e.printStackTrace();
@@ -280,6 +300,8 @@ public class DRMTest {
if (!recoveredKey.equals(com.netscape.osutil.OSUtil.BtoA(vek.getEncoded()))) {
log("Error: recovered and archived keys do not match!");
+ } else {
+ log("Success: recoverd and archived keys match!");
}
// Test 9: Submit a recovery request for the symmetric key using a passphrase
@@ -288,9 +310,10 @@ public class DRMTest {
try {
recoveryKey = kg1.generate();
- wrappedRecoveryPassphrase = wrapPassphrase(token, recoveryPassphrase, IV, recoveryKey);
+ wrappedRecoveryPassphrase = wrapPassphrase(token, recoveryPassphrase, ivSpec, recoveryKey);
wrappedRecoveryKey = wrapSymmetricKey(manager, token, transportCert, recoveryKey);
- requestInfo = client.requestRecovery(keyId, wrappedRecoveryPassphrase, wrappedRecoveryKey);
+
+ requestInfo = client.requestRecovery(keyId, wrappedRecoveryPassphrase, wrappedRecoveryKey, ivSpec.getIV());
recoveryRequestId = getId(requestInfo.getRequestURL());
} catch (Exception e) {
log("Exception in recovering symmetric key using passphrase" + e.toString());
@@ -303,19 +326,25 @@ public class DRMTest {
// Test 11: Get key
log("Getting key: " + keyId);
- keyData = client.retrieveKey(keyId, recoveryRequestId, wrappedRecoveryPassphrase, wrappedRecoveryKey);
+ keyData = client.retrieveKey(keyId, recoveryRequestId, wrappedRecoveryPassphrase, wrappedRecoveryKey, ivSpec.getIV());
wrappedRecoveredKey = keyData.getWrappedPrivateData();
+
recoveredKey = unwrap(wrappedRecoveredKey, recoveryPassphrase);
- if (!recoveredKey.equals(com.netscape.osutil.OSUtil.BtoA(vek.getEncoded()))) {
+
+ if (recoveredKey == null || !recoveredKey.equals(com.netscape.osutil.OSUtil.BtoA(vek.getEncoded()))) {
log("Error: recovered and archived keys do not match!");
+ } else {
+ log("Success: recovered and archived keys do match!");
}
+
+ passphrase = "secret12345";
// Test 12: Generate and archive a passphrase
clientId = "UUID: 123-45-6789 RKEK " + Calendar.getInstance().getTime().toString();
try {
- byte[] encoded = createPKIArchiveOptions(manager, token, transportCert, null, passphrase, kg1);
- requestInfo = client.archiveSecurityData(encoded, clientId);
+ byte[] encoded = createPKIArchiveOptions(manager, token, transportCert, null, passphrase, kg1, ivSpec);
+ requestInfo = client.archiveSecurityData(encoded, clientId, KeyRequestResource.PASS_PHRASE_TYPE);
log("Archival Results:");
printRequestInfo(requestInfo);
keyId = getId(requestInfo.getKeyURL());
@@ -336,6 +365,8 @@ public class DRMTest {
if (!keyId.equals(keyId2)) {
log("Error: key ids from search and archival do not match");
+ } else {
+ log("Success: key ids from search and archival do match!");
}
// Test 14: Submit a recovery request for the passphrase using a session key
@@ -346,7 +377,8 @@ public class DRMTest {
try {
recoveryKey = kg1.generate();
wrappedRecoveryKey = wrapSymmetricKey(manager, token, transportCert, recoveryKey);
- requestInfo = client.requestRecovery(keyId, null, wrappedRecoveryKey);
+ wrappedRecoveryPassphrase = wrapPassphrase(token, recoveryPassphrase, ivSpec, recoveryKey);
+ requestInfo = client.requestRecovery(keyId, null, wrappedRecoveryKey, ivSpec.getIV());
recoveryRequestId = getId(requestInfo.getRequestURL());
} catch (Exception e) {
log("Exception in recovering passphrase using session key: " + e.getMessage());
@@ -359,22 +391,26 @@ public class DRMTest {
// Test 16: Get key
log("Getting passphrase: " + keyId);
- keyData = client.retrieveKey(keyId, recoveryRequestId, null, wrappedRecoveryKey);
+ keyData = client.retrieveKey(keyId, recoveryRequestId, null, wrappedRecoveryKey, ivSpec.getIV());
wrappedRecoveredKey = keyData.getWrappedPrivateData();
+ ivSpecServer = new IVParameterSpec( com.netscape.osutil.OSUtil.AtoB(keyData.getNonceData()));
try {
- recoveredKey = unwrap(token, IV, wrappedRecoveredKey.getBytes("ISO-8859-1"), recoveryKey);
+ recoveredKey = unwrap(token, ivSpecServer, com.netscape.osutil.OSUtil.AtoB(wrappedRecoveredKey), recoveryKey);
+ recoveredKey = new String(com.netscape.osutil.OSUtil.AtoB(recoveredKey), "UTF-8");
} catch (Exception e) {
log("Exception in unwrapping key: " + e.toString());
e.printStackTrace();
}
- if (!recoveredKey.equals(passphrase)) {
+ if (recoveredKey == null || !recoveredKey.equals(passphrase)) {
log("Error: recovered and archived passphrases do not match!");
+ } else {
+ log("Success: recovered and archived passphrases do match!");
}
// Test 17: Submit a recovery request for the passphrase using a passphrase
log("Submitting a recovery request for the passphrase using a passphrase");
- requestInfo = client.requestRecovery(keyId, wrappedRecoveryPassphrase, wrappedRecoveryKey);
+ requestInfo = client.requestRecovery(keyId, wrappedRecoveryPassphrase, wrappedRecoveryKey, ivSpec.getIV());
recoveryRequestId = getId(requestInfo.getRequestURL());
//Test 18: Approve recovery
@@ -383,19 +419,80 @@ public class DRMTest {
// Test 19: Get key
log("Getting passphrase: " + keyId);
- keyData = client.retrieveKey(keyId, recoveryRequestId, wrappedRecoveryPassphrase, wrappedRecoveryKey);
+ keyData = client.retrieveKey(keyId, recoveryRequestId, wrappedRecoveryPassphrase, wrappedRecoveryKey, ivSpec.getIV());
wrappedRecoveredKey = keyData.getWrappedPrivateData();
recoveredKey = unwrap(wrappedRecoveredKey, recoveryPassphrase);
+ try {
+ recoveredKey = new String(com.netscape.osutil.OSUtil.AtoB(recoveredKey), "UTF-8");
+ } catch (Exception e) {
+ log("Error: Can't convert recovered passphrase from binary to ascii!");
+ }
- if (!recoveredKey.equals(passphrase)) {
+ if (recoveredKey == null || !recoveredKey.equals(passphrase)) {
log("Error: recovered and archived passphrases do not match!");
+ } else {
+ log("Success: recovered and archived passphrases do match!");
+ }
+
+ // Test 20: Submit a recovery request for the passphrase using a passphrase
+ //Wait until retrieving key before sending input data.
+
+ log("Submitting a recovery request for the passphrase using a passphrase, wait till end to provide recovery data.");
+ requestInfo = client.requestRecovery(keyId, null, null, null);
+ recoveryRequestId = getId(requestInfo.getRequestURL());
+
+ //Test 21: Approve recovery
+ log("Approving recovery request: " + recoveryRequestId);
+ client.approveRecovery(recoveryRequestId);
+
+ // Test 22: Get key
+ log("Getting passphrase: " + keyId);
+ keyData = client.retrieveKey(keyId, recoveryRequestId, wrappedRecoveryPassphrase, wrappedRecoveryKey, ivSpec.getIV());
+ wrappedRecoveredKey = keyData.getWrappedPrivateData();
+ recoveredKey = unwrap(wrappedRecoveredKey, recoveryPassphrase);
+ try {
+ recoveredKey = new String(com.netscape.osutil.OSUtil.AtoB(recoveredKey), "UTF-8");
+ } catch (Exception e) {
+ log("Error: Can't convert recovered passphrase from binary to ascii!");
}
+ if (recoveredKey == null || !recoveredKey.equals(passphrase)) {
+ log("Error: recovered and archived passphrases do not match!");
+ } else {
+ log("Success: recovered and archived passphrases do match!");
+ }
}
private static String unwrap(String wrappedRecoveredKey, String recoveryPassphrase) {
- // TODO Auto-generated method stub
- return null;
+
+ EncryptedContentInfo cInfo = null;
+ String unwrappedData = null;
+
+ //We have to do this to get the decoding to work.
+ PBEAlgorithm pbeAlg = PBEAlgorithm.PBE_SHA1_DES3_CBC;
+
+ log("pbeAlg: " + pbeAlg);
+ try {
+ Password pass = new Password(recoveryPassphrase.toCharArray());
+ PasswordConverter passConverter = new
+ PasswordConverter();
+
+ byte[] encoded = com.netscape.osutil.OSUtil.AtoB(wrappedRecoveredKey);
+
+ ByteArrayInputStream inStream = new ByteArrayInputStream(encoded);
+ cInfo = (EncryptedContentInfo)
+ new EncryptedContentInfo.Template().decode(inStream);
+
+ byte[] decodedData = cInfo.decrypt(pass, passConverter);
+
+ unwrappedData = com.netscape.osutil.OSUtil.BtoA(decodedData);
+
+ } catch (Exception e) {
+ log("Problem unwraping PBE wrapped datat! " + e.toString());
+
+ }
+
+ return unwrappedData;
}
private static void log(String string) {
@@ -407,31 +504,24 @@ public class DRMTest {
SymmetricKey recoveryKey) throws NoSuchAlgorithmException, TokenException, BadPaddingException,
IllegalBlockSizeException, InvalidKeyException, InvalidAlgorithmParameterException {
- if (wrappedRecoveredKey == null || recoveryKey == null || token == null) {
- return null;
- }
-
Cipher decryptor = token.getCipherContext(EncryptionAlgorithm.DES3_CBC_PAD);
decryptor.initDecrypt(recoveryKey, IV);
byte[] unwrappedData = decryptor.doFinal(wrappedRecoveredKey);
- String unwrappedS = new String(unwrappedData);
+ String unwrappedS = com.netscape.osutil.OSUtil.BtoA( unwrappedData);
return unwrappedS;
}
private static String getId(String link) {
- return link.substring(link.lastIndexOf("/"));
+ return link.substring(link.lastIndexOf("/") + 1);
}
private static byte[] createPKIArchiveOptions(CryptoManager manager, CryptoToken token, String transportCert,
- SymmetricKey vek, String passphrase, KeyGenerator kg1) throws TokenException, CharConversionException,
+ SymmetricKey vek, String passphrase, KeyGenerator kg1, IVParameterSpec IV) throws TokenException, CharConversionException,
NoSuchAlgorithmException, InvalidKeyException, InvalidAlgorithmParameterException,
CertificateEncodingException, IOException, IllegalStateException, IllegalBlockSizeException,
BadPaddingException {
byte[] key_data = null;
- byte iv[] = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 };
- IVParameterSpec IV = null;
- IV = new IVParameterSpec(iv);
//generate session key
SymmetricKey sk = kg1.generate();
@@ -450,17 +540,35 @@ public class DRMTest {
// create PKIArchiveOptions structure
AlgorithmIdentifier algS = new AlgorithmIdentifier(new OBJECT_IDENTIFIER("1.2.840.113549.3.7"),
- new OCTET_STRING(iv));
+ new OCTET_STRING(IV.getIV()));
EncryptedValue encValue = new EncryptedValue(null, algS, new BIT_STRING(session_data, 0), null, null,
new BIT_STRING(key_data, 0));
EncryptedKey key = new EncryptedKey(encValue);
PKIArchiveOptions opt = new PKIArchiveOptions(key);
- SEQUENCE seq = new SEQUENCE();
- seq.addElement(new AVA(new OBJECT_IDENTIFIER("1.3.6.1.5.5.7.5.1.4"), opt));
- ByteArrayOutputStream bo = new ByteArrayOutputStream();
- seq.encode(bo);
- byte[] encoded = bo.toByteArray();
+ byte[] encoded = null;
+
+ try {
+
+ //Let's make sure we can decode the encoded PKIArchiveOptions..
+ ByteArrayOutputStream oStream = new ByteArrayOutputStream();
+
+ opt.encode(oStream);
+
+ encoded = oStream.toByteArray();
+ ByteArrayInputStream inStream = new ByteArrayInputStream( encoded);
+ PKIArchiveOptions options = (PKIArchiveOptions)
+ new PKIArchiveOptions.Template().decode(inStream);
+ log("Decoded PKIArchiveOptions: " + options);
+ } catch (IOException e) {
+ log("Problem with PKIArchiveOptions: " + e.toString());
+ return null;
+
+ } catch (InvalidBERException e) {
+ log("Problem with PKIArchiveOptions: " + e.toString());
+ return null;
+ }
+
return encoded;
}
@@ -470,28 +578,16 @@ public class DRMTest {
byte[] wrappedPassphrase = null;
Cipher encryptor = null;
- if (passphrase == null || sk == null || token == null || IV == null) {
- return null;
- }
-
encryptor = token.getCipherContext(EncryptionAlgorithm.DES3_CBC_PAD);
log("cipher " + encryptor);
if (encryptor != null) {
encryptor.initEncrypt(sk, IV);
- wrappedPassphrase = encryptor.doFinal(passphrase.getBytes());
- log("Pass phrase mode key_data: " + wrappedPassphrase);
-
- // Try to decrypt
- String wrappedS = new String(wrappedPassphrase, "ISO-8859-1");
- byte[] pPhrase = wrappedS.getBytes("ISO-8859-1");
- encryptor.initDecrypt(sk, IV);
- byte[] decrypted = encryptor.doFinal(pPhrase);
- String s = new String(decrypted, "ISO-8859-1");
- log("Re decrypted pass phrase " + s + " decrypted.size " + decrypted.length);
+ wrappedPassphrase = encryptor.doFinal(passphrase.getBytes("UTF-8"));
} else {
throw new IOException("Failed to create cipher");
}
+
return wrappedPassphrase;
}
@@ -513,4 +609,14 @@ public class DRMTest {
log("Type: " + info.getRequestType());
}
+ //Use this when we actually create random initialization vectors
+ private static IVParameterSpec genIV(int blockSize) throws Exception {
+ // generate an IV
+ byte[] iv = new byte[blockSize];
+
+ Random rnd = new Random();
+ rnd.nextBytes(iv);
+
+ return new IVParameterSpec(iv);
+ }
}