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;
import org.spongycastle.asn1.x509.KeyPurposeId;
import org.spongycastle.asn1.x509.KeyUsage;
import org.spongycastle.operator.ContentSigner;
import org.spongycastle.operator.OperatorCreationException;
import org.spongycastle.pkcs.*;
import org.spongycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder;


public class pkiManager {

    static private String keystoreName = "AndroidKeyStore";

    KeyStore keyStore;
    PKCS10CertificationRequest csr;
    String keyAlias;
    String username;


    public pkiManager(String keyAlias) throws KeyStoreException, 
CertificateException, NoSuchAlgorithmException, IOException {
        Security.insertProviderAt(new 
org.spongycastle.jce.provider.BouncyCastleProvider(), 1);
        username = "Default User";
        keyStore = KeyStore.getInstance(keystoreName);
        keyStore.load(null);
        this.keyAlias = keyAlias;
    }

    public PublicKey generateKeypair() throws NoSuchProviderException, 
NoSuchAlgorithmException, InvalidAlgorithmParameterException {

        KeyPairGenerator generator;
        KeyGenParameterSpec.Builder paramBuilder;

        generator = 
KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, keystoreName);

        paramBuilder = new 
KeyGenParameterSpec.Builder(keyAlias,KeyProperties.PURPOSE_SIGN);
        paramBuilder.setDigests(KeyProperties.DIGEST_SHA256, 
KeyProperties.DIGEST_SHA512);
        paramBuilder.setKeySize(2048);
        generator.initialize(paramBuilder.build());

        KeyPair keyPair = generator.generateKeyPair();

        return keyPair.getPublic();
    }

    public void generateCSR(PublicKey publicKey) throws IOException, 
OperatorCreationException {
        // Create principal & set key usage and other extensions
        X500Name principal = new X500Name("CN=" + username +", O=TapID");
        KeyUsage keyUsage = new KeyUsage(KeyUsage.digitalSignature | 
KeyUsage.nonRepudiation | KeyUsage.keyEncipherment | KeyUsage.dataEncipherment 
| KeyUsage.keyAgreement);
        ExtendedKeyUsage extKeyUsage = new 
ExtendedKeyUsage(KeyPurposeId.id_kp_clientAuth);
        NetscapeCertType netCertType = new 
NetscapeCertType(NetscapeCertType.objectSigning | NetscapeCertType.smime | 
NetscapeCertType.sslClient);

        // Setup signer for CSR
        ContentSigner signer = new keystoreContentSigner(keyAlias);

        // Configure CSR builder
        PKCS10CertificationRequestBuilder csrBuilder = new 
JcaPKCS10CertificationRequestBuilder(principal, publicKey);
        csrBuilder.addAttribute(MiscObjectIdentifiers.netscapeCertType, 
netCertType);

        // Configure certificate extensions
        ExtensionsGenerator extGen = new ExtensionsGenerator();
        extGen.addExtension(Extension.basicConstraints, true, new 
BasicConstraints(false));
        extGen.addExtension(Extension.keyUsage, false, keyUsage);
        extGen.addExtension(Extension.extendedKeyUsage, false, extKeyUsage);

        // Build certificate request
        csr = csrBuilder.build(signer);
    }

    public String getCSR()
    {
        return csr.toString();
    }

    public void setName(String username)
    {
        this.username = username;
    }
}

here...

The app activity code is basically just a simple button which generates a 
keypair and spits out the PEM encoded CSR.

-- 
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/c60b1fb6-8260-48b6-8f61-0dce1b056ca0%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to