Merge change 26786 into eclair

* changes:
  Remove old keystore and related files.
This commit is contained in:
Android (Google) Code Review
2009-09-24 01:17:01 -04:00
6 changed files with 0 additions and 1207 deletions

View File

@@ -1,357 +0,0 @@
/*
* Copyright (C) 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.
*/
package android.security;
import android.content.Context;
import android.content.Intent;
import android.security.Keystore;
import android.text.TextUtils;
import android.util.Log;
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 java.util.ArrayList;
/**
* The CertTool class provides the functions to list the certs/keys,
* generate the certificate request(csr) and store certificates into
* keystore.
*
* {@hide}
*/
public class CertTool {
static {
System.loadLibrary("certtool_jni");
}
/** Keystore namespace for CA certificates. */
public static final String CA_CERTIFICATE = "CACERT";
/** Keystore namespace for user certificates. */
public static final String USER_CERTIFICATE = "USRCERT";
/** Keystore namespace for user private keys. */
public static final String USER_KEY = "USRKEY";
/** Action string for adding certificates to keystore. */
public static final String ACTION_ADD_CREDENTIAL =
"android.security.ADD_CREDENTIAL";
/** Action string for installing certificates to keystore from sdcard. */
public static final String ACTION_INSTALL_CERT_FROM_SDCARD =
"android.security.INSTALL_CERT_FROM_SDCARD";
/** Dialog title for adding a CA certificate. */
public static final String TITLE_CA_CERT = "CA Certificate";
/** Dialog title for adding a user certificate. */
public static final String TITLE_USER_CERT = "User Certificate";
/** Dialog title for adding a user private key. */
public static final String TITLE_PRIVATE_KEY = "Private Key";
/** Dialog title for adding a PKCS12 keystore. */
public static final String TITLE_PKCS12_KEYSTORE = "PKCS12 Keystore";
public static final int INCORRECT_PKCS12_PASSPHRASE = -100;
/**
* The builder class for building an add-credential-to-keystore intent.
*/
public static class AddCredentialIntentBuilder {
private Intent mIntent;
private int mCount;
/**
* Creates a builder to build a add-credential-to-keystore intent.
*
* @param title title of the dialog for adding this credential
* @param descriptions description strings to show on the dialog
*/
public AddCredentialIntentBuilder(String title,
String... descriptions) {
Intent intent = new Intent(ACTION_ADD_CREDENTIAL);
intent.putExtra(KEY_TITLE, title);
int i = 0;
for (String description : descriptions) {
intent.putExtra(KEY_DESCRIPTION + (i++), description);
}
mIntent = intent;
}
/**
* Adds credential data to the intent.
*
* @param namespace the namespace of the keystore to add the credential
* data to
* @param data the credential data
* @return this builder
*/
public AddCredentialIntentBuilder addCredential(String namespace,
byte[] data) {
mIntent.putExtra(KEY_NAMESPACE + mCount, namespace);
mIntent.putExtra(KEY_ITEM + mCount, data);
mCount++;
return this;
}
/** Returns the intent. */
public Intent build() {
return mIntent;
}
}
/**
* Request for adding credential data to keystore.
*/
public static class AddCredentialRequest {
private Intent mIntent;
/**
* Creates an add-credential-data-to-keystore request.
*
* @param intent an add-credential-data-to-keystore intent
* @see AddCredentialIntentBuilder
*/
public AddCredentialRequest(Intent intent) {
mIntent = intent;
}
/** Returns the dialog title. */
public String getTitle() {
return mIntent.getStringExtra(KEY_TITLE);
}
/**
* Returns the i'th credential data.
* @return the data or null if not exists
*/
public byte[] getDataAt(int i) {
return mIntent.getByteArrayExtra(KEY_ITEM + i);
}
/**
* Returns the namespace of the i'th credential data.
* @return the namespace string or null if missing
*/
public String getNamespaceAt(int i) {
return mIntent.getStringExtra(KEY_NAMESPACE + i);
}
/** Returns the descriptions of the credential data. */
public String[] getDescriptions() {
ArrayList<String> list = new ArrayList<String>();
for (int i = 0; ; i++) {
String s = mIntent.getStringExtra(KEY_DESCRIPTION + i);
if (s == null) break;
list.add(s);
}
return list.toArray(new String[list.size()]);
}
}
private static final String KEY_TITLE = "typeName";
private static final String KEY_ITEM = "item";
private static final String KEY_NAMESPACE = "namespace";
private static final String KEY_DESCRIPTION = "description";
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:";
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 challenge);
private native boolean isPkcs12Keystore(byte[] data);
private native int generateX509Certificate(byte[] data);
private native boolean isCaCertificate(int handle);
private native String getIssuerDN(int handle);
private native String getCertificateDN(int handle);
private native String getPrivateKeyPEM(int handle);
private native void freeX509Certificate(int handle);
private static CertTool sSingleton = null;
private CertTool() { }
public static final CertTool getInstance() {
if (sSingleton == null) {
sSingleton = new CertTool();
}
return sSingleton;
}
/**
* Gets the full key to retrieve the user private key from the keystore.
* @see #getAllUserCertificateKeys()
*/
public String getUserPrivateKey(String key) {
return USER_KEY + KEYNAME_DELIMITER + key;
}
/**
* Gets the full key to retrieve the user certificate from the keystore.
* @see #getAllUserCertificateKeys()
*/
public String getUserCertificate(String key) {
return USER_CERTIFICATE + KEYNAME_DELIMITER + key;
}
/**
* Gets the full key to retrieve the CA certificate from the keystore.
* @see #getAllCaCertificateKeys()
*/
public String getCaCertificate(String key) {
return CA_CERTIFICATE + KEYNAME_DELIMITER + key;
}
/**
* Gets all the keys to the user certificates/private keys stored in the
* keystore.
* @see #getUserCertificate(String)
* @see #getUserPrivateKey(String)
*/
public String[] getAllUserCertificateKeys() {
return sKeystore.listKeys(USER_KEY);
}
/**
* Gets all the keys to the CA certificates stored in the keystore.
* @see #getCaCertificate(String)
*/
public String[] getAllCaCertificateKeys() {
return sKeystore.listKeys(CA_CERTIFICATE);
}
public String[] getSupportedKeyStrenghs() {
return new String[] {"High Grade", "Medium Grade"};
}
private int getKeyLength(int index) {
if (index == 0) return 2048;
return 1024;
}
/**
* Generates a key pair.
*
* @param keyStrengthIndex index to the array of supported key strengths;
* see {@link #getSupportedKeyStrenghs()}
* @param challenge the challenge string for generating the pair
* @param dirName (not used)
* @return a certificate request from the resulted public key
*/
public String generateKeyPair(int keyStrengthIndex, String challenge,
String dirName) {
return generateCertificateRequest(getKeyLength(keyStrengthIndex),
challenge);
}
private int extractAndStoreKeysFromPkcs12(int handle, String keyname) {
int ret, i = 0;
String pemData;
if ((pemData = getPkcs12Certificate(handle)) != null) {
if ((ret = sKeystore.put(USER_CERTIFICATE, keyname, pemData)) != 0) {
return ret;
}
}
if ((pemData = getPkcs12PrivateKey(handle)) != null) {
if ((ret = sKeystore.put(USER_KEY, keyname, pemData)) != 0) {
return ret;
}
}
if ((pemData = this.popPkcs12CertificateStack(handle)) != null) {
if ((ret = sKeystore.put(CA_CERTIFICATE, keyname, pemData)) != 0) {
return ret;
}
}
return 0;
}
/** Adds a PKCS12 keystore to the keystore. */
public int addPkcs12Keystore(byte[] p12Data, String password,
String keyname) {
int handle, ret;
Log.i("CertTool", "addPkcs12Keystore()");
if ((handle = getPkcs12Handle(p12Data, password)) == 0) {
return INCORRECT_PKCS12_PASSPHRASE;
}
ret = extractAndStoreKeysFromPkcs12(handle, keyname);
freePkcs12Handle(handle);
return ret;
}
/**
* Adds a certificate to the keystore.
*
* @param data the certificate data
* @param context the context to send an add-credential-to-keystore intent
*/
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, UNKNOWN, UNKNOWN)
.addCredential(USER_KEY, data).build();
} else if ((handle = generateX509Certificate(data)) != 0) {
String issuer = getIssuerDN(handle);
String distinctName = getCertificateDN(handle);
String privateKeyPEM = getPrivateKeyPEM(handle);
if (isCaCertificate(handle)) {
intent = prepareIntent(TITLE_CA_CERT, issuer, distinctName)
.addCredential(CA_CERTIFICATE, data).build();
} else {
AddCredentialIntentBuilder builder =
prepareIntent(TITLE_USER_CERT, issuer, distinctName)
.addCredential(USER_CERTIFICATE, data);
if (!TextUtils.isEmpty(privateKeyPEM)) {
builder.addCredential(USER_KEY, privateKeyPEM.getBytes());
}
intent = builder.build();
}
freeX509Certificate(handle);
}
if (intent != null) {
context.startActivity(intent);
} else {
Log.w("CertTool", "incorrect data for addCertificate()");
}
}
private AddCredentialIntentBuilder prepareIntent(
String title, String issuer, String distinctName) {
return new AddCredentialIntentBuilder(title, ISSUER_NAME + issuer,
DISTINCT_NAME + distinctName);
}
}

