blob: 44356795bc296adea8bc2d7c62fe61aa953564d1 [file] [log] [blame]
Shawn Willdenc3864dd2014-08-18 15:20:01 -06001/*
2 * Copyright 2014 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
17#include <openssl/ecdsa.h>
18
19#include "ecdsa_operation.h"
20#include "openssl_utils.h"
21
22namespace keymaster {
23
24struct ECDSA_Delete {
25 void operator()(EC_KEY* p) { EC_KEY_free(p); }
26};
27
28struct EC_GROUP_Delete {
29 void operator()(EC_GROUP* p) { EC_GROUP_free(p); }
30};
31
32/* static */
33keymaster_error_t EcdsaOperation::Generate(uint32_t key_size_bits, UniquePtr<uint8_t[]>* key_data,
34 size_t* key_data_size) {
35 if (key_data == NULL || key_data_size == NULL)
36 return KM_ERROR_OUTPUT_PARAMETER_NULL;
37
38 UniquePtr<EC_KEY, ECDSA_Delete> ecdsa_key(EC_KEY_new());
39 UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(EVP_PKEY_new());
40 if (ecdsa_key.get() == NULL || pkey.get() == NULL)
41 return KM_ERROR_MEMORY_ALLOCATION_FAILED;
42
43 UniquePtr<EC_GROUP, EC_GROUP_Delete> group;
44 switch (key_size_bits) {
45 case 192:
46 group.reset(EC_GROUP_new_by_curve_name(NID_X9_62_prime192v1));
47 break;
48 case 224:
49 group.reset(EC_GROUP_new_by_curve_name(NID_secp224r1));
50 break;
51 case 256:
52 group.reset(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
53 break;
54 case 384:
55 group.reset(EC_GROUP_new_by_curve_name(NID_secp384r1));
56 break;
57 case 521:
58 group.reset(EC_GROUP_new_by_curve_name(NID_secp521r1));
59 break;
60 default:
61 break;
62 }
63
64 if (group.get() == NULL)
65 // Technically, could also have been a memory allocation problem.
66 return KM_ERROR_UNSUPPORTED_KEY_SIZE;
67
68 EC_GROUP_set_point_conversion_form(group.get(), POINT_CONVERSION_UNCOMPRESSED);
69 EC_GROUP_set_asn1_flag(group.get(), OPENSSL_EC_NAMED_CURVE);
70
71 if (EC_KEY_set_group(ecdsa_key.get(), group.get()) != 1 ||
72 EC_KEY_generate_key(ecdsa_key.get()) != 1 || EC_KEY_check_key(ecdsa_key.get()) < 0 ||
73 !EVP_PKEY_assign_EC_KEY(pkey.get(), ecdsa_key.get()))
74 return KM_ERROR_UNKNOWN_ERROR;
75 else
76 release_because_ownership_transferred(ecdsa_key);
77
78 *key_data_size = i2d_PrivateKey(pkey.get(), NULL);
79 if (*key_data_size <= 0)
80 return KM_ERROR_UNKNOWN_ERROR;
81
82 key_data->reset(new uint8_t[*key_data_size]);
83 uint8_t* tmp = key_data->get();
84 i2d_PrivateKey(pkey.get(), &tmp);
85
86 return KM_ERROR_OK;
87}
88
89} // namespace keymaster