I have a system that uses HTTPS client certificates for authentication, but the certificates themselves are generated according to the following process:
- The client device generates a certificate (including public and private keys)
- The client device sends the public key to the server, which signs the public key and returns it as a signed certificate
- The client stores the certificate in a secure manner and then uses it as an HTTPS client certificate
We have this system running on iOS, and I'm trying to connect to Android, but have run into a lot of problems with poorly documented and confusing Android APIs.
My code looks something like this:
Certificate Creation
keyStore = KeyStore.getInstance(ANDROID_KEYSTORE);
keyStore.load(null);
Date startDate = new Date();
Date endDate = new Date(startDate.getTime() + FORTY_YEARS_IN_MILLISECONDS);
KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec.Builder(context)
.setAlias(alias)
.setKeySize(2048)
.setKeyType(KeyProperties.KEY_ALGORITHM_RSA)
.setSubject(new X500Principal("CN=" + alias))
.setSerialNumber(BigInteger.TEN)
.setStartDate(startDate)
.setEndDate(endDate)
.build();
KeyPairGenerator generator = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, ANDROID_KEYSTORE);
generator.initialize(spec);
KeyPair keyPair = generator.generateKeyPair();
dumpKeyStore(keyStore);
byte[] entireKey = keyPair.getPublic().getEncoded();
byte[] publicKeyBytes = Arrays.copyOfRange(entireKey, 24, entireKey.length);
dumpKeyStore - , , keyStore.getEntry, .
, KeyStore.PrivateKeyEntry. , PrivateKeyEntry.
publicKeyBytes , x509, . , . , .
keyStore , () . :
KeyStore keyStore;
try {
keyStore = KeyStore.getInstance(ANDROID_KEYSTORE);
keyStore.load(null);
}catch (IOException | NoSuchAlgorithmException | CertificateException e) {
Log.wtf(TAG, e);
throw new FatalError(TAG, e);
}
CertificateFactory certificateFactory;
try {
certificateFactory = CertificateFactory.getInstance("X.509");
} catch (CertificateException e) {
Log.wtf(TAG, e);
throw new FatalError(TAG, e);
}
Certificate cert = certificateFactory.generateCertificate(new ByteArrayInputStream(certificateFromServer));
try {
KeyStore.PrivateKeyEntry existingPrivateKeyEntry = (KeyStore.PrivateKeyEntry)keyStore.getEntry(alias, null);
KeyStore.PrivateKeyEntry newEntry = new KeyStore.PrivateKeyEntry(existingPrivateKeyEntry.getPrivateKey(), new Certificate[]{ cert });
keyStore.setEntry(alias, newEntry, null);
} catch (Exception e) {
Log.wtf(TAG, e);
throw new FatalError(TAG, e);
}
dumpKeyStore(keyStore);
dumpKeyStore , , "NoSuchAlgorithmException: Unknown key entry", keyStore.getEntry
, ( , ) android? , ? , .