P. S. Typo: bcProviderIndex = i; should be bcProviderIndex = i + 1; 
Security.insertProviderAt uses a 1-based indexing scheme...

Alex

On Wednesday, February 17, 2016 at 6:02:04 PM UTC-8, Alex Klyubin wrote:
>
> Oh, I didn't notice the PkiManager class in OP. It does install Bouncy 
> Castle as the highest-priority JCA Provider. Unfortunately, Bouncy Castle 
> JCA Provider has a bug (http://www.bouncycastle.org/jira/browse/BJA-543 
> <https://www.google.com/url?q=http://www.bouncycastle.org/jira/browse/BJA-543&sa=D&usg=AFQjCNEErNOODYZHHZomGgR1y7NLq2yegw>)
>  
> where is advertises to JCA that it can handle any keys, even those that it 
> actually can't handle, such as Android Keystore keys which don't expose 
> private/secret key material. Here are some options to work around this 
> issue:
> 1. Don't install the Bouncy Castle JCA Provider if you don't need to. For 
> example, you don't need it for crypto operations involving Android Keystore 
> keys.
> 2. If you must install the Bouncy Castle JCA Provider, install it below 
> Android Keystore JCA provider. The best way to achieve that is to find the 
> index at which the platform-bundled Bouncy Castle provider is installed, 
> and then invoke Security.insertProviderAt with that same index and your 
> Bouncy Castle Provider. This will install your Bouncy Castle provider just 
> above the preinstalled Bouncy Castle provider which is itself installed at 
> the correct spot for Android Keystore stuff to work. For example:
>
>   Provider[] providers = Security.getProviders();
>   int bcProviderIndex = -1;
>   for (int i = 0; i < providers.length; i++) {
>     Provider provider = providers[i];
>     if ("BC".equals(provider.getName())) {
>       bcProviderIndex = i;
>       break;
>     }
>   }
>   Security.insertProviderAt(new BouncyCastleProvider(), 
> bcProviderPosition);
>
> Alex
>
> On Wednesday, February 17, 2016 at 5:41:40 PM UTC-8, Alex Klyubin wrote:
>>
>> * Please provide the full stack trace (at least from Signature.initSign 
>> down into the framework).
>> * What version of Android is this (e.g., 6.0)?
>> * Are you installing any additional JCA providers (e.g., 
>> Security.insertProviderAt or Security.addProvider)?
>> * Please confirm that you're not specifying a provider when invoking 
>> Signature.getInstance. (i.e., that you're using the single-arg getInstance, 
>> not the one that takes an additional String or Provider argument).
>>
>> Cheers,
>> Alex
>>
>> On Wednesday, February 17, 2016 at 5:25:34 PM UTC-8, Jacob Taylor wrote:
>>>
>>> Hey Alex,
>>>
>>> When I input PrivateKey object from entry.getPrivateKey() to 
>>> s.initSign(), the following exception occurs:
>>>
>>> java.security.InvalidKeyException: Supplied key 
>>> (android.security.keystore.AndroidKeyStoreRSAPrivateKey) is not a 
>>> RSAPrivateKey instance.
>>>
>>> This is the new code:
>>> Signature s = Signature.getInstance(algorithmText);
>>> KeyStore.Entry entry = ks.getEntry(keyAlias, null);
>>> PrivateKey privateKey = ((KeyStore.PrivateKeyEntry) entry).getPrivateKey
>>> ();
>>>
>>> s.initSign(privateKey); // <--- excepts here
>>>
>>>
>>> For the time being, algorithmText is set to "SHA512withRSA".
>>>
>>> Cheers,
>>> Jake
>>>
>>>
>>>
>>> On Thursday, February 18, 2016 at 6:06:15 AM UTC+11, Alex Klyubin wrote:
>>>>
>>>> Short answer: Drop the cast to RSAPrivateKey. Use entry.getPrivateKey() 
>>>> instead.
>>>>
>>>> Longer answer: RSAPrivateKey interface is for private keys which expose 
>>>> their key material in a structured way (e.g., expose their private 
>>>> exponent). Android Keystore keys by definition do not expose their key 
>>>> material. Thus, Android Keystore private keys are not instances of 
>>>> RSAPrivateKey. They are instance of PrivateKey and RSAKey (this one lets 
>>>> you obtain the modulus). Signature.initSign happily takes a PrivateKey 
>>>> instance. Thus, drop the cast to RSAPrivateKey and it'll work just fine.
>>>>
>>>> On Wednesday, February 17, 2016 at 6:43:04 AM UTC-8, Jacob Taylor wrote:
>>>>>
>>>>> Hey devs,
>>>>>
>>>>> I'm working on a proof of concept app for generating an RSA keypair in 
>>>>> an app, generating a X509 CSR based on the new keypair, then exporting it 
>>>>> to be signed by some CA.
>>>>> As a part o f the CSR generation process the whole CSR must be signed 
>>>>> by the key itself.
>>>>>
>>>>> I've been following along with the Keystore page on the documentation 
>>>>> site (
>>>>> http://developer.android.com/training/articles/keystore.html#SigningAndVerifyingData)
>>>>>  
>>>>> and reached a snag.
>>>>> The generation of the CSR is handled by spongycastle, which in turn 
>>>>> uses a custom build class (called keystoreContentSigner) to sign the 
>>>>> completed CSR with the keys stored in the keystore.
>>>>> According to the above referenced documentation, the call to 
>>>>> ks.getEntry(keyAlias, null) should return an object typecasted to the 
>>>>> Keystore.Entry class, which you then cast into a PrivateKeyEntry which 
>>>>> you 
>>>>> then call against using its .getPrivateKey method.
>>>>>
>>>>> On my test phone (Nexus 6P) this flow doesn't work. It excepts during 
>>>>> the call to initSign, and reports the type of the object return from 
>>>>> ks.getEntry as android.security.keystore.AndroidKeyStoreRSAPrivateKey, 
>>>>> which isn't referenced anywhere I can find.
>>>>>
>>>>> This type can't be casted to anything usable in the current format, is 
>>>>> there some new way to perform cryptographic operations in Marshmallow, or 
>>>>> is there something I'm missing?
>>>>>
>>>>> KeystoreContentSigner class:
>>>>>
>>>>> package au.com.taylornetworks.tapid;
>>>>>
>>>>>
>>>>> import org.spongycastle.asn1.x509.AlgorithmIdentifier;
>>>>> import org.spongycastle.operator.ContentSigner;
>>>>> import 
>>>>> org.spongycastle.operator.DefaultSignatureAlgorithmIdentifierFinder;
>>>>>
>>>>> import java.io.ByteArrayOutputStream;
>>>>> import java.io.OutputStream;
>>>>> import java.security.KeyStore;
>>>>> import java.security.Signature;
>>>>> import java.security.interfaces.RSAPrivateKey;
>>>>>
>>>>>
>>>>> public class keystoreContentSigner implements ContentSigner{
>>>>>
>>>>>     private AlgorithmIdentifier algorithmIdentifier;
>>>>>     private String algorithmText;
>>>>>     private ByteArrayOutputStream dataStream;
>>>>>     private String keyAlias;
>>>>>
>>>>>     public keystoreContentSigner(String keyAlias)
>>>>>     {
>>>>>         algorithmText = "SHA512withRSA";
>>>>>         algorithmIdentifier = new 
>>>>> DefaultSignatureAlgorithmIdentifierFinder().find(algorithmText);
>>>>>         dataStream = new ByteArrayOutputStream();
>>>>>         this.keyAlias = keyAlias;
>>>>>     }
>>>>>
>>>>>     public void setAlgorithm(String algorithmText)
>>>>>     {
>>>>>         this.algorithmText = algorithmText;
>>>>>         algorithmIdentifier = new 
>>>>> DefaultSignatureAlgorithmIdentifierFinder().find(algorithmText);
>>>>>     }
>>>>>
>>>>>     @Override
>>>>>     public OutputStream getOutputStream()
>>>>>     {
>>>>>         return dataStream;
>>>>>     }
>>>>>
>>>>>     @Override
>>>>>     public AlgorithmIdentifier getAlgorithmIdentifier()
>>>>>     {
>>>>>         return algorithmIdentifier;
>>>>>     }
>>>>>
>>>>>     public byte[] getSignature()
>>>>>     {
>>>>>         byte[] data;
>>>>>         byte[] signature = null;
>>>>>         KeyStore ks;
>>>>>
>>>>>         try {
>>>>>             ks = KeyStore.getInstance("AndroidKeyStore");
>>>>>             ks.load(null);
>>>>>
>>>>>             data = dataStream.toByteArray();
>>>>>             dataStream.flush();
>>>>>
>>>>>             Signature s = Signature.getInstance(algorithmText);
>>>>>             KeyStore.Entry entry = ks.getEntry(keyAlias, null);
>>>>>
>>>>>             s.initSign((RSAPrivateKey) entry);
>>>>>             s.update(data);
>>>>>             signature = s.sign();
>>>>>         } catch (Exception e) {
>>>>>             e.printStackTrace();
>>>>>         }
>>>>>
>>>>>         return signature;
>>>>>     }
>>>>>
>>>>> }
>>>>>
>>>>>  
>>>>> PkiManager class:
>>>>> Enter 
>>>>>
>>>>> package au.com.taylornetworks.tapid;
>>>>>
>>>>> import android.security.keystore.*;
>>>>>
>>>>> import java.io.IOException;
>>>>> import java.security.*;
>>>>> import java.security.cert.CertificateException;
>>>>> import org.spongycastle.asn1.misc.MiscObjectIdentifiers;
>>>>> import org.spongycastle.asn1.misc.NetscapeCertType;
>>>>> import org.spongycastle.asn1.x500.X500Name;
>>>>> import org.spongycastle.asn1.x509.BasicConstraints;
>>>>> import org.spongycastle.asn1.x509.ExtendedKeyUsage;
>>>>> import org.spongycastle.asn1.x509.Extension;
>>>>> import org.spongycastle.asn1.x509.ExtensionsGenerator;
>>>>>
>>>>> ...
>>>>
>>>>

-- 
You received this message because you are subscribed to the Google Groups 
"Android Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/android-developers.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/android-developers/726b037a-e13a-4c9e-80f8-089c3aa6a205%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to