summaryrefslogtreecommitdiff
path: root/softkeymaster
diff options
context:
space:
mode:
authorKenny Root <kroot@google.com>2013-08-16 14:02:41 -0700
committerKenny Root <kroot@google.com>2013-08-30 17:25:20 -0700
commit6071179a371fcd4c238375068ffd7d3cedea615d (patch)
tree77c59844bc42c60bfb19bb9ba8e3f97f6dd60e37 /softkeymaster
parent48772e0fe92c75e02a5ea92a6fbfdd0203c910ae (diff)
downloadsecurity-6071179a371fcd4c238375068ffd7d3cedea615d.tar.gz
Add support for DSA and ECDSA key types
Change-Id: Ibee8d172eeb36f1a2e2ce62f275aea55ada5bcbf
Diffstat (limited to 'softkeymaster')
-rw-r--r--softkeymaster/keymaster_openssl.cpp419
1 files changed, 352 insertions, 67 deletions
diff --git a/softkeymaster/keymaster_openssl.cpp b/softkeymaster/keymaster_openssl.cpp
index 36204505..19ec9993 100644
--- a/softkeymaster/keymaster_openssl.cpp
+++ b/softkeymaster/keymaster_openssl.cpp
@@ -57,6 +57,20 @@ struct PKCS8_PRIV_KEY_INFO_Delete {
};
typedef UniquePtr<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_Delete> Unique_PKCS8_PRIV_KEY_INFO;
+struct DSA_Delete {
+ void operator()(DSA* p) const {
+ DSA_free(p);
+ }
+};
+typedef UniquePtr<DSA, DSA_Delete> Unique_DSA;
+
+struct EC_KEY_Delete {
+ void operator()(EC_KEY* p) const {
+ EC_KEY_free(p);
+ }
+};
+typedef UniquePtr<EC_KEY, EC_KEY_Delete> Unique_EC_KEY;
+
struct RSA_Delete {
void operator()(RSA* p) const {
RSA_free(p);
@@ -93,12 +107,15 @@ static void logOpenSSLError(const char* location) {
}
static int wrap_key(EVP_PKEY* pkey, int type, uint8_t** keyBlob, size_t* keyBlobLength) {
- /* Find the length of each size */
- int publicLen = i2d_PublicKey(pkey, NULL);
+ /*
+ * Find the length of each size. Public key is not needed anymore but must be kept for
+ * alignment purposes.
+ */
+ int publicLen = 0;
int privateLen = i2d_PrivateKey(pkey, NULL);
- if (privateLen <= 0 || publicLen <= 0) {
- ALOGE("private or public key size was too big");
+ if (privateLen <= 0) {
+ ALOGE("private key size was too big");
return -1;
}
@@ -106,7 +123,7 @@ static int wrap_key(EVP_PKEY* pkey, int type, uint8_t** keyBlob, size_t* keyBlob
*keyBlobLength = get_softkey_header_size() + sizeof(int) + sizeof(int) + privateLen
+ sizeof(int) + publicLen;
- UniquePtr<unsigned char[]> derData(new unsigned char[*keyBlobLength]);
+ UniquePtr<unsigned char> derData(new unsigned char[*keyBlobLength]);
if (derData.get() == NULL) {
ALOGE("could not allocate memory for key blob");
return -1;
@@ -125,10 +142,6 @@ static int wrap_key(EVP_PKEY* pkey, int type, uint8_t** keyBlob, size_t* keyBlob
for (int i = sizeof(int) - 1; i >= 0; i--) {
*p++ = (publicLen >> (8*i)) & 0xFF;
}
- if (i2d_PublicKey(pkey, &p) != publicLen) {
- logOpenSSLError("wrap_key");
- return -1;
- }
/* Write private key to allocated buffer */
for (int i = sizeof(int) - 1; i >= 0; i--) {
@@ -174,12 +187,6 @@ static EVP_PKEY* unwrap_key(const uint8_t* keyBlob, const size_t keyBlobLength)
type = (type << 8) | *p++;
}
- Unique_EVP_PKEY pkey(EVP_PKEY_new());
- if (pkey.get() == NULL) {
- logOpenSSLError("unwrap_key");
- return NULL;
- }
-
for (size_t i = 0; i < sizeof(int); i++) {
publicLen = (publicLen << 8) | *p++;
}
@@ -187,9 +194,9 @@ static EVP_PKEY* unwrap_key(const uint8_t* keyBlob, const size_t keyBlobLength)
ALOGE("public key length encoding error: size=%ld, end=%d", publicLen, end - p);
return NULL;
}
- EVP_PKEY* tmp = pkey.get();
- d2i_PublicKey(type, &tmp, &p, publicLen);
+ const uint8_t *pubKey = p;
+ p += publicLen;
if (end - p < 2) {
ALOGE("private key truncated");
return NULL;
@@ -201,64 +208,208 @@ static EVP_PKEY* unwrap_key(const uint8_t* keyBlob, const size_t keyBlobLength)
ALOGE("private key length encoding error: size=%ld, end=%d", privateLen, end - p);
return NULL;
}
- d2i_PrivateKey(type, &tmp, &p, privateLen);
+
+ Unique_EVP_PKEY pkey(EVP_PKEY_new());
+ if (pkey.get() == NULL) {
+ logOpenSSLError("unwrap_key");
+ return NULL;
+ }
+ EVP_PKEY* tmp = pkey.get();
+
+ if (d2i_PrivateKey(type, &tmp, &p, privateLen) == NULL) {
+ logOpenSSLError("unwrap_key");
+ return NULL;
+ }
return pkey.release();
}
-static int openssl_generate_keypair(const keymaster_device_t* dev,
- const keymaster_keypair_t key_type, const void* key_params,
- uint8_t** keyBlob, size_t* keyBlobLength) {
- ssize_t privateLen, publicLen;
+static int generate_dsa_keypair(EVP_PKEY* pkey, const keymaster_dsa_keygen_params_t* dsa_params)
+{
+ if (dsa_params->key_size < 512) {
+ ALOGI("Requested DSA key size is too small (<512)");
+ return -1;
+ }
- if (key_type != TYPE_RSA) {
- ALOGW("Unsupported key type %d", key_type);
+ Unique_DSA dsa(DSA_new());
+
+ if (dsa_params->generator_len == 0 ||
+ dsa_params->prime_p_len == 0 ||
+ dsa_params->prime_q_len == 0 ||
+ dsa_params->generator == NULL||
+ dsa_params->prime_p == NULL ||
+ dsa_params->prime_q == NULL) {
+ if (DSA_generate_parameters_ex(dsa.get(), dsa_params->key_size, NULL, 0, NULL, NULL,
+ NULL) != 1) {
+ logOpenSSLError("generate_dsa_keypair");
+ return -1;
+ }
+ } else {
+ dsa->g = BN_bin2bn(dsa_params->generator,
+ dsa_params->generator_len,
+ NULL);
+ if (dsa->g == NULL) {
+ logOpenSSLError("generate_dsa_keypair");
+ return -1;
+ }
+
+ dsa->p = BN_bin2bn(dsa_params->prime_p,
+ dsa_params->prime_p_len,
+ NULL);
+ if (dsa->p == NULL) {
+ logOpenSSLError("generate_dsa_keypair");
+ return -1;
+ }
+
+ dsa->q = BN_bin2bn(dsa_params->prime_q,
+ dsa_params->prime_q_len,
+ NULL);
+ if (dsa->q == NULL) {
+ logOpenSSLError("generate_dsa_keypair");
+ return -1;
+ }
+ }
+
+ if (DSA_generate_key(dsa.get()) != 1) {
+ logOpenSSLError("generate_dsa_keypair");
return -1;
- } else if (key_params == NULL) {
- ALOGW("key_params == null");
+ }
+
+ if (EVP_PKEY_assign_DSA(pkey, dsa.get()) == 0) {
+ logOpenSSLError("generate_dsa_keypair");
+ return -1;
+ }
+ OWNERSHIP_TRANSFERRED(dsa);
+
+ return 0;
+}
+
+static int generate_ec_keypair(EVP_PKEY* pkey, const keymaster_ec_keygen_params_t* ec_params)
+{
+ EC_GROUP* group;
+ switch (ec_params->field_size) {
+ case 192:
+ group = EC_GROUP_new_by_curve_name(NID_X9_62_prime192v1);
+ break;
+ case 224:
+ group = EC_GROUP_new_by_curve_name(NID_secp224r1);
+ break;
+ case 256:
+ group = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
+ break;
+ case 384:
+ group = EC_GROUP_new_by_curve_name(NID_secp384r1);
+ break;
+ case 521:
+ group = EC_GROUP_new_by_curve_name(NID_secp521r1);
+ break;
+ default:
+ group = NULL;
+ break;
+ }
+
+ if (group == NULL) {
+ logOpenSSLError("generate_ec_keypair");
return -1;
}
- keymaster_rsa_keygen_params_t* rsa_params = (keymaster_rsa_keygen_params_t*) key_params;
+ EC_GROUP_set_point_conversion_form(group, POINT_CONVERSION_UNCOMPRESSED);
+ EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE);
+ /* initialize EC key */
+ Unique_EC_KEY eckey(EC_KEY_new());
+ if (eckey.get() == NULL) {
+ logOpenSSLError("generate_ec_keypair");
+ return -1;
+ }
+
+ if (EC_KEY_set_group(eckey.get(), group) != 1) {
+ logOpenSSLError("generate_ec_keypair");
+ return -1;
+ }
+
+ if (EC_KEY_generate_key(eckey.get()) != 1
+ || EC_KEY_check_key(eckey.get()) < 0) {
+ logOpenSSLError("generate_ec_keypair");
+ return -1;
+ }
+
+ if (EVP_PKEY_assign_EC_KEY(pkey, eckey.get()) == 0) {
+ logOpenSSLError("generate_ec_keypair");
+ return -1;
+ }
+ OWNERSHIP_TRANSFERRED(eckey);
+
+ return 0;
+}
+
+static int generate_rsa_keypair(EVP_PKEY* pkey, const keymaster_rsa_keygen_params_t* rsa_params)
+{
Unique_BIGNUM bn(BN_new());
if (bn.get() == NULL) {
- logOpenSSLError("openssl_generate_keypair");
+ logOpenSSLError("generate_rsa_keypair");
return -1;
}
if (BN_set_word(bn.get(), rsa_params->public_exponent) == 0) {
- logOpenSSLError("openssl_generate_keypair");
+ logOpenSSLError("generate_rsa_keypair");
return -1;
}
/* initialize RSA */
Unique_RSA rsa(RSA_new());
if (rsa.get() == NULL) {
- logOpenSSLError("openssl_generate_keypair");
+ logOpenSSLError("generate_rsa_keypair");
return -1;
}
if (!RSA_generate_key_ex(rsa.get(), rsa_params->modulus_size, bn.get(), NULL)
|| RSA_check_key(rsa.get()) < 0) {
- logOpenSSLError("openssl_generate_keypair");
+ logOpenSSLError("generate_rsa_keypair");
return -1;
}
- /* assign to EVP */
+ if (EVP_PKEY_assign_RSA(pkey, rsa.get()) == 0) {
+ logOpenSSLError("generate_rsa_keypair");
+ return -1;
+ }
+ OWNERSHIP_TRANSFERRED(rsa);
+
+ return 0;
+}
+
+static int openssl_generate_keypair(const keymaster_device_t* dev,
+ const keymaster_keypair_t key_type, const void* key_params,
+ uint8_t** keyBlob, size_t* keyBlobLength) {
+ ssize_t privateLen, publicLen;
+
Unique_EVP_PKEY pkey(EVP_PKEY_new());
if (pkey.get() == NULL) {
logOpenSSLError("openssl_generate_keypair");
return -1;
}
- if (EVP_PKEY_assign_RSA(pkey.get(), rsa.get()) == 0) {
- logOpenSSLError("openssl_generate_keypair");
+ if (key_params == NULL) {
+ ALOGW("key_params == null");
+ return -1;
+ } else if (key_type == TYPE_DSA) {
+ const keymaster_dsa_keygen_params_t* dsa_params =
+ (const keymaster_dsa_keygen_params_t*) key_params;
+ generate_dsa_keypair(pkey.get(), dsa_params);
+ } else if (key_type == TYPE_EC) {
+ const keymaster_ec_keygen_params_t* ec_params =
+ (const keymaster_ec_keygen_params_t*) key_params;
+ generate_ec_keypair(pkey.get(), ec_params);
+ } else if (key_type == TYPE_RSA) {
+ const keymaster_rsa_keygen_params_t* rsa_params =
+ (const keymaster_rsa_keygen_params_t*) key_params;
+ generate_rsa_keypair(pkey.get(), rsa_params);
+ } else {
+ ALOGW("Unsupported key type %d", key_type);
return -1;
}
- OWNERSHIP_TRANSFERRED(rsa);
- if (wrap_key(pkey.get(), EVP_PKEY_RSA, keyBlob, keyBlobLength)) {
+ if (wrap_key(pkey.get(), EVP_PKEY_type(pkey->type), keyBlob, keyBlobLength)) {
return -1;
}
@@ -338,35 +489,73 @@ static int openssl_get_keypair_public(const struct keymaster_device* dev,
return 0;
}
-static int openssl_sign_data(const keymaster_device_t* dev,
- const void* params,
- const uint8_t* keyBlob, const size_t keyBlobLength,
- const uint8_t* data, const size_t dataLength,
- uint8_t** signedData, size_t* signedDataLength) {
+static int sign_dsa(EVP_PKEY* pkey, keymaster_dsa_sign_params_t* sign_params, const uint8_t* data,
+ const size_t dataLength, uint8_t** signedData, size_t* signedDataLength) {
+ if (sign_params->digest_type != DIGEST_NONE) {
+ ALOGW("Cannot handle digest type %d", sign_params->digest_type);
+ return -1;
+ }
- int result = -1;
- EVP_MD_CTX ctx;
- size_t maxSize;
+ Unique_DSA dsa(EVP_PKEY_get1_DSA(pkey));
+ if (dsa.get() == NULL) {
+ logOpenSSLError("openssl_sign_dsa");
+ return -1;
+ }
- if (data == NULL) {
- ALOGW("input data to sign == NULL");
+ unsigned int dsaSize = DSA_size(dsa.get());
+ UniquePtr<uint8_t> signedDataPtr(reinterpret_cast<uint8_t*>(malloc(dsaSize)));
+ if (signedDataPtr.get() == NULL) {
+ logOpenSSLError("openssl_sign_dsa");
return -1;
- } else if (signedData == NULL || signedDataLength == NULL) {
- ALOGW("output signature buffer == NULL");
+ }
+
+ unsigned char* tmp = reinterpret_cast<unsigned char*>(signedDataPtr.get());
+ if (DSA_sign(0, data, dataLength, tmp, &dsaSize, dsa.get()) <= 0) {
+ logOpenSSLError("openssl_sign_dsa");
return -1;
}
- Unique_EVP_PKEY pkey(unwrap_key(keyBlob, keyBlobLength));
- if (pkey.get() == NULL) {
+ *signedDataLength = dsaSize;
+ *signedData = signedDataPtr.release();
+
+ return 0;
+}
+
+static int sign_ec(EVP_PKEY* pkey, keymaster_ec_sign_params_t* sign_params, const uint8_t* data,
+ const size_t dataLength, uint8_t** signedData, size_t* signedDataLength) {
+ if (sign_params->digest_type != DIGEST_NONE) {
+ ALOGW("Cannot handle digest type %d", sign_params->digest_type);
+ return -1;
+ }
+
+ Unique_EC_KEY eckey(EVP_PKEY_get1_EC_KEY(pkey));
+ if (eckey.get() == NULL) {
+ logOpenSSLError("openssl_sign_ec");
+ return -1;
+ }
+
+ unsigned int ecdsaSize = ECDSA_size(eckey.get());
+ UniquePtr<uint8_t> signedDataPtr(reinterpret_cast<uint8_t*>(malloc(ecdsaSize)));
+ if (signedDataPtr.get() == NULL) {
+ logOpenSSLError("openssl_sign_ec");
return -1;
}
- if (EVP_PKEY_type(pkey->type) != EVP_PKEY_RSA) {
- ALOGW("Cannot handle non-RSA keys yet");
+ unsigned char* tmp = reinterpret_cast<unsigned char*>(signedDataPtr.get());
+ if (ECDSA_sign(0, data, dataLength, tmp, &ecdsaSize, eckey.get()) <= 0) {
+ logOpenSSLError("openssl_sign_ec");
return -1;
}
- keymaster_rsa_sign_params_t* sign_params = (keymaster_rsa_sign_params_t*) params;
+ *signedDataLength = ecdsaSize;
+ *signedData = signedDataPtr.release();
+
+ return 0;
+}
+
+
+static int sign_rsa(EVP_PKEY* pkey, keymaster_rsa_sign_params_t* sign_params, const uint8_t* data,
+ const size_t dataLength, uint8_t** signedData, size_t* signedDataLength) {
if (sign_params->digest_type != DIGEST_NONE) {
ALOGW("Cannot handle digest type %d", sign_params->digest_type);
return -1;
@@ -375,37 +564,45 @@ static int openssl_sign_data(const keymaster_device_t* dev,
return -1;
}
- Unique_RSA rsa(EVP_PKEY_get1_RSA(pkey.get()));
+ Unique_RSA rsa(EVP_PKEY_get1_RSA(pkey));
if (rsa.get() == NULL) {
- logOpenSSLError("openssl_sign_data");
+ logOpenSSLError("openssl_sign_rsa");
return -1;
}
UniquePtr<uint8_t> signedDataPtr(reinterpret_cast<uint8_t*>(malloc(dataLength)));
if (signedDataPtr.get() == NULL) {
- logOpenSSLError("openssl_sign_data");
+ logOpenSSLError("openssl_sign_rsa");
return -1;
}
unsigned char* tmp = reinterpret_cast<unsigned char*>(signedDataPtr.get());
if (RSA_private_encrypt(dataLength, data, tmp, rsa.get(), RSA_NO_PADDING) <= 0) {
- logOpenSSLError("openssl_sign_data");
+ logOpenSSLError("openssl_sign_rsa");
return -1;
}
*signedDataLength = dataLength;
*signedData = signedDataPtr.release();
+
return 0;
}
-static int openssl_verify_data(const keymaster_device_t* dev,
+static int openssl_sign_data(const keymaster_device_t* dev,
const void* params,
const uint8_t* keyBlob, const size_t keyBlobLength,
- const uint8_t* signedData, const size_t signedDataLength,
- const uint8_t* signature, const size_t signatureLength) {
+ const uint8_t* data, const size_t dataLength,
+ uint8_t** signedData, size_t* signedDataLength) {
- if (signedData == NULL || signature == NULL) {
- ALOGW("data or signature buffers == NULL");
+ int result = -1;
+ EVP_MD_CTX ctx;
+ size_t maxSize;
+
+ if (data == NULL) {
+ ALOGW("input data to sign == NULL");
+ return -1;
+ } else if (signedData == NULL || signedDataLength == NULL) {
+ ALOGW("output signature buffer == NULL");
return -1;
}
@@ -414,12 +611,69 @@ static int openssl_verify_data(const keymaster_device_t* dev,
return -1;
}
- if (EVP_PKEY_type(pkey->type) != EVP_PKEY_RSA) {
- ALOGW("Cannot handle non-RSA keys yet");
+ int type = EVP_PKEY_type(pkey->type);
+ if (type == EVP_PKEY_DSA) {
+ keymaster_dsa_sign_params_t* sign_params = (keymaster_dsa_sign_params_t*) params;
+ return sign_dsa(pkey.get(), sign_params, data, dataLength, signedData, signedDataLength);
+ } else if (type == EVP_PKEY_EC) {
+ keymaster_ec_sign_params_t* sign_params = (keymaster_ec_sign_params_t*) params;
+ return sign_ec(pkey.get(), sign_params, data, dataLength, signedData, signedDataLength);
+ } else if (type == EVP_PKEY_RSA) {
+ keymaster_rsa_sign_params_t* sign_params = (keymaster_rsa_sign_params_t*) params;
+ return sign_rsa(pkey.get(), sign_params, data, dataLength, signedData, signedDataLength);
+ } else {
+ ALOGW("Unsupported key type");
return -1;
}
+}
- keymaster_rsa_sign_params_t* sign_params = (keymaster_rsa_sign_params_t*) params;
+static int verify_dsa(EVP_PKEY* pkey, keymaster_dsa_sign_params_t* sign_params,
+ const uint8_t* signedData, const size_t signedDataLength, const uint8_t* signature,
+ const size_t signatureLength) {
+ if (sign_params->digest_type != DIGEST_NONE) {
+ ALOGW("Cannot handle digest type %d", sign_params->digest_type);
+ return -1;
+ }
+
+ Unique_DSA dsa(EVP_PKEY_get1_DSA(pkey));
+ if (dsa.get() == NULL) {
+ logOpenSSLError("openssl_verify_dsa");
+ return -1;
+ }
+
+ if (DSA_verify(0, signedData, signedDataLength, signature, signatureLength, dsa.get()) <= 0) {
+ logOpenSSLError("openssl_verify_dsa");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int verify_ec(EVP_PKEY* pkey, keymaster_ec_sign_params_t* sign_params,
+ const uint8_t* signedData, const size_t signedDataLength, const uint8_t* signature,
+ const size_t signatureLength) {
+ if (sign_params->digest_type != DIGEST_NONE) {
+ ALOGW("Cannot handle digest type %d", sign_params->digest_type);
+ return -1;
+ }
+
+ Unique_EC_KEY eckey(EVP_PKEY_get1_EC_KEY(pkey));
+ if (eckey.get() == NULL) {
+ logOpenSSLError("openssl_verify_ec");
+ return -1;
+ }
+
+ if (ECDSA_verify(0, signedData, signedDataLength, signature, signatureLength, eckey.get()) <= 0) {
+ logOpenSSLError("openssl_verify_ec");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int verify_rsa(EVP_PKEY* pkey, keymaster_rsa_sign_params_t* sign_params,
+ const uint8_t* signedData, const size_t signedDataLength, const uint8_t* signature,
+ const size_t signatureLength) {
if (sign_params->digest_type != DIGEST_NONE) {
ALOGW("Cannot handle digest type %d", sign_params->digest_type);
return -1;
@@ -431,7 +685,7 @@ static int openssl_verify_data(const keymaster_device_t* dev,
return -1;
}
- Unique_RSA rsa(EVP_PKEY_get1_RSA(pkey.get()));
+ Unique_RSA rsa(EVP_PKEY_get1_RSA(pkey));
if (rsa.get() == NULL) {
logOpenSSLError("openssl_verify_data");
return -1;
@@ -457,9 +711,40 @@ static int openssl_verify_data(const keymaster_device_t* dev,
return result == 0 ? 0 : -1;
}
+static int openssl_verify_data(const keymaster_device_t* dev,
+ const void* params,
+ const uint8_t* keyBlob, const size_t keyBlobLength,
+ const uint8_t* signedData, const size_t signedDataLength,
+ const uint8_t* signature, const size_t signatureLength) {
+
+ if (signedData == NULL || signature == NULL) {
+ ALOGW("data or signature buffers == NULL");
+ return -1;
+ }
+
+ Unique_EVP_PKEY pkey(unwrap_key(keyBlob, keyBlobLength));
+ if (pkey.get() == NULL) {
+ return -1;
+ }
+
+ int type = EVP_PKEY_type(pkey->type);
+ if (type == EVP_PKEY_RSA) {
+ keymaster_rsa_sign_params_t* sign_params = (keymaster_rsa_sign_params_t*) params;
+ return verify_rsa(pkey.get(), sign_params, signedData, signedDataLength, signature,
+ signatureLength);
+ } else if (type == EVP_PKEY_EC) {
+ keymaster_ec_sign_params_t* sign_params = (keymaster_ec_sign_params_t*) params;
+ return verify_ec(pkey.get(), sign_params, signedData, signedDataLength, signature,
+ signatureLength);
+ } else {
+ ALOGW("Unsupported key type %d", type);
+ return -1;
+ }
+}
+
/* Close an opened OpenSSL instance */
static int openssl_close(hw_device_t *dev) {
- free(dev);
+ delete dev;
return 0;
}