/*
**
** Copyright 2009, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
#define LOG_TAG "CertTool"
#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,
jint bits,
jstring jChallenge)
{
int ret = -1;
jboolean bIsCopy;
char csr[REPLY_MAX];
const char* challenge = (*env)->GetStringUTFChars(env, jChallenge, &bIsCopy);
ret = gen_csr(bits, challenge , csr);
(*env)->ReleaseStringUTFChars(env, jChallenge, challenge);
if (ret == 0) return (*env)->NewStringUTF(env, csr);
return NULL;
}
jboolean
android_security_CertTool_isPkcs12Keystore(JNIEnv* env,
jobject thiz,
jbyteArray data)
{
int len = (*env)->GetArrayLength(env, data);
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
android_security_CertTool_generateX509Certificate(JNIEnv* env,
jobject thiz,
jbyteArray data)
{
char buf[REPLY_MAX];
int len = (*env)->GetArrayLength(env, data);
if (len > REPLY_MAX) return 0;
(*env)->GetByteArrayRegion(env, data, 0, len, (jbyte*)buf);
return (jint) parse_cert(buf, len);
}
jboolean android_security_CertTool_isCaCertificate(JNIEnv* env,
jobject thiz,
jint handle)
{
return (handle == 0) ? (jboolean)0 : (jboolean) is_ca_cert((X509*)handle);
}
jstring android_security_CertTool_getIssuerDN(JNIEnv* env,
jobject thiz,
jint handle)
{
char issuer[MAX_CERT_NAME_LEN];
if (handle == 0) return NULL;
if (get_issuer_name((X509*)handle, issuer, MAX_CERT_NAME_LEN)) return NULL;
return (*env)->NewStringUTF(env, issuer);
}
jstring android_security_CertTool_getCertificateDN(JNIEnv* env,
jobject thiz,
jint handle)
{
char name[MAX_CERT_NAME_LEN];
if (handle == 0) return NULL;
if (get_cert_name((X509*)handle, name, MAX_CERT_NAME_LEN)) return NULL;
return (*env)->NewStringUTF(env, name);
}
jstring android_security_CertTool_getPrivateKeyPEM(JNIEnv* env,
jobject thiz,
jint handle)
{
char pem[MAX_PEM_LENGTH];
if (handle == 0) return NULL;
if (get_private_key_pem((X509*)handle, pem, MAX_PEM_LENGTH)) return NULL;
return (*env)->NewStringUTF(env, pem);
}
void android_security_CertTool_freeX509Certificate(JNIEnv* env,
jobject thiz,
jint handle)
{
if (handle != 0) X509_free((X509*)handle);
}
/*
* Table of methods associated with the CertTool class.
*/
static JNINativeMethod gCertToolMethods[] = {
/* name, signature, funcPtr */
{"generateCertificateRequest", "(ILjava/lang/String;)Ljava/lang/String;",
(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",
(void*)android_security_CertTool_isCaCertificate},
{"getIssuerDN", "(I)Ljava/lang/String;",
(void*)android_security_CertTool_getIssuerDN},
{"getCertificateDN", "(I)Ljava/lang/String;",
(void*)android_security_CertTool_getCertificateDN},
{"getPrivateKeyPEM", "(I)Ljava/lang/String;",
(void*)android_security_CertTool_getPrivateKeyPEM},
{"freeX509Certificate", "(I)V",
(void*)android_security_CertTool_freeX509Certificate},
};
/*
* Register several native methods for one class.
*/
static int registerNatives(JNIEnv* env, const char* className,
JNINativeMethod* gMethods, int numMethods)
{
jclass clazz;
clazz = (*env)->FindClass(env, className);
if (clazz == NULL) {
LOGE("Can not find class %s\n", className);
return JNI_FALSE;
}
if ((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0) {
LOGE("Can not RegisterNatives\n");
return JNI_FALSE;
}
return JNI_TRUE;
}
jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
JNIEnv* env = NULL;
jint result = -1;
if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) {
goto bail;
}
if (!registerNatives(env, "android/security/CertTool",
gCertToolMethods, nelem(gCertToolMethods))) {
goto bail;
}
/* success -- return valid version number */
result = JNI_VERSION_1_4;
bail:
return result;
}