diff options
author | Alex Klyubin <klyubin@google.com> | 2015-06-25 17:13:30 -0700 |
---|---|---|
committer | Alex Klyubin <klyubin@google.com> | 2015-06-25 18:44:43 -0700 |
commit | 903d0fb98817dca284a640dbc853c7fcbbdc8313 (patch) | |
tree | ff21d11dec3828c271cce69800591ad380e96aac /keystore | |
parent | 0f61c7dcc40276788f58300d5d8ca85be2ce0e59 (diff) | |
download | frameworks_base-903d0fb98817dca284a640dbc853c7fcbbdc8313.zip frameworks_base-903d0fb98817dca284a640dbc853c7fcbbdc8313.tar.gz frameworks_base-903d0fb98817dca284a640dbc853c7fcbbdc8313.tar.bz2 |
Don't offer crypto ops for public keys of trusted cert entries.
Android Keystore cannot offer crypto operations for public keys of
trusted certificate entries (entries without a private key). Prior to
this CL it accidentally tried to do so, causing crypto operations on
these keys to fail.
The fix is for Android Keystore to offer crypto operations only for
public keys for which there is a corresponding private key in the
keystore. Crypto operations on public keys from trusted certificate
entries will be handled by other installed crypto providers. Those
providers don't need a private key to carry out these operations on
public keys.
Bug: 22091725
Bug: 21835320
Change-Id: Ib7d92b067711e4c57128d0db72c08bf288a45ce1
Diffstat (limited to 'keystore')
-rw-r--r-- | keystore/java/android/security/keystore/AndroidKeyStoreSpi.java | 59 |
1 files changed, 51 insertions, 8 deletions
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java index de483f4..dc8f1e3 100644 --- a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java +++ b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java @@ -140,21 +140,64 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi { throw new NullPointerException("alias == null"); } - byte[] certificate = mKeyStore.get(Credentials.USER_CERTIFICATE + alias); - if (certificate != null) { - return wrapIntoKeyStoreCertificate( - Credentials.USER_PRIVATE_KEY + alias, toCertificate(certificate)); + byte[] encodedCert = mKeyStore.get(Credentials.USER_CERTIFICATE + alias); + if (encodedCert != null) { + return getCertificateForPrivateKeyEntry(alias, encodedCert); } - certificate = mKeyStore.get(Credentials.CA_CERTIFICATE + alias); - if (certificate != null) { - return wrapIntoKeyStoreCertificate( - Credentials.USER_PRIVATE_KEY + alias, toCertificate(certificate)); + encodedCert = mKeyStore.get(Credentials.CA_CERTIFICATE + alias); + if (encodedCert != null) { + return getCertificateForTrustedCertificateEntry(encodedCert); } + // This entry/alias does not contain a certificate. return null; } + private Certificate getCertificateForTrustedCertificateEntry(byte[] encodedCert) { + // For this certificate there shouldn't be a private key in this KeyStore entry. Thus, + // there's no need to wrap this certificate as opposed to the certificate associated with + // a private key entry. + return toCertificate(encodedCert); + } + + private Certificate getCertificateForPrivateKeyEntry(String alias, byte[] encodedCert) { + // All crypto algorithms offered by Android Keystore for its private keys must also + // be offered for the corresponding public keys stored in the Android Keystore. The + // complication is that the underlying keystore service operates only on full key pairs, + // rather than just public keys or private keys. As a result, Android Keystore-backed + // crypto can only be offered for public keys for which keystore contains the + // corresponding private key. This is not the case for certificate-only entries (e.g., + // trusted certificates). + // + // getCertificate().getPublicKey() is the only way to obtain the public key + // corresponding to the private key stored in the KeyStore. Thus, we need to make sure + // that the returned public key points to the underlying key pair / private key + // when available. + + X509Certificate cert = toCertificate(encodedCert); + if (cert == null) { + // Failed to parse the certificate. + return null; + } + + String privateKeyAlias = Credentials.USER_PRIVATE_KEY + alias; + if (mKeyStore.contains(privateKeyAlias)) { + // As expected, keystore contains the private key corresponding to this public key. Wrap + // the certificate so that its getPublicKey method returns an Android Keystore + // PublicKey. This key will delegate crypto operations involving this public key to + // Android Keystore when higher-priority providers do not offer these crypto + // operations for this key. + return wrapIntoKeyStoreCertificate(privateKeyAlias, cert); + } else { + // This KeyStore entry/alias is supposed to contain the private key corresponding to + // the public key in this certificate, but it does not for some reason. It's probably a + // bug. Let other providers handle crypto operations involving the public key returned + // by this certificate's getPublicKey. + return cert; + } + } + /** * Wraps the provided cerificate into {@link KeyStoreX509Certificate} so that the public key * returned by the certificate contains information about the alias of the private key in |