summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJack Magne <jmagne@localhost.localdomain>2015-09-22 10:26:07 -0700
committerMatthew Harmsen <mharmsen@redhat.com>2015-09-25 17:01:40 -0600
commitbaae3557b19b8b59813959e18473b3d2c395dd95 (patch)
treeec0cc14b5065138bcf2eee36fdde7aecd084bc4a
parentc5853ed032768a32ba496f21db3720c6c3dd61e5 (diff)
downloadpki-baae3557b19b8b59813959e18473b3d2c395dd95.tar.gz
pki-baae3557b19b8b59813959e18473b3d2c395dd95.tar.xz
pki-baae3557b19b8b59813959e18473b3d2c395dd95.zip
KRA: key archival/recovery via cli - should honor encryption/decryption flags.
Ticket # 1597 Currently, KRA allows sites to opt for doing encryption/decryption instead of wrapping/unwrapping for key archival and recovery. The new cli code was later added without such support. We should honor the same flags when cli is called to do key archival and recovery. This feature was due to a specific customer request. Here is what is now supported: 1. When the pki cli tool is used to recover a asymmetric private key, support is there to do so with encrypt / decrypt. 2. The passphrase and generic data facility already uses encrypt / decrypt so nothing here was needed. Calling it out since this will possibly be a customer issue. 3. While under the hood, it made sense to add this functionality to the Symmetric key archival and recovery operations. 4. All tests in DRMTest.java worked successfully when the kra was configured to support this feature and configured to not observe this feature. What is missing: We have since added a method to do a server side key generation of an asymmetric key pair in the kra and also archive it there at the same time. In order to do encrypt / decrypt in this case we need to extract the key contents out of a key object that is used to generate this key. It proved problematic to extract said key. This should be ok since the customer only needs to recover an asymmetric key in their test cases. We could look into doing this later if a pressing need arises. (cherry picked from commit a5a50e95a691587e22335018538b4f578dfee6d1)
-rw-r--r--base/kra/src/com/netscape/kra/SecurityDataRecoveryService.java107
-rw-r--r--base/kra/src/com/netscape/kra/SecurityDataService.java61
2 files changed, 138 insertions, 30 deletions
diff --git a/base/kra/src/com/netscape/kra/SecurityDataRecoveryService.java b/base/kra/src/com/netscape/kra/SecurityDataRecoveryService.java
index b2449677f..f12222bc7 100644
--- a/base/kra/src/com/netscape/kra/SecurityDataRecoveryService.java
+++ b/base/kra/src/com/netscape/kra/SecurityDataRecoveryService.java
@@ -25,6 +25,7 @@ import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.AlgorithmParameterSpec;
+import java.util.Arrays;
import java.util.Hashtable;
import java.util.Random;
@@ -57,6 +58,7 @@ import org.mozilla.jss.util.Password;
import com.netscape.certsrv.apps.CMS;
import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.base.IConfigStore;
import com.netscape.certsrv.dbs.keydb.IKeyRecord;
import com.netscape.certsrv.dbs.keydb.IKeyRepository;
import com.netscape.certsrv.key.KeyRequestResource;
@@ -91,6 +93,7 @@ public class SecurityDataRecoveryService implements IService {
"LOGGING_SIGNED_AUDIT_SECURITY_DATA_RECOVERY_REQUEST_PROCESSED_5";
public static final String ATTR_SERIALNO = "serialNumber";
public static final String ATTR_KEY_RECORD = "keyRecord";
+ private static boolean allowEncDecrypt_recovery = false;
public SecurityDataRecoveryService(IKeyRecoveryAuthority kra) {
mKRA = kra;
@@ -124,6 +127,15 @@ public class SecurityDataRecoveryService implements IService {
byte iv_default[] = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 };
byte iv_in[] = null;
+ IConfigStore config = null;
+
+ try {
+ config = CMS.getConfigStore();
+ allowEncDecrypt_recovery = config.getBoolean("kra.allowEncDecrypt.recovery", false);
+ } catch (Exception e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_CERT_ERROR", e.toString()));
+ }
+
String requestor = request.getExtDataInString(IRequest.ATTR_REQUEST_OWNER);
String auditSubjectID = requestor;
@@ -185,15 +197,24 @@ public class SecurityDataRecoveryService implements IService {
PrivateKey privateKey = null;
if (dataType.equals(KeyRequestResource.SYMMETRIC_KEY_TYPE)) {
- symKey = recoverSymKey(keyRecord);
+ if (allowEncDecrypt_recovery == true) {
+ CMS.debug("Recover symmetric key by decrypting as per allowEncDecrypt_recovery: true.");
+ unwrappedSecData = recoverSecurityData(keyRecord);
+ } else {
+ 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())));
+ if (allowEncDecrypt_recovery == true) {
+ CMS.debug("Recover asymmetric key by decrypting as per allowEncDecrypt_recovery: true.");
+ unwrappedSecData = recoverSecurityData(keyRecord);
+ } else {
+ privateKey = mStorageUnit.unwrap(keyRecord.getPrivateKeyData(),
+ X509Key.parsePublicKey(new DerValue(keyRecord.getPublicKeyData())));
+ }
} catch (IOException e) {
throw new EBaseException("Cannot fetch the private key from the database.", e);
@@ -223,17 +244,27 @@ public class SecurityDataRecoveryService implements IService {
passStr = null;
if (dataType.equals(KeyRequestResource.SYMMETRIC_KEY_TYPE)) {
- CMS.debug("SecurityDataRecoveryService: wrap stored symmetric key with transport passphrase");
- pbeWrappedData = createEncryptedContentInfo(ct, symKey, null, null,
- pass);
- } else if (dataType.equals(KeyRequestResource.PASS_PHRASE_TYPE)){
+ CMS.debug("SecurityDataRecoveryService: wrap or encrypt stored symmetric key with transport passphrase");
+ if (allowEncDecrypt_recovery == true) {
+ CMS.debug("SecurityDataRecoveryServic: allowEncDecyypt_recovery: true, symmetric key: create blob with unwrapped key.");
+ pbeWrappedData = createEncryptedContentInfo(ct, null, unwrappedSecData, null, pass);
+ } else {
+ pbeWrappedData = createEncryptedContentInfo(ct, symKey, null, null,
+ pass);
+ }
+ } else if (dataType.equals(KeyRequestResource.PASS_PHRASE_TYPE)) {
CMS.debug("SecurityDataRecoveryService: encrypt stored passphrase with transport passphrase");
pbeWrappedData = createEncryptedContentInfo(ct, null, unwrappedSecData, null,
pass);
} else if (dataType.equals(KeyRequestResource.ASYMMETRIC_KEY_TYPE)) {
- CMS.debug("SecurityDataRecoveryService: wrap stored private key with transport passphrase");
- pbeWrappedData = createEncryptedContentInfo(ct, null, null, privateKey,
- pass);
+ if (allowEncDecrypt_recovery == true) {
+ CMS.debug("SecurityDataRecoveryService: allowEncDecyypt_recovery: true, asymmetric key: create blob with unwrapped key.");
+ pbeWrappedData = createEncryptedContentInfo(ct, null, unwrappedSecData, null, pass);
+ } else {
+ CMS.debug("SecurityDataRecoveryService: wrap stored private key with transport passphrase");
+ pbeWrappedData = createEncryptedContentInfo(ct, null, null, privateKey,
+ pass);
+ }
}
params.put(IRequest.SECURITY_DATA_PASS_WRAPPED_DATA, pbeWrappedData);
@@ -257,12 +288,27 @@ public class SecurityDataRecoveryService implements IService {
CMS.debug("SecurityDataRecoveryService: secure retrieved data with session key");
if (dataType.equals(KeyRequestResource.SYMMETRIC_KEY_TYPE)) {
- CMS.debug("SecurityDataRecoveryService: wrap stored symmetric key with session key");
+ CMS.debug("SecurityDataRecoveryService: wrap or encrypt stored symmetric key with 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(symKey);
+ if (allowEncDecrypt_recovery == true) {
+ CMS.debug("SecurityDataRecoveryService: encrypt symmetric key with session key as per allowEncDecrypt_recovery: true.");
+ unwrappedSess = mTransportUnit.unwrap_sym(wrappedSessKey, SymmetricKey.Usage.ENCRYPT);
+ Cipher encryptor = ct.getCipherContext(EncryptionAlgorithm.DES3_CBC_PAD);
+ if (encryptor != null) {
+ encryptor.initEncrypt(unwrappedSess, new IVParameterSpec(iv));
+ key_data = encryptor.doFinal(unwrappedSecData);
+ } else {
+ auditRecoveryRequestProcessed(auditSubjectID, ILogger.FAILURE, requestID,
+ serialno.toString(), "Failed to create cipher encrypting symmetric key");
+ throw new IOException("Failed to create cipher encryping symmetric key");
+ }
+
+ } else {
+ 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(symKey);
+ }
} catch (Exception e) {
auditRecoveryRequestProcessed(auditSubjectID, ILogger.FAILURE, requestID, serialno.toString(),
@@ -292,12 +338,27 @@ public class SecurityDataRecoveryService implements IService {
}
} else if (dataType.equals(KeyRequestResource.ASYMMETRIC_KEY_TYPE)) {
- CMS.debug("SecurityDataRecoveryService: wrap stored private key with session key");
+ CMS.debug("SecurityDataRecoveryService: wrap or encrypt stored private key with 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);
+ if (allowEncDecrypt_recovery == true) {
+ CMS.debug("SecurityDataRecoveryService: encrypt symmetric key with session key as per allowEncDecrypt_recovery: true.");
+ unwrappedSess = mTransportUnit.unwrap_sym(wrappedSessKey, SymmetricKey.Usage.ENCRYPT);
+ Cipher encryptor = ct.getCipherContext(EncryptionAlgorithm.DES3_CBC_PAD);
+ if (encryptor != null) {
+ encryptor.initEncrypt(unwrappedSess, new IVParameterSpec(iv));
+ key_data = encryptor.doFinal(unwrappedSecData);
+ } else {
+ auditRecoveryRequestProcessed(auditSubjectID, ILogger.FAILURE, requestID,
+ serialno.toString(), "Failed to create cipher encrypting asymmetric key");
+ throw new IOException("Failed to create cipher encrypting asymmetric key");
+ }
+
+ } else {
+ 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(),
@@ -311,6 +372,10 @@ public class SecurityDataRecoveryService implements IService {
params.put(IRequest.SECURITY_DATA_IV_STRING_OUT, ivStr);
}
+ if(unwrappedSecData != null && unwrappedSecData.length > 0) {
+ Arrays.fill(unwrappedSecData, (byte)0);
+ }
+
auditRecoveryRequestProcessed(auditSubjectID, ILogger.SUCCESS, requestID, serialno.toString(),
"None");
request.setExtData(IRequest.RESULT, IRequest.RES_SUCCESS);
diff --git a/base/kra/src/com/netscape/kra/SecurityDataService.java b/base/kra/src/com/netscape/kra/SecurityDataService.java
index 25bb240e1..3a163e23b 100644
--- a/base/kra/src/com/netscape/kra/SecurityDataService.java
+++ b/base/kra/src/com/netscape/kra/SecurityDataService.java
@@ -18,12 +18,14 @@
package com.netscape.kra;
import java.math.BigInteger;
+import java.util.Arrays;
import org.dogtagpki.server.kra.rest.KeyRequestService;
import org.mozilla.jss.crypto.SymmetricKey;
import com.netscape.certsrv.apps.CMS;
import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.base.IConfigStore;
import com.netscape.certsrv.dbs.keydb.IKeyRecord;
import com.netscape.certsrv.dbs.keydb.IKeyRepository;
import com.netscape.certsrv.key.KeyRequestResource;
@@ -53,6 +55,7 @@ public class SecurityDataService implements IService {
private ITransportKeyUnit mTransportUnit = null;
private IStorageKeyUnit mStorageUnit = null;
private ILogger signedAuditLogger = CMS.getSignedAuditLogger();
+ private Boolean allowEncDecrypt_archival = false;
private final static String LOGGING_SIGNED_AUDIT_SECURITY_DATA_ARCHIVAL_REQUEST_PROCESSED =
"LOGGING_SIGNED_AUDIT_SECURITY_DATA_ARCHIVAL_REQUEST_PROCESSED_6";
@@ -100,6 +103,16 @@ public class SecurityDataService implements IService {
CMS.debug("SecurityDataService.serviceRequest. Request id: " + id);
CMS.debug("SecurityDataService.serviceRequest wrappedSecurityData: " + wrappedSecurityData);
+ IConfigStore config = null;
+
+ try {
+ config = CMS.getConfigStore();
+ allowEncDecrypt_archival = config.getBoolean("kra.allowEncDecrypt.archival", false);
+ } catch (Exception e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_CERT_ERROR", e.toString()));
+ }
+
+
String owner = request.getExtDataInString(IRequest.ATTR_REQUEST_OWNER);
String auditSubjectID = owner;
@@ -146,16 +159,42 @@ public class SecurityDataService implements IService {
byte[] securityData = null;
String keyType = null;
+ byte [] tmp_unwrapped = null;
+ byte [] unwrapped = null;
if (dataType.equals(KeyRequestResource.SYMMETRIC_KEY_TYPE)) {
// Symmetric Key
keyType = KeyRequestResource.SYMMETRIC_KEY_TYPE;
- securitySymKey = mTransportUnit.unwrap_symmetric(
- wrappedSessionKey,
- algStr,
- sparams,
- secdata,
- KeyRequestService.SYMKEY_TYPES.get(algorithm),
- strength);
+
+ if (allowEncDecrypt_archival == true) {
+ tmp_unwrapped = mTransportUnit.decryptExternalPrivate(
+ wrappedSessionKey,
+ algStr,
+ sparams,
+ secdata);
+
+ if(tmp_unwrapped == null ) {
+ throw new EBaseException("Can't decrypt symm key using allEncDecrypt_archival : true .");
+ }
+
+ /* making sure leading 0's are removed */
+ int first=0;
+ for (int j=0; (j< tmp_unwrapped.length) && (tmp_unwrapped[j]==0); j++) {
+ first++;
+ }
+ unwrapped = Arrays.copyOfRange(tmp_unwrapped, first, tmp_unwrapped.length);
+ Arrays.fill(tmp_unwrapped, (byte)0);
+
+
+ } else {
+
+ securitySymKey = mTransportUnit.unwrap_symmetric(
+ wrappedSessionKey,
+ algStr,
+ sparams,
+ secdata,
+ KeyRequestService.SYMKEY_TYPES.get(algorithm),
+ strength);
+ }
} else if (dataType.equals(KeyRequestResource.PASS_PHRASE_TYPE)) {
keyType = KeyRequestResource.PASS_PHRASE_TYPE;
@@ -170,9 +209,13 @@ public class SecurityDataService implements IService {
byte[] publicKey = null;
byte privateSecurityData[] = null;
- if (securitySymKey != null) {
+ if (securitySymKey != null && unwrapped == null) {
privateSecurityData = mStorageUnit.wrap(securitySymKey);
- } else if (securityData != null) {
+ } else if (unwrapped != null && allowEncDecrypt_archival == true) {
+ privateSecurityData = mStorageUnit.encryptInternalPrivate(unwrapped);
+ Arrays.fill(unwrapped, (byte)0);
+ CMS.debug("allowEncDecrypt_archival of symmetric key.");
+ }else if (securityData != null) {
privateSecurityData = mStorageUnit.encryptInternalPrivate(securityData);
} else { // We have no data.
auditArchivalRequestProcessed(auditSubjectID, ILogger.FAILURE, request.getRequestId(),