pkcs11: Use get_ck_attribute for DH.
[strongswan.git] / src / libstrongswan / plugins / pkcs11 / pkcs11_dh.c
1 /*
2 * Copyright (C) 2011 Tobias Brunner
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "pkcs11_dh.h"
17
18 #include <debug.h>
19 #include <library.h>
20
21 #include "pkcs11_manager.h"
22
23 typedef struct private_pkcs11_dh_t private_pkcs11_dh_t;
24
25 /**
26 * Private data of an pkcs11_dh_t object.
27 */
28 struct private_pkcs11_dh_t {
29
30 /**
31 * Public pkcs11_dh_t interface
32 */
33 pkcs11_dh_t public;
34
35 /**
36 * PKCS#11 library
37 */
38 pkcs11_library_t *lib;
39
40 /**
41 * Session handle for this objct
42 */
43 CK_SESSION_HANDLE session;
44
45 /**
46 * Diffie Hellman group number.
47 */
48 u_int16_t group;
49
50 /**
51 * Handle for own private value
52 */
53 CK_OBJECT_HANDLE pri_key;
54
55 /**
56 * Own public value
57 */
58 chunk_t pub_key;
59
60 /**
61 * Shared secret
62 */
63 chunk_t secret;
64
65 };
66
67 METHOD(diffie_hellman_t, set_other_public_value, void,
68 private_pkcs11_dh_t *this, chunk_t value)
69 {
70 CK_OBJECT_CLASS klass = CKO_SECRET_KEY;
71 CK_KEY_TYPE type = CKK_GENERIC_SECRET;
72 CK_ATTRIBUTE attr[] = {
73 { CKA_CLASS, &klass, sizeof(klass) },
74 { CKA_KEY_TYPE, &type, sizeof(type) },
75 };
76 CK_MECHANISM mech = {
77 CKM_DH_PKCS_DERIVE,
78 value.ptr,
79 value.len,
80 };
81 CK_OBJECT_HANDLE secret;
82 CK_RV rv;
83
84 rv = this->lib->f->C_DeriveKey(this->session, &mech, this->pri_key,
85 attr, countof(attr), &secret);
86 if (rv != CKR_OK)
87 {
88 DBG1(DBG_CFG, "C_DeriveKey() error: %N", ck_rv_names, rv);
89 return;
90 }
91 if (!this->lib->get_ck_attribute(this->lib, this->session, secret,
92 CKA_VALUE, &this->secret))
93 {
94 chunk_free(&this->secret);
95 return;
96 }
97 }
98
99 METHOD(diffie_hellman_t, get_my_public_value, void,
100 private_pkcs11_dh_t *this, chunk_t *value)
101 {
102 *value = chunk_clone(this->pub_key);
103 }
104
105 METHOD(diffie_hellman_t, get_shared_secret, status_t,
106 private_pkcs11_dh_t *this, chunk_t *secret)
107 {
108 if (!this->secret.ptr)
109 {
110 return FAILED;
111 }
112 *secret = chunk_clone(this->secret);
113 return SUCCESS;
114 }
115
116 METHOD(diffie_hellman_t, get_dh_group, diffie_hellman_group_t,
117 private_pkcs11_dh_t *this)
118 {
119 return this->group;
120 }
121
122 METHOD(diffie_hellman_t, destroy, void,
123 private_pkcs11_dh_t *this)
124 {
125 this->lib->f->C_CloseSession(this->session);
126 chunk_clear(&this->pub_key);
127 chunk_clear(&this->secret);
128 free(this);
129 }
130
131 /**
132 * Generate DH key pair
133 */
134 static bool generate_key_pair(private_pkcs11_dh_t *this, size_t exp_len,
135 chunk_t g, chunk_t p)
136 {
137 CK_ULONG bits = exp_len * 8;
138 CK_ATTRIBUTE pub_attr[] = {
139 { CKA_PRIME, p.ptr, p.len },
140 { CKA_BASE, g.ptr, g.len },
141 };
142 CK_ATTRIBUTE pri_attr[] = {
143 { CKA_VALUE_BITS, &bits, sizeof(bits) },
144 };
145 CK_MECHANISM mech = {
146 CKM_DH_PKCS_KEY_PAIR_GEN,
147 NULL,
148 0,
149 };
150 CK_OBJECT_HANDLE pub_key;
151 CK_RV rv;
152
153 rv = this->lib->f->C_GenerateKeyPair(this->session, &mech, pub_attr,
154 countof(pub_attr), pri_attr, countof(pri_attr),
155 &pub_key, &this->pri_key);
156 if (rv != CKR_OK)
157 {
158 DBG1(DBG_CFG, "C_GenerateKeyPair() error: %N", ck_rv_names, rv);
159 return FALSE;
160 }
161
162 if (!this->lib->get_ck_attribute(this->lib, this->session, pub_key,
163 CKA_VALUE, &this->pub_key))
164 {
165 chunk_free(&this->pub_key);
166 return FALSE;
167 }
168 return TRUE;
169 }
170
171 /**
172 * Find a token we can use for DH algorithm
173 */
174 static pkcs11_library_t *find_token(CK_SESSION_HANDLE *session)
175 {
176 enumerator_t *tokens, *mechs;
177 pkcs11_manager_t *manager;
178 pkcs11_library_t *current, *found = NULL;
179 CK_MECHANISM_TYPE type;
180 CK_SLOT_ID slot;
181
182 manager = lib->get(lib, "pkcs11-manager");
183 if (!manager)
184 {
185 return NULL;
186 }
187 tokens = manager->create_token_enumerator(manager);
188 while (tokens->enumerate(tokens, &current, &slot))
189 {
190 mechs = current->create_mechanism_enumerator(current, slot);
191 while (mechs->enumerate(mechs, &type, NULL))
192 {
193 /* we assume CKM_DH_PKCS_DERIVE is supported too */
194 if (type == CKM_DH_PKCS_KEY_PAIR_GEN)
195 {
196 if (current->f->C_OpenSession(slot, CKF_SERIAL_SESSION,
197 NULL, NULL, session) == CKR_OK)
198 {
199 found = current;
200 break;
201 }
202 }
203 }
204 mechs->destroy(mechs);
205 if (found)
206 {
207 break;
208 }
209 }
210 tokens->destroy(tokens);
211 return found;
212 }
213
214 /*
215 * Generic internal constructor
216 */
217 pkcs11_dh_t *create_generic(diffie_hellman_group_t group, size_t exp_len,
218 chunk_t g, chunk_t p)
219 {
220 private_pkcs11_dh_t *this;
221
222 INIT(this,
223 .public = {
224 .dh = {
225 .get_shared_secret = _get_shared_secret,
226 .set_other_public_value = _set_other_public_value,
227 .get_my_public_value = _get_my_public_value,
228 .get_dh_group = _get_dh_group,
229 .destroy = _destroy,
230 },
231 },
232 .group = group,
233 );
234
235 this->lib = find_token(&this->session);
236 if (!this->lib)
237 {
238 free(this);
239 return NULL;
240 }
241
242 if (!generate_key_pair(this, exp_len, g, p))
243 {
244 free(this);
245 return NULL;
246 }
247 return &this->public;
248 }
249
250
251 /*
252 * Described in header.
253 */
254 pkcs11_dh_t *pkcs11_dh_create(diffie_hellman_group_t group,
255 chunk_t g, chunk_t p)
256 {
257 diffie_hellman_params_t *params;
258
259 if (group == MODP_CUSTOM)
260 {
261 return create_generic(group, p.len, g, p);
262 }
263
264 params = diffie_hellman_get_params(group);
265 if (!params)
266 {
267 return NULL;
268 }
269 return create_generic(group, params->exp_len,
270 params->generator, params->prime);
271 }
272