View File

@@ -1,133 +0,0 @@
/*
* Copyright (C) 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.
*/
package android.security;
/**
* The Keystore class provides the functions to list the certs/keys in keystore.
* {@hide}
*/
public abstract class Keystore {
/** Action to unlock (or initialize) the keystore. */
public static final String ACTION_UNLOCK_CREDENTIAL_STORAGE =
"android.security.UNLOCK_CREDENTIAL_STORAGE";
// Keystore States
public static final int BOOTUP = 0;
public static final int UNINITIALIZED = 1;
public static final int LOCKED = 2;
public static final int UNLOCKED = 3;
private static final String TAG = "Keystore";
private static final String[] NOTFOUND = new String[0];
public static Keystore getInstance() {
return new FileKeystore();
}
public abstract int lock();
public abstract int unlock(String password);
public abstract int getState();
public abstract int changePassword(String oldPassword, String newPassword);
public abstract int setPassword(String firstPassword);
public abstract String[] listKeys(String namespace);
public abstract int put(String namespace, String keyname, String value);
public abstract String get(String namespace, String keyname);
public abstract int remove(String namespace, String keyname);
public abstract int reset();
private static class FileKeystore extends Keystore {
private static final String SERVICE_NAME = "keystore";
private static final String CA_CERTIFICATE = "CaCertificate";
private static final String USER_CERTIFICATE = "UserCertificate";
private static final String USER_KEY = "UserPrivateKey";
private static final ServiceCommand mServiceCommand =
new ServiceCommand(SERVICE_NAME);
@Override
public int lock() {
Reply result = mServiceCommand.execute(ServiceCommand.LOCK);
return (result != null) ? result.returnCode : -1;
}
@Override
public int unlock(String password) {
Reply result = mServiceCommand.execute(ServiceCommand.UNLOCK,
password);
return (result != null) ? result.returnCode : -1;
}
@Override
public int getState() {
Reply result = mServiceCommand.execute(ServiceCommand.GET_STATE);
return (result != null) ? result.returnCode : -1;
}
@Override
public int changePassword(String oldPassword, String newPassword) {
Reply result = mServiceCommand.execute(ServiceCommand.PASSWD,
oldPassword, newPassword);
return (result != null) ? result.returnCode : -1;
}
@Override
public int setPassword(String firstPassword) {
Reply result = mServiceCommand.execute(ServiceCommand.PASSWD,
firstPassword);
return (result != null) ? result.returnCode : -1;
}
@Override
public String[] listKeys(String namespace) {
Reply result = mServiceCommand.execute(ServiceCommand.LIST_KEYS,
namespace);
if ((result == null) || (result.returnCode != 0) ||
(result.len == 0)) {
return NOTFOUND;
}
return new String(result.data, 0, result.len).split("\\s+");
}
@Override
public int put(String namespace, String keyname, String value) {
Reply result = mServiceCommand.execute(ServiceCommand.PUT_KEY,
namespace, keyname, value);
return (result != null) ? result.returnCode : -1;
}
@Override
public String get(String namespace, String keyname) {
Reply result = mServiceCommand.execute(ServiceCommand.GET_KEY,
namespace, keyname);
return (result != null) ? ((result.returnCode != 0) ? null :
new String(result.data, 0, result.len)) : null;
}
@Override
public int remove(String namespace, String keyname) {
Reply result = mServiceCommand.execute(ServiceCommand.REMOVE_KEY,
namespace, keyname);
return (result != null) ? result.returnCode : -1;
}
@Override
public int reset() {
Reply result = mServiceCommand.execute(ServiceCommand.RESET);
return (result != null) ? result.returnCode : -1;
}
}
}

