Annotation of embedaddon/strongswan/src/libstrongswan/plugins/pkcs11/pkcs11_dh.c, revision 1.1.1.2
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: value = chunk_from_thing(params);
143: break;
144: }
145: default:
146: break;
147: }
148: return derive_secret(this, value);
149: }
150:
151: METHOD(diffie_hellman_t, get_my_public_value, bool,
152: private_pkcs11_dh_t *this, chunk_t *value)
153: {
154: *value = chunk_clone(this->pub_key);
155: return TRUE;
156: }
157:
158: METHOD(diffie_hellman_t, get_shared_secret, bool,
159: private_pkcs11_dh_t *this, chunk_t *secret)
160: {
161: if (!this->secret.ptr)
162: {
163: return FALSE;
164: }
165: *secret = chunk_clone(this->secret);
166: return TRUE;
167: }
168:
169: METHOD(diffie_hellman_t, get_dh_group, diffie_hellman_group_t,
170: private_pkcs11_dh_t *this)
171: {
172: return this->group;
173: }
174:
175: METHOD(diffie_hellman_t, destroy, void,
176: private_pkcs11_dh_t *this)
177: {
178: this->lib->f->C_CloseSession(this->session);
179: chunk_clear(&this->pub_key);
180: chunk_clear(&this->secret);
181: free(this);
182: }
183:
184: /**
185: * Generate a DH/ECDH key pair.
186: *
187: * If this succeeds, this->pri_key has a handle to the private key and
188: * this->pub_key stores the public key.
189: */
190: static bool generate_key_pair(private_pkcs11_dh_t *this, CK_ATTRIBUTE_PTR pub,
191: int pub_len, CK_ATTRIBUTE_PTR pri, int pri_len,
192: CK_ATTRIBUTE_TYPE attr)
193: {
194: CK_MECHANISM mech = {
195: this->mech_key,
196: NULL,
197: 0,
198: };
199: CK_OBJECT_HANDLE pub_key;
200: CK_RV rv;
201:
202: rv = this->lib->f->C_GenerateKeyPair(this->session, &mech, pub, pub_len,
203: pri, pri_len, &pub_key, &this->pri_key);
204: if (rv != CKR_OK)
205: {
206: DBG1(DBG_CFG, "C_GenerateKeyPair() error: %N", ck_rv_names, rv);
207: return FALSE;
208: }
209: if (!this->lib->get_ck_attribute(this->lib, this->session, pub_key,
210: attr, &this->pub_key))
211: {
212: chunk_free(&this->pub_key);
213: return FALSE;
214: }
215: return TRUE;
216: }
217:
218: /**
219: * Generate DH key pair.
220: */
221: static bool generate_key_pair_modp(private_pkcs11_dh_t *this, size_t exp_len,
222: chunk_t g, chunk_t p)
223: {
224: CK_BBOOL ck_true = CK_TRUE;
225: CK_ATTRIBUTE pub_attr[] = {
226: { CKA_DERIVE, &ck_true, sizeof(ck_true) },
227: { CKA_PRIME, p.ptr, p.len },
228: { CKA_BASE, g.ptr, g.len },
229: };
230: CK_ULONG bits = exp_len * 8;
231: CK_ATTRIBUTE pri_attr[] = {
232: { CKA_DERIVE, &ck_true, sizeof(ck_true) },
233: { CKA_VALUE_BITS, &bits, sizeof(bits) },
234: };
235: return generate_key_pair(this, pub_attr, countof(pub_attr), pri_attr,
236: countof(pri_attr), CKA_VALUE);
237: }
238:
239: /**
240: * Generate ECDH key pair.
241: */
242: static bool generate_key_pair_ecp(private_pkcs11_dh_t *this,
243: chunk_t ecparams)
244: {
245: CK_BBOOL ck_true = CK_TRUE;
246: CK_ATTRIBUTE pub_attr[] = {
247: { CKA_DERIVE, &ck_true, sizeof(ck_true) },
248: { CKA_EC_PARAMS, ecparams.ptr, ecparams.len },
249: };
250: CK_ATTRIBUTE pri_attr[] = {
251: { CKA_DERIVE, &ck_true, sizeof(ck_true) },
252: };
253: chunk_t pub_key;
254: if (!generate_key_pair(this, pub_attr, countof(pub_attr), pri_attr,
255: countof(pri_attr), CKA_EC_POINT))
256: {
257: return FALSE;
258: }
259: if (this->pub_key.len <= 0 || this->pub_key.ptr[0] != 0x04)
260: { /* we currently only support the point in uncompressed form which
261: * looks like this: 0x04 || x || y */
262: chunk_clear(&this->pub_key);
263: return FALSE;
264: }
265: pub_key = chunk_clone(chunk_skip(this->pub_key, 1));
266: chunk_clear(&this->pub_key);
267: this->pub_key = pub_key;
268: return TRUE;
269: }
270:
271: /**
272: * Find a token we can use for DH/ECDH algorithm
273: */
274: static pkcs11_library_t *find_token(private_pkcs11_dh_t *this,
275: CK_SESSION_HANDLE *session)
276: {
277: enumerator_t *tokens, *mechs;
278: pkcs11_manager_t *manager;
279: pkcs11_library_t *current, *found = NULL;
280: CK_MECHANISM_TYPE type;
281: CK_SLOT_ID slot;
282:
283: manager = lib->get(lib, "pkcs11-manager");
284: if (!manager)
285: {
286: return NULL;
287: }
288: tokens = manager->create_token_enumerator(manager);
289: while (tokens->enumerate(tokens, ¤t, &slot))
290: {
291: mechs = current->create_mechanism_enumerator(current, slot);
292: while (mechs->enumerate(mechs, &type, NULL))
293: { /* we assume we can generate key pairs if the derive mechanism
294: * is supported */
295: if (type == this->mech_derive)
296: {
297: if (current->f->C_OpenSession(slot, CKF_SERIAL_SESSION,
298: NULL, NULL, session) == CKR_OK)
299: {
300: found = current;
301: break;
302: }
303: }
304: }
305: mechs->destroy(mechs);
306: if (found)
307: {
308: break;
309: }
310: }
311: tokens->destroy(tokens);
312: return found;
313: }
314:
315: /**
316: * Generic internal constructor
317: */
318: static private_pkcs11_dh_t *create_generic(diffie_hellman_group_t group,
319: CK_MECHANISM_TYPE key,
320: CK_MECHANISM_TYPE derive)
321: {
322: private_pkcs11_dh_t *this;
323:
324: INIT(this,
325: .public = {
326: .dh = {
327: .get_shared_secret = _get_shared_secret,
328: .set_other_public_value = _set_other_public_value,
329: .get_my_public_value = _get_my_public_value,
330: .get_dh_group = _get_dh_group,
331: .destroy = _destroy,
332: },
333: },
334: .group = group,
335: .mech_key = key,
336: .mech_derive = derive,
337: );
338:
339: this->lib = find_token(this, &this->session);
340: if (!this->lib)
341: {
342: free(this);
343: return NULL;
344: }
345: return this;
346: }
347:
348: static pkcs11_dh_t *create_ecp(diffie_hellman_group_t group, chunk_t ecparam)
349: {
350: private_pkcs11_dh_t *this = create_generic(group, CKM_EC_KEY_PAIR_GEN,
351: CKM_ECDH1_DERIVE);
352:
353: if (this)
354: {
355: if (generate_key_pair_ecp(this, ecparam))
356: {
357: chunk_free(&ecparam);
358: return &this->public;
359: }
360: chunk_free(&ecparam);
361: free(this);
362: }
363: return NULL;
364: }
365:
366: /**
367: * Constructor for MODP DH
368: */
369: static pkcs11_dh_t *create_modp(diffie_hellman_group_t group, size_t exp_len,
370: chunk_t g, chunk_t p)
371: {
372: private_pkcs11_dh_t *this = create_generic(group, CKM_DH_PKCS_KEY_PAIR_GEN,
373: CKM_DH_PKCS_DERIVE);
374:
375: if (this)
376: {
377: if (generate_key_pair_modp(this, exp_len, g, p))
378: {
379: return &this->public;
380: }
381: free(this);
382: }
383: return NULL;
384: }
385:
386: /**
387: * Lookup the EC params for the given group.
388: */
389: static chunk_t ecparams_lookup(diffie_hellman_group_t group)
390: {
391: switch (group)
392: {
393: case ECP_192_BIT:
394: return asn1_build_known_oid(OID_PRIME192V1);
395: case ECP_224_BIT:
396: return asn1_build_known_oid(OID_SECT224R1);
397: case ECP_256_BIT:
398: return asn1_build_known_oid(OID_PRIME256V1);
399: case ECP_384_BIT:
400: return asn1_build_known_oid(OID_SECT384R1);
401: case ECP_521_BIT:
402: return asn1_build_known_oid(OID_SECT521R1);
403: default:
404: break;
405: }
406: return chunk_empty;
407: }
408:
409: /**
410: * Described in header.
411: */
412: pkcs11_dh_t *pkcs11_dh_create(diffie_hellman_group_t group, ...)
413: {
414: switch (group)
415: {
416: case MODP_CUSTOM:
417: {
418: chunk_t g, p;
419:
420: VA_ARGS_GET(group, g, p);
421: return create_modp(group, p.len, g, p);
422: }
423: case ECP_192_BIT:
424: case ECP_224_BIT:
425: case ECP_256_BIT:
426: case ECP_384_BIT:
427: case ECP_521_BIT:
428: {
429: chunk_t params = ecparams_lookup(group);
430: if (params.ptr)
431: {
432: return create_ecp(group, params);
433: }
434: break;
435: }
436: default:
437: {
438: diffie_hellman_params_t *params = diffie_hellman_get_params(group);
439: if (params)
440: {
441: return create_modp(group, params->exp_len, params->generator,
442: params->prime);
443: }
444: break;
445: }
446: }
447: return NULL;
448: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>