| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 1 | /* | 
|  | 2 | * Copyright (C) 2012 The Android Open Source Project | 
|  | 3 | * | 
|  | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | 5 | * you may not use this file except in compliance with the License. | 
|  | 6 | * You may obtain a copy of the License at | 
|  | 7 | * | 
|  | 8 | *      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | 9 | * | 
|  | 10 | * Unless required by applicable law or agreed to in writing, software | 
|  | 11 | * distributed under the License is distributed on an "AS IS" BASIS, | 
|  | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | 13 | * See the License for the specific language governing permissions and | 
|  | 14 | * limitations under the License. | 
|  | 15 | */ | 
|  | 16 | #include <errno.h> | 
|  | 17 | #include <string.h> | 
|  | 18 | #include <stdint.h> | 
|  | 19 |  | 
| Kenny Root | 07438c8 | 2012-11-02 15:41:02 -0700 | [diff] [blame] | 20 | #include <keystore/keystore.h> | 
| Shawn Willden | 461d97e | 2015-03-17 20:44:39 -0600 | [diff] [blame] | 21 | #include <keymaster/softkeymaster.h> | 
| Kenny Root | 822c3a9 | 2012-03-23 16:34:39 -0700 | [diff] [blame] | 22 |  | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 23 | #include <hardware/hardware.h> | 
| Shawn Willden | a5bbf2f | 2015-02-24 09:31:25 -0700 | [diff] [blame] | 24 | #include <hardware/keymaster0.h> | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 25 |  | 
|  | 26 | #include <openssl/evp.h> | 
|  | 27 | #include <openssl/bio.h> | 
|  | 28 | #include <openssl/rsa.h> | 
|  | 29 | #include <openssl/err.h> | 
|  | 30 | #include <openssl/x509.h> | 
|  | 31 |  | 
| Kenny Root | 26cfc08 | 2013-09-11 14:38:56 -0700 | [diff] [blame] | 32 | #include <UniquePtr.h> | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 33 |  | 
|  | 34 | // For debugging | 
| Shawn Willden | 1406b8a | 2014-06-12 11:39:48 -0600 | [diff] [blame] | 35 | // #define LOG_NDEBUG 0 | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 36 |  | 
|  | 37 | #define LOG_TAG "OpenSSLKeyMaster" | 
|  | 38 | #include <cutils/log.h> | 
|  | 39 |  | 
|  | 40 | struct BIGNUM_Delete { | 
| Shawn Willden | a5bbf2f | 2015-02-24 09:31:25 -0700 | [diff] [blame] | 41 | void operator()(BIGNUM* p) const { BN_free(p); } | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 42 | }; | 
|  | 43 | typedef UniquePtr<BIGNUM, BIGNUM_Delete> Unique_BIGNUM; | 
|  | 44 |  | 
|  | 45 | struct EVP_PKEY_Delete { | 
| Shawn Willden | a5bbf2f | 2015-02-24 09:31:25 -0700 | [diff] [blame] | 46 | void operator()(EVP_PKEY* p) const { EVP_PKEY_free(p); } | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 47 | }; | 
|  | 48 | typedef UniquePtr<EVP_PKEY, EVP_PKEY_Delete> Unique_EVP_PKEY; | 
|  | 49 |  | 
|  | 50 | struct PKCS8_PRIV_KEY_INFO_Delete { | 
| Shawn Willden | a5bbf2f | 2015-02-24 09:31:25 -0700 | [diff] [blame] | 51 | void operator()(PKCS8_PRIV_KEY_INFO* p) const { PKCS8_PRIV_KEY_INFO_free(p); } | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 52 | }; | 
|  | 53 | typedef UniquePtr<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_Delete> Unique_PKCS8_PRIV_KEY_INFO; | 
|  | 54 |  | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 55 | struct DSA_Delete { | 
| Shawn Willden | a5bbf2f | 2015-02-24 09:31:25 -0700 | [diff] [blame] | 56 | void operator()(DSA* p) const { DSA_free(p); } | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 57 | }; | 
|  | 58 | typedef UniquePtr<DSA, DSA_Delete> Unique_DSA; | 
|  | 59 |  | 
|  | 60 | struct EC_KEY_Delete { | 
| Shawn Willden | a5bbf2f | 2015-02-24 09:31:25 -0700 | [diff] [blame] | 61 | void operator()(EC_KEY* p) const { EC_KEY_free(p); } | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 62 | }; | 
|  | 63 | typedef UniquePtr<EC_KEY, EC_KEY_Delete> Unique_EC_KEY; | 
|  | 64 |  | 
| Shawn Willden | 18a00e1 | 2014-06-17 10:50:03 -0600 | [diff] [blame] | 65 | struct EC_GROUP_Delete { | 
| Shawn Willden | a5bbf2f | 2015-02-24 09:31:25 -0700 | [diff] [blame] | 66 | void operator()(EC_GROUP* p) const { EC_GROUP_free(p); } | 
| Shawn Willden | 18a00e1 | 2014-06-17 10:50:03 -0600 | [diff] [blame] | 67 | }; | 
|  | 68 | typedef UniquePtr<EC_GROUP, EC_GROUP_Delete> Unique_EC_GROUP; | 
|  | 69 |  | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 70 | struct RSA_Delete { | 
| Shawn Willden | a5bbf2f | 2015-02-24 09:31:25 -0700 | [diff] [blame] | 71 | void operator()(RSA* p) const { RSA_free(p); } | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 72 | }; | 
|  | 73 | typedef UniquePtr<RSA, RSA_Delete> Unique_RSA; | 
|  | 74 |  | 
| Shawn Willden | 8d0531e | 2014-06-17 11:45:07 -0600 | [diff] [blame] | 75 | struct Malloc_Free { | 
| Shawn Willden | a5bbf2f | 2015-02-24 09:31:25 -0700 | [diff] [blame] | 76 | void operator()(void* p) const { free(p); } | 
| Shawn Willden | 8d0531e | 2014-06-17 11:45:07 -0600 | [diff] [blame] | 77 | }; | 
|  | 78 |  | 
| Shawn Willden | a5bbf2f | 2015-02-24 09:31:25 -0700 | [diff] [blame] | 79 | typedef UniquePtr<keymaster0_device_t> Unique_keymaster_device_t; | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 80 |  | 
|  | 81 | /** | 
| Shawn Willden | 1406b8a | 2014-06-12 11:39:48 -0600 | [diff] [blame] | 82 | * Many OpenSSL APIs take ownership of an argument on success but | 
|  | 83 | * don't free the argument on failure. This means we need to tell our | 
|  | 84 | * scoped pointers when we've transferred ownership, without | 
|  | 85 | * triggering a warning by not using the result of release(). | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 86 | */ | 
| Shawn Willden | 2cd28fa | 2014-06-13 11:51:08 -0600 | [diff] [blame] | 87 | template <typename T, typename Delete_T> | 
|  | 88 | inline void release_because_ownership_transferred(UniquePtr<T, Delete_T>& p) { | 
|  | 89 | T* val __attribute__((unused)) = p.release(); | 
|  | 90 | } | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 91 |  | 
|  | 92 | /* | 
|  | 93 | * Checks this thread's OpenSSL error queue and logs if | 
|  | 94 | * necessary. | 
|  | 95 | */ | 
|  | 96 | static void logOpenSSLError(const char* location) { | 
|  | 97 | int error = ERR_get_error(); | 
|  | 98 |  | 
|  | 99 | if (error != 0) { | 
|  | 100 | char message[256]; | 
|  | 101 | ERR_error_string_n(error, message, sizeof(message)); | 
|  | 102 | ALOGE("OpenSSL error in %s %d: %s", location, error, message); | 
|  | 103 | } | 
|  | 104 |  | 
|  | 105 | ERR_clear_error(); | 
| Adam Langley | 53d13c5 | 2014-09-23 17:40:53 -0700 | [diff] [blame] | 106 | ERR_remove_thread_state(NULL); | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 107 | } | 
|  | 108 |  | 
|  | 109 | static int wrap_key(EVP_PKEY* pkey, int type, uint8_t** keyBlob, size_t* keyBlobLength) { | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 110 | /* | 
| Shawn Willden | 1406b8a | 2014-06-12 11:39:48 -0600 | [diff] [blame] | 111 | * Find the length of each size. Public key is not needed anymore | 
|  | 112 | * but must be kept for alignment purposes. | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 113 | */ | 
|  | 114 | int publicLen = 0; | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 115 | int privateLen = i2d_PrivateKey(pkey, NULL); | 
|  | 116 |  | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 117 | if (privateLen <= 0) { | 
|  | 118 | ALOGE("private key size was too big"); | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 119 | return -1; | 
|  | 120 | } | 
|  | 121 |  | 
|  | 122 | /* int type + int size + private key data + int size + public key data */ | 
| Shawn Willden | 1406b8a | 2014-06-12 11:39:48 -0600 | [diff] [blame] | 123 | *keyBlobLength = get_softkey_header_size() + sizeof(type) + sizeof(publicLen) + privateLen + | 
|  | 124 | sizeof(privateLen) + publicLen; | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 125 |  | 
| Shawn Willden | 8d0531e | 2014-06-17 11:45:07 -0600 | [diff] [blame] | 126 | // derData will be returned to the caller, so allocate it with malloc. | 
|  | 127 | UniquePtr<unsigned char, Malloc_Free> derData( | 
|  | 128 | static_cast<unsigned char*>(malloc(*keyBlobLength))); | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 129 | if (derData.get() == NULL) { | 
|  | 130 | ALOGE("could not allocate memory for key blob"); | 
|  | 131 | return -1; | 
|  | 132 | } | 
|  | 133 | unsigned char* p = derData.get(); | 
|  | 134 |  | 
| Kenny Root | 822c3a9 | 2012-03-23 16:34:39 -0700 | [diff] [blame] | 135 | /* Write the magic value for software keys. */ | 
|  | 136 | p = add_softkey_header(p, *keyBlobLength); | 
|  | 137 |  | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 138 | /* Write key type to allocated buffer */ | 
| Shawn Willden | 1406b8a | 2014-06-12 11:39:48 -0600 | [diff] [blame] | 139 | for (int i = sizeof(type) - 1; i >= 0; i--) { | 
|  | 140 | *p++ = (type >> (8 * i)) & 0xFF; | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 141 | } | 
|  | 142 |  | 
|  | 143 | /* Write public key to allocated buffer */ | 
| Shawn Willden | 1406b8a | 2014-06-12 11:39:48 -0600 | [diff] [blame] | 144 | for (int i = sizeof(publicLen) - 1; i >= 0; i--) { | 
|  | 145 | *p++ = (publicLen >> (8 * i)) & 0xFF; | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 146 | } | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 147 |  | 
|  | 148 | /* Write private key to allocated buffer */ | 
| Shawn Willden | 1406b8a | 2014-06-12 11:39:48 -0600 | [diff] [blame] | 149 | for (int i = sizeof(privateLen) - 1; i >= 0; i--) { | 
|  | 150 | *p++ = (privateLen >> (8 * i)) & 0xFF; | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 151 | } | 
|  | 152 | if (i2d_PrivateKey(pkey, &p) != privateLen) { | 
|  | 153 | logOpenSSLError("wrap_key"); | 
|  | 154 | return -1; | 
|  | 155 | } | 
|  | 156 |  | 
|  | 157 | *keyBlob = derData.release(); | 
|  | 158 |  | 
|  | 159 | return 0; | 
|  | 160 | } | 
|  | 161 |  | 
|  | 162 | static EVP_PKEY* unwrap_key(const uint8_t* keyBlob, const size_t keyBlobLength) { | 
|  | 163 | long publicLen = 0; | 
|  | 164 | long privateLen = 0; | 
|  | 165 | const uint8_t* p = keyBlob; | 
| Shawn Willden | 1406b8a | 2014-06-12 11:39:48 -0600 | [diff] [blame] | 166 | const uint8_t* const end = keyBlob + keyBlobLength; | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 167 |  | 
|  | 168 | if (keyBlob == NULL) { | 
|  | 169 | ALOGE("supplied key blob was NULL"); | 
|  | 170 | return NULL; | 
|  | 171 | } | 
|  | 172 |  | 
| Shawn Willden | 1406b8a | 2014-06-12 11:39:48 -0600 | [diff] [blame] | 173 | int type = 0; | 
|  | 174 | if (keyBlobLength < (get_softkey_header_size() + sizeof(type) + sizeof(publicLen) + 1 + | 
|  | 175 | sizeof(privateLen) + 1)) { | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 176 | ALOGE("key blob appears to be truncated"); | 
|  | 177 | return NULL; | 
|  | 178 | } | 
|  | 179 |  | 
| Kenny Root | 822c3a9 | 2012-03-23 16:34:39 -0700 | [diff] [blame] | 180 | if (!is_softkey(p, keyBlobLength)) { | 
|  | 181 | ALOGE("cannot read key; it was not made by this keymaster"); | 
|  | 182 | return NULL; | 
|  | 183 | } | 
|  | 184 | p += get_softkey_header_size(); | 
|  | 185 |  | 
| Shawn Willden | 1406b8a | 2014-06-12 11:39:48 -0600 | [diff] [blame] | 186 | for (size_t i = 0; i < sizeof(type); i++) { | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 187 | type = (type << 8) | *p++; | 
|  | 188 | } | 
|  | 189 |  | 
| Shawn Willden | 1406b8a | 2014-06-12 11:39:48 -0600 | [diff] [blame] | 190 | for (size_t i = 0; i < sizeof(type); i++) { | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 191 | publicLen = (publicLen << 8) | *p++; | 
|  | 192 | } | 
|  | 193 | if (p + publicLen > end) { | 
| Matteo Franchin | 6489e02 | 2013-12-02 14:46:29 +0000 | [diff] [blame] | 194 | ALOGE("public key length encoding error: size=%ld, end=%td", publicLen, end - p); | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 195 | return NULL; | 
|  | 196 | } | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 197 |  | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 198 | p += publicLen; | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 199 | if (end - p < 2) { | 
|  | 200 | ALOGE("private key truncated"); | 
|  | 201 | return NULL; | 
|  | 202 | } | 
| Shawn Willden | 1406b8a | 2014-06-12 11:39:48 -0600 | [diff] [blame] | 203 | for (size_t i = 0; i < sizeof(type); i++) { | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 204 | privateLen = (privateLen << 8) | *p++; | 
|  | 205 | } | 
|  | 206 | if (p + privateLen > end) { | 
| Matteo Franchin | 6489e02 | 2013-12-02 14:46:29 +0000 | [diff] [blame] | 207 | ALOGE("private key length encoding error: size=%ld, end=%td", privateLen, end - p); | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 208 | return NULL; | 
|  | 209 | } | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 210 |  | 
|  | 211 | Unique_EVP_PKEY pkey(EVP_PKEY_new()); | 
|  | 212 | if (pkey.get() == NULL) { | 
|  | 213 | logOpenSSLError("unwrap_key"); | 
|  | 214 | return NULL; | 
|  | 215 | } | 
|  | 216 | EVP_PKEY* tmp = pkey.get(); | 
|  | 217 |  | 
|  | 218 | if (d2i_PrivateKey(type, &tmp, &p, privateLen) == NULL) { | 
|  | 219 | logOpenSSLError("unwrap_key"); | 
|  | 220 | return NULL; | 
|  | 221 | } | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 222 |  | 
|  | 223 | return pkey.release(); | 
|  | 224 | } | 
|  | 225 |  | 
| Shawn Willden | 1406b8a | 2014-06-12 11:39:48 -0600 | [diff] [blame] | 226 | static int generate_dsa_keypair(EVP_PKEY* pkey, const keymaster_dsa_keygen_params_t* dsa_params) { | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 227 | if (dsa_params->key_size < 512) { | 
|  | 228 | ALOGI("Requested DSA key size is too small (<512)"); | 
|  | 229 | return -1; | 
|  | 230 | } | 
|  | 231 |  | 
|  | 232 | Unique_DSA dsa(DSA_new()); | 
|  | 233 |  | 
| Shawn Willden | 1406b8a | 2014-06-12 11:39:48 -0600 | [diff] [blame] | 234 | if (dsa_params->generator_len == 0 || dsa_params->prime_p_len == 0 || | 
|  | 235 | dsa_params->prime_q_len == 0 || dsa_params->generator == NULL || | 
|  | 236 | dsa_params->prime_p == NULL || dsa_params->prime_q == NULL) { | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 237 | if (DSA_generate_parameters_ex(dsa.get(), dsa_params->key_size, NULL, 0, NULL, NULL, | 
| Shawn Willden | 1406b8a | 2014-06-12 11:39:48 -0600 | [diff] [blame] | 238 | NULL) != 1) { | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 239 | logOpenSSLError("generate_dsa_keypair"); | 
|  | 240 | return -1; | 
|  | 241 | } | 
|  | 242 | } else { | 
| Shawn Willden | 1406b8a | 2014-06-12 11:39:48 -0600 | [diff] [blame] | 243 | dsa->g = BN_bin2bn(dsa_params->generator, dsa_params->generator_len, NULL); | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 244 | if (dsa->g == NULL) { | 
|  | 245 | logOpenSSLError("generate_dsa_keypair"); | 
|  | 246 | return -1; | 
|  | 247 | } | 
|  | 248 |  | 
| Shawn Willden | 1406b8a | 2014-06-12 11:39:48 -0600 | [diff] [blame] | 249 | dsa->p = BN_bin2bn(dsa_params->prime_p, dsa_params->prime_p_len, NULL); | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 250 | if (dsa->p == NULL) { | 
|  | 251 | logOpenSSLError("generate_dsa_keypair"); | 
|  | 252 | return -1; | 
|  | 253 | } | 
|  | 254 |  | 
| Shawn Willden | 1406b8a | 2014-06-12 11:39:48 -0600 | [diff] [blame] | 255 | dsa->q = BN_bin2bn(dsa_params->prime_q, dsa_params->prime_q_len, NULL); | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 256 | if (dsa->q == NULL) { | 
|  | 257 | logOpenSSLError("generate_dsa_keypair"); | 
|  | 258 | return -1; | 
|  | 259 | } | 
|  | 260 | } | 
|  | 261 |  | 
|  | 262 | if (DSA_generate_key(dsa.get()) != 1) { | 
|  | 263 | logOpenSSLError("generate_dsa_keypair"); | 
|  | 264 | return -1; | 
|  | 265 | } | 
|  | 266 |  | 
|  | 267 | if (EVP_PKEY_assign_DSA(pkey, dsa.get()) == 0) { | 
|  | 268 | logOpenSSLError("generate_dsa_keypair"); | 
|  | 269 | return -1; | 
|  | 270 | } | 
| Shawn Willden | 2cd28fa | 2014-06-13 11:51:08 -0600 | [diff] [blame] | 271 | release_because_ownership_transferred(dsa); | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 272 |  | 
|  | 273 | return 0; | 
|  | 274 | } | 
|  | 275 |  | 
| Shawn Willden | 1406b8a | 2014-06-12 11:39:48 -0600 | [diff] [blame] | 276 | static int generate_ec_keypair(EVP_PKEY* pkey, const keymaster_ec_keygen_params_t* ec_params) { | 
| Shawn Willden | 18a00e1 | 2014-06-17 10:50:03 -0600 | [diff] [blame] | 277 | Unique_EC_GROUP group; | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 278 | switch (ec_params->field_size) { | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 279 | case 224: | 
| Shawn Willden | 18a00e1 | 2014-06-17 10:50:03 -0600 | [diff] [blame] | 280 | group.reset(EC_GROUP_new_by_curve_name(NID_secp224r1)); | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 281 | break; | 
|  | 282 | case 256: | 
| Shawn Willden | 18a00e1 | 2014-06-17 10:50:03 -0600 | [diff] [blame] | 283 | group.reset(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1)); | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 284 | break; | 
|  | 285 | case 384: | 
| Shawn Willden | 18a00e1 | 2014-06-17 10:50:03 -0600 | [diff] [blame] | 286 | group.reset(EC_GROUP_new_by_curve_name(NID_secp384r1)); | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 287 | break; | 
|  | 288 | case 521: | 
| Shawn Willden | 18a00e1 | 2014-06-17 10:50:03 -0600 | [diff] [blame] | 289 | group.reset(EC_GROUP_new_by_curve_name(NID_secp521r1)); | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 290 | break; | 
|  | 291 | default: | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 292 | break; | 
|  | 293 | } | 
|  | 294 |  | 
| Shawn Willden | 18a00e1 | 2014-06-17 10:50:03 -0600 | [diff] [blame] | 295 | if (group.get() == NULL) { | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 296 | logOpenSSLError("generate_ec_keypair"); | 
|  | 297 | return -1; | 
|  | 298 | } | 
|  | 299 |  | 
| Adam Langley | 53d13c5 | 2014-09-23 17:40:53 -0700 | [diff] [blame] | 300 | #if !defined(OPENSSL_IS_BORINGSSL) | 
| Adam Langley | b2747fe | 2014-12-11 17:19:31 -0800 | [diff] [blame] | 301 | EC_GROUP_set_point_conversion_form(group.get(), POINT_CONVERSION_UNCOMPRESSED); | 
| Shawn Willden | 18a00e1 | 2014-06-17 10:50:03 -0600 | [diff] [blame] | 302 | EC_GROUP_set_asn1_flag(group.get(), OPENSSL_EC_NAMED_CURVE); | 
| Adam Langley | 53d13c5 | 2014-09-23 17:40:53 -0700 | [diff] [blame] | 303 | #endif | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 304 |  | 
|  | 305 | /* initialize EC key */ | 
|  | 306 | Unique_EC_KEY eckey(EC_KEY_new()); | 
|  | 307 | if (eckey.get() == NULL) { | 
|  | 308 | logOpenSSLError("generate_ec_keypair"); | 
|  | 309 | return -1; | 
|  | 310 | } | 
|  | 311 |  | 
| Shawn Willden | 18a00e1 | 2014-06-17 10:50:03 -0600 | [diff] [blame] | 312 | if (EC_KEY_set_group(eckey.get(), group.get()) != 1) { | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 313 | logOpenSSLError("generate_ec_keypair"); | 
|  | 314 | return -1; | 
|  | 315 | } | 
|  | 316 |  | 
| Shawn Willden | 1406b8a | 2014-06-12 11:39:48 -0600 | [diff] [blame] | 317 | if (EC_KEY_generate_key(eckey.get()) != 1 || EC_KEY_check_key(eckey.get()) < 0) { | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 318 | logOpenSSLError("generate_ec_keypair"); | 
|  | 319 | return -1; | 
|  | 320 | } | 
|  | 321 |  | 
|  | 322 | if (EVP_PKEY_assign_EC_KEY(pkey, eckey.get()) == 0) { | 
|  | 323 | logOpenSSLError("generate_ec_keypair"); | 
|  | 324 | return -1; | 
|  | 325 | } | 
| Shawn Willden | 2cd28fa | 2014-06-13 11:51:08 -0600 | [diff] [blame] | 326 | release_because_ownership_transferred(eckey); | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 327 |  | 
|  | 328 | return 0; | 
|  | 329 | } | 
|  | 330 |  | 
| Shawn Willden | 1406b8a | 2014-06-12 11:39:48 -0600 | [diff] [blame] | 331 | static int generate_rsa_keypair(EVP_PKEY* pkey, const keymaster_rsa_keygen_params_t* rsa_params) { | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 332 | Unique_BIGNUM bn(BN_new()); | 
|  | 333 | if (bn.get() == NULL) { | 
|  | 334 | logOpenSSLError("generate_rsa_keypair"); | 
|  | 335 | return -1; | 
|  | 336 | } | 
|  | 337 |  | 
|  | 338 | if (BN_set_word(bn.get(), rsa_params->public_exponent) == 0) { | 
|  | 339 | logOpenSSLError("generate_rsa_keypair"); | 
|  | 340 | return -1; | 
|  | 341 | } | 
|  | 342 |  | 
|  | 343 | /* initialize RSA */ | 
|  | 344 | Unique_RSA rsa(RSA_new()); | 
|  | 345 | if (rsa.get() == NULL) { | 
|  | 346 | logOpenSSLError("generate_rsa_keypair"); | 
|  | 347 | return -1; | 
|  | 348 | } | 
|  | 349 |  | 
| Shawn Willden | 1406b8a | 2014-06-12 11:39:48 -0600 | [diff] [blame] | 350 | if (!RSA_generate_key_ex(rsa.get(), rsa_params->modulus_size, bn.get(), NULL) || | 
|  | 351 | RSA_check_key(rsa.get()) < 0) { | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 352 | logOpenSSLError("generate_rsa_keypair"); | 
|  | 353 | return -1; | 
|  | 354 | } | 
|  | 355 |  | 
|  | 356 | if (EVP_PKEY_assign_RSA(pkey, rsa.get()) == 0) { | 
|  | 357 | logOpenSSLError("generate_rsa_keypair"); | 
|  | 358 | return -1; | 
|  | 359 | } | 
| Shawn Willden | 2cd28fa | 2014-06-13 11:51:08 -0600 | [diff] [blame] | 360 | release_because_ownership_transferred(rsa); | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 361 |  | 
|  | 362 | return 0; | 
|  | 363 | } | 
|  | 364 |  | 
| Shawn Willden | 1406b8a | 2014-06-12 11:39:48 -0600 | [diff] [blame] | 365 | __attribute__((visibility("default"))) int openssl_generate_keypair( | 
| Shawn Willden | a5bbf2f | 2015-02-24 09:31:25 -0700 | [diff] [blame] | 366 | const keymaster0_device_t*, const keymaster_keypair_t key_type, const void* key_params, | 
| Shawn Willden | 1406b8a | 2014-06-12 11:39:48 -0600 | [diff] [blame] | 367 | uint8_t** keyBlob, size_t* keyBlobLength) { | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 368 | Unique_EVP_PKEY pkey(EVP_PKEY_new()); | 
|  | 369 | if (pkey.get() == NULL) { | 
|  | 370 | logOpenSSLError("openssl_generate_keypair"); | 
|  | 371 | return -1; | 
|  | 372 | } | 
|  | 373 |  | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 374 | if (key_params == NULL) { | 
|  | 375 | ALOGW("key_params == null"); | 
|  | 376 | return -1; | 
|  | 377 | } else if (key_type == TYPE_DSA) { | 
|  | 378 | const keymaster_dsa_keygen_params_t* dsa_params = | 
| Shawn Willden | 1406b8a | 2014-06-12 11:39:48 -0600 | [diff] [blame] | 379 | (const keymaster_dsa_keygen_params_t*)key_params; | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 380 | generate_dsa_keypair(pkey.get(), dsa_params); | 
|  | 381 | } else if (key_type == TYPE_EC) { | 
|  | 382 | const keymaster_ec_keygen_params_t* ec_params = | 
| Shawn Willden | 1406b8a | 2014-06-12 11:39:48 -0600 | [diff] [blame] | 383 | (const keymaster_ec_keygen_params_t*)key_params; | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 384 | generate_ec_keypair(pkey.get(), ec_params); | 
|  | 385 | } else if (key_type == TYPE_RSA) { | 
|  | 386 | const keymaster_rsa_keygen_params_t* rsa_params = | 
| Shawn Willden | 1406b8a | 2014-06-12 11:39:48 -0600 | [diff] [blame] | 387 | (const keymaster_rsa_keygen_params_t*)key_params; | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 388 | generate_rsa_keypair(pkey.get(), rsa_params); | 
|  | 389 | } else { | 
|  | 390 | ALOGW("Unsupported key type %d", key_type); | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 391 | return -1; | 
|  | 392 | } | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 393 |  | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 394 | if (wrap_key(pkey.get(), EVP_PKEY_type(pkey->type), keyBlob, keyBlobLength)) { | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 395 | return -1; | 
|  | 396 | } | 
|  | 397 |  | 
|  | 398 | return 0; | 
|  | 399 | } | 
|  | 400 |  | 
| Shawn Willden | a5bbf2f | 2015-02-24 09:31:25 -0700 | [diff] [blame] | 401 | __attribute__((visibility("default"))) int openssl_import_keypair(const keymaster0_device_t*, | 
| Shawn Willden | 1406b8a | 2014-06-12 11:39:48 -0600 | [diff] [blame] | 402 | const uint8_t* key, | 
|  | 403 | const size_t key_length, | 
|  | 404 | uint8_t** key_blob, | 
|  | 405 | size_t* key_blob_length) { | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 406 | if (key == NULL) { | 
|  | 407 | ALOGW("input key == NULL"); | 
|  | 408 | return -1; | 
|  | 409 | } else if (key_blob == NULL || key_blob_length == NULL) { | 
|  | 410 | ALOGW("output key blob or length == NULL"); | 
|  | 411 | return -1; | 
|  | 412 | } | 
|  | 413 |  | 
|  | 414 | Unique_PKCS8_PRIV_KEY_INFO pkcs8(d2i_PKCS8_PRIV_KEY_INFO(NULL, &key, key_length)); | 
|  | 415 | if (pkcs8.get() == NULL) { | 
|  | 416 | logOpenSSLError("openssl_import_keypair"); | 
|  | 417 | return -1; | 
|  | 418 | } | 
|  | 419 |  | 
|  | 420 | /* assign to EVP */ | 
|  | 421 | Unique_EVP_PKEY pkey(EVP_PKCS82PKEY(pkcs8.get())); | 
|  | 422 | if (pkey.get() == NULL) { | 
|  | 423 | logOpenSSLError("openssl_import_keypair"); | 
|  | 424 | return -1; | 
|  | 425 | } | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 426 |  | 
|  | 427 | if (wrap_key(pkey.get(), EVP_PKEY_type(pkey->type), key_blob, key_blob_length)) { | 
|  | 428 | return -1; | 
|  | 429 | } | 
|  | 430 |  | 
|  | 431 | return 0; | 
|  | 432 | } | 
|  | 433 |  | 
| Shawn Willden | a5bbf2f | 2015-02-24 09:31:25 -0700 | [diff] [blame] | 434 | __attribute__((visibility("default"))) int openssl_get_keypair_public(const keymaster0_device_t*, | 
|  | 435 | const uint8_t* key_blob, | 
|  | 436 | const size_t key_blob_length, | 
|  | 437 | uint8_t** x509_data, | 
|  | 438 | size_t* x509_data_length) { | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 439 | if (x509_data == NULL || x509_data_length == NULL) { | 
|  | 440 | ALOGW("output public key buffer == NULL"); | 
|  | 441 | return -1; | 
|  | 442 | } | 
|  | 443 |  | 
|  | 444 | Unique_EVP_PKEY pkey(unwrap_key(key_blob, key_blob_length)); | 
|  | 445 | if (pkey.get() == NULL) { | 
|  | 446 | return -1; | 
|  | 447 | } | 
|  | 448 |  | 
|  | 449 | int len = i2d_PUBKEY(pkey.get(), NULL); | 
|  | 450 | if (len <= 0) { | 
|  | 451 | logOpenSSLError("openssl_get_keypair_public"); | 
|  | 452 | return -1; | 
|  | 453 | } | 
|  | 454 |  | 
| Shawn Willden | 8d0531e | 2014-06-17 11:45:07 -0600 | [diff] [blame] | 455 | UniquePtr<uint8_t, Malloc_Free> key(static_cast<uint8_t*>(malloc(len))); | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 456 | if (key.get() == NULL) { | 
|  | 457 | ALOGE("Could not allocate memory for public key data"); | 
|  | 458 | return -1; | 
|  | 459 | } | 
|  | 460 |  | 
|  | 461 | unsigned char* tmp = reinterpret_cast<unsigned char*>(key.get()); | 
|  | 462 | if (i2d_PUBKEY(pkey.get(), &tmp) != len) { | 
|  | 463 | logOpenSSLError("openssl_get_keypair_public"); | 
|  | 464 | return -1; | 
|  | 465 | } | 
|  | 466 |  | 
|  | 467 | ALOGV("Length of x509 data is %d", len); | 
|  | 468 | *x509_data_length = len; | 
|  | 469 | *x509_data = key.release(); | 
|  | 470 |  | 
|  | 471 | return 0; | 
|  | 472 | } | 
|  | 473 |  | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 474 | static int sign_dsa(EVP_PKEY* pkey, keymaster_dsa_sign_params_t* sign_params, const uint8_t* data, | 
| Shawn Willden | 1406b8a | 2014-06-12 11:39:48 -0600 | [diff] [blame] | 475 | const size_t dataLength, uint8_t** signedData, size_t* signedDataLength) { | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 476 | if (sign_params->digest_type != DIGEST_NONE) { | 
|  | 477 | ALOGW("Cannot handle digest type %d", sign_params->digest_type); | 
|  | 478 | return -1; | 
|  | 479 | } | 
|  | 480 |  | 
|  | 481 | Unique_DSA dsa(EVP_PKEY_get1_DSA(pkey)); | 
|  | 482 | if (dsa.get() == NULL) { | 
|  | 483 | logOpenSSLError("openssl_sign_dsa"); | 
|  | 484 | return -1; | 
|  | 485 | } | 
|  | 486 |  | 
|  | 487 | unsigned int dsaSize = DSA_size(dsa.get()); | 
| Shawn Willden | 8d0531e | 2014-06-17 11:45:07 -0600 | [diff] [blame] | 488 | UniquePtr<uint8_t, Malloc_Free> signedDataPtr(reinterpret_cast<uint8_t*>(malloc(dsaSize))); | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 489 | if (signedDataPtr.get() == NULL) { | 
|  | 490 | logOpenSSLError("openssl_sign_dsa"); | 
|  | 491 | return -1; | 
|  | 492 | } | 
|  | 493 |  | 
|  | 494 | unsigned char* tmp = reinterpret_cast<unsigned char*>(signedDataPtr.get()); | 
|  | 495 | if (DSA_sign(0, data, dataLength, tmp, &dsaSize, dsa.get()) <= 0) { | 
|  | 496 | logOpenSSLError("openssl_sign_dsa"); | 
|  | 497 | return -1; | 
|  | 498 | } | 
|  | 499 |  | 
|  | 500 | *signedDataLength = dsaSize; | 
|  | 501 | *signedData = signedDataPtr.release(); | 
|  | 502 |  | 
|  | 503 | return 0; | 
|  | 504 | } | 
|  | 505 |  | 
|  | 506 | static int sign_ec(EVP_PKEY* pkey, keymaster_ec_sign_params_t* sign_params, const uint8_t* data, | 
| Shawn Willden | 1406b8a | 2014-06-12 11:39:48 -0600 | [diff] [blame] | 507 | const size_t dataLength, uint8_t** signedData, size_t* signedDataLength) { | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 508 | if (sign_params->digest_type != DIGEST_NONE) { | 
|  | 509 | ALOGW("Cannot handle digest type %d", sign_params->digest_type); | 
|  | 510 | return -1; | 
|  | 511 | } | 
|  | 512 |  | 
|  | 513 | Unique_EC_KEY eckey(EVP_PKEY_get1_EC_KEY(pkey)); | 
|  | 514 | if (eckey.get() == NULL) { | 
|  | 515 | logOpenSSLError("openssl_sign_ec"); | 
|  | 516 | return -1; | 
|  | 517 | } | 
|  | 518 |  | 
|  | 519 | unsigned int ecdsaSize = ECDSA_size(eckey.get()); | 
| Shawn Willden | 8d0531e | 2014-06-17 11:45:07 -0600 | [diff] [blame] | 520 | UniquePtr<uint8_t, Malloc_Free> signedDataPtr(reinterpret_cast<uint8_t*>(malloc(ecdsaSize))); | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 521 | if (signedDataPtr.get() == NULL) { | 
|  | 522 | logOpenSSLError("openssl_sign_ec"); | 
|  | 523 | return -1; | 
|  | 524 | } | 
|  | 525 |  | 
|  | 526 | unsigned char* tmp = reinterpret_cast<unsigned char*>(signedDataPtr.get()); | 
|  | 527 | if (ECDSA_sign(0, data, dataLength, tmp, &ecdsaSize, eckey.get()) <= 0) { | 
|  | 528 | logOpenSSLError("openssl_sign_ec"); | 
|  | 529 | return -1; | 
|  | 530 | } | 
|  | 531 |  | 
|  | 532 | *signedDataLength = ecdsaSize; | 
|  | 533 | *signedData = signedDataPtr.release(); | 
|  | 534 |  | 
|  | 535 | return 0; | 
|  | 536 | } | 
|  | 537 |  | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 538 | static int sign_rsa(EVP_PKEY* pkey, keymaster_rsa_sign_params_t* sign_params, const uint8_t* data, | 
| Shawn Willden | 1406b8a | 2014-06-12 11:39:48 -0600 | [diff] [blame] | 539 | const size_t dataLength, uint8_t** signedData, size_t* signedDataLength) { | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 540 | if (sign_params->digest_type != DIGEST_NONE) { | 
|  | 541 | ALOGW("Cannot handle digest type %d", sign_params->digest_type); | 
|  | 542 | return -1; | 
|  | 543 | } else if (sign_params->padding_type != PADDING_NONE) { | 
|  | 544 | ALOGW("Cannot handle padding type %d", sign_params->padding_type); | 
|  | 545 | return -1; | 
|  | 546 | } | 
|  | 547 |  | 
|  | 548 | Unique_RSA rsa(EVP_PKEY_get1_RSA(pkey)); | 
|  | 549 | if (rsa.get() == NULL) { | 
|  | 550 | logOpenSSLError("openssl_sign_rsa"); | 
|  | 551 | return -1; | 
|  | 552 | } | 
|  | 553 |  | 
| Shawn Willden | 8d0531e | 2014-06-17 11:45:07 -0600 | [diff] [blame] | 554 | UniquePtr<uint8_t, Malloc_Free> signedDataPtr(reinterpret_cast<uint8_t*>(malloc(dataLength))); | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 555 | if (signedDataPtr.get() == NULL) { | 
|  | 556 | logOpenSSLError("openssl_sign_rsa"); | 
|  | 557 | return -1; | 
|  | 558 | } | 
|  | 559 |  | 
|  | 560 | unsigned char* tmp = reinterpret_cast<unsigned char*>(signedDataPtr.get()); | 
|  | 561 | if (RSA_private_encrypt(dataLength, data, tmp, rsa.get(), RSA_NO_PADDING) <= 0) { | 
|  | 562 | logOpenSSLError("openssl_sign_rsa"); | 
|  | 563 | return -1; | 
|  | 564 | } | 
|  | 565 |  | 
|  | 566 | *signedDataLength = dataLength; | 
|  | 567 | *signedData = signedDataPtr.release(); | 
|  | 568 |  | 
|  | 569 | return 0; | 
|  | 570 | } | 
|  | 571 |  | 
| Shawn Willden | 1406b8a | 2014-06-12 11:39:48 -0600 | [diff] [blame] | 572 | __attribute__((visibility("default"))) int openssl_sign_data( | 
| Shawn Willden | a5bbf2f | 2015-02-24 09:31:25 -0700 | [diff] [blame] | 573 | const keymaster0_device_t*, const void* params, const uint8_t* keyBlob, | 
| Shawn Willden | 1406b8a | 2014-06-12 11:39:48 -0600 | [diff] [blame] | 574 | const size_t keyBlobLength, const uint8_t* data, const size_t dataLength, uint8_t** signedData, | 
|  | 575 | size_t* signedDataLength) { | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 576 | if (data == NULL) { | 
|  | 577 | ALOGW("input data to sign == NULL"); | 
|  | 578 | return -1; | 
|  | 579 | } else if (signedData == NULL || signedDataLength == NULL) { | 
|  | 580 | ALOGW("output signature buffer == NULL"); | 
|  | 581 | return -1; | 
|  | 582 | } | 
|  | 583 |  | 
|  | 584 | Unique_EVP_PKEY pkey(unwrap_key(keyBlob, keyBlobLength)); | 
|  | 585 | if (pkey.get() == NULL) { | 
|  | 586 | return -1; | 
|  | 587 | } | 
|  | 588 |  | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 589 | int type = EVP_PKEY_type(pkey->type); | 
|  | 590 | if (type == EVP_PKEY_DSA) { | 
| Shawn Willden | 1406b8a | 2014-06-12 11:39:48 -0600 | [diff] [blame] | 591 | const keymaster_dsa_sign_params_t* sign_params = | 
|  | 592 | reinterpret_cast<const keymaster_dsa_sign_params_t*>(params); | 
|  | 593 | return sign_dsa(pkey.get(), const_cast<keymaster_dsa_sign_params_t*>(sign_params), data, | 
|  | 594 | dataLength, signedData, signedDataLength); | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 595 | } else if (type == EVP_PKEY_EC) { | 
| Shawn Willden | 1406b8a | 2014-06-12 11:39:48 -0600 | [diff] [blame] | 596 | const keymaster_ec_sign_params_t* sign_params = | 
|  | 597 | reinterpret_cast<const keymaster_ec_sign_params_t*>(params); | 
|  | 598 | return sign_ec(pkey.get(), const_cast<keymaster_ec_sign_params_t*>(sign_params), data, | 
|  | 599 | dataLength, signedData, signedDataLength); | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 600 | } else if (type == EVP_PKEY_RSA) { | 
| Shawn Willden | 1406b8a | 2014-06-12 11:39:48 -0600 | [diff] [blame] | 601 | const keymaster_rsa_sign_params_t* sign_params = | 
|  | 602 | reinterpret_cast<const keymaster_rsa_sign_params_t*>(params); | 
|  | 603 | return sign_rsa(pkey.get(), const_cast<keymaster_rsa_sign_params_t*>(sign_params), data, | 
|  | 604 | dataLength, signedData, signedDataLength); | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 605 | } else { | 
|  | 606 | ALOGW("Unsupported key type"); | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 607 | return -1; | 
|  | 608 | } | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 609 | } | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 610 |  | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 611 | static int verify_dsa(EVP_PKEY* pkey, keymaster_dsa_sign_params_t* sign_params, | 
| Shawn Willden | 1406b8a | 2014-06-12 11:39:48 -0600 | [diff] [blame] | 612 | const uint8_t* signedData, const size_t signedDataLength, | 
|  | 613 | const uint8_t* signature, const size_t signatureLength) { | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 614 | if (sign_params->digest_type != DIGEST_NONE) { | 
|  | 615 | ALOGW("Cannot handle digest type %d", sign_params->digest_type); | 
|  | 616 | return -1; | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 617 | } | 
|  | 618 |  | 
|  | 619 | Unique_DSA dsa(EVP_PKEY_get1_DSA(pkey)); | 
|  | 620 | if (dsa.get() == NULL) { | 
|  | 621 | logOpenSSLError("openssl_verify_dsa"); | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 622 | return -1; | 
|  | 623 | } | 
|  | 624 |  | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 625 | if (DSA_verify(0, signedData, signedDataLength, signature, signatureLength, dsa.get()) <= 0) { | 
|  | 626 | logOpenSSLError("openssl_verify_dsa"); | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 627 | return -1; | 
|  | 628 | } | 
|  | 629 |  | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 630 | return 0; | 
|  | 631 | } | 
|  | 632 |  | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 633 | static int verify_ec(EVP_PKEY* pkey, keymaster_ec_sign_params_t* sign_params, | 
| Shawn Willden | 1406b8a | 2014-06-12 11:39:48 -0600 | [diff] [blame] | 634 | const uint8_t* signedData, const size_t signedDataLength, | 
|  | 635 | const uint8_t* signature, const size_t signatureLength) { | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 636 | if (sign_params->digest_type != DIGEST_NONE) { | 
|  | 637 | ALOGW("Cannot handle digest type %d", sign_params->digest_type); | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 638 | return -1; | 
|  | 639 | } | 
|  | 640 |  | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 641 | Unique_EC_KEY eckey(EVP_PKEY_get1_EC_KEY(pkey)); | 
|  | 642 | if (eckey.get() == NULL) { | 
|  | 643 | logOpenSSLError("openssl_verify_ec"); | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 644 | return -1; | 
|  | 645 | } | 
|  | 646 |  | 
| Shawn Willden | 1406b8a | 2014-06-12 11:39:48 -0600 | [diff] [blame] | 647 | if (ECDSA_verify(0, signedData, signedDataLength, signature, signatureLength, eckey.get()) <= | 
|  | 648 | 0) { | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 649 | logOpenSSLError("openssl_verify_ec"); | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 650 | return -1; | 
|  | 651 | } | 
|  | 652 |  | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 653 | return 0; | 
|  | 654 | } | 
|  | 655 |  | 
|  | 656 | static int verify_rsa(EVP_PKEY* pkey, keymaster_rsa_sign_params_t* sign_params, | 
| Shawn Willden | 1406b8a | 2014-06-12 11:39:48 -0600 | [diff] [blame] | 657 | const uint8_t* signedData, const size_t signedDataLength, | 
|  | 658 | const uint8_t* signature, const size_t signatureLength) { | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 659 | if (sign_params->digest_type != DIGEST_NONE) { | 
|  | 660 | ALOGW("Cannot handle digest type %d", sign_params->digest_type); | 
|  | 661 | return -1; | 
|  | 662 | } else if (sign_params->padding_type != PADDING_NONE) { | 
|  | 663 | ALOGW("Cannot handle padding type %d", sign_params->padding_type); | 
|  | 664 | return -1; | 
|  | 665 | } else if (signatureLength != signedDataLength) { | 
|  | 666 | ALOGW("signed data length must be signature length"); | 
|  | 667 | return -1; | 
|  | 668 | } | 
|  | 669 |  | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 670 | Unique_RSA rsa(EVP_PKEY_get1_RSA(pkey)); | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 671 | if (rsa.get() == NULL) { | 
|  | 672 | logOpenSSLError("openssl_verify_data"); | 
|  | 673 | return -1; | 
|  | 674 | } | 
|  | 675 |  | 
| Shawn Willden | 8d0531e | 2014-06-17 11:45:07 -0600 | [diff] [blame] | 676 | UniquePtr<uint8_t[]> dataPtr(new uint8_t[signedDataLength]); | 
| Kenny Root | 70e3a86 | 2012-02-15 17:20:23 -0800 | [diff] [blame] | 677 | if (dataPtr.get() == NULL) { | 
|  | 678 | logOpenSSLError("openssl_verify_data"); | 
|  | 679 | return -1; | 
|  | 680 | } | 
|  | 681 |  | 
|  | 682 | unsigned char* tmp = reinterpret_cast<unsigned char*>(dataPtr.get()); | 
|  | 683 | if (!RSA_public_decrypt(signatureLength, signature, tmp, rsa.get(), RSA_NO_PADDING)) { | 
|  | 684 | logOpenSSLError("openssl_verify_data"); | 
|  | 685 | return -1; | 
|  | 686 | } | 
|  | 687 |  | 
|  | 688 | int result = 0; | 
|  | 689 | for (size_t i = 0; i < signedDataLength; i++) { | 
|  | 690 | result |= tmp[i] ^ signedData[i]; | 
|  | 691 | } | 
|  | 692 |  | 
|  | 693 | return result == 0 ? 0 : -1; | 
|  | 694 | } | 
|  | 695 |  | 
| Shawn Willden | 1406b8a | 2014-06-12 11:39:48 -0600 | [diff] [blame] | 696 | __attribute__((visibility("default"))) int openssl_verify_data( | 
| Shawn Willden | a5bbf2f | 2015-02-24 09:31:25 -0700 | [diff] [blame] | 697 | const keymaster0_device_t*, const void* params, const uint8_t* keyBlob, | 
| Shawn Willden | 1406b8a | 2014-06-12 11:39:48 -0600 | [diff] [blame] | 698 | const size_t keyBlobLength, const uint8_t* signedData, const size_t signedDataLength, | 
|  | 699 | const uint8_t* signature, const size_t signatureLength) { | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 700 | if (signedData == NULL || signature == NULL) { | 
|  | 701 | ALOGW("data or signature buffers == NULL"); | 
|  | 702 | return -1; | 
|  | 703 | } | 
|  | 704 |  | 
|  | 705 | Unique_EVP_PKEY pkey(unwrap_key(keyBlob, keyBlobLength)); | 
|  | 706 | if (pkey.get() == NULL) { | 
|  | 707 | return -1; | 
|  | 708 | } | 
|  | 709 |  | 
|  | 710 | int type = EVP_PKEY_type(pkey->type); | 
| Kenny Root | b4d2e02 | 2013-09-04 13:56:03 -0700 | [diff] [blame] | 711 | if (type == EVP_PKEY_DSA) { | 
| Shawn Willden | 1406b8a | 2014-06-12 11:39:48 -0600 | [diff] [blame] | 712 | const keymaster_dsa_sign_params_t* sign_params = | 
|  | 713 | reinterpret_cast<const keymaster_dsa_sign_params_t*>(params); | 
|  | 714 | return verify_dsa(pkey.get(), const_cast<keymaster_dsa_sign_params_t*>(sign_params), | 
|  | 715 | signedData, signedDataLength, signature, signatureLength); | 
| Kenny Root | b4d2e02 | 2013-09-04 13:56:03 -0700 | [diff] [blame] | 716 | } else if (type == EVP_PKEY_RSA) { | 
| Shawn Willden | 1406b8a | 2014-06-12 11:39:48 -0600 | [diff] [blame] | 717 | const keymaster_rsa_sign_params_t* sign_params = | 
|  | 718 | reinterpret_cast<const keymaster_rsa_sign_params_t*>(params); | 
|  | 719 | return verify_rsa(pkey.get(), const_cast<keymaster_rsa_sign_params_t*>(sign_params), | 
|  | 720 | signedData, signedDataLength, signature, signatureLength); | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 721 | } else if (type == EVP_PKEY_EC) { | 
| Shawn Willden | 1406b8a | 2014-06-12 11:39:48 -0600 | [diff] [blame] | 722 | const keymaster_ec_sign_params_t* sign_params = | 
|  | 723 | reinterpret_cast<const keymaster_ec_sign_params_t*>(params); | 
|  | 724 | return verify_ec(pkey.get(), const_cast<keymaster_ec_sign_params_t*>(sign_params), | 
|  | 725 | signedData, signedDataLength, signature, signatureLength); | 
| Kenny Root | 6071179 | 2013-08-16 14:02:41 -0700 | [diff] [blame] | 726 | } else { | 
|  | 727 | ALOGW("Unsupported key type %d", type); | 
|  | 728 | return -1; | 
|  | 729 | } | 
|  | 730 | } | 
| Chad Brubaker | c0703ac | 2015-01-12 14:13:14 -0800 | [diff] [blame] | 731 |  | 
|  | 732 | /* Close an opened OpenSSL instance */ | 
|  | 733 | static int openssl_close(hw_device_t* dev) { | 
|  | 734 | delete dev; | 
|  | 735 | return 0; | 
|  | 736 | } | 
|  | 737 |  | 
|  | 738 | /* | 
|  | 739 | * Generic device handling | 
|  | 740 | */ | 
| Shawn Willden | a5bbf2f | 2015-02-24 09:31:25 -0700 | [diff] [blame] | 741 | __attribute__((visibility("default"))) int openssl_open(const hw_module_t* module, const char* name, | 
|  | 742 | hw_device_t** device) { | 
| Chad Brubaker | c0703ac | 2015-01-12 14:13:14 -0800 | [diff] [blame] | 743 | if (strcmp(name, KEYSTORE_KEYMASTER) != 0) | 
|  | 744 | return -EINVAL; | 
|  | 745 |  | 
| Shawn Willden | a5bbf2f | 2015-02-24 09:31:25 -0700 | [diff] [blame] | 746 | Unique_keymaster_device_t dev(new keymaster0_device_t); | 
| Chad Brubaker | c0703ac | 2015-01-12 14:13:14 -0800 | [diff] [blame] | 747 | if (dev.get() == NULL) | 
|  | 748 | return -ENOMEM; | 
|  | 749 |  | 
|  | 750 | dev->common.tag = HARDWARE_DEVICE_TAG; | 
|  | 751 | dev->common.version = 1; | 
|  | 752 | dev->common.module = (struct hw_module_t*)module; | 
|  | 753 | dev->common.close = openssl_close; | 
|  | 754 |  | 
| Shawn Willden | 0e8b2df | 2015-05-11 07:12:50 -0600 | [diff] [blame] | 755 | dev->flags = KEYMASTER_SOFTWARE_ONLY | KEYMASTER_BLOBS_ARE_STANDALONE | KEYMASTER_SUPPORTS_DSA | | 
|  | 756 | KEYMASTER_SUPPORTS_EC; | 
| Chad Brubaker | c0703ac | 2015-01-12 14:13:14 -0800 | [diff] [blame] | 757 |  | 
|  | 758 | dev->generate_keypair = openssl_generate_keypair; | 
|  | 759 | dev->import_keypair = openssl_import_keypair; | 
|  | 760 | dev->get_keypair_public = openssl_get_keypair_public; | 
|  | 761 | dev->delete_keypair = NULL; | 
|  | 762 | dev->delete_all = NULL; | 
|  | 763 | dev->sign_data = openssl_sign_data; | 
|  | 764 | dev->verify_data = openssl_verify_data; | 
|  | 765 |  | 
|  | 766 | ERR_load_crypto_strings(); | 
|  | 767 | ERR_load_BIO_strings(); | 
|  | 768 |  | 
|  | 769 | *device = reinterpret_cast<hw_device_t*>(dev.release()); | 
|  | 770 |  | 
|  | 771 | return 0; | 
|  | 772 | } | 
|  | 773 |  | 
|  | 774 | static struct hw_module_methods_t keystore_module_methods = { | 
|  | 775 | .open = openssl_open, | 
|  | 776 | }; | 
|  | 777 |  | 
|  | 778 | struct keystore_module softkeymaster_module __attribute__((visibility("default"))) = { | 
| Shawn Willden | a5bbf2f | 2015-02-24 09:31:25 -0700 | [diff] [blame] | 779 | .common = | 
|  | 780 | { | 
|  | 781 | .tag = HARDWARE_MODULE_TAG, | 
|  | 782 | .module_api_version = KEYMASTER_MODULE_API_VERSION_0_2, | 
|  | 783 | .hal_api_version = HARDWARE_HAL_API_VERSION, | 
|  | 784 | .id = KEYSTORE_HARDWARE_MODULE_ID, | 
|  | 785 | .name = "Keymaster OpenSSL HAL", | 
|  | 786 | .author = "The Android Open Source Project", | 
|  | 787 | .methods = &keystore_module_methods, | 
|  | 788 | .dso = 0, | 
|  | 789 | .reserved = {}, | 
|  | 790 | }, | 
| Chad Brubaker | c0703ac | 2015-01-12 14:13:14 -0800 | [diff] [blame] | 791 | }; |