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