Commit 9467d22b authored by Kenny Root's avatar Kenny Root
Browse files

Try to get preferred external provider

When using an opaque key, try to honor the system's preferred provider
which is selected via late binding. If it's not found, try to find the
first provider that initializes correctly with the given key.

(cherry picked from commit c590a930)

Bug: 21737886
Change-Id: I17483136aa5c1c5e474109525aefac9facaf7379
parent d1b4488c
......@@ -16,11 +16,13 @@
package org.conscrypt;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.Security;
import java.security.Signature;
import java.util.ArrayList;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
......@@ -33,22 +35,24 @@ public final class CryptoUpcalls {
private CryptoUpcalls() {
}
private static boolean isOurProvider(Provider p) {
return p.getClass().getPackage().equals(CryptoUpcalls.class.getPackage());
}
/**
* Finds the first provider which provides {@code algorithm} but is not from
* the same ClassLoader as ours.
* Finds providers that are not us that provide the requested algorithms.
*/
public static Provider getExternalProvider(String algorithm) {
Provider selectedProvider = null;
private static ArrayList<Provider> getExternalProviders(String algorithm) {
ArrayList<Provider> providers = new ArrayList<>(1);
for (Provider p : Security.getProviders(algorithm)) {
if (!p.getClass().getClassLoader().equals(CryptoUpcalls.class.getClassLoader())) {
selectedProvider = p;
break;
if (!isOurProvider(p)) {
providers.add(p);
}
}
if (selectedProvider == null) {
if (providers.isEmpty()) {
System.err.println("Could not find external provider for algorithm: " + algorithm);
}
return selectedProvider;
return providers;
}
public static byte[] rawSignDigestWithPrivateKey(PrivateKey javaKey, byte[] message) {
......@@ -69,23 +73,47 @@ public final class CryptoUpcalls {
throw new RuntimeException("Unexpected key type: " + javaKey.toString());
}
Provider p = getExternalProvider("Signature." + algorithm);
if (p == null) {
return null;
}
// Get the Signature for this key.
Signature signature;
// First try to get the most preferred provider as long as it isn't us.
try {
signature = Signature.getInstance(algorithm, p);
signature = Signature.getInstance(algorithm);
signature.initSign(javaKey);
// Ignore it if it points back to us.
if (isOurProvider(signature.getProvider())) {
signature = null;
}
} catch (NoSuchAlgorithmException e) {
System.err.println("Unsupported signature algorithm: " + algorithm);
return null;
} catch (InvalidKeyException e) {
System.err.println("Preferred provider doesn't support key:");
e.printStackTrace();
signature = null;
}
// If the preferred provider was us, fall back to trying to find the
// first not-us provider that initializes correctly.
if (signature == null) {
ArrayList<Provider> providers = getExternalProviders("Signature." + algorithm);
for (Provider p : providers) {
try {
signature = Signature.getInstance(algorithm, p);
signature.initSign(javaKey);
break;
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
signature = null;
}
}
if (signature == null) {
System.err.println("Could not find provider for algorithm: " + algorithm);
return null;
}
}
// Sign the message.
try {
signature.initSign(javaKey);
signature.update(message);
return signature.sign();
} catch (Exception e) {
......@@ -121,27 +149,47 @@ public final class CryptoUpcalls {
}
String transformation = "RSA/ECB/" + jcaPadding;
Provider p = getExternalProvider("Cipher." + transformation);
if (p == null) {
return null;
}
Cipher c = null;
// First try to get the most preferred provider as long as it isn't us.
try {
c = Cipher.getInstance(transformation, p);
} catch (NoSuchAlgorithmException e) {
;
} catch (NoSuchPaddingException e) {
;
c = Cipher.getInstance(transformation);
c.init(Cipher.DECRYPT_MODE, javaKey);
// Ignore it if it points back to us.
if (isOurProvider(c.getProvider())) {
c = null;
}
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
System.err.println("Unsupported cipher algorithm: " + transformation);
return null;
} catch (InvalidKeyException e) {
System.err.println("Preferred provider doesn't support key:");
e.printStackTrace();
c = null;
}
// If the preferred provider was us, fall back to trying to find the
// first not-us provider that initializes correctly.
if (c == null) {
System.err.println("Unsupported transformation: " + transformation);
return null;
ArrayList<Provider> providers = getExternalProviders("Cipher." + transformation);
for (Provider p : providers) {
try {
c = Cipher.getInstance(transformation, p);
c.init(Cipher.DECRYPT_MODE, javaKey);
break;
} catch (NoSuchAlgorithmException | InvalidKeyException
| NoSuchPaddingException e) {
c = null;
}
}
if (c == null) {
System.err.println("Could not find provider for algorithm: " + transformation);
return null;
}
}
try {
c.init(Cipher.DECRYPT_MODE, javaKey);
return c.doFinal(input);
} catch (Exception e) {
System.err.println("Exception while decrypting message with " + javaKey.getAlgorithm()
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment