summaryrefslogtreecommitdiffstats
path: root/base
diff options
context:
space:
mode:
authorAde Lee <alee@redhat.com>2017-03-28 13:01:30 -0400
committerAde Lee <alee@redhat.com>2017-03-28 14:18:14 -0400
commita5cbfd0fcd966604a5188352bb09042e3132eb32 (patch)
treec8c8f4a44363860149d604a0b45d8e78da53f06b /base
parent358064eed09fd43e9fe7b08e43bd03775df880df (diff)
downloadpki-a5cbfd0fcd966604a5188352bb09042e3132eb32.tar.gz
pki-a5cbfd0fcd966604a5188352bb09042e3132eb32.tar.xz
pki-a5cbfd0fcd966604a5188352bb09042e3132eb32.zip
Fix retrieval for symmetric keys
Up to now, we have only ever used the same algorithm (DES3_CBC) for key wrapping and encryption. With the change to use AES Keywrap and AES CBC, we need to know which mechanism was used to encrypt/wrap the secrets when returned to the client. This means passing back more information to the client with the key data, and also modifying the client to use this information to decode the data correctly. Change-Id: I7232085c1eedf38c63abad81db08acc912fa1da1
Diffstat (limited to 'base')
-rw-r--r--base/common/src/com/netscape/certsrv/key/Key.java48
-rw-r--r--base/common/src/com/netscape/certsrv/key/KeyClient.java53
-rw-r--r--base/common/src/com/netscape/certsrv/key/KeyData.java56
-rw-r--r--base/common/src/com/netscape/certsrv/request/IRequest.java1
-rw-r--r--base/common/src/com/netscape/certsrv/util/CryptoProvider.java10
-rw-r--r--base/common/src/com/netscape/certsrv/util/NSSCryptoProvider.java35
-rw-r--r--base/java-tools/src/com/netscape/cmstools/CRMFPopClient.java2
-rw-r--r--base/kra/src/com/netscape/kra/SecurityDataProcessor.java43
-rw-r--r--base/kra/src/org/dogtagpki/server/kra/rest/KeyService.java21
-rw-r--r--base/util/src/netscape/security/util/WrappingParams.java18
10 files changed, 258 insertions, 29 deletions
diff --git a/base/common/src/com/netscape/certsrv/key/Key.java b/base/common/src/com/netscape/certsrv/key/Key.java
index 60cc1b0c8..1afd54c20 100644
--- a/base/common/src/com/netscape/certsrv/key/Key.java
+++ b/base/common/src/com/netscape/certsrv/key/Key.java
@@ -41,6 +41,18 @@ public class Key {
@XmlElement
private RequestId requestId;
+ @XmlElement
+ private String wrapAlgorithm;
+
+ @XmlElement
+ private String encryptAlgorithmOID;
+
+ @XmlElement
+ private String type;
+
+ @XmlElement
+ private String publicKey;
+
public Key() {
super();
}
@@ -54,6 +66,10 @@ public class Key {
algorithm = data.getAlgorithm();
size = data.getSize();
requestId = data.requestID;
+ wrapAlgorithm = data.getWrapAlgorithm();
+ encryptAlgorithmOID = data.getEncryptAlgorithmOID();
+ type = data.getType();
+ publicKey = data.getPublicKey();
}
public byte[] getEncryptedData() {
@@ -111,4 +127,36 @@ public class Key {
public void setRequestId(RequestId requestId) {
this.requestId = requestId;
}
+
+ public String getWrapAlgorithm() {
+ return wrapAlgorithm;
+ }
+
+ public void setWrapAlgorithm(String wrapAlgorithm) {
+ this.wrapAlgorithm = wrapAlgorithm;
+ }
+
+ public String getEncryptAlgorithmOID() {
+ return encryptAlgorithmOID;
+ }
+
+ public void setEncryptAlgorithmOID(String encryptAlgorithmOID) {
+ this.encryptAlgorithmOID = encryptAlgorithmOID;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public String getPublicKey() {
+ return publicKey;
+ }
+
+ public void setPublicKey(String publicKey) {
+ this.publicKey = publicKey;
+ }
}
diff --git a/base/common/src/com/netscape/certsrv/key/KeyClient.java b/base/common/src/com/netscape/certsrv/key/KeyClient.java
index f459737e7..750d27081 100644
--- a/base/common/src/com/netscape/certsrv/key/KeyClient.java
+++ b/base/common/src/com/netscape/certsrv/key/KeyClient.java
@@ -18,7 +18,10 @@
package com.netscape.certsrv.key;
import java.net.URISyntaxException;
+import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
+import java.security.spec.X509EncodedKeySpec;
import java.util.List;
import javax.ws.rs.core.Response;
@@ -401,11 +404,51 @@ public class KeyClient extends Client {
byte[] transWrappedSessionKey = crypto.wrapSessionKeyWithTransportCert(sessionKey, transportCert);
Key data = retrieveKey(keyId, transWrappedSessionKey);
- if (data.getEncryptedData()!= null)
+ processKeyData(data, sessionKey);
+ return data;
+ }
+
+ public void processKeyData(Key data, SymmetricKey sessionKey) throws Exception {
+ if (data.getEncryptedData() == null)
+ return;
+
+ if (data.getWrapAlgorithm() == null) {
+ // data was encrypted
data.setData(crypto.unwrapWithSessionKey(data.getEncryptedData(), sessionKey,
- encryptAlgorithm, data.getNonceData()));
+ encryptAlgorithm, data.getNonceData()));
+ return;
+ }
- return data;
+ // data was key-wrapped and is a private or symmetric key
+ byte[] bytes = null;
+
+ if (data.getType().equalsIgnoreCase(KeyRequestResource.SYMMETRIC_KEY_TYPE)) {
+ bytes = crypto.unwrapSymmetricKeyWithSessionKey(
+ data.getEncryptedData(),
+ sessionKey,
+ wrapAlgorithm,
+ data.getNonceData(),
+ data.getAlgorithm(),
+ data.getSize());
+ } else {
+ // private key in asymmetric key pair
+
+ // get public key from key_info
+ // TODO(alee) This assumes RSA for now
+
+ byte[] pubKeyBytes = Utils.base64decode(data.getPublicKey());
+ PublicKey pubKey = KeyFactory.getInstance("RSA").generatePublic(
+ new X509EncodedKeySpec(pubKeyBytes));
+
+ bytes = crypto.unwrapAsymmetricKeyWithSessionKey(
+ data.getEncryptedData(),
+ sessionKey,
+ wrapAlgorithm,
+ data.getNonceData(),
+ pubKey);
+ }
+
+ data.setData(bytes);
}
public Key retrieveKeyByRequest(RequestId requestId) throws Exception {
@@ -421,9 +464,7 @@ public class KeyClient extends Client {
recoveryRequest.setPayloadEncryptionOID(getEncryptAlgorithmOID());
Key data = retrieveKeyData(recoveryRequest);
- if (data.getEncryptedData() != null)
- data.setData(crypto.unwrapWithSessionKey(data.getEncryptedData(), sessionKey,
- encryptAlgorithm, data.getNonceData()));
+ processKeyData(data, sessionKey);
return data;
}
diff --git a/base/common/src/com/netscape/certsrv/key/KeyData.java b/base/common/src/com/netscape/certsrv/key/KeyData.java
index ee13812b1..abf45caae 100644
--- a/base/common/src/com/netscape/certsrv/key/KeyData.java
+++ b/base/common/src/com/netscape/certsrv/key/KeyData.java
@@ -62,6 +62,18 @@ public class KeyData {
@XmlJavaTypeAdapter(RequestIdAdapter.class)
RequestId requestID;
+ @XmlElement
+ String encryptAlgorithmOID;
+
+ @XmlElement
+ String wrapAlgorithm;
+
+ @XmlElement
+ String type;
+
+ @XmlElement
+ String publicKey;
+
public KeyData() {
// required for JAXB (defaults)
}
@@ -162,4 +174,48 @@ public class KeyData {
public void setRequestID(RequestId requestID) {
this.requestID = requestID;
}
+
+ /**
+ * Symmetric and Asymmetric keys will be returned either encrypted or wrapped
+ * by the client provided symmetric key. Which mechanism is used depends on the
+ * capabilities of the server (and the HSM behind it). One (and only one) of
+ * encryptionAlgorithm or wrapAlgorithm will be set.
+ *
+ * @return OID of encryption algorithm used to wrap the secret.
+ */
+ public String getEncryptAlgorithmOID() {
+ return encryptAlgorithmOID;
+ }
+
+ public void setEncryptAlgorithmOID(String encryptAlgorithmOID) {
+ this.encryptAlgorithmOID = encryptAlgorithmOID;
+ }
+
+ /**
+ * @return name (as known by JSS) of algorithm used to wrap secret if key
+ * wrapping is used
+ */
+ public String getWrapAlgorithm() {
+ return wrapAlgorithm;
+ }
+
+ public void setWrapAlgorithm(String wrapAlgorithm) {
+ this.wrapAlgorithm = wrapAlgorithm;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public String getPublicKey() {
+ return publicKey;
+ }
+
+ public void setPublicKey(String publicKey) {
+ this.publicKey = publicKey;
+ }
}
diff --git a/base/common/src/com/netscape/certsrv/request/IRequest.java b/base/common/src/com/netscape/certsrv/request/IRequest.java
index 94fd2fd3f..a57f08eb1 100644
--- a/base/common/src/com/netscape/certsrv/request/IRequest.java
+++ b/base/common/src/com/netscape/certsrv/request/IRequest.java
@@ -181,6 +181,7 @@ public interface IRequest extends Serializable {
public static final String SECURITY_DATA_PASS_WRAPPED_DATA = "passPhraseWrappedData";
public static final String SECURITY_DATA_PL_ENCRYPTION_OID = "payloadEncryptionOID";
public static final String SECURITY_DATA_PL_WRAPPING_NAME = "payloadWrappingName";
+ public static final String SECURITY_DATA_PL_WRAPPED = "payloadWrapped";
// key generation request attributes
public static final String ASYMKEY_GENERATION_REQUEST = "asymkeyGenRequest";
diff --git a/base/common/src/com/netscape/certsrv/util/CryptoProvider.java b/base/common/src/com/netscape/certsrv/util/CryptoProvider.java
index 6746db960..28d619208 100644
--- a/base/common/src/com/netscape/certsrv/util/CryptoProvider.java
+++ b/base/common/src/com/netscape/certsrv/util/CryptoProvider.java
@@ -1,5 +1,7 @@
package com.netscape.certsrv.util;
+import java.security.PublicKey;
+
import org.mozilla.jss.crypto.EncryptionAlgorithm;
import org.mozilla.jss.crypto.KeyWrapAlgorithm;
import org.mozilla.jss.crypto.SymmetricKey;
@@ -44,4 +46,12 @@ public abstract class CryptoProvider {
public abstract byte[] unwrapWithPassphrase(byte[] wrappedRecoveredKey, String recoveryPassphrase)
throws Exception;
+ public abstract byte[] unwrapSymmetricKeyWithSessionKey(byte[] wrappedRecoveredKey, SymmetricKey recoveryKey,
+ KeyWrapAlgorithm wrapAlgorithm, byte[] nonceData, String algorithm, int size)
+ throws Exception;
+
+ public abstract byte[] unwrapAsymmetricKeyWithSessionKey(byte[] wrappedRecoveredKey, SymmetricKey recoveryKey,
+ KeyWrapAlgorithm wrapAlgorithm, byte[] nonceData, PublicKey pubKey)
+ throws Exception;
+
}
diff --git a/base/common/src/com/netscape/certsrv/util/NSSCryptoProvider.java b/base/common/src/com/netscape/certsrv/util/NSSCryptoProvider.java
index ec9a13407..1d2edbc77 100644
--- a/base/common/src/com/netscape/certsrv/util/NSSCryptoProvider.java
+++ b/base/common/src/com/netscape/certsrv/util/NSSCryptoProvider.java
@@ -3,6 +3,7 @@ package com.netscape.certsrv.util;
import java.io.File;
import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
import org.mozilla.jss.CertDatabaseException;
import org.mozilla.jss.CryptoManager;
@@ -14,6 +15,7 @@ import org.mozilla.jss.crypto.EncryptionAlgorithm;
import org.mozilla.jss.crypto.IVParameterSpec;
import org.mozilla.jss.crypto.KeyGenAlgorithm;
import org.mozilla.jss.crypto.KeyWrapAlgorithm;
+import org.mozilla.jss.crypto.PrivateKey;
import org.mozilla.jss.crypto.SymmetricKey;
import org.mozilla.jss.crypto.TokenException;
import org.mozilla.jss.util.IncorrectPasswordException;
@@ -163,6 +165,39 @@ public class NSSCryptoProvider extends CryptoProvider {
}
@Override
+ public byte[] unwrapSymmetricKeyWithSessionKey(byte[] wrappedRecoveredKey, SymmetricKey recoveryKey,
+ KeyWrapAlgorithm wrapAlgorithm, byte[] nonceData, String algorithm, int size)
+ throws Exception {
+ if (token == null) {
+ throw new NotInitializedException();
+ }
+ IVParameterSpec ivps = null;
+ if (nonceData != null) {
+ ivps = new IVParameterSpec(nonceData);
+ }
+ SymmetricKey key = CryptoUtil.unwrap(
+ token, SymmetricKey.Type.fromName(algorithm),
+ size, SymmetricKey.Usage.DECRYPT, recoveryKey,
+ wrappedRecoveredKey, wrapAlgorithm, ivps);
+ return key.getEncoded();
+ }
+
+ @Override
+ public byte[] unwrapAsymmetricKeyWithSessionKey(byte[] wrappedRecoveredKey, SymmetricKey recoveryKey,
+ KeyWrapAlgorithm wrapAlgorithm, byte[] nonceData, PublicKey pubKey)
+ throws Exception {
+ if (token == null) {
+ throw new NotInitializedException();
+ }
+ IVParameterSpec ivps = null;
+ if (nonceData != null) {
+ ivps = new IVParameterSpec(nonceData);
+ }
+ PrivateKey key = CryptoUtil.unwrap(token, pubKey, true, recoveryKey, wrappedRecoveredKey, wrapAlgorithm, ivps);
+ return key.getEncoded();
+ }
+
+ @Override
public byte[] unwrapWithPassphrase(byte[] wrappedRecoveredKey, String recoveryPassphrase) throws Exception {
return CryptoUtil.unwrapUsingPassphrase(wrappedRecoveredKey, recoveryPassphrase);
}
diff --git a/base/java-tools/src/com/netscape/cmstools/CRMFPopClient.java b/base/java-tools/src/com/netscape/cmstools/CRMFPopClient.java
index fafe956e7..901528c2f 100644
--- a/base/java-tools/src/com/netscape/cmstools/CRMFPopClient.java
+++ b/base/java-tools/src/com/netscape/cmstools/CRMFPopClient.java
@@ -554,7 +554,7 @@ public class CRMFPopClient {
EncryptionAlgorithm encryptAlg = null;
String keyset = System.getenv("KEY_WRAP_PARAMETER_SET");
- if ((keyset != null) && (keyset.equalsIgnoreCase("0"))) {
+ if (keyset != null && keyset.equalsIgnoreCase("0")) {
// talking to an old server?
encryptAlg = EncryptionAlgorithm.DES3_CBC;
} else {
diff --git a/base/kra/src/com/netscape/kra/SecurityDataProcessor.java b/base/kra/src/com/netscape/kra/SecurityDataProcessor.java
index 6c4851f13..3475eaef9 100644
--- a/base/kra/src/com/netscape/kra/SecurityDataProcessor.java
+++ b/base/kra/src/com/netscape/kra/SecurityDataProcessor.java
@@ -313,8 +313,6 @@ public class SecurityDataProcessor {
throws EBaseException {
CMS.debug("SecurityDataService.recover(): start");
-
- byte iv_in[] = null;
IConfigStore config = null;
try {
@@ -352,11 +350,6 @@ public class SecurityDataProcessor {
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.
CMS.debug("SecurityDataProcessor.recover(): No params provided.");
@@ -377,22 +370,18 @@ public class SecurityDataProcessor {
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 {
if (allowEncDecrypt_recovery == true) {
CMS.debug("Recover asymmetric key by decrypting as per allowEncDecrypt_recovery: true.");
unwrappedSecData = recoverSecurityData(keyRecord);
-
} else {
-
byte[] publicKeyData = keyRecord.getPublicKeyData();
byte[] privateKeyData = keyRecord.getPrivateKeyData();
@@ -475,24 +464,18 @@ public class SecurityDataProcessor {
if (allowEncDecrypt_recovery == true) {
CMS.debug("SecurityDataProcessor.recover(): 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);
+ pbeWrappedData = createEncryptedContentInfo(ct, symKey, null, null, pass);
}
} else if (dataType.equals(KeyRequestResource.PASS_PHRASE_TYPE)) {
CMS.debug("SecurityDataProcessor.recover(): encrypt stored passphrase with transport passphrase");
- pbeWrappedData = createEncryptedContentInfo(ct, null, unwrappedSecData, null,
- pass);
-
+ pbeWrappedData = createEncryptedContentInfo(ct, null, unwrappedSecData, null, pass);
} else if (dataType.equals(KeyRequestResource.ASYMMETRIC_KEY_TYPE)) {
-
if (allowEncDecrypt_recovery == true) {
CMS.debug("SecurityDataProcessor.recover(): allowEncDecyypt_recovery: true, asymmetric key: create blob with unwrapped key.");
pbeWrappedData = createEncryptedContentInfo(ct, null, unwrappedSecData, null, pass);
-
} else {
CMS.debug("SecurityDataProcessor.recover(): wrap stored private key with transport passphrase");
pbeWrappedData = createEncryptedContentInfo(ct, null, null, privateKey,
@@ -603,13 +586,33 @@ public class SecurityDataProcessor {
String wrappedKeyData = Utils.base64encode(key_data);
params.put(IRequest.SECURITY_DATA_SESS_WRAPPED_DATA, wrappedKeyData);
- params.put(IRequest.SECURITY_DATA_IV_STRING_OUT, ivStr);
+ }
+
+ params.put(IRequest.SECURITY_DATA_PL_ENCRYPTION_OID,
+ wrapParams.getPayloadEncryptionAlgorithmName());
+
+ params.put(IRequest.SECURITY_DATA_PL_WRAPPING_NAME,
+ wrapParams.getPayloadWrapAlgorithm().toString());
+
+ if ((allowEncDecrypt_recovery == true) || (dataType.equals(KeyRequestResource.PASS_PHRASE_TYPE))) {
+ params.put(IRequest.SECURITY_DATA_PL_WRAPPED, Boolean.toString(false));
+ if (wrapParams.getPayloadEncryptionIV() != null) {
+ params.put(IRequest.SECURITY_DATA_IV_STRING_OUT, ivStr);
+ }
+ } else {
+ //secret has wrapped using a key wrapping algorithm
+ params.put(IRequest.SECURITY_DATA_PL_WRAPPED, Boolean.toString(true));
+ if (wrapParams.getPayloadWrappingIV() != null) {
+ params.put(IRequest.SECURITY_DATA_IV_STRING_OUT, ivStr);
+ }
}
if(unwrappedSecData != null && unwrappedSecData.length > 0) {
Arrays.fill(unwrappedSecData, (byte)0);
}
+ params.put(IRequest.SECURITY_DATA_TYPE, dataType);
+
auditRecoveryRequestProcessed(auditSubjectID, ILogger.SUCCESS, requestID, serialno.toString(),
"None");
request.setExtData(IRequest.RESULT, IRequest.RES_SUCCESS);
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 a8b895fec..e8cb6e9b7 100644
--- a/base/kra/src/org/dogtagpki/server/kra/rest/KeyService.java
+++ b/base/kra/src/org/dogtagpki/server/kra/rest/KeyService.java
@@ -345,17 +345,34 @@ public class KeyService extends SubsystemService implements KeyResource {
keyData.setNonceData(nonceData);
}
- String algorithm = rec.getAlgorithm();
- Integer keySize = rec.getKeySize();
+ keyData.setType((String) requestParams.get(IRequest.SECURITY_DATA_TYPE));
+
+ String payloadWrapped = (String) requestParams.get(IRequest.SECURITY_DATA_PL_WRAPPED);
+ // either wrapAlgorithm or encryptAlgorithm will be set. This will tell the
+ // client which mechanism was used to encrypt the secret
+ if (payloadWrapped.equalsIgnoreCase("true")) {
+ keyData.setWrapAlgorithm(
+ (String) requestParams.get(IRequest.SECURITY_DATA_PL_WRAPPING_NAME));
+ } else {
+ keyData.setEncryptAlgorithmOID(
+ (String) requestParams.get(IRequest.SECURITY_DATA_PL_ENCRYPTION_OID));
+ }
+ String algorithm = rec.getAlgorithm();
if (algorithm != null) {
keyData.setAlgorithm(algorithm);
}
+ Integer keySize = rec.getKeySize();
if (keySize != null) {
keyData.setSize(keySize);
}
+ byte[] pubKeyBytes = rec.getPublicKeyData();
+ if (pubKeyBytes != null) {
+ keyData.setPublicKey(Utils.base64encode(pubKeyBytes));
+ }
+
kra.destroyVolatileRequest(request.getRequestId());
if (!synchronous) {
diff --git a/base/util/src/netscape/security/util/WrappingParams.java b/base/util/src/netscape/security/util/WrappingParams.java
index ab7868097..b2814a356 100644
--- a/base/util/src/netscape/security/util/WrappingParams.java
+++ b/base/util/src/netscape/security/util/WrappingParams.java
@@ -45,6 +45,15 @@ public class WrappingParams {
this.payloadWrappingIV = payloadWrapIV;
}
+ public static EncryptionAlgorithm getEncryptionAlgorithmFromName(String name) throws Exception {
+ String fields[] = name.split("//");
+ String alg = fields[0];
+ String mode = fields[1];
+ String padding = fields[2];
+ int strength = Integer.parseInt(fields[3]);
+ return EncryptionAlgorithm.lookup(alg, mode, padding, strength);
+ }
+
public WrappingParams() {}
public WrappingParams(String encryptOID, String wrapName, String priKeyAlgo, IVParameterSpec encryptIV, IVParameterSpec wrapIV)
@@ -172,6 +181,15 @@ public class WrappingParams {
this.payloadEncryptionAlgorithm = EncryptionAlgorithm.lookup(algName, modeName, paddingName, keyStrength);
}
+ public String getPayloadEncryptionAlgorithmName() {
+ // work around some of the issues with OIDs in JSS
+ int strength = payloadEncryptionAlgorithm.getKeyStrength();
+ String mode = payloadEncryptionAlgorithm.getMode().toString();
+ String padding = payloadEncryptionAlgorithm.getPadding().toString();
+ String alg = payloadEncryptionAlgorithm.getAlg().toString();
+ return alg + "/" + mode + "/" + padding + "/" + Integer.toString(strength);
+ }
+
public KeyWrapAlgorithm getPayloadWrapAlgorithm() {
return payloadWrapAlgorithm;
}