diff options
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; } |