--- a/jdk/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java Tue Dec 23 15:10:15 2014 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java Tue Dec 23 16:30:57 2014 +0000
@@ -69,6 +69,8 @@
import sun.security.pkcs.ContentInfo;
import sun.security.x509.AlgorithmId;
import sun.security.pkcs.EncryptedPrivateKeyInfo;
+import sun.security.provider.JavaKeyStore.JKS;
+import sun.security.util.KeyStoreDelegator;
/**
@@ -129,6 +131,13 @@
*/
public final class PKCS12KeyStore extends KeyStoreSpi {
+ // special PKCS12 keystore that supports PKCS12 and JKS file formats
+ public static final class DualFormatPKCS12 extends KeyStoreDelegator {
+ public DualFormatPKCS12() {
+ super("PKCS12", PKCS12KeyStore.class, "JKS", JKS.class);
+ }
+ }
+
public static final int VERSION_3 = 3;
private static final String[] KEY_PROTECTION_ALGORITHM = {
@@ -1053,6 +1062,39 @@
}
/**
+ * Determines if the keystore {@code Entry} for the specified
+ * {@code alias} is an instance or subclass of the specified
+ * {@code entryClass}.
+ *
+ * @param alias the alias name
+ * @param entryClass the entry class
+ *
+ * @return true if the keystore {@code Entry} for the specified
+ * {@code alias} is an instance or subclass of the
+ * specified {@code entryClass}, false otherwise
+ *
+ * @since 1.5
+ */
+ @Override
+ public boolean
+ engineEntryInstanceOf(String alias,
+ Class<? extends KeyStore.Entry> entryClass)
+ {
+ if (entryClass == KeyStore.TrustedCertificateEntry.class) {
+ return engineIsCertificateEntry(alias);
+ }
+
+ Entry entry = entries.get(alias.toLowerCase(Locale.ENGLISH));
+ if (entryClass == KeyStore.PrivateKeyEntry.class) {
+ return (entry != null && entry instanceof PrivateKeyEntry);
+ }
+ if (entryClass == KeyStore.SecretKeyEntry.class) {
+ return (entry != null && entry instanceof SecretKeyEntry);
+ }
+ return false;
+ }
+
+ /**
* Returns the (alias) name of the first keystore entry whose certificate
* matches the given certificate.
*
@@ -1084,7 +1126,7 @@
} else {
continue;
}
- if (certElem.equals(cert)) {
+ if (certElem != null && certElem.equals(cert)) {
return alias;
}
}
@@ -1923,7 +1965,12 @@
safeContentsData = safeContents.getData();
} else if (contentType.equals((Object)ContentInfo.ENCRYPTED_DATA_OID)) {
if (password == null) {
- continue;
+
+ if (debug != null) {
+ debug.println("Warning: skipping PKCS#7 encryptedData" +
+ " content-type - no password was supplied");
+ }
+ continue;
}
if (debug != null) {
@@ -1965,8 +2012,9 @@
password = new char[1];
continue;
}
- throw new IOException(
- "failed to decrypt safe contents entry: " + e, e);
+ throw new IOException("keystore password was incorrect",
+ new UnrecoverableKeyException(
+ "failed to decrypt safe contents entry: " + e));
}
}
} else {
@@ -2284,4 +2332,73 @@
counter++;
return (String.valueOf(counter));
}
+
+ /*
+ * PKCS12 permitted first 24 bytes:
+ *
+ * 30 82 -- -- 02 01 03 30 82 -- -- 06 09 2A 86 48 86 F7 0D 01 07 01 A0 8-
+ * 30 -- 02 01 03 30 -- 06 09 2A 86 48 86 F7 0D 01 07 01 A0 -- 04 -- -- --
+ * 30 81 -- 02 01 03 30 81 -- 06 09 2A 86 48 86 F7 0D 01 07 01 A0 81 -- 04
+ * 30 82 -- -- 02 01 03 30 81 -- 06 09 2A 86 48 86 F7 0D 01 07 01 A0 81 --
+ * 30 83 -- -- -- 02 01 03 30 82 -- -- 06 09 2A 86 48 86 F7 0D 01 07 01 A0
+ * 30 83 -- -- -- 02 01 03 30 83 -- -- -- 06 09 2A 86 48 86 F7 0D 01 07 01
+ * 30 84 -- -- -- -- 02 01 03 30 83 -- -- -- 06 09 2A 86 48 86 F7 0D 01 07
+ * 30 84 -- -- -- -- 02 01 03 30 84 -- -- -- -- 06 09 2A 86 48 86 F7 0D 01
+ */
+
+ private static final long[][] PKCS12_HEADER_PATTERNS = {
+ { 0x3082000002010330L, 0x82000006092A8648L, 0x86F70D010701A080L },
+ { 0x3000020103300006L, 0x092A864886F70D01L, 0x0701A00004000000L },
+ { 0x3081000201033081L, 0x0006092A864886F7L, 0x0D010701A0810004L },
+ { 0x3082000002010330L, 0x810006092A864886L, 0xF70D010701A08100L },
+ { 0x3083000000020103L, 0x3082000006092A86L, 0x4886F70D010701A0L },
+ { 0x3083000000020103L, 0x308200000006092AL, 0x864886F70D010701L },
+ { 0x3084000000000201L, 0x0330820000000609L, 0x2A864886F70D0107L },
+ { 0x3084000000000201L, 0x0330820000000006L, 0x092A864886F70D01L }
+ };
+
+ private static final long[][] PKCS12_HEADER_MASKS = {
+ { 0xFFFF0000FFFFFFFFL, 0xFF0000FFFFFFFFFFL, 0xFFFFFFFFFFFFFFF0L },
+ { 0xFF00FFFFFFFF00FFL, 0xFFFFFFFFFFFFFFFFL, 0xFFFFFF00FF000000L },
+ { 0xFFFF00FFFFFFFFFFL, 0x00FFFFFFFFFFFFFFL, 0xFFFFFFFFFFFF00FFL },
+ { 0xFFFF0000FFFFFFFFL, 0xFF00FFFFFFFFFFFFL, 0xFFFFFFFFFFFFFF00L },
+ { 0xFFFF000000FFFFFFL, 0xFFFF0000FFFFFFFFL, 0xFFFFFFFFFFFFFFFFL },
+ { 0xFFFF000000FFFFFFL, 0xFFFF000000FFFFFFL, 0xFFFFFFFFFFFFFFFFL },
+ { 0xFFFF00000000FFFFL, 0xFFFFFF000000FFFFL, 0xFFFFFFFFFFFFFFFFL },
+ { 0xFFFF00000000FFFFL, 0xFFFFFF00000000FFL, 0xFFFFFFFFFFFFFFFFL }
+ };
+
+ /**
+ * Probe the first few bytes of the keystore data stream for a valid
+ * PKCS12 keystore encoding.
+ */
+ @Override
+ public boolean engineProbe(InputStream stream) throws IOException {
+
+ DataInputStream dataStream;
+ if (stream instanceof DataInputStream) {
+ dataStream = (DataInputStream)stream;
+ } else {
+ dataStream = new DataInputStream(stream);
+ }
+
+ long firstPeek = dataStream.readLong();
+ long nextPeek = dataStream.readLong();
+ long finalPeek = dataStream.readLong();
+ boolean result = false;
+
+ for (int i = 0; i < PKCS12_HEADER_PATTERNS.length; i++) {
+ if (PKCS12_HEADER_PATTERNS[i][0] ==
+ (firstPeek & PKCS12_HEADER_MASKS[i][0]) &&
+ (PKCS12_HEADER_PATTERNS[i][1] ==
+ (nextPeek & PKCS12_HEADER_MASKS[i][1])) &&
+ (PKCS12_HEADER_PATTERNS[i][2] ==
+ (finalPeek & PKCS12_HEADER_MASKS[i][2]))) {
+ result = true;
+ break;
+ }
+ }
+
+ return result;
+ }
}