diff options
author | Abhishek Koneru <akoneru@redhat.com> | 2014-03-27 04:14:01 -0400 |
---|---|---|
committer | Abhishek Koneru <akoneru@redhat.com> | 2014-03-31 03:01:28 -0400 |
commit | 86f4022cc0598353d16901fa2d1ef90f474baaca (patch) | |
tree | afd5728380709c6bce5c1141bcf67186bb0badde | |
parent | a75e0f80e79804e36e5d0a67039bbe89c26807e4 (diff) | |
download | pki-86f4022cc0598353d16901fa2d1ef90f474baaca.tar.gz pki-86f4022cc0598353d16901fa2d1ef90f474baaca.tar.xz pki-86f4022cc0598353d16901fa2d1ef90f474baaca.zip |
Refactoring KeyClient class and crypto classes.
9 files changed, 324 insertions, 165 deletions
diff --git a/base/common/python/pki/key.py b/base/common/python/pki/key.py index 69e01c852..bd37a1623 100644 --- a/base/common/python/pki/key.py +++ b/base/common/python/pki/key.py @@ -52,8 +52,9 @@ class RequestId(object): #pylint: disable-msg=R0903 class KeyData(object): ''' - This is the object that contains the wrapped secret - when that secret is retrieved. + This is the object that contains the encoded wrapped secret + when that secret is retrieved. It is used by the DRM + to send information of the key in the key retrieval requests. ''' # pylint: disable-msg=C0103 @@ -63,22 +64,33 @@ class KeyData(object): self.nonceData = None self.size = None self.wrappedPrivateData = None - - # To store the unwrapped key information. - # Is not transferred in the response. - self.private_data = None @classmethod def from_json(cls, attr_list): ''' Return a KeyData object from a JSON dict ''' key_data = cls() for key in attr_list: - if (key == "wrappedPrivateData") or (key == "nonceData"): - setattr(key_data, key, base64.decodestring(attr_list[key])) - else: - setattr(key_data, key, attr_list[key]) + setattr(key_data, key, attr_list[key]) return key_data +class Key(object): + ''' + An instance of this class stores the decoded encrypted secret + present in the KeyData object passed in the constructor. + All the key retrieval requests return this object. + ''' + def __init__(self, key_data): + ''' Constructor ''' + self.encrypted_data = base64.decodestring(key_data.wrappedPrivateData) + self.nonce_data = base64.decodestring(key_data.nonceData) + self.algorithm = key_data.algorithm + self.size = key_data.size + + # To store the unwrapped key information. + # The decryption takes place on the client side. + self.data = None + + class KeyInfo(object): ''' This is the object that contains information stored @@ -542,14 +554,14 @@ class KeyClient(object): algorithm_oid = self.DES_EDE3_CBC_OID symkey_params = base64.encodestring(nonce_iv) - return self.archive_wrapped_data(client_key_id, data_type, wrapped_private_data, + return self.archive_encrypted_data(client_key_id, data_type, wrapped_private_data, trans_wrapped_session_key, algorithm_oid, symkey_params, key_algorithm=key_algorithm, key_size=key_size) @pki.handle_exceptions() - def archive_wrapped_data(self, client_key_id, data_type, - wrapped_private_data, trans_wrapped_session_key, + def archive_encrypted_data(self, client_key_id, data_type, + encrypted_data, trans_wrapped_session_key, algorithm_oid, symkey_params, key_algorithm=None, key_size=None): ''' Archive a secret (symmetric key or passphrase) on the DRM. @@ -580,12 +592,12 @@ class KeyClient(object): raise TypeError( "For symmetric keys, key algorithm and key size must be specified") - if (wrapped_private_data is None) or (trans_wrapped_session_key is None) or \ + if (encrypted_data is None) or (trans_wrapped_session_key is None) or \ (algorithm_oid is None) or (symkey_params is None): raise TypeError("All data and wrapping parameters must be specified") twsk = base64.encodestring(trans_wrapped_session_key) - data = base64.encodestring(wrapped_private_data) + data = base64.encodestring(encrypted_data) request = KeyArchivalRequest(client_key_id=client_key_id, data_type=data_type, wrapped_private_data=data, @@ -598,7 +610,7 @@ class KeyClient(object): return self.create_request(request) @pki.handle_exceptions() - def archive_options_data(self, client_key_id, data_type, pki_archive_options, + def archive_pki_options(self, client_key_id, data_type, pki_archive_options, key_algorithm=None, key_size=None): ''' Archive a secret (symmetric key or passphrase) on the DRM. @@ -671,7 +683,8 @@ class KeyClient(object): url = self.key_url + '/retrieve' key_request = json.dumps(data, cls=encoder.CustomTypeEncoder, sort_keys=True) response = self.connection.post(url, key_request, self.headers) - return KeyData.from_json(response.json()) + key_data = KeyData.from_json(response.json()) + return Key(key_data) @pki.handle_exceptions() def retrieve_key(self, key_id, trans_wrapped_session_key=None): @@ -721,13 +734,13 @@ class KeyClient(object): request_id=request_id, trans_wrapped_session_key=base64.encodestring(trans_wrapped_session_key)) - key_data = self.retrieve_key_data(request) + key = self.retrieve_key_data(request) if not key_provided: - key_data.private_data = self.crypto.symmetric_unwrap( - key_data.wrappedPrivateData, + key.data = self.crypto.symmetric_unwrap( + key.encrypted_data, session_key, - nonce_iv=key_data.nonceData) - return key_data + nonce_iv=key.nonce_data) + return key @pki.handle_exceptions() def retrieve_key_by_passphrase(self, key_id, passphrase=None, diff --git a/base/common/src/com/netscape/certsrv/key/Key.java b/base/common/src/com/netscape/certsrv/key/Key.java new file mode 100644 index 000000000..1b88075e4 --- /dev/null +++ b/base/common/src/com/netscape/certsrv/key/Key.java @@ -0,0 +1,87 @@ +package com.netscape.certsrv.key; + +import com.netscape.cmsutil.util.Utils; + +/** + * Represents a Key stored in the DRM. + * Return type for all the key retrieval requests of + * the KeyClient. + * + * @author akoneru + * + */ +public class Key { + + private byte[] encryptedData; + + private byte[] nonceData; + + private String p12Data; + + private String algorithm; + + private Integer size; + + private byte[] data; + + public Key() { + super(); + } + + public Key(KeyData data) { + encryptedData = Utils.base64decode(data.getWrappedPrivateData()); + nonceData = Utils.base64decode(data.getNonceData()); + p12Data = data.getP12Data(); + algorithm = data.getAlgorithm(); + size = data.getSize(); + } + + public byte[] getEncryptedData() { + return encryptedData; + } + + public void setEncryptedData(byte[] encryptedData) { + this.encryptedData = encryptedData; + } + + public byte[] getNonceData() { + return nonceData; + } + + public void setNonceData(byte[] nonceData) { + this.nonceData = nonceData; + } + + public String getP12Data() { + return p12Data; + } + + public void setP12Data(String p12Data) { + this.p12Data = p12Data; + } + + public String getAlgorithm() { + return algorithm; + } + + public void setAlgorithm(String algorithm) { + this.algorithm = algorithm; + } + + public Integer getSize() { + return size; + } + + public void setSize(Integer size) { + this.size = size; + } + + public byte[] getData() { + return data; + } + + public void setData(byte[] data) { + this.data = data; + } + +} diff --git a/base/common/src/com/netscape/certsrv/key/KeyClient.java b/base/common/src/com/netscape/certsrv/key/KeyClient.java index 68c70fb68..a3382c3b9 100644 --- a/base/common/src/com/netscape/certsrv/key/KeyClient.java +++ b/base/common/src/com/netscape/certsrv/key/KeyClient.java @@ -49,7 +49,7 @@ public class KeyClient extends Client { public KeyClient(PKIClient client, String subsystem) throws Exception { super(client, subsystem, "key"); init(); - this.crypto=client.getCrypto(); + this.crypto = client.getCrypto(); } public void init() throws URISyntaxException { @@ -70,6 +70,7 @@ public class KeyClient extends Client { * The HEADER and FOOTER should be removed from the string. * HEADER - CertData.HEADER * FOOTER - CertData.FOOTER + * * @param transportCert */ public void setTransportCert(String transportCert) { @@ -247,7 +248,7 @@ public class KeyClient extends Client { * @param data -- A KeyArchivalRequest/KeyRecoveryRequest/SymKeyGenerationRequest object * @return A KeyRequestResponse object */ - public KeyRequestResponse createRequest(ResourceMessage request) { + private KeyRequestResponse createRequest(ResourceMessage request) { if (request == null) { throw new IllegalArgumentException("A Request object must be specified."); } @@ -303,14 +304,14 @@ public class KeyClient extends Client { * @param data -- a KeyRecoveryRequest containing the keyId of the * secret being retrieved, the request_id of the approved recovery * request and a wrapping mechanism. - * @return A KeyData object containing the wrapped secret. + * @return A Key object containing the wrapped secret. */ - public KeyData retrieveKeyData(KeyRecoveryRequest data) { + public Key retrieveKeyData(KeyRecoveryRequest data) { if (data == null) { throw new IllegalArgumentException("A KeyRecoveryRequest object must be specified"); } Response response = keyClient.retrieveKey(data); - return client.getEntity(response, KeyData.class); + return new Key(client.getEntity(response, KeyData.class)); } /** @@ -321,27 +322,27 @@ public class KeyClient extends Client { * key of the DRM transport certificate before being sent to the DRM. * * This method will call CryptoUtil methods to generate the session key and wrap it - * with the DRM transport cert. The function will return the KeyData object, but with the secret - * set to the variable privateData. (The decryption of the wrappedPrivateData is done + * with the DRM transport cert. The function will return the Key object, but with the secret + * set to the variable data. (The decryption of the encryptedData is done * on the client side i.e. the secret is not transmitted as it is by the server.) * * @param keyId -- key id for secret - * @return A KeyData object containing the unwrapped secret. + * @return A Key object containing the unwrapped secret (set to the attribute data). * @throws Exception - Exceptions of type NoSuchAlgorithmException, IllegalStateException, TokenException, - * CertificateEncodingException, InvalidKeyException, InvalidAlgorithmParameterException, BadPaddingException, IllegalBlockSizeException + * CertificateEncodingException, InvalidKeyException, InvalidAlgorithmParameterException, + * BadPaddingException, IllegalBlockSizeException */ - public KeyData retrieveKey(KeyId keyId) throws Exception { + public Key retrieveKey(KeyId keyId) throws Exception { if (keyId == null) { throw new IllegalArgumentException("KeyId must be specified."); } SymmetricKey sessionKey = crypto.generateSessionKey(); byte[] transWrappedSessionKey = crypto.wrapSessionKeyWithTransportCert(sessionKey, transportCert); - KeyData data = retrieveKey(keyId, transWrappedSessionKey); + Key data = retrieveKey(keyId, transWrappedSessionKey); - data.setPrivateData(crypto.unwrapUsingSessionKey( - Utils.base64decode(data.getWrappedPrivateData()), sessionKey, - KeyRequestResource.DES3_ALGORITHM, Utils.base64decode(data.getNonceData()))); + data.setData(crypto.unwrapWithSessionKey(data.getEncryptedData(), sessionKey, + KeyRequestResource.DES3_ALGORITHM, data.getNonceData())); return data; } @@ -360,16 +361,17 @@ public class KeyClient extends Client { * * @param keyId -- key id for secret * @param transWrappedSessionKey -- session key wrapped by the transport cert. - * @return A KeyData object containing the wrapped secret. + * @return A Key object containing the wrapped secret. * @throws Exception - Exceptions of type NoSuchAlgorithmException, IllegalStateException, TokenException, - * CertificateEncodingException, InvalidKeyException, InvalidAlgorithmParameterException, BadPaddingException, IllegalBlockSizeException + * CertificateEncodingException, InvalidKeyException, InvalidAlgorithmParameterException, + * BadPaddingException, IllegalBlockSizeException */ - public KeyData retrieveKey(KeyId keyId, byte[] transWrappedSessionKey) throws Exception{ + public Key retrieveKey(KeyId keyId, byte[] transWrappedSessionKey) throws Exception { if (keyId == null) { throw new IllegalArgumentException("KeyId must be specified."); } - if (transWrappedSessionKey == null){ + if (transWrappedSessionKey == null) { throw new IllegalArgumentException("A transport cert wrapped session key cannot be null."); } @@ -398,11 +400,12 @@ public class KeyClient extends Client { * * @param keyId -- key id of secret. * @param passphrase -- passphrase used to wrap the secret in the response. - * @return KeyData object with the secret wrapped with the passphrase. + * @return A Key object with the secret wrapped with the passphrase. * @throws Exception - Exceptions of type NoSuchAlgorithmException, IllegalStateException, TokenException, - * CertificateEncodingException, InvalidKeyException, InvalidAlgorithmParameterException, BadPaddingException, IllegalBlockSizeException + * CertificateEncodingException, InvalidKeyException, InvalidAlgorithmParameterException, + * BadPaddingException, IllegalBlockSizeException */ - public KeyData retrieveKeyByPassphrase(KeyId keyId, String passphrase) throws Exception{ + public Key retrieveKeyByPassphrase(KeyId keyId, String passphrase) throws Exception { if (keyId == null) { throw new IllegalArgumentException("KeyId must be specified."); } @@ -412,7 +415,7 @@ public class KeyClient extends Client { SymmetricKey sessionKey = crypto.generateSessionKey(); byte[] transWrappedSessionKey = crypto.wrapSessionKeyWithTransportCert(sessionKey, this.transportCert); byte[] nonceData = CryptoUtil.getNonceData(8); - byte[] sessionWrappedPassphrase = crypto.wrapUsingSessionKey(passphrase, nonceData, sessionKey, + byte[] sessionWrappedPassphrase = crypto.wrapWithSessionKey(passphrase, nonceData, sessionKey, KeyRequestResource.DES3_ALGORITHM); return retrieveKeyUsingWrappedPassphrase(keyId, transWrappedSessionKey, sessionWrappedPassphrase, nonceData); @@ -431,11 +434,12 @@ public class KeyClient extends Client { * @param transWrappedSessionKey -- Session key wrapped with the transport cert * @param sessionWrappedPassphrase -- Passphrase wrapped with the session key * @param nonceData -- nonce data used for encryption. - * @return A KeyData object with the secret wrapped by the passphrase provided. + * @return A Key object with the secret wrapped by the passphrase provided. * @throws Exception - Exceptions of type NoSuchAlgorithmException, IllegalStateException, TokenException, - * CertificateEncodingException, InvalidKeyException, InvalidAlgorithmParameterException, BadPaddingException, IllegalBlockSizeException + * CertificateEncodingException, InvalidKeyException, InvalidAlgorithmParameterException, + * BadPaddingException, IllegalBlockSizeException */ - public KeyData retrieveKeyUsingWrappedPassphrase(KeyId keyId, byte[] transWrappedSessionKey, + public Key retrieveKeyUsingWrappedPassphrase(KeyId keyId, byte[] transWrappedSessionKey, byte[] sessionWrappedPassphrase, byte[] nonceData) throws Exception { if (keyId == null) { @@ -485,9 +489,9 @@ public class KeyClient extends Client { * @param keyId -- key id for secret * @param certificate -- the certificate associated with the private key * @param passphrase -- A passphrase for the pkcs12 file. - * @return A KeyData object with the wrapped secret + * @return A Key object with the wrapped secret */ - public KeyData retrieveKeyByPKCS12(KeyId keyId, String certificate, String passphrase) { + public Key retrieveKeyByPKCS12(KeyId keyId, String certificate, String passphrase) { if (keyId == null || certificate == null || passphrase == null) { throw new IllegalArgumentException("KeyId, certificate and passphrase must be specified."); } @@ -503,55 +507,61 @@ public class KeyClient extends Client { } /** - * Archive a secret (symmetric key or passphrase) on the DRM. + * Archive a passphrase on the DRM. * * Requires a user-supplied client ID. There can be only one active * key with a specified client ID. If a record for a duplicate active * key exists, a BadRequestException is thrown. * - * dataType can be one of the following: - * KeyClient.SYMMETRIC_KEY_TYPE, - * KeyClient.ASYMMETRIC_KEY_TYPE, - * KeyClient.PASS_PHRASE_TYPE * * @param clientKeyId -- Client Key Identfier - * @param dataType -- Type of the secret being archived. - * @param privateData -- the raw secret to be archived. - * @param keyAlgorithm - * @param keySize - * keyAlgorithm and keySize are applicable to symmetric keys only. - * If a symmetric key is being archived, these parameters are required. + * @param passphrase -- Secret passphrase to be archived * @return A KeyRequestResponse object with information about the request. * @throws Exception - Exceptions of type NoSuchAlgorithmException, IllegalStateException, TokenException, - * IOException, CertificateEncodingException, InvalidKeyException, InvalidAlgorithmParameterException, - * BadPaddingException, IllegalBlockSizeException + * IOException, CertificateEncodingException, InvalidKeyException, InvalidAlgorithmParameterException, + * BadPaddingException, IllegalBlockSizeException */ - public KeyRequestResponse archiveKey(String clientKeyId, String dataType, String privateData, String keyAlgorithm, - int keySize) throws Exception { + public KeyRequestResponse archivePassphrase(String clientKeyId, String passphrase) throws Exception { - if (clientKeyId == null || dataType == null) { - throw new IllegalArgumentException("Client key id and data type must be specified."); - } - if (dataType == KeyRequestResource.SYMMETRIC_KEY_TYPE) { - if (keyAlgorithm == null || keySize < 0) { - throw new IllegalArgumentException( - "Key algorithm and key size must be specified for a symmetric key type request."); - } - } - if (privateData == null) { - throw new IllegalArgumentException("No data provided to archive. privateData must be specified."); - } // Default algorithm OID for DES_EDE3_CBC String algorithmOID = EncryptionAlgorithm.DES3_CBC.toOID().toString(); byte[] nonceData = CryptoUtil.getNonceData(8); - String symAlgParams = Utils.base64encode(nonceData); SymmetricKey sessionKey = crypto.generateSessionKey(); byte[] transWrappedSessionKey = crypto.wrapSessionKeyWithTransportCert(sessionKey, this.transportCert); - byte[] wrappedPrivateData = crypto.wrapUsingSessionKey(privateData, nonceData, + byte[] encryptedData = crypto.wrapWithSessionKey(passphrase, nonceData, sessionKey, KeyRequestResource.DES3_ALGORITHM); - return archiveWrappedData(clientKeyId, dataType, keyAlgorithm, keySize, algorithmOID, - symAlgParams, wrappedPrivateData, transWrappedSessionKey); + return archiveEncryptedData(clientKeyId, KeyRequestResource.PASS_PHRASE_TYPE, null, 0, algorithmOID, + nonceData, encryptedData, transWrappedSessionKey); + } + + /** + * Archive a symmetric key on the DRM. + * + * Requires a user-supplied client ID. There can be only one active + * key with a specified client ID. If a record for a duplicate active + * key exists, a BadRequestException is thrown. + * + * @param clientKeyId -- Client Key Identifier + * @param keyAlgorithm -- Algorithm used by the symmetric key + * @param keySize -- Strength of the symmetric key (secret) + * @return A KeyRequestResponse object with information about the request. + * @throws Exception - Exceptions of type NoSuchAlgorithmException, IllegalStateException, TokenException, + * IOException, CertificateEncodingException, InvalidKeyException, InvalidAlgorithmParameterException, + * BadPaddingException, IllegalBlockSizeException + */ + public KeyRequestResponse archiveSymmetricKey(String clientKeyId, SymmetricKey secret, String keyAlgorithm, + int keySize) throws Exception { + + // Default algorithm OID for DES_EDE3_CBC + String algorithmOID = EncryptionAlgorithm.DES3_CBC.toOID().toString(); + SymmetricKey sessionKey = crypto.generateSessionKey(); + byte[] nonceData = CryptoUtil.getNonceData(8); + byte[] encryptedData = crypto.wrapWithSessionKey(secret, sessionKey, nonceData); + byte[] transWrappedSessionKey = crypto.wrapSessionKeyWithTransportCert(sessionKey, this.transportCert); + + return archiveEncryptedData(clientKeyId, KeyRequestResource.SYMMETRIC_KEY_TYPE, keyAlgorithm, keySize, + algorithmOID, nonceData, encryptedData, transWrappedSessionKey); } /** @@ -565,15 +575,16 @@ public class KeyClient extends Client { * @param dataType -- Type of secret being archived * @param keyAlgorithm -- Algorithm used - if the secret is a symmetric key * @param keySize -- Strength of the symmetric key (secret) - * @param algorithmOID -- string for the symmetric key wrap + * @param algorithmOID -- OID of the algorithm used for the symmetric key wrap * @param symAlgParams -- storing the value of Utils.base64encode(nonceData) - * @param wrappedPrivateData -- which is the secret wrapped by a session - * key (168 bit 3DES symmetric key) + * @param encryptedData -- which is the secret wrapped by a session + * key (168 bit 3DES symmetric key) * @param transWrappedSessionKey -- session key wrapped by the transport cert. * @return A KeyRequestResponse object with information about the request. */ - public KeyRequestResponse archiveWrappedData(String clientKeyId, String dataType, String keyAlgorithm, int keySize, - String algorithmOID, String symAlgParams, byte[] wrappedPrivateData, byte[] transWrappedSessionKey) { + public KeyRequestResponse archiveEncryptedData(String clientKeyId, String dataType, String keyAlgorithm, + int keySize, + String algorithmOID, byte[] nonceData, byte[] encryptedData, byte[] transWrappedSessionKey) { if (clientKeyId == null || dataType == null) { throw new IllegalArgumentException("Client key id and data type must be specified."); @@ -584,8 +595,8 @@ public class KeyClient extends Client { "Key algorithm and key size must be specified for a symmetric key type request."); } } - if (wrappedPrivateData == null || transWrappedSessionKey == null || algorithmOID == null - || symAlgParams == null) { + if (encryptedData == null || transWrappedSessionKey == null || algorithmOID == null + || nonceData == null) { throw new IllegalArgumentException("All data and wrapping parameters must be specified."); } KeyArchivalRequest data = new KeyArchivalRequest(); @@ -595,8 +606,8 @@ public class KeyClient extends Client { data.setKeySize(keySize); data.setClientKeyId(clientKeyId); data.setAlgorithmOID(algorithmOID); - data.setSymmetricAlgorithmParams(symAlgParams); - String req1 = Utils.base64encode(wrappedPrivateData); + data.setSymmetricAlgorithmParams(Utils.base64encode(nonceData)); + String req1 = Utils.base64encode(encryptedData); data.setWrappedPrivateData(req1); data.setTransWrappedSessionKey(Utils.base64encode(transWrappedSessionKey)); @@ -615,7 +626,7 @@ public class KeyClient extends Client { * @return A KeyRequestResponse object with information about the request. * @throws Exception */ - public KeyRequestResponse archiveOptionsData(String clientKeyId, String dataType, String keyAlgorithm, int keySize, + public KeyRequestResponse archivePKIOptions(String clientKeyId, String dataType, String keyAlgorithm, int keySize, byte[] pkiArchiveOptions) { if (clientKeyId == null || dataType == null) { diff --git a/base/common/src/com/netscape/certsrv/util/CryptoProvider.java b/base/common/src/com/netscape/certsrv/util/CryptoProvider.java index f5e5603aa..d0c753ae0 100644 --- a/base/common/src/com/netscape/certsrv/util/CryptoProvider.java +++ b/base/common/src/com/netscape/certsrv/util/CryptoProvider.java @@ -2,6 +2,13 @@ package com.netscape.certsrv.util; import org.mozilla.jss.crypto.SymmetricKey; +/** + * An abstract class defining the functionality to be provided by + * sub classes to perform cryptographic operations. + * + * @author akoneru + * + */ public abstract class CryptoProvider { public abstract void initialize() throws Exception; @@ -13,13 +20,18 @@ public abstract class CryptoProvider { public abstract byte[] wrapSessionKeyWithTransportCert(SymmetricKey sessionKey, String transportCert) throws Exception; - public abstract byte[] wrapUsingSessionKey(String passphrase, byte[] iv, SymmetricKey key, String keyAlgorithm) + public abstract byte[] wrapWithSessionKey(String passphrase, byte[] iv, SymmetricKey key, String keyAlgorithm) throws Exception; - public abstract String unwrapUsingSessionKey(byte[] wrappedRecoveredKey, SymmetricKey recoveryKey, + public abstract byte[] wrapWithSessionKey(SymmetricKey secret, SymmetricKey sessionKey, byte[] iv) throws Exception; + + public abstract byte[] unwrapWithSessionKey(byte[] wrappedRecoveredKey, SymmetricKey recoveryKey, String keyAlgorithm, byte[] nonceData) throws Exception; - public abstract String unWrapUsingPassphrase(String wrappedRecoveredKey, String recoveryPassphrase) + public abstract byte[] unwrapWithPassphrase(byte[] wrappedRecoveredKey, String recoveryPassphrase) throws Exception; + public abstract byte[] createPKIArchiveOptions(String transportCert, SymmetricKey secret, String passphrase, + String keyAlgorithm, int symKeySize, byte[] nonceData) 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 ae4e0d168..7c20e5cf4 100644 --- a/base/common/src/com/netscape/certsrv/util/NSSCryptoProvider.java +++ b/base/common/src/com/netscape/certsrv/util/NSSCryptoProvider.java @@ -1,17 +1,25 @@ package com.netscape.certsrv.util; +import java.io.CharConversionException; import java.io.File; +import java.io.IOException; import java.security.GeneralSecurityException; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateEncodingException; import org.mozilla.jss.CertDatabaseException; import org.mozilla.jss.CryptoManager; import org.mozilla.jss.CryptoManager.NotInitializedException; import org.mozilla.jss.KeyDatabaseException; +import org.mozilla.jss.asn1.InvalidBERException; import org.mozilla.jss.crypto.AlreadyInitializedException; +import org.mozilla.jss.crypto.BadPaddingException; import org.mozilla.jss.crypto.CryptoToken; import org.mozilla.jss.crypto.EncryptionAlgorithm; import org.mozilla.jss.crypto.IVParameterSpec; +import org.mozilla.jss.crypto.IllegalBlockSizeException; import org.mozilla.jss.crypto.KeyGenAlgorithm; import org.mozilla.jss.crypto.SymmetricKey; import org.mozilla.jss.crypto.TokenException; @@ -119,7 +127,7 @@ public class NSSCryptoProvider extends CryptoProvider { } @Override - public byte[] wrapUsingSessionKey(String passphrase, byte[] iv, SymmetricKey key, String encryptionAlgorithm) + public byte[] wrapWithSessionKey(String passphrase, byte[] iv, SymmetricKey key, String encryptionAlgorithm) throws Exception { if (token == null) { throw new NotInitializedException(); @@ -129,7 +137,7 @@ public class NSSCryptoProvider extends CryptoProvider { } @Override - public String unwrapUsingSessionKey(byte[] wrappedRecoveredKey, SymmetricKey recoveryKey, + public byte[] unwrapWithSessionKey(byte[] wrappedRecoveredKey, SymmetricKey recoveryKey, String encryptionAlgorithm, byte[] nonceData) throws Exception { if (token == null) { throw new NotInitializedException(); @@ -140,7 +148,7 @@ public class NSSCryptoProvider extends CryptoProvider { } @Override - public String unWrapUsingPassphrase(String wrappedRecoveredKey, String recoveryPassphrase) throws Exception { + public byte[] unwrapWithPassphrase(byte[] wrappedRecoveredKey, String recoveryPassphrase) throws Exception { return CryptoUtil.unwrapUsingPassphrase(wrappedRecoveredKey, recoveryPassphrase); } @@ -201,4 +209,21 @@ public class NSSCryptoProvider extends CryptoProvider { return alg; } + @Override + public byte[] createPKIArchiveOptions(String transportCert, SymmetricKey secret, String passphrase, + String keyAlgorithm, int symKeySize, byte[] nonceData) throws InvalidKeyException, + CertificateEncodingException, CharConversionException, NoSuchAlgorithmException, + InvalidAlgorithmParameterException, IllegalStateException, TokenException, IOException, + IllegalBlockSizeException, BadPaddingException, InvalidBERException { + + return CryptoUtil.createPKIArchiveOptions(manager, token, transportCert, secret, passphrase, + getKeyGenAlgorithm(keyAlgorithm), symKeySize, new IVParameterSpec(nonceData)); + } + + @Override + public byte[] wrapWithSessionKey(SymmetricKey secret, SymmetricKey sessionKey, byte[] iv) + throws InvalidKeyException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, TokenException { + return CryptoUtil.wrapSymmetricKey(token, secret, sessionKey, new IVParameterSpec(iv)); + } + } diff --git a/base/kra/functional/drmtest.py b/base/kra/functional/drmtest.py index 268c50913..b6fa18dcb 100644 --- a/base/kra/functional/drmtest.py +++ b/base/kra/functional/drmtest.py @@ -54,14 +54,14 @@ def print_key_info(key_info): print "Owner Name: " + str(key_info.ownerName) print "Size: " + str(key_info.size) -def print_key_data(key_data): +def print_key_data(key): ''' Prints the relevant fields of a KeyData object ''' - print "Key Algorithm: " + str(key_data.algorithm) - print "Key Size: " + str(key_data.size) - print "Nonce Data: " + base64.encodestring(key_data.nonceData) - print "Wrapped Private Data: " + base64.encodestring(key_data.wrappedPrivateData) - if key_data.private_data is not None: - print "Private Data: " + base64.encodestring(key_data.private_data) + print "Key Algorithm: " + str(key.algorithm) + print "Key Size: " + str(key.size) + print "Nonce Data: " + base64.encodestring(key.nonce_data) + print "Wrapped Private Data: " + base64.encodestring(key.encrypted_data) + if key.data is not None: + print "Private Data: " + base64.encodestring(key.data) def main(): ''' test code execution ''' @@ -139,15 +139,15 @@ def main(): print "My key id is " + str(key_id) key_data = keyclient.retrieve_key(key_id, trans_wrapped_session_key=wrapped_session_key) print_key_data(key_data) - unwrapped_key = crypto.symmetric_unwrap(key_data.wrappedPrivateData, + unwrapped_key = crypto.symmetric_unwrap(key_data.encrypted_data, session_key, - nonce_iv=key_data.nonceData) + nonce_iv=key_data.nonce_data) key1 = base64.encodestring(unwrapped_key) # Test 7: Recover key without providing trans_wrapped_session_key key_data = keyclient.retrieve_key(key_id) print_key_data(key_data) - key2 = base64.encodestring(key_data.private_data) + key2 = base64.encodestring(key_data.data) # Test 8 - Confirm that keys returned are the same if key1 == key2: @@ -233,7 +233,7 @@ def main(): key_data = keyclient.retrieve_key(key_info.get_key_id()) print_key_data(key_data) - key2 = base64.encodestring(key_data.private_data) + key2 = base64.encodestring(key_data.data) if key1 == key2: print "Success: archived and recovered keys match" 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 3fc2984a9..cb80039b7 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 @@ -40,8 +40,8 @@ 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.Key; import com.netscape.certsrv.key.KeyClient; -import com.netscape.certsrv.key.KeyData; import com.netscape.certsrv.key.KeyInfo; import com.netscape.certsrv.key.KeyRequestInfo; import com.netscape.certsrv.key.KeyRequestInfoCollection; @@ -148,13 +148,13 @@ public class DRMTest { String passphrase = null; // Session keys and passphrases for recovery - SymmetricKey recoveryKey = null; + SymmetricKey sessionKey = null; byte[] wrappedRecoveryKey = null; String recoveryPassphrase = null; byte[] wrappedRecoveryPassphrase = null; // retrieved data (should match archived data) - String wrappedRecoveredKey = null; + byte[] encryptedData = null; String recoveredKey = null; // various ids used in recovery/archival operations @@ -164,7 +164,7 @@ public class DRMTest { // Variables for data structures from calls KeyRequestResponse requestResponse = null; - KeyData keyData = null; + Key keyData = null; KeyInfo keyInfo = null; // Initialize token @@ -239,15 +239,14 @@ public class DRMTest { clientKeyId = "UUID: 123-45-6789 VEK " + Calendar.getInstance().getTime().toString(); try { vek = nssCrypto.generateSessionKey(); - byte[] encoded = CryptoUtil.createPKIArchiveOptions(nssCrypto.getManager(), nssCrypto.getToken(), - transportCert, vek, null, - KeyGenAlgorithm.DES3, 0, new IVParameterSpec(iv)); + byte[] encoded = nssCrypto.createPKIArchiveOptions(transportCert, vek, null, + KeyRequestResource.DES3_ALGORITHM, 0, iv); - KeyRequestResponse info = keyClient.archiveOptionsData(clientKeyId, KeyRequestResource.SYMMETRIC_KEY_TYPE, + KeyRequestResponse info = keyClient.archivePKIOptions(clientKeyId, KeyRequestResource.SYMMETRIC_KEY_TYPE, KeyRequestResource.DES3_ALGORITHM, 0, encoded); log("Archival Results:"); printRequestInfo(info.getRequestInfo()); - keyId = info.getRequestInfo().getKeyId(); + keyId = info.getKeyId(); } catch (Exception e) { log("Exception in archiving symmetric key:" + e.getMessage()); e.printStackTrace(); @@ -274,20 +273,20 @@ public class DRMTest { // Test 6: Submit a recovery request for the symmetric key using a session key log("Submitting a recovery request for the symmetric key using session key"); try { - recoveryKey = nssCrypto.generateSessionKey(); + sessionKey = nssCrypto.generateSessionKey(); wrappedRecoveryKey = CryptoUtil.wrapSymmetricKey(nssCrypto.getManager(), nssCrypto.getToken(), - transportCert, recoveryKey); + transportCert, sessionKey); keyData = keyClient.retrieveKey(keyId, wrappedRecoveryKey); } catch (Exception e) { log("Exception in recovering symmetric key using session key: " + e.getMessage()); } - wrappedRecoveredKey = keyData.getWrappedPrivateData(); + encryptedData = keyData.getEncryptedData(); try { - recoveredKey = new String(Utils.base64decode(nssCrypto.unwrapUsingSessionKey( - Utils.base64decode(wrappedRecoveredKey), recoveryKey, - KeyRequestResource.DES3_ALGORITHM, Utils.base64decode(keyData.getNonceData())))); + recoveredKey = Utils.base64encode(nssCrypto.unwrapWithSessionKey( + encryptedData, sessionKey, + KeyRequestResource.DES3_ALGORITHM, keyData.getNonceData())); } catch (Exception e) { log("Exception in unwrapping key: " + e.toString()); e.printStackTrace(); @@ -304,10 +303,10 @@ public class DRMTest { recoveryPassphrase = "Gimme me keys please"; try { - recoveryKey = nssCrypto.generateSessionKey(); - wrappedRecoveryPassphrase = nssCrypto.wrapUsingSessionKey(recoveryPassphrase, iv, recoveryKey, + sessionKey = nssCrypto.generateSessionKey(); + wrappedRecoveryPassphrase = nssCrypto.wrapWithSessionKey(recoveryPassphrase, iv, sessionKey, KeyRequestResource.DES3_ALGORITHM); - wrappedRecoveryKey = nssCrypto.wrapSessionKeyWithTransportCert(recoveryKey, transportCert); + wrappedRecoveryKey = nssCrypto.wrapSessionKeyWithTransportCert(sessionKey, transportCert); keyData = keyClient.retrieveKeyUsingWrappedPassphrase(keyId, wrappedRecoveryKey, wrappedRecoveryPassphrase, iv); @@ -316,10 +315,10 @@ public class DRMTest { e.printStackTrace(); } - wrappedRecoveredKey = keyData.getWrappedPrivateData(); + encryptedData = keyData.getEncryptedData(); try { - recoveredKey = CryptoUtil.unwrapUsingPassphrase(wrappedRecoveredKey, recoveryPassphrase); + recoveredKey = Utils.base64encode(nssCrypto.unwrapWithPassphrase(encryptedData, recoveryPassphrase)); } catch (Exception e) { log("Error: unable to unwrap key using passphrase"); e.printStackTrace(); @@ -335,12 +334,11 @@ public class DRMTest { // Test 8: Generate and archive a passphrase clientKeyId = "UUID: 123-45-6789 RKEK " + Calendar.getInstance().getTime().toString(); try { - requestResponse = keyClient.archiveKey(clientKeyId, KeyRequestResource.PASS_PHRASE_TYPE, passphrase, null, - 0); + requestResponse = keyClient.archivePassphrase(clientKeyId, passphrase); log("Archival Results:"); printRequestInfo(requestResponse.getRequestInfo()); - keyId = requestResponse.getRequestInfo().getKeyId(); + keyId = requestResponse.getKeyId(); } catch (Exception e) { log("Exception in archiving symmetric key:" + e.toString()); e.printStackTrace(); @@ -365,17 +363,16 @@ public class DRMTest { // Test 10: Submit a recovery request for the passphrase using a session key log("Submitting a recovery request for the passphrase using session key"); - recoveryKey = null; + sessionKey = null; wrappedRecoveryKey = null; try { keyData = keyClient.retrieveKeyByPassphrase(keyId, recoveryPassphrase); } catch (Exception e) { log("Exception in recovering passphrase using session key: " + e.getMessage()); } - wrappedRecoveredKey = keyData.getWrappedPrivateData(); + encryptedData = keyData.getEncryptedData(); try { - recoveredKey = CryptoUtil.unwrapUsingPassphrase(wrappedRecoveredKey, recoveryPassphrase); - recoveredKey = new String(Utils.base64decode(recoveredKey), "UTF-8"); + recoveredKey = new String(nssCrypto.unwrapWithPassphrase(encryptedData, recoveryPassphrase), "UTF-8"); } catch (Exception e) { log("Exception in unwrapping key: " + e.toString()); e.printStackTrace(); @@ -389,9 +386,9 @@ public class DRMTest { // Test 11: Submit a recovery request for the passphrase using a passphrase try { - recoveryKey = nssCrypto.generateSessionKey(); - wrappedRecoveryKey = nssCrypto.wrapSessionKeyWithTransportCert(recoveryKey, transportCert); - wrappedRecoveryPassphrase = nssCrypto.wrapUsingSessionKey(recoveryPassphrase, iv, recoveryKey, + sessionKey = nssCrypto.generateSessionKey(); + wrappedRecoveryKey = nssCrypto.wrapSessionKeyWithTransportCert(sessionKey, transportCert); + wrappedRecoveryPassphrase = nssCrypto.wrapWithSessionKey(recoveryPassphrase, iv, sessionKey, KeyRequestResource.DES3_ALGORITHM); keyData = keyClient.retrieveKeyUsingWrappedPassphrase(keyId, wrappedRecoveryKey, wrappedRecoveryPassphrase, iv); @@ -400,10 +397,9 @@ public class DRMTest { System.out.println("Test 17: " + e1.getMessage()); System.exit(-1); } - wrappedRecoveredKey = keyData.getWrappedPrivateData(); + encryptedData = keyData.getEncryptedData(); try { - recoveredKey = CryptoUtil.unwrapUsingPassphrase(wrappedRecoveredKey, recoveryPassphrase); - recoveredKey = new String(Utils.base64decode(recoveredKey), "UTF-8"); + recoveredKey = new String(nssCrypto.unwrapWithPassphrase(encryptedData, recoveryPassphrase), "UTF-8"); } catch (Exception e) { log("Error: cannot unwrap key using passphrase"); e.printStackTrace(); @@ -422,10 +418,9 @@ public class DRMTest { } catch (Exception e1) { e1.printStackTrace(); } - wrappedRecoveredKey = keyData.getWrappedPrivateData(); + encryptedData = keyData.getEncryptedData(); try { - recoveredKey = CryptoUtil.unwrapUsingPassphrase(wrappedRecoveredKey, recoveryPassphrase); - recoveredKey = new String(Utils.base64decode(recoveredKey), "UTF-8"); + recoveredKey = new String(nssCrypto.unwrapWithPassphrase(encryptedData, recoveryPassphrase), "UTF-8"); } catch (Exception e) { log("Error: Can't unwrap recovered key using passphrase"); e.printStackTrace(); @@ -516,7 +511,7 @@ public class DRMTest { KeyRequestResource.AES_ALGORITHM, 128, usages, null); printRequestInfo(genKeyResponse.getRequestInfo()); - keyId = genKeyResponse.getRequestInfo().getKeyId(); + keyId = genKeyResponse.getKeyId(); // test 19: Get keyId for active key with client ID log("Getting key ID for symmetric key"); @@ -538,19 +533,19 @@ public class DRMTest { // Test 20: Submit a recovery request for the symmetric key using a session key log("Submitting a recovery request for the symmetric key using session key"); try { - recoveryKey = nssCrypto.generateSessionKey(); - wrappedRecoveryKey = nssCrypto.wrapSessionKeyWithTransportCert(recoveryKey, transportCert); + sessionKey = nssCrypto.generateSessionKey(); + wrappedRecoveryKey = nssCrypto.wrapSessionKeyWithTransportCert(sessionKey, transportCert); keyData = keyClient.retrieveKey(keyId, wrappedRecoveryKey); } catch (Exception e) { log("Exception in recovering symmetric key using session key: " + e.getMessage()); } - wrappedRecoveredKey = keyData.getWrappedPrivateData(); + encryptedData = keyData.getEncryptedData(); try { - recoveredKey = new String(Utils.base64decode(nssCrypto.unwrapUsingSessionKey( - Utils.base64decode(wrappedRecoveredKey), recoveryKey, KeyRequestResource.DES3_ALGORITHM, - Utils.base64decode(keyData.getNonceData())))); + recoveredKey = new String(nssCrypto.unwrapWithSessionKey( + encryptedData, sessionKey, KeyRequestResource.DES3_ALGORITHM, + keyData.getNonceData())); } catch (Exception e) { log("Exception in unwrapping key: " + e.toString()); e.printStackTrace(); @@ -587,11 +582,11 @@ public class DRMTest { transportCert, vek, null, KeyGenAlgorithm.DES3, 0, new IVParameterSpec(iv)); - KeyRequestResponse response = keyClient.archiveOptionsData(clientKeyId, + KeyRequestResponse response = keyClient.archivePKIOptions(clientKeyId, KeyRequestResource.SYMMETRIC_KEY_TYPE, KeyRequestResource.AES_ALGORITHM, 128, encoded); log("Archival Results:"); printRequestInfo(response.getRequestInfo()); - keyId = response.getRequestInfo().getKeyId(); + keyId = response.getKeyId(); } catch (Exception e) { log("Exception in archiving symmetric key:" + e.getMessage()); e.printStackTrace(); @@ -626,7 +621,7 @@ public class DRMTest { // generates a session key, wraps it with transport cert and completes the request. // The encrypted data is then unwrapped using the temporary session key and set to // the attribute privateData. - recoveredKey = keyData.getPrivateData(); + recoveredKey = Utils.base64encode(keyData.getData()); if (!recoveredKey.equals(Utils.base64encode(vek.getEncoded()))) { log("Error: recovered and archived keys do not match!"); 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 f72c4c78b..0202af4bc 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 @@ -169,7 +169,7 @@ public class KeyRequestDAO extends CMSRequestDAO { boolean keyExists = doesKeyExist(clientKeyId, "active"); if (keyExists == true) { - throw new EBaseException("Can not archive already active existing key!"); + throw new BadRequestException("Can not archive already active existing key!"); } IRequest request = queue.newRequest(IRequest.SECURITY_DATA_ENROLLMENT_REQUEST); diff --git a/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java b/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java index d3eafd7f5..ee077872f 100644 --- a/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java +++ b/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java @@ -1551,12 +1551,11 @@ public class CryptoUtil { return iv; } - public static String unwrapUsingPassphrase(String wrappedRecoveredKey, String recoveryPassphrase) + public static byte[] unwrapUsingPassphrase(byte[] wrappedRecoveredKey, String recoveryPassphrase) throws IOException, InvalidBERException, InvalidKeyException, IllegalStateException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, NotInitializedException, TokenException, IllegalBlockSizeException, BadPaddingException { EncryptedContentInfo cInfo = null; - String unwrappedData = null; //We have to do this to get the decoding to work. @SuppressWarnings("unused") @@ -1566,20 +1565,16 @@ public class CryptoUtil { PasswordConverter passConverter = new PasswordConverter(); - byte[] encoded = Utils.base64decode(wrappedRecoveredKey); - - ByteArrayInputStream inStream = new ByteArrayInputStream(encoded); + ByteArrayInputStream inStream = new ByteArrayInputStream(wrappedRecoveredKey); cInfo = (EncryptedContentInfo) new EncryptedContentInfo.Template().decode(inStream); byte[] decodedData = cInfo.decrypt(pass, passConverter); - unwrappedData = Utils.base64encode(decodedData); - - return unwrappedData; + return decodedData; } - public static String unwrapUsingSymmetricKey(CryptoToken token, IVParameterSpec IV, byte[] wrappedRecoveredKey, + public static byte[] unwrapUsingSymmetricKey(CryptoToken token, IVParameterSpec IV, byte[] wrappedRecoveredKey, SymmetricKey recoveryKey, EncryptionAlgorithm alg) throws NoSuchAlgorithmException, TokenException, BadPaddingException, IllegalBlockSizeException, InvalidKeyException, InvalidAlgorithmParameterException { @@ -1587,9 +1582,8 @@ public class CryptoUtil { Cipher decryptor = token.getCipherContext(alg); decryptor.initDecrypt(recoveryKey, IV); byte[] unwrappedData = decryptor.doFinal(wrappedRecoveredKey); - String unwrappedS = Utils.base64encode(unwrappedData); - return unwrappedS; + return unwrappedData; } public static byte[] wrapPassphrase(CryptoToken token, String passphrase, IVParameterSpec IV, SymmetricKey sk, @@ -1622,6 +1616,28 @@ public class CryptoUtil { return session_data; } + /** + * Wrap a symmetric Key with a SymmetricKey + * + * @param token + * @param secret + * @param wrapper + * @return + * @throws TokenException + * @throws NoSuchAlgorithmException + * @throws InvalidAlgorithmParameterException + * @throws InvalidKeyException + */ + public static byte[] wrapSymmetricKey(CryptoToken token, SymmetricKey secret, SymmetricKey wrapper, + IVParameterSpec IV) throws NoSuchAlgorithmException, TokenException, InvalidKeyException, + InvalidAlgorithmParameterException { + KeyWrapper wrapper1 = token.getKeyWrapper(KeyWrapAlgorithm.DES3_CBC_PAD); + wrapper1.initWrap(wrapper, IV); + byte[] keyData = wrapper1.wrap(secret); + + return keyData; + } + public static byte[] createPKIArchiveOptions(CryptoManager manager, CryptoToken token, String transportCert, SymmetricKey vek, String passphrase, KeyGenAlgorithm keyGenAlg, int symKeySize, IVParameterSpec IV) throws TokenException, CharConversionException, |