blob: 5065660a3d39a824df2d32bcdd0eba2e5fe4fb72 [file] [log] [blame]
Shawn Willden28e41472014-08-18 13:35:22 -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/bn.h>
18
19#include "dsa_operation.h"
20#include "openssl_utils.h"
21
22namespace keymaster {
23
24struct DSA_Delete {
25 void operator()(DSA* p) { DSA_free(p); }
26};
27
28/* static */
29keymaster_error_t DsaOperation::Generate(uint32_t key_size_bits, keymaster_blob_t* g,
30 keymaster_blob_t* p, keymaster_blob_t* q,
31 UniquePtr<uint8_t[]>* key_data, size_t* key_data_size) {
32 if (g == NULL || p == NULL || q == NULL || key_data == NULL || key_data_size == NULL)
33 return KM_ERROR_OUTPUT_PARAMETER_NULL;
34
35 UniquePtr<DSA, DSA_Delete> dsa_key(DSA_new());
36 UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(EVP_PKEY_new());
37 if (dsa_key.get() == NULL || pkey.get() == NULL)
38 return KM_ERROR_MEMORY_ALLOCATION_FAILED;
39
40 if (g->data == NULL && p->data == NULL && q->data == NULL) {
41 // No params provided, generate them.
42 if (!DSA_generate_parameters_ex(dsa_key.get(), key_size_bits, NULL /* seed */,
43 0 /* seed_len */, NULL /* counter_ret */, NULL /* h_ret */,
44 NULL /* callback */)) {
45 // TODO(swillden): return a more precise error, depending on ERR_get_error();
46 return KM_ERROR_INVALID_DSA_PARAMS;
47 }
48 convert_bn_to_blob(dsa_key->g, g);
49 convert_bn_to_blob(dsa_key->p, p);
50 convert_bn_to_blob(dsa_key->q, q);
51 } else if (g->data == NULL || p->data == NULL || q->data == NULL) {
52 // Some params provided, that's an error. Provide them all or provide none.
53 return KM_ERROR_INVALID_DSA_PARAMS;
54 } else {
55 // All params provided. Use them.
56 dsa_key->g = BN_bin2bn(g->data, g->data_length, NULL);
57 dsa_key->p = BN_bin2bn(p->data, p->data_length, NULL);
58 dsa_key->q = BN_bin2bn(q->data, q->data_length, NULL);
59
60 if (dsa_key->g == NULL || dsa_key->p == NULL || dsa_key->q == NULL)
61 return KM_ERROR_INVALID_DSA_PARAMS;
62 }
63
64 if (!DSA_generate_key(dsa_key.get()) || !EVP_PKEY_assign_DSA(pkey.get(), dsa_key.get()))
65 return KM_ERROR_UNKNOWN_ERROR;
66 release_because_ownership_transferred(dsa_key);
67
68 *key_data_size = i2d_PrivateKey(pkey.get(), NULL);
69 if (*key_data_size <= 0)
70 return KM_ERROR_UNKNOWN_ERROR;
71
72 key_data->reset(new uint8_t[*key_data_size]);
73 uint8_t* tmp = key_data->get();
74 i2d_PrivateKey(pkey.get(), &tmp);
75
76 return KM_ERROR_OK;
77}
78
79} // namespace keymaster