diff options
author | Fraser Tweedale <ftweedal@redhat.com> | 2017-03-23 14:34:31 +1100 |
---|---|---|
committer | Matthew Harmsen <mharmsen@redhat.com> | 2017-04-29 23:49:48 -0600 |
commit | 633c7c6519c925af7e3700adff29961d72435c7f (patch) | |
tree | 00f5e127f2b682351f209be1862043f8b8f1f0b0 /base/util | |
parent | f31ad87440332845e7e5a1d6ea1f092fefd9eef1 (diff) | |
download | pki-633c7c6519c925af7e3700adff29961d72435c7f.tar.gz pki-633c7c6519c925af7e3700adff29961d72435c7f.tar.xz pki-633c7c6519c925af7e3700adff29961d72435c7f.zip |
PKCS12Util: use AES to encrypt private keys
Update PKCS12Util to use AES-256-CBC to encrypt private keys.
Use JSS CryptoStore methods to ensure that all key wrapping and
unwrapping is done on the token.
Specifically, CryptoStore.getEncryptedPrivateKeyInfo replaces the
previous process where a symmetric key was generated, the private
key wrapped to the symmetric key, then decryted into Dogtag's
memory, then re-encrypted under the supplied passphrase. Now the
key gets wrapped directly to the supplied passphrase.
Similarly, for import, the EncryptedPrivateKeyInfo was decrypted
using the supplied passphrase, then encrypted to a freshly generated
symmetric key, which was then used to unwrap the key into the token.
Now, the new JSS method CryptoStore.importEncryptedPrivateKeyInfo is
used to unwrap the EncryptedPrivateKeyInfo directly into the token,
using the supplied passphrase.
As a result, the PKCS12KeyInfo class, which previously stored
unencrypted key material (a PrivateKeyInfo object), it now only
deals with PrivateKey (an opaque handle to an PKCS #11 object)
on export and encoded (byte[]) EncryptedPrivateKeyInfo data on
import. This split suggests that PKCS12KeyInfo should be decomposed
into two classes - one containing a PrivateKey and the other
containing a byte[] encryptedPrivateKeyInfo - but this refactoring
is left for another day.
Part of: https://pagure.io/dogtagpki/issue/2610
Change-Id: I75d48de4d7040c9fb3a9a6d1e920c191aa757b70
(cherry picked from commit 2e198ddbe9ec5000ee7e14df0aa364b600d3aa92)
Diffstat (limited to 'base/util')
-rw-r--r-- | base/util/src/netscape/security/pkcs/PKCS12KeyInfo.java | 29 | ||||
-rw-r--r-- | base/util/src/netscape/security/pkcs/PKCS12Util.java | 122 |
2 files changed, 63 insertions, 88 deletions
diff --git a/base/util/src/netscape/security/pkcs/PKCS12KeyInfo.java b/base/util/src/netscape/security/pkcs/PKCS12KeyInfo.java index c7e84f01f..f180cf23b 100644 --- a/base/util/src/netscape/security/pkcs/PKCS12KeyInfo.java +++ b/base/util/src/netscape/security/pkcs/PKCS12KeyInfo.java @@ -19,31 +19,40 @@ package netscape.security.pkcs; import java.math.BigInteger; -import org.mozilla.jss.pkix.primitive.PrivateKeyInfo; +import org.mozilla.jss.crypto.PrivateKey; public class PKCS12KeyInfo { + private PrivateKey privateKey; + private byte[] epkiBytes; BigInteger id; - PrivateKeyInfo privateKeyInfo; String subjectDN; public PKCS12KeyInfo() { } - public BigInteger getID() { - return id; + public PKCS12KeyInfo(PrivateKey k) { + this.privateKey = k; } - public void setID(BigInteger id) { - this.id = id; + public PKCS12KeyInfo(byte[] epkiBytes) { + this.epkiBytes = epkiBytes; + } + + public PrivateKey getPrivateKey() { + return this.privateKey; } - public PrivateKeyInfo getPrivateKeyInfo() { - return privateKeyInfo; + public byte[] getEncryptedPrivateKeyInfoBytes() { + return epkiBytes; } - public void setPrivateKeyInfo(PrivateKeyInfo privateKeyInfo) { - this.privateKeyInfo = privateKeyInfo; + public BigInteger getID() { + return id; + } + + public void setID(BigInteger id) { + this.id = id; } public String getSubjectDN() { diff --git a/base/util/src/netscape/security/pkcs/PKCS12Util.java b/base/util/src/netscape/security/pkcs/PKCS12Util.java index 0b164aafc..9f9a35e16 100644 --- a/base/util/src/netscape/security/pkcs/PKCS12Util.java +++ b/base/util/src/netscape/security/pkcs/PKCS12Util.java @@ -33,27 +33,19 @@ import java.util.Collection; import org.apache.commons.lang.StringUtils; import org.mozilla.jss.CryptoManager; import org.mozilla.jss.asn1.ANY; -import org.mozilla.jss.asn1.ASN1Util; import org.mozilla.jss.asn1.ASN1Value; import org.mozilla.jss.asn1.BMPString; import org.mozilla.jss.asn1.OBJECT_IDENTIFIER; import org.mozilla.jss.asn1.OCTET_STRING; import org.mozilla.jss.asn1.SEQUENCE; import org.mozilla.jss.asn1.SET; -import org.mozilla.jss.crypto.Cipher; import org.mozilla.jss.crypto.CryptoStore; import org.mozilla.jss.crypto.CryptoToken; import org.mozilla.jss.crypto.EncryptionAlgorithm; -import org.mozilla.jss.crypto.IVParameterSpec; import org.mozilla.jss.crypto.InternalCertificate; -import org.mozilla.jss.crypto.KeyGenAlgorithm; -import org.mozilla.jss.crypto.KeyWrapAlgorithm; -import org.mozilla.jss.crypto.KeyWrapper; import org.mozilla.jss.crypto.NoSuchItemOnTokenException; import org.mozilla.jss.crypto.ObjectNotFoundException; -import org.mozilla.jss.crypto.PBEAlgorithm; import org.mozilla.jss.crypto.PrivateKey; -import org.mozilla.jss.crypto.SymmetricKey; import org.mozilla.jss.crypto.X509Certificate; import org.mozilla.jss.pkcs12.AuthenticatedSafes; import org.mozilla.jss.pkcs12.CertBag; @@ -61,14 +53,10 @@ import org.mozilla.jss.pkcs12.PFX; import org.mozilla.jss.pkcs12.PasswordConverter; import org.mozilla.jss.pkcs12.SafeBag; import org.mozilla.jss.pkix.primitive.Attribute; -import org.mozilla.jss.pkix.primitive.EncryptedPrivateKeyInfo; -import org.mozilla.jss.pkix.primitive.PrivateKeyInfo; import org.mozilla.jss.util.Password; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.netscape.cmsutil.crypto.CryptoUtil; - import netscape.ldap.LDAPDN; import netscape.ldap.util.DN; import netscape.security.x509.X509CertImpl; @@ -114,41 +102,30 @@ public class PKCS12Util { icert.setObjectSigningTrust(PKCS12.decodeFlags(flags[2])); } - byte[] getEncodedKey(PrivateKey privateKey) throws Exception { - CryptoManager cm = CryptoManager.getInstance(); - CryptoToken token = cm.getInternalKeyStorageToken(); - - byte[] iv = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 }; - IVParameterSpec param = new IVParameterSpec(iv); - - SymmetricKey sk = CryptoUtil.generateKey(token, KeyGenAlgorithm.DES3, 0, null, true); - byte[] enckey = CryptoUtil.wrapUsingSymmetricKey( - token, - sk, - privateKey, - param, - KeyWrapAlgorithm.DES3_CBC_PAD); - - Cipher c = token.getCipherContext(EncryptionAlgorithm.DES3_CBC_PAD); - c.initDecrypt(sk, param); - return c.doFinal(enckey); - } - public void addKeyBag(PKCS12KeyInfo keyInfo, Password password, SEQUENCE encSafeContents) throws Exception { + PrivateKey k = keyInfo.getPrivateKey(); + if (k == null) { + logger.debug("NO PRIVATE KEY for " + keyInfo.subjectDN); + return; + } logger.debug("Creating key bag for " + keyInfo.subjectDN); PasswordConverter passConverter = new PasswordConverter(); - byte salt[] = { 0x01, 0x01, 0x01, 0x01 }; - - EncryptedPrivateKeyInfo encPrivateKeyInfo = EncryptedPrivateKeyInfo.createPBE( - PBEAlgorithm.PBE_SHA1_DES3_CBC, - password, salt, 1, passConverter, keyInfo.privateKeyInfo); + byte[] epkiBytes = CryptoManager.getInstance() + .getInternalKeyStorageToken() + .getCryptoStore() + .getEncryptedPrivateKeyInfo( + /* NSS has a bug that causes any AES CBC encryption + * to use AES-256, but AlgorithmID contains chosen + * alg. To avoid mismatch, use AES_256_CBC. */ + passConverter, password, EncryptionAlgorithm.AES_256_CBC, 0, k); SET keyAttrs = createKeyBagAttrs(keyInfo); - SafeBag safeBag = new SafeBag(SafeBag.PKCS8_SHROUDED_KEY_BAG, encPrivateKeyInfo, keyAttrs); + SafeBag safeBag = new SafeBag( + SafeBag.PKCS8_SHROUDED_KEY_BAG, new ANY(epkiBytes), keyAttrs); encSafeContents.addElement(safeBag); } @@ -318,14 +295,10 @@ public class PKCS12Util { PrivateKey privateKey = cm.findPrivKeyByCert(cert); logger.debug("Certificate \"" + nickname + "\" has private key"); - PKCS12KeyInfo keyInfo = new PKCS12KeyInfo(); + PKCS12KeyInfo keyInfo = new PKCS12KeyInfo(privateKey); keyInfo.id = id; keyInfo.subjectDN = cert.getSubjectDN().toString(); - byte[] privateData = getEncodedKey(privateKey); - keyInfo.privateKeyInfo = (PrivateKeyInfo) - ASN1Util.decode(PrivateKeyInfo.getTemplate(), privateData); - pkcs12.addKeyInfo(keyInfo); } catch (ObjectNotFoundException e) { @@ -375,11 +348,7 @@ public class PKCS12Util { public PKCS12KeyInfo getKeyInfo(SafeBag bag, Password password) throws Exception { - PKCS12KeyInfo keyInfo = new PKCS12KeyInfo(); - - // get private key info - EncryptedPrivateKeyInfo encPrivateKeyInfo = (EncryptedPrivateKeyInfo) bag.getInterpretedBagContent(); - keyInfo.privateKeyInfo = encPrivateKeyInfo.decrypt(password, new PasswordConverter()); + PKCS12KeyInfo keyInfo = new PKCS12KeyInfo(bag.getBagContent().getEncoded()); // get key attributes SET bagAttrs = bag.getBagAttributes(); @@ -491,7 +460,7 @@ public class PKCS12Util { public void getKeyInfos(PKCS12 pkcs12, PFX pfx, Password password) throws Exception { - logger.debug("Load private keys:"); + logger.debug("Load encrypted private keys:"); AuthenticatedSafes safes = pfx.getAuthSafes(); @@ -590,20 +559,12 @@ public class PKCS12Util { public void importKey( PKCS12 pkcs12, + Password password, + String nickname, PKCS12KeyInfo keyInfo) throws Exception { logger.debug("Importing private key " + keyInfo.subjectDN); - byte iv[] = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 }; - IVParameterSpec param = new IVParameterSpec(iv); - - PrivateKeyInfo privateKeyInfo = keyInfo.privateKeyInfo; - - // encode private key - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - privateKeyInfo.encode(bos); - byte[] privateKey = bos.toByteArray(); - PKCS12CertInfo certInfo = pkcs12.getCertInfoByID(keyInfo.getID()); if (certInfo == null) { logger.debug("Private key has no certificate, ignore"); @@ -619,26 +580,29 @@ public class PKCS12Util { // get public key PublicKey publicKey = cert.getPublicKey(); - // delete the cert again + byte[] epkiBytes = keyInfo.getEncryptedPrivateKeyInfoBytes(); + if (epkiBytes == null) { + logger.debug( + "No EncryptedPrivateKeyInfo for key '" + + keyInfo.subjectDN + "'; skipping key"); + } + store.importEncryptedPrivateKeyInfo( + new PasswordConverter(), password, nickname, publicKey, epkiBytes); + + // delete the cert again (it will be imported again later + // with the correct nickname) try { store.deleteCert(cert); } catch (NoSuchItemOnTokenException e) { // this is OK } - - // encrypt private key - SymmetricKey sk = CryptoUtil.generateKey(token, KeyGenAlgorithm.DES3, 0, null, true); - byte[] encpkey = CryptoUtil.encryptUsingSymmetricKey( - token, sk, privateKey, EncryptionAlgorithm.DES3_CBC_PAD, param); - - // unwrap private key to load into database - KeyWrapper wrapper = token.getKeyWrapper(KeyWrapAlgorithm.DES3_CBC_PAD); - wrapper.initUnwrap(sk, param); - wrapper.unwrapPrivate(encpkey, getPrivateKeyType(publicKey), publicKey); } - public void storeCertIntoNSS(PKCS12 pkcs12, PKCS12CertInfo certInfo, boolean overwrite) throws Exception { - + public void storeCertIntoNSS( + PKCS12 pkcs12, Password password, + PKCS12CertInfo certInfo, boolean overwrite) + throws Exception + { CryptoManager cm = CryptoManager.getInstance(); CryptoToken ct = cm.getInternalKeyStorageToken(); CryptoStore store = ct.getCryptoStore(); @@ -656,7 +620,7 @@ public class PKCS12Util { X509Certificate cert; if (keyInfo != null) { // cert has key logger.debug("Importing user key for " + certInfo.nickname); - importKey(pkcs12, keyInfo); + importKey(pkcs12, password, certInfo.nickname, keyInfo); logger.debug("Importing user certificate " + certInfo.nickname); cert = cm.importUserCACertPackage(certInfo.cert.getEncoded(), certInfo.nickname); @@ -671,19 +635,21 @@ public class PKCS12Util { setTrustFlags(cert, certInfo.trustFlags); } - public void storeCertIntoNSS(PKCS12 pkcs12, String nickname, boolean overwrite) throws Exception { + public void storeCertIntoNSS(PKCS12 pkcs12, Password password, String nickname, boolean overwrite) throws Exception { Collection<PKCS12CertInfo> certInfos = pkcs12.getCertInfosByNickname(nickname); for (PKCS12CertInfo certInfo : certInfos) { - storeCertIntoNSS(pkcs12, certInfo, overwrite); + storeCertIntoNSS(pkcs12, password, certInfo, overwrite); } } - public void storeIntoNSS(PKCS12 pkcs12, boolean overwrite) throws Exception { - + public void storeIntoNSS( + PKCS12 pkcs12, Password password, boolean overwrite) + throws Exception + { logger.info("Storing data into NSS database"); for (PKCS12CertInfo certInfo : pkcs12.getCertInfos()) { - storeCertIntoNSS(pkcs12, certInfo, overwrite); + storeCertIntoNSS(pkcs12, password, certInfo, overwrite); } } } |