summaryrefslogtreecommitdiffstats
path: root/base/common/src
diff options
context:
space:
mode:
authorAde Lee <alee@redhat.com>2017-03-15 17:19:01 -0400
committerAde Lee <alee@redhat.com>2017-03-21 18:49:07 -0400
commit82478227debddbe11bd9b9eeb0e1e2f3bd5282fb (patch)
tree62418ffdfff9d90cec9ca6749f0524a83bf41233 /base/common/src
parentf40e0d002e57cadd5dc254d096db52de439ed900 (diff)
Fix Java client to use AES
* Changed the client to use AES-128-CBC-PAD rather than DES-3. Because AES-256-CBC-PAD has no OID defined, we use the following hack: * Pass in the AES-256-CBC OID as the encrypt algorithm OID * Use PKCS#1.5 Padding. * Changed the client to use AES for the wrapping key on retrieval. * Changed the server to implicitly assume PKCS#1.5 (and a key size of 128) when recieving the OID for AES. * Changed the client to send, and the server to pass through the encryption algorithm expected when retrieving the key. * Fixed the generate_iv() function to generate an appropriately sized IV on retrieval. This code has been tested to successfully create and retrieve secrets using AES. Ideally, we'd be using GCM rather than CBC, which then requires no padding - and no hack needed. Hopefully, we can get that working in a subsequent commit. Change-Id: Ic9e8d50169be0fe357a48a5a1b1c452c7a3dfad0
Diffstat (limited to 'base/common/src')
-rw-r--r--base/common/src/com/netscape/certsrv/key/KeyClient.java117
-rw-r--r--base/common/src/com/netscape/certsrv/security/WrappingParams.java5
-rw-r--r--base/common/src/com/netscape/certsrv/util/CryptoProvider.java13
-rw-r--r--base/common/src/com/netscape/certsrv/util/NSSCryptoProvider.java52
-rw-r--r--base/common/src/org/dogtagpki/common/Version.java85
5 files changed, 238 insertions, 34 deletions
diff --git a/base/common/src/com/netscape/certsrv/key/KeyClient.java b/base/common/src/com/netscape/certsrv/key/KeyClient.java
index 8236d7f6b..a05bb78df 100644
--- a/base/common/src/com/netscape/certsrv/key/KeyClient.java
+++ b/base/common/src/com/netscape/certsrv/key/KeyClient.java
@@ -18,11 +18,16 @@
package com.netscape.certsrv.key;
import java.net.URISyntaxException;
+import java.security.NoSuchAlgorithmException;
import java.util.List;
import javax.ws.rs.core.Response;
+import org.dogtagpki.common.Info;
+import org.dogtagpki.common.InfoResource;
+import org.dogtagpki.common.Version;
import org.mozilla.jss.crypto.EncryptionAlgorithm;
+import org.mozilla.jss.crypto.KeyWrapAlgorithm;
import org.mozilla.jss.crypto.SymmetricKey;
import com.netscape.certsrv.base.ResourceMessage;
@@ -42,19 +47,55 @@ public class KeyClient extends Client {
public KeyResource keyClient;
public KeyRequestResource keyRequestClient;
+ public InfoResource infoClient;
private CryptoProvider crypto;
private String transportCert;
+ private EncryptionAlgorithm encryptAlgorithm;
+ private KeyWrapAlgorithm wrapAlgorithm;
+ private int wrapIVLength;
public KeyClient(PKIClient client, String subsystem) throws Exception {
super(client, subsystem, "key");
init();
- this.crypto = client.getCrypto();
+ crypto = client.getCrypto();
+
+ // TODO(alee) enable this when we figure out why its not working
+ // Version serverVersion = getServerVersion();
+
+ Version serverVersion= new Version("10.4.0");
+ if ((serverVersion.getMajor() >= 10) && (serverVersion.getMinor() >=4)) {
+ encryptAlgorithm = EncryptionAlgorithm.AES_128_CBC_PAD;
+ wrapAlgorithm = KeyWrapAlgorithm.AES_KEY_WRAP_PAD;
+ wrapIVLength = 0;
+ } else {
+ encryptAlgorithm = EncryptionAlgorithm.DES3_CBC;
+ wrapAlgorithm = KeyWrapAlgorithm.DES3_CBC_PAD;
+ wrapIVLength = 8;
+ }
+ }
+
+ private Version getServerVersion() {
+ Version ret = null;
+ try {
+ Response response = infoClient.getInfo();
+ Info info = client.getEntity(response, Info.class);
+ String version = info.getVersion();
+ ret = new Version(version);
+ } catch (Exception e) {
+ // TODO(alee) - narrow the exception here. We should only
+ // return Version(0.0.0) in the case where get a 404 response.
+
+ // old server - may not have the Info service
+ ret = new Version("0.0.0");
+ }
+ return ret;
}
public void init() throws URISyntaxException {
keyClient = createProxy(KeyResource.class);
keyRequestClient = createProxy(KeyRequestResource.class);
+ infoClient = createProxy(InfoResource.class);
}
public CryptoProvider getCrypto() {
@@ -363,13 +404,13 @@ public class KeyClient extends Client {
if (keyId == null) {
throw new IllegalArgumentException("KeyId must be specified.");
}
- SymmetricKey sessionKey = crypto.generateSessionKey();
+ SymmetricKey sessionKey = crypto.generateSessionKey(encryptAlgorithm);
byte[] transWrappedSessionKey = crypto.wrapSessionKeyWithTransportCert(sessionKey, transportCert);
Key data = retrieveKey(keyId, transWrappedSessionKey);
if (data.getEncryptedData()!= null)
data.setData(crypto.unwrapWithSessionKey(data.getEncryptedData(), sessionKey,
- KeyRequestResource.DES3_ALGORITHM, data.getNonceData()));
+ encryptAlgorithm, data.getNonceData()));
return data;
}
@@ -378,17 +419,18 @@ public class KeyClient extends Client {
if (requestId == null) {
throw new IllegalArgumentException("RequestId must be specified.");
}
- SymmetricKey sessionKey = crypto.generateSessionKey();
+ SymmetricKey sessionKey = crypto.generateSessionKey(encryptAlgorithm);
byte[] transWrappedSessionKey = crypto.wrapSessionKeyWithTransportCert(sessionKey, transportCert);
KeyRecoveryRequest recoveryRequest = new KeyRecoveryRequest();
recoveryRequest.setRequestId(requestId);
recoveryRequest.setTransWrappedSessionKey(Utils.base64encode(transWrappedSessionKey));
+ recoveryRequest.setPayloadEncryptionOID(getEncryptAlgorithmOID());
Key data = retrieveKeyData(recoveryRequest);
if (data.getEncryptedData() != null)
data.setData(crypto.unwrapWithSessionKey(data.getEncryptedData(), sessionKey,
- KeyRequestResource.DES3_ALGORITHM, data.getNonceData()));
+ encryptAlgorithm, data.getNonceData()));
return data;
}
@@ -423,6 +465,7 @@ public class KeyClient extends Client {
KeyRecoveryRequest recoveryRequest = new KeyRecoveryRequest();
recoveryRequest.setKeyId(keyId);
recoveryRequest.setTransWrappedSessionKey(Utils.base64encode(transWrappedSessionKey));
+ recoveryRequest.setPayloadEncryptionOID(getEncryptAlgorithmOID());
return retrieveKeyData(recoveryRequest);
}
@@ -453,11 +496,11 @@ public class KeyClient extends Client {
if (passphrase == null) {
throw new IllegalArgumentException("Passphrase must be specified.");
}
- SymmetricKey sessionKey = crypto.generateSessionKey();
- byte[] transWrappedSessionKey = crypto.wrapSessionKeyWithTransportCert(sessionKey, this.transportCert);
- byte[] nonceData = CryptoUtil.getNonceData(8);
+ SymmetricKey sessionKey = crypto.generateSessionKey(encryptAlgorithm);
+ byte[] transWrappedSessionKey = crypto.wrapSessionKeyWithTransportCert(sessionKey, transportCert);
+ byte[] nonceData = CryptoUtil.getNonceData(encryptAlgorithm.getIVLength());
byte[] sessionWrappedPassphrase = crypto.wrapWithSessionKey(passphrase, nonceData, sessionKey,
- KeyRequestResource.DES3_ALGORITHM);
+ encryptAlgorithm);
return retrieveKeyUsingWrappedPassphrase(keyId, transWrappedSessionKey, sessionWrappedPassphrase, nonceData);
}
@@ -470,17 +513,18 @@ public class KeyClient extends Client {
throw new IllegalArgumentException("Passphrase must be specified.");
}
- SymmetricKey sessionKey = crypto.generateSessionKey();
- byte[] transWrappedSessionKey = crypto.wrapSessionKeyWithTransportCert(sessionKey, this.transportCert);
- byte[] nonceData = CryptoUtil.getNonceData(8);
+ SymmetricKey sessionKey = crypto.generateSessionKey(encryptAlgorithm);
+ byte[] transWrappedSessionKey = crypto.wrapSessionKeyWithTransportCert(sessionKey, transportCert);
+ byte[] nonceData = CryptoUtil.getNonceData(encryptAlgorithm.getIVLength());
byte[] sessionWrappedPassphrase = crypto.wrapWithSessionKey(passphrase, nonceData, sessionKey,
- KeyRequestResource.DES3_ALGORITHM);
+ encryptAlgorithm);
KeyRecoveryRequest data = new KeyRecoveryRequest();
data.setRequestId(requestId);
data.setTransWrappedSessionKey(Utils.base64encode(transWrappedSessionKey));
data.setSessionWrappedPassphrase(Utils.base64encode(sessionWrappedPassphrase));
data.setNonceData(Utils.base64encode(nonceData));
+ data.setPayloadEncryptionOID(getEncryptAlgorithmOID());
return retrieveKeyData(data);
}
@@ -528,6 +572,7 @@ public class KeyClient extends Client {
KeyRecoveryRequest data = new KeyRecoveryRequest();
data.setKeyId(keyId);
data.setRequestId(requestId);
+ data.setPayloadEncryptionOID(getEncryptAlgorithmOID());
if (transWrappedSessionKey != null) {
data.setTransWrappedSessionKey(Utils.base64encode(transWrappedSessionKey));
@@ -589,18 +634,34 @@ public class KeyClient extends Client {
*/
public KeyRequestResponse archivePassphrase(String clientKeyId, String passphrase, String realm)
throws Exception {
- // Default algorithm OID for DES_EDE3_CBC
- String algorithmOID = EncryptionAlgorithm.DES3_CBC.toOID().toString();
- byte[] nonceData = CryptoUtil.getNonceData(8);
- SymmetricKey sessionKey = crypto.generateSessionKey();
- byte[] transWrappedSessionKey = crypto.wrapSessionKeyWithTransportCert(sessionKey, this.transportCert);
- byte[] encryptedData = crypto.wrapWithSessionKey(passphrase, nonceData,
- sessionKey, KeyRequestResource.DES3_ALGORITHM);
+ String algorithmOID = getEncryptAlgorithmOID();
+
+ byte[] nonceData = CryptoUtil.getNonceData(encryptAlgorithm.getIVLength());
+ SymmetricKey sessionKey = crypto.generateSessionKey(encryptAlgorithm);
+ byte[] transWrappedSessionKey = crypto.wrapSessionKeyWithTransportCert(sessionKey, transportCert);
+
+ byte[] encryptedData = crypto.wrapWithSessionKey(
+ passphrase,
+ nonceData,
+ sessionKey,
+ encryptAlgorithm);
return archiveEncryptedData(clientKeyId, KeyRequestResource.PASS_PHRASE_TYPE, null, 0, algorithmOID,
nonceData, encryptedData, transWrappedSessionKey, realm);
}
+ private String getEncryptAlgorithmOID() throws NoSuchAlgorithmException {
+ String algorithmOID;
+ if (encryptAlgorithm.getAlg().toString().equalsIgnoreCase("AES")) {
+ // TODO(alee) - horrible hack until we figure out how to do GCM right
+ // We assume the client will have AES 128 CBC with padding
+ algorithmOID = EncryptionAlgorithm.AES_128_CBC.toOID().toString();
+ } else {
+ algorithmOID = encryptAlgorithm.toOID().toString();
+ }
+ return algorithmOID;
+ }
+
/* Old signature for backwards compatibility */
@Deprecated
public KeyRequestResponse archivePassphrase(String clientKeyId, String passphrase) throws Exception {
@@ -626,12 +687,16 @@ public class KeyClient extends Client {
public KeyRequestResponse archiveSymmetricKey(String clientKeyId, SymmetricKey secret, String keyAlgorithm,
int keySize, String realm) 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);
+ String algorithmOID = getEncryptAlgorithmOID();
+
+ byte[] nonceData = null;
+ if (wrapIVLength > 0) {
+ nonceData = CryptoUtil.getNonceData(wrapIVLength);
+ }
+
+ SymmetricKey sessionKey = crypto.generateSessionKey(encryptAlgorithm);
+ byte[] encryptedData = crypto.wrapWithSessionKey(secret, sessionKey, nonceData, wrapAlgorithm);
+ byte[] transWrappedSessionKey = crypto.wrapSessionKeyWithTransportCert(sessionKey, transportCert);
return archiveEncryptedData(clientKeyId, KeyRequestResource.SYMMETRIC_KEY_TYPE, keyAlgorithm, keySize,
algorithmOID, nonceData, encryptedData, transWrappedSessionKey, realm);
diff --git a/base/common/src/com/netscape/certsrv/security/WrappingParams.java b/base/common/src/com/netscape/certsrv/security/WrappingParams.java
index 5d8dc3a6e..e1bc83500 100644
--- a/base/common/src/com/netscape/certsrv/security/WrappingParams.java
+++ b/base/common/src/com/netscape/certsrv/security/WrappingParams.java
@@ -59,6 +59,11 @@ public class WrappingParams {
switch (encrypt.getAlg().toString()) {
case "AES":
+ // TODO(alee) - Terrible hack till we figure out why GCM is not working
+ // or a way to detect the padding.
+ // We are going to assume AES-128-PAD
+ encrypt = EncryptionAlgorithm.AES_128_CBC_PAD;
+
this.skType = SymmetricKey.AES;
this.skKeyGenAlgorithm = KeyGenAlgorithm.AES;
if (wrap == null) this.payloadWrapAlgorithm = KeyWrapAlgorithm.AES_KEY_WRAP_PAD;
diff --git a/base/common/src/com/netscape/certsrv/util/CryptoProvider.java b/base/common/src/com/netscape/certsrv/util/CryptoProvider.java
index d0c753ae0..0ec520580 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 org.mozilla.jss.crypto.EncryptionAlgorithm;
+import org.mozilla.jss.crypto.KeyWrapAlgorithm;
import org.mozilla.jss.crypto.SymmetricKey;
/**
@@ -17,17 +19,28 @@ public abstract class CryptoProvider {
public abstract SymmetricKey generateSessionKey() throws Exception;
+ public abstract SymmetricKey generateSessionKey(EncryptionAlgorithm algorithm) throws Exception;
+
public abstract byte[] wrapSessionKeyWithTransportCert(SymmetricKey sessionKey, String transportCert)
throws Exception;
public abstract byte[] wrapWithSessionKey(String passphrase, byte[] iv, SymmetricKey key, String keyAlgorithm)
throws Exception;
+ public abstract byte[] wrapWithSessionKey(String passphrase, byte[] iv, SymmetricKey key, EncryptionAlgorithm keyAlgorithm)
+ throws Exception;
+
public abstract byte[] wrapWithSessionKey(SymmetricKey secret, SymmetricKey sessionKey, byte[] iv) throws Exception;
+ public abstract byte[] wrapWithSessionKey(SymmetricKey secret, SymmetricKey sessionKey, byte[] iv,
+ KeyWrapAlgorithm wrapAlg) throws Exception;
+
public abstract byte[] unwrapWithSessionKey(byte[] wrappedRecoveredKey, SymmetricKey recoveryKey,
String keyAlgorithm, byte[] nonceData) throws Exception;
+ public abstract byte[] unwrapWithSessionKey(byte[] wrappedRecoveredKey, SymmetricKey recoveryKey,
+ EncryptionAlgorithm keyAlgorithm, byte[] nonceData) throws Exception;
+
public abstract byte[] unwrapWithPassphrase(byte[] wrappedRecoveredKey, String recoveryPassphrase)
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 a2d204347..423ad68e6 100644
--- a/base/common/src/com/netscape/certsrv/util/NSSCryptoProvider.java
+++ b/base/common/src/com/netscape/certsrv/util/NSSCryptoProvider.java
@@ -108,7 +108,14 @@ public class NSSCryptoProvider extends CryptoProvider {
@Override
public SymmetricKey generateSessionKey() throws Exception {
- return generateSymmetricKey(KeyRequestResource.DES3_ALGORITHM, 168);
+ return generateSymmetricKey(KeyRequestResource.AES_ALGORITHM, 128);
+ }
+
+ @Override
+ public SymmetricKey generateSessionKey(EncryptionAlgorithm algorithm) throws Exception {
+ return generateSymmetricKey(
+ algorithm.getAlg().toString(),
+ algorithm.getKeyStrength());
}
@Override
@@ -122,22 +129,37 @@ public class NSSCryptoProvider extends CryptoProvider {
@Override
public byte[] wrapWithSessionKey(String passphrase, byte[] iv, SymmetricKey key, String encryptionAlgorithm)
throws Exception {
+ return wrapWithSessionKey(passphrase, iv, key, getEncryptionAlgorithm(encryptionAlgorithm));
+ }
+
+ @Override
+ public byte[] wrapWithSessionKey(String passphrase, byte[] iv, SymmetricKey key, EncryptionAlgorithm encryptionAlgorithm)
+ throws Exception {
if (token == null) {
throw new NotInitializedException();
}
- return CryptoUtil.wrapPassphrase(token, passphrase, new IVParameterSpec(iv), key,
- getEncryptionAlgorithm(encryptionAlgorithm));
+ return CryptoUtil.wrapPassphrase(token, passphrase, new IVParameterSpec(iv), key, encryptionAlgorithm);
}
@Override
public byte[] unwrapWithSessionKey(byte[] wrappedRecoveredKey, SymmetricKey recoveryKey,
String encryptionAlgorithm, byte[] nonceData) throws Exception {
+ return unwrapWithSessionKey(wrappedRecoveredKey, recoveryKey,
+ getEncryptionAlgorithm(encryptionAlgorithm), nonceData);
+ }
+
+ @Override
+ public byte[] unwrapWithSessionKey(byte[] wrappedRecoveredKey, SymmetricKey recoveryKey,
+ EncryptionAlgorithm encryptionAlgorithm, byte[] nonceData) throws Exception {
if (token == null) {
throw new NotInitializedException();
}
- return CryptoUtil.decryptUsingSymmetricKey(token, new IVParameterSpec(nonceData), wrappedRecoveredKey,
- recoveryKey,
- getEncryptionAlgorithm(encryptionAlgorithm));
+ IVParameterSpec ivps = null;
+ if (nonceData != null) {
+ ivps = new IVParameterSpec(nonceData);
+ }
+ return CryptoUtil.decryptUsingSymmetricKey(token, ivps, wrappedRecoveredKey,
+ recoveryKey, encryptionAlgorithm);
}
@Override
@@ -217,8 +239,22 @@ public class NSSCryptoProvider extends CryptoProvider {
token,
sessionKey,
secret,
- new IVParameterSpec(iv),
- KeyWrapAlgorithm.DES3_CBC_PAD);
+ null,
+ KeyWrapAlgorithm.AES_KEY_WRAP_PAD);
}
+ @Override
+ public byte[] wrapWithSessionKey(SymmetricKey secret, SymmetricKey sessionKey, byte[] iv, KeyWrapAlgorithm wrapAlg)
+ throws Exception {
+ IVParameterSpec ivps = null;
+ if (iv != null) {
+ ivps = new IVParameterSpec(iv);
+ }
+ return CryptoUtil.wrapUsingSymmetricKey(
+ token,
+ sessionKey,
+ secret,
+ ivps,
+ wrapAlg);
+ }
}
diff --git a/base/common/src/org/dogtagpki/common/Version.java b/base/common/src/org/dogtagpki/common/Version.java
new file mode 100644
index 000000000..4f87e07ec
--- /dev/null
+++ b/base/common/src/org/dogtagpki/common/Version.java
@@ -0,0 +1,85 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2017 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package org.dogtagpki.common;
+
+public class Version {
+
+ private int major;
+ private int minor;
+ private int micro;
+
+ public Version(String version) {
+ String[] parts = version.split("[.]");
+ major = Integer.valueOf(parts[0]);
+
+ if (parts.length > 1) {
+ minor = Integer.valueOf(parts[1]);
+ }
+ if (parts.length > 2) {
+ micro = Integer.valueOf(parts[2]);
+ }
+ }
+
+ public int getMajor() {
+ return major;
+ }
+
+ public void setMajor(int major) {
+ this.major = major;
+ }
+
+ public int getMinor() {
+ return minor;
+ }
+
+ public void setMinor(int minor) {
+ this.minor = minor;
+ }
+
+ public int getMicro() {
+ return micro;
+ }
+
+ public void setMicro(int micro) {
+ this.micro = micro;
+ }
+
+ public static void main(String args[]) throws Exception {
+ Version version = new Version("10.4.0");
+ if (version.getMajor() != 10) System.out.println("Error in getting major");
+ if (version.getMinor() != 4) System.out.println("Error in getting minor");
+ if (version.getMicro() != 0) System.out.println("Error in getting micro");
+
+ version = new Version("9.1");
+ if (version.getMajor() != 9) System.out.println("Error in getting major");
+ if (version.getMinor() != 1) System.out.println("Error in getting minor");
+ if (version.getMicro() != 0) System.out.println("Error in getting micro");
+
+ version = new Version("4");
+ if (version.getMajor() != 4) System.out.println("Error in getting major");
+ if (version.getMinor() != 0) System.out.println("Error in getting minor");
+ if (version.getMicro() != 0) System.out.println("Error in getting micro");
+
+ version = new Version("8.53.2.6");
+ if (version.getMajor() != 8) System.out.println("Error in getting major");
+ if (version.getMinor() != 53) System.out.println("Error in getting minor");
+ if (version.getMicro() != 2) System.out.println("Error in getting micro");
+ }
+
+}