Add support for DSA and ECDSA key types
Change-Id: Ibee8d172eeb36f1a2e2ce62f275aea55ada5bcbf
diff --git a/keystore/keystore.cpp b/keystore/keystore.cpp
index 2859caf..12d3b44 100644
--- a/keystore/keystore.cpp
+++ b/keystore/keystore.cpp
@@ -56,6 +56,8 @@
#include <keystore/keystore.h>
+#include "defaults.h"
+
/* KeyStore is a secured storage for key-value pairs. In this implementation,
* each file stores one key-value pair. Keys are encoded in file names, and
* values are encrypted with checksums. The encryption key is protected by a
@@ -67,6 +69,13 @@
#define PASSWORD_SIZE VALUE_SIZE
+struct BIGNUM_Delete {
+ void operator()(BIGNUM* p) const {
+ BN_free(p);
+ }
+};
+typedef UniquePtr<BIGNUM, BIGNUM_Delete> Unique_BIGNUM;
+
struct BIO_Delete {
void operator()(BIO* p) const {
BIO_free(p);
@@ -1656,7 +1665,8 @@
return mKeyStore->isEmpty(callingUid) ? ::KEY_NOT_FOUND : ::NO_ERROR;
}
- int32_t generate(const String16& name, int targetUid, int32_t flags) {
+ int32_t generate(const String16& name, int32_t targetUid, int32_t keyType, int32_t keySize,
+ int32_t flags, Vector<sp<KeystoreArg> >* args) {
uid_t callingUid = IPCThreadState::self()->getCallingUid();
if (!has_permission(callingUid, P_INSERT)) {
ALOGW("permission denied for %d: generate", callingUid);
@@ -1688,11 +1698,97 @@
return ::SYSTEM_ERROR;
}
- keymaster_rsa_keygen_params_t rsa_params;
- rsa_params.modulus_size = 2048;
- rsa_params.public_exponent = 0x10001;
+ if (keyType == EVP_PKEY_DSA && device->client_version >= 2) {
+ keymaster_dsa_keygen_params_t dsa_params;
+ memset(&dsa_params, '\0', sizeof(dsa_params));
- rc = device->generate_keypair(device, TYPE_RSA, &rsa_params, &data, &dataLength);
+ if (keySize == -1) {
+ keySize = DSA_DEFAULT_KEY_SIZE;
+ } else if ((keySize % 64) != 0 || keySize < DSA_MIN_KEY_SIZE
+ || keySize > DSA_MAX_KEY_SIZE) {
+ ALOGI("invalid key size %d", keySize);
+ return ::SYSTEM_ERROR;
+ }
+ dsa_params.key_size = keySize;
+
+ if (args->size() == 3) {
+ sp<KeystoreArg> gArg = args->itemAt(0);
+ sp<KeystoreArg> pArg = args->itemAt(1);
+ sp<KeystoreArg> qArg = args->itemAt(2);
+
+ if (gArg != NULL && pArg != NULL && qArg != NULL) {
+ dsa_params.generator = reinterpret_cast<const uint8_t*>(gArg->data());
+ dsa_params.generator_len = gArg->size();
+
+ dsa_params.prime_p = reinterpret_cast<const uint8_t*>(pArg->data());
+ dsa_params.prime_p_len = pArg->size();
+
+ dsa_params.prime_q = reinterpret_cast<const uint8_t*>(qArg->data());
+ dsa_params.prime_q_len = qArg->size();
+ } else {
+ ALOGI("not all DSA parameters were read");
+ return ::SYSTEM_ERROR;
+ }
+ } else if (args->size() != 0) {
+ ALOGI("DSA args must be 3");
+ return ::SYSTEM_ERROR;
+ }
+
+ rc = device->generate_keypair(device, TYPE_DSA, &dsa_params, &data, &dataLength);
+ } else if (keyType == EVP_PKEY_EC && device->client_version >= 2) {
+ keymaster_ec_keygen_params_t ec_params;
+ memset(&ec_params, '\0', sizeof(ec_params));
+
+ if (keySize == -1) {
+ keySize = EC_DEFAULT_KEY_SIZE;
+ } else if (keySize < EC_MIN_KEY_SIZE || keySize > EC_MAX_KEY_SIZE) {
+ ALOGI("invalid key size %d", keySize);
+ return ::SYSTEM_ERROR;
+ }
+ ec_params.field_size = keySize;
+
+ rc = device->generate_keypair(device, TYPE_EC, &ec_params, &data, &dataLength);
+ } else if (keyType == EVP_PKEY_RSA) {
+ keymaster_rsa_keygen_params_t rsa_params;
+ memset(&rsa_params, '\0', sizeof(rsa_params));
+ rsa_params.public_exponent = RSA_DEFAULT_EXPONENT;
+
+ if (keySize == -1) {
+ keySize = RSA_DEFAULT_KEY_SIZE;
+ } else if (keySize < RSA_MIN_KEY_SIZE || keySize > RSA_MAX_KEY_SIZE) {
+ ALOGI("invalid key size %d", keySize);
+ return ::SYSTEM_ERROR;
+ }
+ rsa_params.modulus_size = keySize;
+
+ if (args->size() > 1) {
+ ALOGI("invalid number of arguments: %d", args->size());
+ return ::SYSTEM_ERROR;
+ } else if (args->size() == 1) {
+ sp<KeystoreArg> pubExpBlob = args->itemAt(0);
+ if (pubExpBlob != NULL) {
+ Unique_BIGNUM pubExpBn(
+ BN_bin2bn(reinterpret_cast<const unsigned char*>(pubExpBlob->data()),
+ pubExpBlob->size(), NULL));
+ if (pubExpBn.get() == NULL) {
+ ALOGI("Could not convert public exponent to BN");
+ return ::SYSTEM_ERROR;
+ }
+ unsigned long pubExp = BN_get_word(pubExpBn.get());
+ if (pubExp == 0xFFFFFFFFL) {
+ ALOGI("cannot represent public exponent as a long value");
+ return ::SYSTEM_ERROR;
+ }
+ rsa_params.public_exponent = pubExp;
+ }
+ }
+
+ rc = device->generate_keypair(device, TYPE_RSA, &rsa_params, &data, &dataLength);
+ } else {
+ ALOGW("Unsupported key type %d", keyType);
+ rc = -1;
+ }
+
if (rc) {
return ::SYSTEM_ERROR;
}