]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/libstrongswan/plugins/pkcs11/pkcs11_dh.c
lib: All settings use configured namespace
[thirdparty/strongswan.git] / src / libstrongswan / plugins / pkcs11 / pkcs11_dh.c
CommitLineData
1bb5d7c3
TB
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
f05b4272 18#include <utils/debug.h>
1bb5d7c3 19#include <library.h>
10b82be6
TB
20#include <asn1/asn1.h>
21#include <asn1/oid.h>
1bb5d7c3
TB
22
23#include "pkcs11_manager.h"
24
25typedef struct private_pkcs11_dh_t private_pkcs11_dh_t;
26
27/**
28 * Private data of an pkcs11_dh_t object.
29 */
30struct private_pkcs11_dh_t {
31
32 /**
33 * Public pkcs11_dh_t interface
34 */
35 pkcs11_dh_t public;
36
37 /**
38 * PKCS#11 library
39 */
40 pkcs11_library_t *lib;
41
42 /**
43 * Session handle for this objct
44 */
45 CK_SESSION_HANDLE session;
46
47 /**
48 * Diffie Hellman group number.
49 */
50 u_int16_t group;
51
52 /**
53 * Handle for own private value
54 */
55 CK_OBJECT_HANDLE pri_key;
56
57 /**
58 * Own public value
59 */
60 chunk_t pub_key;
61
62 /**
63 * Shared secret
64 */
65 chunk_t secret;
66
10b82be6
TB
67 /**
68 * Mechanism to use to generate a key pair
69 */
70 CK_MECHANISM_TYPE mech_key;
71
72 /**
73 * Mechanism to use to derive a shared secret
74 */
75 CK_MECHANISM_TYPE mech_derive;
76
1bb5d7c3
TB
77};
78
10b82be6
TB
79/**
80 * Derive a DH/ECDH shared secret.
81 *
82 * If this succeeds the shared secret is stored in this->secret.
83 */
84static void derive_secret(private_pkcs11_dh_t *this, chunk_t other)
1bb5d7c3 85{
7c78a6e6
TB
86 CK_OBJECT_CLASS klass = CKO_SECRET_KEY;
87 CK_KEY_TYPE type = CKK_GENERIC_SECRET;
1bb5d7c3 88 CK_ATTRIBUTE attr[] = {
7c78a6e6
TB
89 { CKA_CLASS, &klass, sizeof(klass) },
90 { CKA_KEY_TYPE, &type, sizeof(type) },
1bb5d7c3
TB
91 };
92 CK_MECHANISM mech = {
10b82be6
TB
93 this->mech_derive,
94 other.ptr,
95 other.len,
1bb5d7c3
TB
96 };
97 CK_OBJECT_HANDLE secret;
98 CK_RV rv;
99
100 rv = this->lib->f->C_DeriveKey(this->session, &mech, this->pri_key,
101 attr, countof(attr), &secret);
102 if (rv != CKR_OK)
103 {
104 DBG1(DBG_CFG, "C_DeriveKey() error: %N", ck_rv_names, rv);
105 return;
106 }
cac68531
TB
107 if (!this->lib->get_ck_attribute(this->lib, this->session, secret,
108 CKA_VALUE, &this->secret))
1bb5d7c3 109 {
cac68531 110 chunk_free(&this->secret);
1bb5d7c3
TB
111 return;
112 }
113}
114
10b82be6
TB
115METHOD(diffie_hellman_t, set_other_public_value, void,
116 private_pkcs11_dh_t *this, chunk_t value)
117{
118 switch (this->group)
119 {
120 case ECP_192_BIT:
121 case ECP_224_BIT:
122 case ECP_256_BIT:
123 case ECP_384_BIT:
124 case ECP_521_BIT:
125 { /* we expect the public value to just be the concatenated x and y
126 * coordinates, so we tag the value as an uncompressed ECPoint */
127 chunk_t tag = chunk_from_chars(0x04);
128 chunk_t pubkey = chunk_cata("cc", tag, value);
129 CK_ECDH1_DERIVE_PARAMS params = {
130 CKD_NULL,
131 0,
132 NULL,
133 pubkey.len,
134 pubkey.ptr,
135 };
136
137 if (!lib->settings->get_bool(lib->settings,
8dc6e716 138 "%s.ecp_x_coordinate_only", TRUE, lib->ns))
10b82be6
TB
139 { /* we only get the x coordinate back */
140 return;
141 }
142 value = chunk_from_thing(params);
143 break;
144 }
145 default:
146 break;
147 }
148 derive_secret(this, value);
149}
150
1bb5d7c3
TB
151METHOD(diffie_hellman_t, get_my_public_value, void,
152 private_pkcs11_dh_t *this, chunk_t *value)
153{
154 *value = chunk_clone(this->pub_key);
155}
156
157METHOD(diffie_hellman_t, get_shared_secret, status_t,
158 private_pkcs11_dh_t *this, chunk_t *secret)
159{
160 if (!this->secret.ptr)
161 {
162 return FAILED;
163 }
164 *secret = chunk_clone(this->secret);
165 return SUCCESS;
166}
167
168METHOD(diffie_hellman_t, get_dh_group, diffie_hellman_group_t,
169 private_pkcs11_dh_t *this)
170{
171 return this->group;
172}
173
174METHOD(diffie_hellman_t, destroy, void,
175 private_pkcs11_dh_t *this)
176{
177 this->lib->f->C_CloseSession(this->session);
178 chunk_clear(&this->pub_key);
179 chunk_clear(&this->secret);
180 free(this);
181}
182
183/**
10b82be6
TB
184 * Generate a DH/ECDH key pair.
185 *
186 * If this succeeds, this->pri_key has a handle to the private key and
187 * this->pub_key stores the public key.
1bb5d7c3 188 */
10b82be6
TB
189static bool generate_key_pair(private_pkcs11_dh_t *this, CK_ATTRIBUTE_PTR pub,
190 int pub_len, CK_ATTRIBUTE_PTR pri, int pri_len,
191 CK_ATTRIBUTE_TYPE attr)
1bb5d7c3 192{
1bb5d7c3 193 CK_MECHANISM mech = {
10b82be6 194 this->mech_key,
1bb5d7c3
TB
195 NULL,
196 0,
197 };
198 CK_OBJECT_HANDLE pub_key;
199 CK_RV rv;
200
10b82be6
TB
201 rv = this->lib->f->C_GenerateKeyPair(this->session, &mech, pub, pub_len,
202 pri, pri_len, &pub_key, &this->pri_key);
1bb5d7c3
TB
203 if (rv != CKR_OK)
204 {
205 DBG1(DBG_CFG, "C_GenerateKeyPair() error: %N", ck_rv_names, rv);
206 return FALSE;
207 }
cac68531 208 if (!this->lib->get_ck_attribute(this->lib, this->session, pub_key,
10b82be6 209 attr, &this->pub_key))
1bb5d7c3 210 {
cac68531 211 chunk_free(&this->pub_key);
1bb5d7c3
TB
212 return FALSE;
213 }
214 return TRUE;
215}
216
217/**
10b82be6
TB
218 * Generate DH key pair.
219 */
220static bool generate_key_pair_modp(private_pkcs11_dh_t *this, size_t exp_len,
221 chunk_t g, chunk_t p)
222{
cf9d45ea 223 CK_BBOOL ck_true = CK_TRUE;
10b82be6 224 CK_ATTRIBUTE pub_attr[] = {
cf9d45ea 225 { CKA_DERIVE, &ck_true, sizeof(ck_true) },
10b82be6
TB
226 { CKA_PRIME, p.ptr, p.len },
227 { CKA_BASE, g.ptr, g.len },
228 };
229 CK_ULONG bits = exp_len * 8;
230 CK_ATTRIBUTE pri_attr[] = {
cf9d45ea 231 { CKA_DERIVE, &ck_true, sizeof(ck_true) },
10b82be6
TB
232 { CKA_VALUE_BITS, &bits, sizeof(bits) },
233 };
234 return generate_key_pair(this, pub_attr, countof(pub_attr), pri_attr,
235 countof(pri_attr), CKA_VALUE);
236}
237
238/**
239 * Generate ECDH key pair.
1bb5d7c3 240 */
10b82be6
TB
241static bool generate_key_pair_ecp(private_pkcs11_dh_t *this,
242 chunk_t ecparams)
243{
cf9d45ea 244 CK_BBOOL ck_true = CK_TRUE;
10b82be6 245 CK_ATTRIBUTE pub_attr[] = {
cf9d45ea 246 { CKA_DERIVE, &ck_true, sizeof(ck_true) },
10b82be6
TB
247 { CKA_EC_PARAMS, ecparams.ptr, ecparams.len },
248 };
cf9d45ea
TB
249 CK_ATTRIBUTE pri_attr[] = {
250 { CKA_DERIVE, &ck_true, sizeof(ck_true) },
251 };
43cd036a 252 chunk_t pub_key;
cf9d45ea
TB
253 if (!generate_key_pair(this, pub_attr, countof(pub_attr), pri_attr,
254 countof(pri_attr), CKA_EC_POINT))
10b82be6
TB
255 {
256 return FALSE;
257 }
258 if (this->pub_key.len <= 0 || this->pub_key.ptr[0] != 0x04)
259 { /* we currently only support the point in uncompressed form which
260 * looks like this: 0x04 || x || y */
261 chunk_clear(&this->pub_key);
262 return FALSE;
263 }
43cd036a
TB
264 pub_key = chunk_clone(chunk_skip(this->pub_key, 1));
265 chunk_clear(&this->pub_key);
266 this->pub_key = pub_key;
10b82be6
TB
267 return TRUE;
268}
269
270/**
271 * Find a token we can use for DH/ECDH algorithm
272 */
273static pkcs11_library_t *find_token(private_pkcs11_dh_t *this,
274 CK_SESSION_HANDLE *session)
1bb5d7c3
TB
275{
276 enumerator_t *tokens, *mechs;
277 pkcs11_manager_t *manager;
278 pkcs11_library_t *current, *found = NULL;
279 CK_MECHANISM_TYPE type;
280 CK_SLOT_ID slot;
281
282 manager = lib->get(lib, "pkcs11-manager");
283 if (!manager)
284 {
285 return NULL;
286 }
287 tokens = manager->create_token_enumerator(manager);
288 while (tokens->enumerate(tokens, &current, &slot))
289 {
290 mechs = current->create_mechanism_enumerator(current, slot);
291 while (mechs->enumerate(mechs, &type, NULL))
10b82be6
TB
292 { /* we assume we can generate key pairs if the derive mechanism
293 * is supported */
294 if (type == this->mech_derive)
1bb5d7c3
TB
295 {
296 if (current->f->C_OpenSession(slot, CKF_SERIAL_SESSION,
297 NULL, NULL, session) == CKR_OK)
298 {
299 found = current;
300 break;
301 }
302 }
303 }
304 mechs->destroy(mechs);
305 if (found)
306 {
307 break;
308 }
309 }
310 tokens->destroy(tokens);
311 return found;
312}
313
10b82be6 314/**
1bb5d7c3
TB
315 * Generic internal constructor
316 */
10b82be6
TB
317static private_pkcs11_dh_t *create_generic(diffie_hellman_group_t group,
318 CK_MECHANISM_TYPE key,
319 CK_MECHANISM_TYPE derive)
1bb5d7c3
TB
320{
321 private_pkcs11_dh_t *this;
322
323 INIT(this,
324 .public = {
325 .dh = {
326 .get_shared_secret = _get_shared_secret,
327 .set_other_public_value = _set_other_public_value,
328 .get_my_public_value = _get_my_public_value,
329 .get_dh_group = _get_dh_group,
330 .destroy = _destroy,
331 },
332 },
333 .group = group,
10b82be6
TB
334 .mech_key = key,
335 .mech_derive = derive,
1bb5d7c3
TB
336 );
337
10b82be6 338 this->lib = find_token(this, &this->session);
1bb5d7c3
TB
339 if (!this->lib)
340 {
341 free(this);
342 return NULL;
343 }
10b82be6
TB
344 return this;
345}
1bb5d7c3 346
10b82be6
TB
347static pkcs11_dh_t *create_ecp(diffie_hellman_group_t group, chunk_t ecparam)
348{
349 private_pkcs11_dh_t *this = create_generic(group, CKM_EC_KEY_PAIR_GEN,
350 CKM_ECDH1_DERIVE);
351
352 if (this)
1bb5d7c3 353 {
10b82be6
TB
354 if (generate_key_pair_ecp(this, ecparam))
355 {
817d165c 356 chunk_free(&ecparam);
10b82be6
TB
357 return &this->public;
358 }
817d165c 359 chunk_free(&ecparam);
1bb5d7c3 360 free(this);
1bb5d7c3 361 }
10b82be6 362 return NULL;
1bb5d7c3
TB
363}
364
10b82be6
TB
365/**
366 * Constructor for MODP DH
1bb5d7c3 367 */
10b82be6
TB
368static pkcs11_dh_t *create_modp(diffie_hellman_group_t group, size_t exp_len,
369 chunk_t g, chunk_t p)
1bb5d7c3 370{
10b82be6
TB
371 private_pkcs11_dh_t *this = create_generic(group, CKM_DH_PKCS_KEY_PAIR_GEN,
372 CKM_DH_PKCS_DERIVE);
373
374 if (this)
375 {
376 if (generate_key_pair_modp(this, exp_len, g, p))
377 {
378 return &this->public;
379 }
380 free(this);
381 }
382 return NULL;
383}
1bb5d7c3 384
10b82be6
TB
385/**
386 * Lookup the EC params for the given group.
387 */
388static chunk_t ecparams_lookup(diffie_hellman_group_t group)
389{
390 switch (group)
b730fd6f 391 {
10b82be6
TB
392 case ECP_192_BIT:
393 return asn1_build_known_oid(OID_PRIME192V1);
394 case ECP_224_BIT:
395 return asn1_build_known_oid(OID_SECT224R1);
396 case ECP_256_BIT:
397 return asn1_build_known_oid(OID_PRIME256V1);
398 case ECP_384_BIT:
399 return asn1_build_known_oid(OID_SECT384R1);
400 case ECP_521_BIT:
401 return asn1_build_known_oid(OID_SECT521R1);
402 default:
403 break;
b730fd6f 404 }
10b82be6
TB
405 return chunk_empty;
406}
b730fd6f 407
10b82be6
TB
408/**
409 * Described in header.
410 */
411pkcs11_dh_t *pkcs11_dh_create(diffie_hellman_group_t group,
412 chunk_t g, chunk_t p)
413{
414 switch (group)
1bb5d7c3 415 {
10b82be6
TB
416 case MODP_CUSTOM:
417 {
418 return create_modp(group, p.len, g, p);
419 }
420 case ECP_192_BIT:
421 case ECP_224_BIT:
422 case ECP_256_BIT:
423 case ECP_384_BIT:
424 case ECP_521_BIT:
425 {
426 chunk_t params = ecparams_lookup(group);
427 if (params.ptr)
428 {
429 return create_ecp(group, params);
430 }
431 break;
432 }
433 default:
434 {
435 diffie_hellman_params_t *params = diffie_hellman_get_params(group);
436 if (params)
437 {
438 return create_modp(group, params->exp_len, params->generator,
439 params->prime);
440 }
441 break;
442 }
1bb5d7c3 443 }
10b82be6 444 return NULL;
1bb5d7c3
TB
445}
446