Merge change 7511 into donut
* changes: Support addPkcs12Keystore function in CertTool library.
This commit is contained in:
@@ -16,11 +16,19 @@
|
|||||||
|
|
||||||
package android.security;
|
package android.security;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.security.cert.Certificate;
|
||||||
|
import java.security.cert.CertificateException;
|
||||||
|
import java.security.KeyStoreException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.UnrecoverableKeyException;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.security.Keystore;
|
import android.security.Keystore;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The CertTool class provides the functions to list the certs/keys,
|
* The CertTool class provides the functions to list the certs/keys,
|
||||||
@@ -41,12 +49,12 @@ public class CertTool {
|
|||||||
public static final String KEY_NAMESPACE = "namespace";
|
public static final String KEY_NAMESPACE = "namespace";
|
||||||
public static final String KEY_DESCRIPTION = "description";
|
public static final String KEY_DESCRIPTION = "description";
|
||||||
|
|
||||||
private static final String TAG = "CertTool";
|
public static final String TITLE_CA_CERT = "CA Certificate";
|
||||||
|
public static final String TITLE_USER_CERT = "User Certificate";
|
||||||
|
public static final String TITLE_PKCS12_KEYSTORE = "PKCS12 Keystore";
|
||||||
|
public static final String TITLE_PRIVATE_KEY = "Private Key";
|
||||||
|
|
||||||
private static final String TITLE_CA_CERT = "CA Certificate";
|
private static final String TAG = "CertTool";
|
||||||
private static final String TITLE_USER_CERT = "User Certificate";
|
|
||||||
private static final String TITLE_PKCS12_KEYSTORE = "PKCS12 Keystore";
|
|
||||||
private static final String TITLE_PRIVATE_KEY = "Private Key";
|
|
||||||
private static final String UNKNOWN = "Unknown";
|
private static final String UNKNOWN = "Unknown";
|
||||||
private static final String ISSUER_NAME = "Issuer Name:";
|
private static final String ISSUER_NAME = "Issuer Name:";
|
||||||
private static final String DISTINCT_NAME = "Distinct Name:";
|
private static final String DISTINCT_NAME = "Distinct Name:";
|
||||||
@@ -58,6 +66,11 @@ public class CertTool {
|
|||||||
private static final String KEYNAME_DELIMITER = "_";
|
private static final String KEYNAME_DELIMITER = "_";
|
||||||
private static final Keystore sKeystore = Keystore.getInstance();
|
private static final Keystore sKeystore = Keystore.getInstance();
|
||||||
|
|
||||||
|
private native int getPkcs12Handle(byte[] data, String password);
|
||||||
|
private native String getPkcs12Certificate(int handle);
|
||||||
|
private native String getPkcs12PrivateKey(int handle);
|
||||||
|
private native String popPkcs12CertificateStack(int handle);
|
||||||
|
private native void freePkcs12Handle(int handle);
|
||||||
private native String generateCertificateRequest(int bits, String subject);
|
private native String generateCertificateRequest(int bits, String subject);
|
||||||
private native boolean isPkcs12Keystore(byte[] data);
|
private native boolean isPkcs12Keystore(byte[] data);
|
||||||
private native int generateX509Certificate(byte[] data);
|
private native int generateX509Certificate(byte[] data);
|
||||||
@@ -130,10 +143,35 @@ public class CertTool {
|
|||||||
intent.putExtra(KEY_NAMESPACE + "1", namespace);
|
intent.putExtra(KEY_NAMESPACE + "1", namespace);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int addPkcs12Keystore(byte[] p12Data, String password,
|
||||||
|
String keyname) {
|
||||||
|
int handle, i = 0;
|
||||||
|
String pemData;
|
||||||
|
Log.i("CertTool", "addPkcs12Keystore()");
|
||||||
|
|
||||||
|
if ((handle = getPkcs12Handle(p12Data, password)) == 0) return -1;
|
||||||
|
if ((pemData = getPkcs12Certificate(handle)) != null) {
|
||||||
|
sKeystore.put(USER_CERTIFICATE, keyname, pemData);
|
||||||
|
}
|
||||||
|
if ((pemData = getPkcs12PrivateKey(handle)) != null) {
|
||||||
|
sKeystore.put(USER_KEY, keyname, pemData);
|
||||||
|
}
|
||||||
|
while ((pemData = this.popPkcs12CertificateStack(handle)) != null) {
|
||||||
|
if (i++ > 0) {
|
||||||
|
sKeystore.put(CA_CERTIFICATE, keyname + i, pemData);
|
||||||
|
} else {
|
||||||
|
sKeystore.put(CA_CERTIFICATE, keyname, pemData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
freePkcs12Handle(handle);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
public synchronized void addCertificate(byte[] data, Context context) {
|
public synchronized void addCertificate(byte[] data, Context context) {
|
||||||
int handle;
|
int handle;
|
||||||
Intent intent = null;
|
Intent intent = null;
|
||||||
|
|
||||||
|
Log.i("CertTool", "addCertificate()");
|
||||||
if (isPkcs12Keystore(data)) {
|
if (isPkcs12Keystore(data)) {
|
||||||
intent = prepareIntent(TITLE_PKCS12_KEYSTORE, data, USER_KEY,
|
intent = prepareIntent(TITLE_PKCS12_KEYSTORE, data, USER_KEY,
|
||||||
UNKNOWN, UNKNOWN);
|
UNKNOWN, UNKNOWN);
|
||||||
|
|||||||
@@ -136,30 +136,126 @@ err:
|
|||||||
return ret_code;
|
return ret_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
int is_pkcs12(const char *buf, int bufLen)
|
PKCS12 *get_p12_handle(const char *buf, int bufLen)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
|
||||||
BIO *bp = NULL;
|
BIO *bp = NULL;
|
||||||
PKCS12 *p12 = NULL;
|
PKCS12 *p12 = NULL;
|
||||||
|
|
||||||
if (!buf || bufLen < 1) goto err;
|
if (!buf || (bufLen < 1) || (buf[0] != 48)) goto err;
|
||||||
|
|
||||||
bp = BIO_new(BIO_s_mem());
|
bp = BIO_new(BIO_s_mem());
|
||||||
if (!bp) goto err;
|
if (!bp) goto err;
|
||||||
|
|
||||||
if (buf[0] != 48) goto err; // it is not DER.
|
|
||||||
|
|
||||||
if (!BIO_write(bp, buf, bufLen)) goto err;
|
if (!BIO_write(bp, buf, bufLen)) goto err;
|
||||||
|
|
||||||
if ((p12 = d2i_PKCS12_bio(bp, NULL)) != NULL) {
|
p12 = d2i_PKCS12_bio(bp, NULL);
|
||||||
PKCS12_free(p12);
|
|
||||||
ret = 1;
|
|
||||||
}
|
|
||||||
err:
|
err:
|
||||||
if (bp) BIO_free(bp);
|
if (bp) BIO_free(bp);
|
||||||
|
return p12;
|
||||||
|
}
|
||||||
|
|
||||||
|
PKCS12_KEYSTORE *get_pkcs12_keystore_handle(const char *buf, int bufLen,
|
||||||
|
const char *passwd)
|
||||||
|
{
|
||||||
|
PKCS12_KEYSTORE *p12store = NULL;
|
||||||
|
EVP_PKEY *pkey = NULL;
|
||||||
|
X509 *cert = NULL;
|
||||||
|
STACK_OF(X509) *certs = NULL;
|
||||||
|
PKCS12 *p12 = get_p12_handle(buf, bufLen);
|
||||||
|
|
||||||
|
if (p12 == NULL) return NULL;
|
||||||
|
if (!PKCS12_parse(p12, passwd, &pkey, &cert, &certs)) {
|
||||||
|
LOGE("Can not parse PKCS12 content");
|
||||||
|
PKCS12_free(p12);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if ((p12store = malloc(sizeof(PKCS12_KEYSTORE))) == NULL) {
|
||||||
|
if (cert) X509_free(cert);
|
||||||
|
if (pkey) EVP_PKEY_free(pkey);
|
||||||
|
if (certs) sk_X509_free(certs);
|
||||||
|
}
|
||||||
|
p12store->p12 = p12;
|
||||||
|
p12store->pkey = pkey;
|
||||||
|
p12store->cert = cert;
|
||||||
|
p12store->certs = certs;
|
||||||
|
return p12store;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_pkcs12_keystore(PKCS12_KEYSTORE *p12store)
|
||||||
|
{
|
||||||
|
if (p12store != NULL) {
|
||||||
|
if (p12store->cert) X509_free(p12store->cert);
|
||||||
|
if (p12store->pkey) EVP_PKEY_free(p12store->pkey);
|
||||||
|
if (p12store->certs) sk_X509_free(p12store->certs);
|
||||||
|
free(p12store);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int is_pkcs12(const char *buf, int bufLen)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
PKCS12 *p12 = get_p12_handle(buf, bufLen);
|
||||||
|
if (p12 != NULL) ret = 1;
|
||||||
|
PKCS12_free(p12);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int convert_to_pem(void *data, int is_cert, char *buf, int size)
|
||||||
|
{
|
||||||
|
int len = 0;
|
||||||
|
BIO *bio = NULL;
|
||||||
|
|
||||||
|
if (data == NULL) return -1;
|
||||||
|
|
||||||
|
if ((bio = BIO_new(BIO_s_mem())) == NULL) goto err;
|
||||||
|
if (is_cert) {
|
||||||
|
if ((len = PEM_write_bio_X509(bio, (X509*)data)) == 0) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ((len = PEM_write_bio_PrivateKey(bio, (EVP_PKEY *)data, NULL,
|
||||||
|
NULL, 0, NULL, NULL)) == 0) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (len < size && (len = BIO_read(bio, buf, size - 1)) > 0) {
|
||||||
|
buf[len] = 0;
|
||||||
|
}
|
||||||
|
err:
|
||||||
|
if (bio) BIO_free(bio);
|
||||||
|
return (len == 0) ? -1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_pkcs12_certificate(PKCS12_KEYSTORE *p12store, char *buf, int size)
|
||||||
|
{
|
||||||
|
if ((p12store != NULL) && (p12store->cert != NULL)) {
|
||||||
|
return convert_to_pem((void*)p12store->cert, 1, buf, size);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_pkcs12_private_key(PKCS12_KEYSTORE *p12store, char *buf, int size)
|
||||||
|
{
|
||||||
|
if ((p12store != NULL) && (p12store->pkey != NULL)) {
|
||||||
|
return convert_to_pem((void*)p12store->pkey, 0, buf, size);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pop_pkcs12_certs_stack(PKCS12_KEYSTORE *p12store, char *buf, int size)
|
||||||
|
{
|
||||||
|
X509 *cert = NULL;
|
||||||
|
|
||||||
|
if ((p12store != NULL) && (p12store->certs != NULL) &&
|
||||||
|
((cert = sk_X509_pop(p12store->certs)) != NULL)) {
|
||||||
|
int ret = convert_to_pem((void*)cert, 1, buf, size);
|
||||||
|
X509_free(cert);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
X509* parse_cert(const char *buf, int bufLen)
|
X509* parse_cert(const char *buf, int bufLen)
|
||||||
{
|
{
|
||||||
X509 *cert = NULL;
|
X509 *cert = NULL;
|
||||||
|
|||||||
@@ -41,6 +41,13 @@ typedef struct {
|
|||||||
int key_len;
|
int key_len;
|
||||||
} PKEY_STORE;
|
} PKEY_STORE;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
PKCS12 *p12;
|
||||||
|
EVP_PKEY *pkey;
|
||||||
|
X509 *cert;
|
||||||
|
STACK_OF(X509) *certs;
|
||||||
|
} PKCS12_KEYSTORE;
|
||||||
|
|
||||||
#define PKEY_STORE_free(x) { \
|
#define PKEY_STORE_free(x) { \
|
||||||
if(x.pkey) EVP_PKEY_free(x.pkey); \
|
if(x.pkey) EVP_PKEY_free(x.pkey); \
|
||||||
if(x.public_key) free(x.public_key); \
|
if(x.public_key) free(x.public_key); \
|
||||||
@@ -49,8 +56,14 @@ typedef struct {
|
|||||||
#define nelem(x) (sizeof (x) / sizeof *(x))
|
#define nelem(x) (sizeof (x) / sizeof *(x))
|
||||||
|
|
||||||
int gen_csr(int bits, const char *organizations, char reply[REPLY_MAX]);
|
int gen_csr(int bits, const char *organizations, char reply[REPLY_MAX]);
|
||||||
|
PKCS12_KEYSTORE *get_pkcs12_keystore_handle(const char *buf, int bufLen,
|
||||||
|
const char *passwd);
|
||||||
|
int get_pkcs12_certificate(PKCS12_KEYSTORE *p12store, char *buf, int size);
|
||||||
|
int get_pkcs12_private_key(PKCS12_KEYSTORE *p12store, char *buf, int size);
|
||||||
|
int pop_pkcs12_certs_stack(PKCS12_KEYSTORE *p12store, char *buf, int size);
|
||||||
|
void free_pkcs12_keystore(PKCS12_KEYSTORE *p12store);
|
||||||
int is_pkcs12(const char *buf, int bufLen);
|
int is_pkcs12(const char *buf, int bufLen);
|
||||||
X509* parse_cert(const char *buf, int bufLen);
|
X509 *parse_cert(const char *buf, int bufLen);
|
||||||
int get_cert_name(X509 *cert, char *buf, int size);
|
int get_cert_name(X509 *cert, char *buf, int size);
|
||||||
int get_issuer_name(X509 *cert, char *buf, int size);
|
int get_issuer_name(X509 *cert, char *buf, int size);
|
||||||
int is_ca_cert(X509 *cert);
|
int is_ca_cert(X509 *cert);
|
||||||
|
|||||||
@@ -19,10 +19,13 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <jni.h>
|
#include <jni.h>
|
||||||
#include <cutils/log.h>
|
#include <cutils/log.h>
|
||||||
|
#include <openssl/pkcs12.h>
|
||||||
#include <openssl/x509v3.h>
|
#include <openssl/x509v3.h>
|
||||||
|
|
||||||
#include "cert.h"
|
#include "cert.h"
|
||||||
|
|
||||||
|
typedef int PKCS12_KEYSTORE_FUNC(PKCS12_KEYSTORE *store, char *buf, int size);
|
||||||
|
|
||||||
jstring
|
jstring
|
||||||
android_security_CertTool_generateCertificateRequest(JNIEnv* env,
|
android_security_CertTool_generateCertificateRequest(JNIEnv* env,
|
||||||
jobject thiz,
|
jobject thiz,
|
||||||
@@ -42,12 +45,88 @@ android_security_CertTool_isPkcs12Keystore(JNIEnv* env,
|
|||||||
jobject thiz,
|
jobject thiz,
|
||||||
jbyteArray data)
|
jbyteArray data)
|
||||||
{
|
{
|
||||||
char buf[REPLY_MAX];
|
|
||||||
int len = (*env)->GetArrayLength(env, data);
|
int len = (*env)->GetArrayLength(env, data);
|
||||||
|
|
||||||
if (len > REPLY_MAX) return 0;
|
if (len > 0) {
|
||||||
(*env)->GetByteArrayRegion(env, data, 0, len, (jbyte*)buf);
|
PKCS12 *handle = NULL;
|
||||||
return (jboolean) is_pkcs12(buf, len);
|
char buf[len];
|
||||||
|
|
||||||
|
(*env)->GetByteArrayRegion(env, data, 0, len, (jbyte*)buf);
|
||||||
|
return (jboolean)is_pkcs12(buf, len);
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jint
|
||||||
|
android_security_CertTool_getPkcs12Handle(JNIEnv* env,
|
||||||
|
jobject thiz,
|
||||||
|
jbyteArray data,
|
||||||
|
jstring jPassword)
|
||||||
|
{
|
||||||
|
jboolean bIsCopy;
|
||||||
|
int len = (*env)->GetArrayLength(env, data);
|
||||||
|
const char* passwd = (*env)->GetStringUTFChars(env, jPassword , &bIsCopy);
|
||||||
|
|
||||||
|
if (len > 0) {
|
||||||
|
PKCS12_KEYSTORE *handle = NULL;
|
||||||
|
char buf[len];
|
||||||
|
|
||||||
|
(*env)->GetByteArrayRegion(env, data, 0, len, (jbyte*)buf);
|
||||||
|
handle = get_pkcs12_keystore_handle(buf, len, passwd);
|
||||||
|
(*env)->ReleaseStringUTFChars(env, jPassword, passwd);
|
||||||
|
return (jint)handle;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jstring call_pkcs12_ks_func(PKCS12_KEYSTORE_FUNC *func,
|
||||||
|
JNIEnv* env,
|
||||||
|
jobject thiz,
|
||||||
|
jint phandle)
|
||||||
|
{
|
||||||
|
char buf[REPLY_MAX];
|
||||||
|
|
||||||
|
if (phandle == 0) return NULL;
|
||||||
|
if (func((PKCS12_KEYSTORE*)phandle, buf, sizeof(buf)) == 0) {
|
||||||
|
return (*env)->NewStringUTF(env, buf);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
jstring
|
||||||
|
android_security_CertTool_getPkcs12Certificate(JNIEnv* env,
|
||||||
|
jobject thiz,
|
||||||
|
jint phandle)
|
||||||
|
{
|
||||||
|
return call_pkcs12_ks_func((PKCS12_KEYSTORE_FUNC *)get_pkcs12_certificate,
|
||||||
|
env, thiz, phandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
jstring
|
||||||
|
android_security_CertTool_getPkcs12PrivateKey(JNIEnv* env,
|
||||||
|
jobject thiz,
|
||||||
|
jint phandle)
|
||||||
|
{
|
||||||
|
return call_pkcs12_ks_func((PKCS12_KEYSTORE_FUNC *)get_pkcs12_private_key,
|
||||||
|
env, thiz, phandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
jstring
|
||||||
|
android_security_CertTool_popPkcs12CertificateStack(JNIEnv* env,
|
||||||
|
jobject thiz,
|
||||||
|
jint phandle)
|
||||||
|
{
|
||||||
|
return call_pkcs12_ks_func((PKCS12_KEYSTORE_FUNC *)pop_pkcs12_certs_stack,
|
||||||
|
env, thiz, phandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void android_security_CertTool_freePkcs12Handle(JNIEnv* env,
|
||||||
|
jobject thiz,
|
||||||
|
jint handle)
|
||||||
|
{
|
||||||
|
if (handle != 0) free_pkcs12_keystore((PKCS12_KEYSTORE*)handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
jint
|
jint
|
||||||
@@ -117,6 +196,16 @@ static JNINativeMethod gCertToolMethods[] = {
|
|||||||
(void*)android_security_CertTool_generateCertificateRequest},
|
(void*)android_security_CertTool_generateCertificateRequest},
|
||||||
{"isPkcs12Keystore", "([B)Z",
|
{"isPkcs12Keystore", "([B)Z",
|
||||||
(void*)android_security_CertTool_isPkcs12Keystore},
|
(void*)android_security_CertTool_isPkcs12Keystore},
|
||||||
|
{"getPkcs12Handle", "([BLjava/lang/String;)I",
|
||||||
|
(void*)android_security_CertTool_getPkcs12Handle},
|
||||||
|
{"getPkcs12Certificate", "(I)Ljava/lang/String;",
|
||||||
|
(void*)android_security_CertTool_getPkcs12Certificate},
|
||||||
|
{"getPkcs12PrivateKey", "(I)Ljava/lang/String;",
|
||||||
|
(void*)android_security_CertTool_getPkcs12PrivateKey},
|
||||||
|
{"popPkcs12CertificateStack", "(I)Ljava/lang/String;",
|
||||||
|
(void*)android_security_CertTool_popPkcs12CertificateStack},
|
||||||
|
{"freePkcs12Handle", "(I)V",
|
||||||
|
(void*)android_security_CertTool_freePkcs12Handle},
|
||||||
{"generateX509Certificate", "([B)I",
|
{"generateX509Certificate", "([B)I",
|
||||||
(void*)android_security_CertTool_generateX509Certificate},
|
(void*)android_security_CertTool_generateX509Certificate},
|
||||||
{"isCaCertificate", "(I)Z",
|
{"isCaCertificate", "(I)Z",
|
||||||
|
|||||||
Reference in New Issue
Block a user