View File

@@ -1,31 +0,0 @@
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)

View File

@@ -1,344 +0,0 @@
/*
**
** 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/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_SPKAC_TOO_LONG),
STR(ERR_INVALID_ARGS),
};
static void save_in_store(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_RSA_PUBKEY(rsa, &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 *challenge, char reply[REPLY_MAX])
{
int len, ret_code = 0;
BIGNUM *bn = NULL;
char *spkstr = NULL;
EVP_PKEY *pkey = NULL;
RSA *rsa = NULL;
NETSCAPE_SPKI *req = NULL;
if (challenge == NULL) {
ret_code = ERR_INVALID_ARGS;
goto err;
}
if ((bits != KEYLENGTH_MEDIUM) && (bits != KEYLENGTH_MAXIMUM)) {
ret_code = ERR_INVALID_KEY_LENGTH;
goto err;
}
if (((pkey = EVP_PKEY_new()) == NULL) ||
((req = NETSCAPE_SPKI_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 = NULL;
ASN1_STRING_set(req->spkac->challenge, challenge, (int)strlen(challenge));
NETSCAPE_SPKI_set_pubkey(req, pkey);
NETSCAPE_SPKI_sign(req, pkey, EVP_md5());
spkstr = NETSCAPE_SPKI_b64_encode(req);
if ((strlcpy(reply, spkstr, REPLY_MAX)) < REPLY_MAX) {
save_in_store(pkey);
} else {
ret_code = ERR_SPKAC_TOO_LONG;
}
err:
if (rsa) RSA_free(rsa);
if (bn) BN_free(bn);
if (req) NETSCAPE_SPKI_free(req);
if (pkey) EVP_PKEY_free(pkey);
if (spkstr) OPENSSL_free(spkstr);
if ((ret_code > 0) && (ret_code < ERR_MAXIMUM)) LOGE(emsg[ret_code]);
return -ret_code;
}
PKCS12 *get_p12_handle(const char *buf, int bufLen)
{
BIO *bp = NULL;
PKCS12 *p12 = NULL;
if (!buf || (bufLen < 1) || (buf[0] != 48)) goto err;
bp = BIO_new(BIO_s_mem());
if (!bp) goto err;
if (!BIO_write(bp, buf, bufLen)) goto err;
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);
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 (bio) BIO_free(bio);
return len;
}
int get_pkcs12_certificate(PKCS12_KEYSTORE *p12store, char *buf, int size)
{
if ((p12store != NULL) && (p12store->cert != NULL)) {
int len = convert_to_pem((void*)p12store->cert, 1, buf, size);
return (len == 0) ? -1 : 0;
}
return -1;
}
int get_pkcs12_private_key(PKCS12_KEYSTORE *p12store, char *buf, int size)
{
if ((p12store != NULL) && (p12store->pkey != NULL)) {
int len = convert_to_pem((void*)p12store->pkey, 0, buf, size);
return (len == 0) ? -1 : 0;
}
return -1;
}
int pop_pkcs12_certs_stack(PKCS12_KEYSTORE *p12store, char *buf, int size)
{
X509 *cert = NULL;
int len = 0;
if ((p12store != NULL) && (p12store->certs != NULL)) {
while (((cert = sk_X509_pop(p12store->certs)) != NULL) && (len < size)) {
int s = convert_to_pem((void*)cert, 1, buf + len, size - len);
if (s == 0) {
LOGE("buffer size is too small. len=%d size=%d\n", len, size);
return -1;
}
len += s;
X509_free(cert);
}
return (len == 0) ? -1 : 0;
}
return -1;
}
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;
}

View File

@@ -1,73 +0,0 @@
/*
**
** 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_SPKAC_TOO_LONG 5
#define ERR_INVALID_ARGS 6
#define ERR_MAXIMUM 7
typedef struct {
EVP_PKEY *pkey;
unsigned char *public_key;
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); \
}
#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);
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

View File

@@ -1,269 +0,0 @@
/*
**
** 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;
}