Creating an Https connecion with Client Side Certificate from PKCS#10 with SpongyCastle

前端 未结 1 516
小蘑菇
小蘑菇 2020-12-30 18:39

The goal

I\'m working on implementing communication with Client-Certificate.

Step 1: Create a PKCS#10 request (CSR) and give it to the my se

1条回答
  •  囚心锁ツ
    2020-12-30 19:27

    Maybe not the best code, but it works, it does not strictly answer all you questions but maybe you will find pieces you can use.

    Your flow is good, I'm doing the almost the same thing.

    I'm keeping my keys in dynamically created keystore. Additionaly i have keystore with trusted certificates created with openssl tool.

    For communication I've used okHttp + retrofit

    https://github.com/square/okhttp https://github.com/square/retrofit

    Generate KeyPair:

    public static KeyPair generateKeyPair() throws NoSuchAlgorithmException {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        keyPairGenerator.initialize(2048);
        KeyPair keyPair = keyPairGenerator.genKeyPair();
        return keyPair;
    }
    

    Generate csr:

    private static PKCS10CertificationRequest generateCSRFile(KeyPair keyPair) throws IOException, OperatorCreationException {
        String principal = "CN=company1, OU=company1, O=company1, C=GB";
        AsymmetricKeyParameter privateKey = PrivateKeyFactory.createKey(keyPair.getPrivate().getEncoded());
        AlgorithmIdentifier signatureAlgorithm = new DefaultSignatureAlgorithmIdentifierFinder()
                .find("SHA1WITHRSA");
        AlgorithmIdentifier digestAlgorithm = new DefaultDigestAlgorithmIdentifierFinder().find("SHA-1");
        ContentSigner signer = new BcRSAContentSignerBuilder(signatureAlgorithm, digestAlgorithm).build(privateKey);
    
        PKCS10CertificationRequestBuilder csrBuilder = new JcaPKCS10CertificationRequestBuilder(new X500Name(
                principal), keyPair.getPublic());
        ExtensionsGenerator extensionsGenerator = new ExtensionsGenerator();
        extensionsGenerator.addExtension(X509Extension.basicConstraints, true, new BasicConstraints(true));
        extensionsGenerator.addExtension(X509Extension.keyUsage, true, new KeyUsage(KeyUsage.keyCertSign
                | KeyUsage.cRLSign));
        csrBuilder.addAttribute(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest, extensionsGenerator.generate());
        PKCS10CertificationRequest csr = csrBuilder.build(signer);
    
        return csr;
    }
    

    Send csr (you may need to convert it to pem format), receive certificate .

    Init keystore:

    KeyStore store = KeyStore.getInstance("BKS");
    InputStream in;
    try {
        in = App.getInstance().getApplicationContext().openFileInput(filename);
            try {
                store.load(in, password);
            } finally {
                in.close();
            }
        } catch (FileNotFoundException e) {
            //create new keystore
            store.load(null, password);
        }
    

    Init truststore:

    KeyStore trustStore = KeyStore.getInstance("BKS");
    InputStream in = App.getInstance().getApplicationContext().getResources().openRawResource(R.raw.truststore);
    try {
        trustStore.load(in, trustorePassword);
    } finally {
        in.close();
    }
    

    Add key to keystore (make sure your private key, and certificate match, keystore won't throw exception if they don't, and with okHttp this can cause libssl crashes (only on devices with api below 4.1):

    keyStore.setKeyEntry(alias, privateKey, password, new X509Certificate[]{certificate});
    

    Create okHttpClient with its own SSLContext:

    OkHttpClient client = new OkHttpClient();
    KeyStore keyStore = App.getInstance().getKeyStoreUtil().getKeyStore();
    KeyStore trustStore = App.getInstance().getKeyStoreUtil().getTrustStore();
    
    TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
    tmf.init(trustStore);
    
    KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
    kmf.init(keyStore, keyStorePassword);
    
    SSLContext sslCtx = SSLContext.getInstance("TLS");
    sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
    client.setSslSocketFactory(sslCtx.getSocketFactory());
    client.setHostnameVerifier(org.apache.http.conn.ssl.SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);
    

    Look at Nikolay Elenkov blog, you can find many usefull informations with source code as well.

    • http://nelenkov.blogspot.com/
    • http://nelenkov.blogspot.com/2011/11/using-ics-keychain-api.html
    • http://nelenkov.blogspot.in/2011/12/ics-trust-store-implementation.html
    • http://nelenkov.blogspot.com/2011/12/using-custom-certificate-trust-store-on.html
    • http://nelenkov.blogspot.com/2012/05/storing-application-secrets-in-androids.html
    • http://nelenkov.blogspot.com/2013/08/credential-storage-enhancements-android-43.html

    @edit

    Post your exception

    @edit2

    In your case you need to extract your X509Certificate from webservice response, store it in keystore with privatekey used for generating csr request and store CA cert in another keystore which will work as truststore. (It can be the same keystore, but it's not recommended).

    0 讨论(0)
提交回复
热议问题