Add CertTool for handling the keygen and certificate download.

1. Have the new Keystore for mini-keystore impelemntation.
2. Add CertTool library and jni dll for handling keygen and certificates.
3. Make Reply hidden.
4. Revert some 'incorrect' change and correct the description.
diff --git a/keystore/jni/Android.mk b/keystore/jni/Android.mk
new file mode 100644
index 0000000..92c2d6d
--- /dev/null
+++ b/keystore/jni/Android.mk
@@ -0,0 +1,31 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+    cert.c certtool.c
+
+LOCAL_C_INCLUDES += \
+  $(JNI_H_INCLUDE) \
+  external/openssl/include
+
+LOCAL_SHARED_LIBRARIES := \
+  libcutils \
+  libnativehelper \
+  libutils \
+  libcrypto
+
+ifeq ($(TARGET_SIMULATOR),true)
+ifeq ($(TARGET_OS),linux)
+ifeq ($(TARGET_ARCH),x86)
+LOCAL_LDLIBS += -lpthread -ldl -lrt -lssl
+endif
+endif
+endif
+
+ifeq ($(WITH_MALLOC_LEAK_CHECK),true)
+  LOCAL_CFLAGS += -DMALLOC_LEAK_CHECK
+endif
+
+LOCAL_MODULE:= libcerttool_jni
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/keystore/jni/cert.c b/keystore/jni/cert.c
new file mode 100644
index 0000000..07f0e86
--- /dev/null
+++ b/keystore/jni/cert.c
@@ -0,0 +1,249 @@
+/*
+**
+** 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 <stdio.h>
+#include <openssl/engine.h>
+#include <openssl/pem.h>
+#include <openssl/pkcs12.h>
+#include <openssl/rsa.h>
+#include <openssl/x509v3.h>
+#include <cutils/log.h>
+
+#include "cert.h"
+
+static PKEY_STORE pkey_store[KEYGEN_STORE_SIZE];
+static int store_index = 0;
+
+static char emsg[][30] = {
+    "",
+    STR(ERR_INVALID_KEY_LENGTH),
+    STR(ERR_CONSTRUCT_NEW_DATA),
+    STR(ERR_RSA_KEYGEN),
+    STR(ERR_X509_PROCESS),
+    STR(ERR_BIO_READ),
+};
+
+static void save_in_store(X509_REQ *req, EVP_PKEY *pkey)
+{
+    EVP_PKEY *newpkey = EVP_PKEY_new();
+    RSA *rsa = EVP_PKEY_get1_RSA(pkey);
+    EVP_PKEY_set1_RSA(newpkey, rsa);
+    PKEY_STORE_free(pkey_store[store_index]);
+    pkey_store[store_index].key_len =
+    i2d_X509_PUBKEY(req->req_info->pubkey, &pkey_store[store_index].public_key);
+    pkey_store[store_index++].pkey = newpkey;
+    store_index %= KEYGEN_STORE_SIZE;
+    RSA_free(rsa);
+}
+
+static EVP_PKEY *get_pkey_from_store(X509 *cert)
+{
+    int i, key_len;
+    unsigned char *buf = NULL;
+    if ((key_len = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), &buf)) == 0) {
+        return NULL;
+    }
+    for (i = 0 ; i < KEYGEN_STORE_SIZE ; ++i) {
+        if ((key_len == pkey_store[i].key_len) &&
+            memcmp(buf, pkey_store[i].public_key, key_len) == 0) {
+            break;
+        }
+    }
+    free(buf);
+    return (i == KEYGEN_STORE_SIZE) ? NULL : pkey_store[i].pkey;
+}
+
+int gen_csr(int bits, const char *organizations, char reply[REPLY_MAX])
+{
+    int len, ret_code = 0;
+    BIGNUM *bn = NULL;
+    BIO *bio = NULL;
+    EVP_PKEY *pkey = NULL;
+    RSA *rsa = NULL;
+    X509_REQ *req = NULL;
+    X509_NAME *name = NULL;
+
+    if ((bio = BIO_new(BIO_s_mem())) == NULL) goto err;
+
+    if ((bits != KEYLENGTH_MEDIUM) && (bits != KEYLENGTH_MAXIMUM)) {
+        ret_code = ERR_INVALID_KEY_LENGTH;
+        goto err;
+    }
+
+    if (((pkey = EVP_PKEY_new()) == NULL) ||
+        ((req = X509_REQ_new()) == NULL) ||
+        ((rsa = RSA_new()) == NULL) || ((bn = BN_new()) == NULL)) {
+        ret_code = ERR_CONSTRUCT_NEW_DATA;
+        goto err;
+    }
+
+    if (!BN_set_word(bn, RSA_F4) ||
+        !RSA_generate_key_ex(rsa, bits, bn, NULL) ||
+        !EVP_PKEY_assign_RSA(pkey, rsa)) {
+        ret_code = ERR_RSA_KEYGEN;
+        goto err;
+    }
+
+    // rsa will be part of the req, it will be freed in X509_REQ_free(req)
+    rsa = NULL;
+
+    X509_REQ_set_pubkey(req, pkey);
+    name = X509_REQ_get_subject_name(req);
+
+    X509_NAME_add_entry_by_txt(name, "C",  MBSTRING_ASC,
+                               (const unsigned char *)"US", -1, -1, 0);
+    X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
+                               (const unsigned char *) ANDROID_KEYSTORE,
+                               -1, -1, 0);
+    X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC,
+                               (const unsigned char *)organizations, -1, -1, 0);
+
+    if (!X509_REQ_sign(req, pkey, EVP_md5()) ||
+        (PEM_write_bio_X509_REQ(bio, req) <= 0)) {
+        ret_code = ERR_X509_PROCESS;
+        goto err;
+    }
+    if ((len = BIO_read(bio, reply, REPLY_MAX - 1)) > 0) {
+      reply[len] = 0;
+      save_in_store(req, pkey);
+    } else {
+      ret_code = ERR_BIO_READ;
+    }
+
+err:
+    if (rsa) RSA_free(rsa);
+    if (bn) BN_free(bn);
+    if (req) X509_REQ_free(req);
+    if (pkey) EVP_PKEY_free(pkey);
+    if (bio) BIO_free(bio);
+    if ((ret_code > 0) && (ret_code < ERR_MAXIMUM)) LOGE(emsg[ret_code]);
+    return ret_code;
+}
+
+int is_pkcs12(const char *buf, int bufLen)
+{
+    int ret = 0;
+    BIO *bp = NULL;
+    PKCS12  *p12 = NULL;
+
+    if (!buf || bufLen < 1) 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) {
+        PKCS12_free(p12);
+        ret = 1;
+    }
+err:
+    if (bp) BIO_free(bp);
+    return ret;
+}
+
+X509* parse_cert(const char *buf, int bufLen)
+{
+    X509 *cert = NULL;
+    BIO *bp = NULL;
+
+    if(!buf || bufLen < 1)
+        return NULL;
+
+    bp = BIO_new(BIO_s_mem());
+    if (!bp) goto err;
+
+    if (!BIO_write(bp, buf, bufLen)) goto err;
+
+    cert = PEM_read_bio_X509(bp, NULL, NULL, NULL);
+    if (!cert) {
+        BIO_free(bp);
+        if((bp = BIO_new(BIO_s_mem())) == NULL) goto err;
+
+        if(!BIO_write(bp, (char *) buf, bufLen)) goto err;
+        cert = d2i_X509_bio(bp, NULL);
+   }
+
+err:
+    if (bp) BIO_free(bp);
+    return cert;
+}
+
+static int get_distinct_name(X509_NAME *dname, char *buf, int size)
+{
+   int i, len;
+   char *p, *name;
+
+   if (X509_NAME_oneline(dname, buf, size) == NULL) {
+      return -1;
+   }
+   name = strstr(buf, "/CN=");
+   p = name = name ? (name + 4) : buf;
+   while (*p != 0) {
+       if (*p == ' ') *p = '_';
+       if (*p == '/') {
+          *p = 0;
+          break;
+       }
+       ++p;
+   }
+   return 0;
+}
+
+int get_cert_name(X509 *cert, char *buf, int size)
+{
+   if (!cert) return -1;
+   return get_distinct_name(X509_get_subject_name(cert), buf, size);
+}
+
+int get_issuer_name(X509 *cert, char *buf, int size)
+{
+   if (!cert) return -1;
+   return get_distinct_name(X509_get_issuer_name(cert), buf, size);
+}
+
+int is_ca_cert(X509 *cert)
+{
+    int ret = 0;
+    BASIC_CONSTRAINTS *bs = (BASIC_CONSTRAINTS *)
+            X509_get_ext_d2i(cert, NID_basic_constraints, NULL, NULL);
+    if (bs != NULL) ret = bs->ca;
+    if (bs) BASIC_CONSTRAINTS_free(bs);
+    return ret;
+}
+
+int get_private_key_pem(X509 *cert, char *buf, int size)
+{
+    int len = 0;
+    BIO *bio = NULL;
+    EVP_PKEY *pkey = get_pkey_from_store(cert);
+
+    if (pkey == NULL) return -1;
+
+    bio = BIO_new(BIO_s_mem());
+    if ((bio = BIO_new(BIO_s_mem())) == NULL) goto err;
+    if (!PEM_write_bio_PrivateKey(bio, pkey, NULL,NULL,0,NULL, NULL)) {
+        goto err;
+    }
+    if ((len = BIO_read(bio, buf, size - 1)) > 0) {
+        buf[len] = 0;
+    }
+err:
+    if (bio) BIO_free(bio);
+    return (len == 0) ? -1 : 0;
+}
diff --git a/keystore/jni/cert.h b/keystore/jni/cert.h
new file mode 100644
index 0000000..a9807b1
--- /dev/null
+++ b/keystore/jni/cert.h
@@ -0,0 +1,59 @@
+/*
+**
+** 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.
+*/
+
+#ifndef __CERT_H__
+#define __CERT_H__
+
+#define ANDROID_KEYSTORE "Android Keystore"
+#define KEYGEN_STORE_SIZE     5
+#define KEYLENGTH_MEDIUM      1024
+#define KEYLENGTH_MAXIMUM     2048
+#define MAX_CERT_NAME_LEN     128
+#define MAX_PEM_LENGTH        4096
+#define REPLY_MAX             MAX_PEM_LENGTH
+
+
+#define STR(token) #token
+#define ERR_INVALID_KEY_LENGTH  1
+#define ERR_CONSTRUCT_NEW_DATA  2
+#define ERR_RSA_KEYGEN          3
+#define ERR_X509_PROCESS        4
+#define ERR_BIO_READ            5
+#define ERR_MAXIMUM             6
+
+typedef struct {
+    EVP_PKEY *pkey;
+    unsigned char *public_key;
+    int key_len;
+} PKEY_STORE;
+
+#define PKEY_STORE_free(x) { \
+    if(x.pkey) EVP_PKEY_free(x.pkey); \
+    if(x.public_key) free(x.public_key); \
+}
+
+#define nelem(x) (sizeof (x) / sizeof *(x))
+
+int gen_csr(int bits, const char *organizations, char reply[REPLY_MAX]);
+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);
+int get_issuer_name(X509 *cert, char *buf, int size);
+int is_ca_cert(X509 *cert);
+int get_private_key_pem(X509 *cert, char *buf, int size);
+
+#endif
diff --git a/keystore/jni/certtool.c b/keystore/jni/certtool.c
new file mode 100644
index 0000000..c2a137e
--- /dev/null
+++ b/keystore/jni/certtool.c
@@ -0,0 +1,176 @@
+/*
+**
+** 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/x509v3.h>
+
+#include "cert.h"
+
+jstring
+android_security_CertTool_generateCertificateRequest(JNIEnv* env,
+                                                     jobject thiz,
+                                                     jint bits,
+                                                     jstring subject)
+
+{
+    char csr[REPLY_MAX];
+    if (gen_csr(bits, subject, csr) == 0) {
+        return (*env)->NewStringUTF(env, csr);
+    }
+    return NULL;
+}
+
+jboolean
+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;
+    (*env)->GetByteArrayRegion(env, data, 0, len, (jbyte*)buf);
+    return (jboolean) is_pkcs12(buf, len);
+}
+
+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[)I",
+        (void*)android_security_CertTool_isPkcs12Keystore},
+    {"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;
+}