Loading keystore/java/android/security/CertTool.java +44 −6 Original line number Diff line number Diff line Loading @@ -16,11 +16,19 @@ 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.Intent; import android.security.Keystore; import android.text.TextUtils; import android.util.Log; /** * The CertTool class provides the functions to list the certs/keys, Loading @@ -41,12 +49,12 @@ public class CertTool { public static final String KEY_NAMESPACE = "namespace"; 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 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 TAG = "CertTool"; private static final String UNKNOWN = "Unknown"; private static final String ISSUER_NAME = "Issuer Name:"; private static final String DISTINCT_NAME = "Distinct Name:"; Loading @@ -58,6 +66,11 @@ public class CertTool { private static final String KEYNAME_DELIMITER = "_"; 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 boolean isPkcs12Keystore(byte[] data); private native int generateX509Certificate(byte[] data); Loading Loading @@ -130,10 +143,35 @@ public class CertTool { 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) { int handle; Intent intent = null; Log.i("CertTool", "addCertificate()"); if (isPkcs12Keystore(data)) { intent = prepareIntent(TITLE_PKCS12_KEYSTORE, data, USER_KEY, UNKNOWN, UNKNOWN); Loading keystore/jni/cert.c +105 −9 Original line number Diff line number Diff line Loading @@ -136,29 +136,125 @@ err: 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; PKCS12 *p12 = NULL; if (!buf || bufLen < 1) goto err; if (!buf || (bufLen < 1) || (buf[0] != 48)) goto err; bp = BIO_new(BIO_s_mem()); if (!bp) goto err; if (buf[0] != 48) goto err; // it is not DER. if (!BIO_write(bp, buf, bufLen)) goto err; if ((p12 = d2i_PKCS12_bio(bp, NULL)) != NULL) { p12 = d2i_PKCS12_bio(bp, NULL); err: 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); ret = 1; 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; } 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 (bp) BIO_free(bp); 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) { Loading keystore/jni/cert.h +14 −1 Original line number Diff line number Diff line Loading @@ -41,6 +41,13 @@ typedef struct { int key_len; } PKEY_STORE; typedef struct { PKCS12 *p12; EVP_PKEY *pkey; X509 *cert; STACK_OF(X509) *certs; } PKCS12_KEYSTORE; #define PKEY_STORE_free(x) { \ if(x.pkey) EVP_PKEY_free(x.pkey); \ if(x.public_key) free(x.public_key); \ Loading @@ -49,6 +56,12 @@ typedef struct { #define nelem(x) (sizeof (x) / sizeof *(x)) 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); X509 *parse_cert(const char *buf, int bufLen); int get_cert_name(X509 *cert, char *buf, int size); Loading keystore/jni/certtool.c +93 −4 Original line number Diff line number Diff line Loading @@ -19,10 +19,13 @@ #include <string.h> #include <jni.h> #include <cutils/log.h> #include <openssl/pkcs12.h> #include <openssl/x509v3.h> #include "cert.h" typedef int PKCS12_KEYSTORE_FUNC(PKCS12_KEYSTORE *store, char *buf, int size); jstring android_security_CertTool_generateCertificateRequest(JNIEnv* env, jobject thiz, Loading @@ -42,12 +45,88 @@ android_security_CertTool_isPkcs12Keystore(JNIEnv* env, jobject thiz, jbyteArray data) { char buf[REPLY_MAX]; int len = (*env)->GetArrayLength(env, data); if (len > REPLY_MAX) return 0; if (len > 0) { PKCS12 *handle = NULL; 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 Loading Loading @@ -117,6 +196,16 @@ static JNINativeMethod gCertToolMethods[] = { (void*)android_security_CertTool_generateCertificateRequest}, {"isPkcs12Keystore", "([B)Z", (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", (void*)android_security_CertTool_generateX509Certificate}, {"isCaCertificate", "(I)Z", Loading Loading
keystore/java/android/security/CertTool.java +44 −6 Original line number Diff line number Diff line Loading @@ -16,11 +16,19 @@ 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.Intent; import android.security.Keystore; import android.text.TextUtils; import android.util.Log; /** * The CertTool class provides the functions to list the certs/keys, Loading @@ -41,12 +49,12 @@ public class CertTool { public static final String KEY_NAMESPACE = "namespace"; 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 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 TAG = "CertTool"; private static final String UNKNOWN = "Unknown"; private static final String ISSUER_NAME = "Issuer Name:"; private static final String DISTINCT_NAME = "Distinct Name:"; Loading @@ -58,6 +66,11 @@ public class CertTool { private static final String KEYNAME_DELIMITER = "_"; 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 boolean isPkcs12Keystore(byte[] data); private native int generateX509Certificate(byte[] data); Loading Loading @@ -130,10 +143,35 @@ public class CertTool { 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) { int handle; Intent intent = null; Log.i("CertTool", "addCertificate()"); if (isPkcs12Keystore(data)) { intent = prepareIntent(TITLE_PKCS12_KEYSTORE, data, USER_KEY, UNKNOWN, UNKNOWN); Loading
keystore/jni/cert.c +105 −9 Original line number Diff line number Diff line Loading @@ -136,29 +136,125 @@ err: 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; PKCS12 *p12 = NULL; if (!buf || bufLen < 1) goto err; if (!buf || (bufLen < 1) || (buf[0] != 48)) goto err; bp = BIO_new(BIO_s_mem()); if (!bp) goto err; if (buf[0] != 48) goto err; // it is not DER. if (!BIO_write(bp, buf, bufLen)) goto err; if ((p12 = d2i_PKCS12_bio(bp, NULL)) != NULL) { p12 = d2i_PKCS12_bio(bp, NULL); err: 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); ret = 1; 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; } 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 (bp) BIO_free(bp); 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) { Loading
keystore/jni/cert.h +14 −1 Original line number Diff line number Diff line Loading @@ -41,6 +41,13 @@ typedef struct { int key_len; } PKEY_STORE; typedef struct { PKCS12 *p12; EVP_PKEY *pkey; X509 *cert; STACK_OF(X509) *certs; } PKCS12_KEYSTORE; #define PKEY_STORE_free(x) { \ if(x.pkey) EVP_PKEY_free(x.pkey); \ if(x.public_key) free(x.public_key); \ Loading @@ -49,6 +56,12 @@ typedef struct { #define nelem(x) (sizeof (x) / sizeof *(x)) 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); X509 *parse_cert(const char *buf, int bufLen); int get_cert_name(X509 *cert, char *buf, int size); Loading
keystore/jni/certtool.c +93 −4 Original line number Diff line number Diff line Loading @@ -19,10 +19,13 @@ #include <string.h> #include <jni.h> #include <cutils/log.h> #include <openssl/pkcs12.h> #include <openssl/x509v3.h> #include "cert.h" typedef int PKCS12_KEYSTORE_FUNC(PKCS12_KEYSTORE *store, char *buf, int size); jstring android_security_CertTool_generateCertificateRequest(JNIEnv* env, jobject thiz, Loading @@ -42,12 +45,88 @@ android_security_CertTool_isPkcs12Keystore(JNIEnv* env, jobject thiz, jbyteArray data) { char buf[REPLY_MAX]; int len = (*env)->GetArrayLength(env, data); if (len > REPLY_MAX) return 0; if (len > 0) { PKCS12 *handle = NULL; 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 Loading Loading @@ -117,6 +196,16 @@ static JNINativeMethod gCertToolMethods[] = { (void*)android_security_CertTool_generateCertificateRequest}, {"isPkcs12Keystore", "([B)Z", (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", (void*)android_security_CertTool_generateX509Certificate}, {"isCaCertificate", "(I)Z", Loading