Annotation of embedaddon/strongswan/src/libstrongswan/plugins/pkcs11/pkcs11_hasher.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2010 Martin Willi
3: * Copyright (C) 2010 revosec AG
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_hasher.h"
17:
18: #include <unistd.h>
19:
20: #include <utils/debug.h>
21: #include <threading/mutex.h>
22:
23: #include "pkcs11_manager.h"
24:
25: typedef struct private_pkcs11_hasher_t private_pkcs11_hasher_t;
26:
27: /**
28: * Private data of an pkcs11_hasher_t object.
29: */
30: struct private_pkcs11_hasher_t {
31:
32: /**
33: * Public pkcs11_hasher_t interface.
34: */
35: pkcs11_hasher_t public;
36:
37: /**
38: * PKCS#11 library
39: */
40: pkcs11_library_t *lib;
41:
42: /**
43: * Mechanism for this hasher
44: */
45: CK_MECHANISM_PTR mech;
46:
47: /**
48: * Token session
49: */
50: CK_SESSION_HANDLE session;
51:
52: /**
53: * size of the hash
54: */
55: size_t size;
56:
57: /**
58: * Mutex to lock the tokens hashing engine
59: */
60: mutex_t *mutex;
61:
62: /**
63: * do we have an initialized state?
64: */
65: bool have_state;
66:
67: /**
68: * state buffer
69: */
70: CK_BYTE_PTR state;
71:
72: /**
73: * Length of the state buffer
74: */
75: CK_ULONG state_len;
76: };
77:
78: METHOD(hasher_t, get_hash_size, size_t,
79: private_pkcs11_hasher_t *this)
80: {
81: return this->size;
82: }
83:
84: /**
85: * Save the Operation state to host memory
86: */
87: static bool save_state(private_pkcs11_hasher_t *this)
88: {
89: CK_RV rv;
90:
91: while (TRUE)
92: {
93: if (!this->state)
94: {
95: rv = this->lib->f->C_GetOperationState(this->session, NULL,
96: &this->state_len);
97: if (rv != CKR_OK)
98: {
99: break;
100: }
101: this->state = malloc(this->state_len);
102: }
103: rv = this->lib->f->C_GetOperationState(this->session, this->state,
104: &this->state_len);
105: switch (rv)
106: {
107: case CKR_BUFFER_TOO_SMALL:
108: free(this->state);
109: this->state = NULL;
110: continue;
111: case CKR_OK:
112: this->have_state = TRUE;
113: return TRUE;
114: default:
115: break;
116: }
117: break;
118: }
119: DBG1(DBG_CFG, "C_GetOperationState() failed: %N", ck_rv_names, rv);
120: return FALSE;
121: }
122:
123: /**
124: * Load the Operation state from host memory
125: */
126: static bool load_state(private_pkcs11_hasher_t *this)
127: {
128: CK_RV rv;
129:
130: rv = this->lib->f->C_SetOperationState(this->session, this->state,
131: this->state_len, CK_INVALID_HANDLE, CK_INVALID_HANDLE);
132: if (rv != CKR_OK)
133: {
134: DBG1(DBG_CFG, "C_SetOperationState() failed: %N", ck_rv_names, rv);
135: return FALSE;
136: }
137: this->have_state = FALSE;
138: return TRUE;
139: }
140:
141: METHOD(hasher_t, reset, bool,
142: private_pkcs11_hasher_t *this)
143: {
144: this->have_state = FALSE;
145: return TRUE;
146: }
147:
148: METHOD(hasher_t, get_hash, bool,
149: private_pkcs11_hasher_t *this, chunk_t chunk, uint8_t *hash)
150: {
151: CK_RV rv;
152: CK_ULONG len;
153:
154: this->mutex->lock(this->mutex);
155: if (this->have_state)
156: {
157: if (!load_state(this))
158: {
159: this->mutex->unlock(this->mutex);
160: return FALSE;
161: }
162: }
163: else
164: {
165: rv = this->lib->f->C_DigestInit(this->session, this->mech);
166: if (rv != CKR_OK)
167: {
168: DBG1(DBG_CFG, "C_DigestInit() failed: %N", ck_rv_names, rv);
169: this->mutex->unlock(this->mutex);
170: return FALSE;
171: }
172: }
173: if (chunk.len)
174: {
175: rv = this->lib->f->C_DigestUpdate(this->session, chunk.ptr, chunk.len);
176: if (rv != CKR_OK)
177: {
178: DBG1(DBG_CFG, "C_DigestUpdate() failed: %N", ck_rv_names, rv);
179: this->mutex->unlock(this->mutex);
180: return FALSE;
181: }
182: }
183: if (hash)
184: {
185: len = this->size;
186: rv = this->lib->f->C_DigestFinal(this->session,
187: hash, &len);
188: if (rv != CKR_OK)
189: {
190: DBG1(DBG_CFG, "C_DigestFinal() failed: %N", ck_rv_names, rv);
191: this->mutex->unlock(this->mutex);
192: return FALSE;
193: }
194: }
195: else
196: {
197: if (!save_state(this))
198: {
199: this->mutex->unlock(this->mutex);
200: return FALSE;
201: }
202: }
203: this->mutex->unlock(this->mutex);
204: return TRUE;
205: }
206:
207: METHOD(hasher_t, allocate_hash, bool,
208: private_pkcs11_hasher_t *this, chunk_t chunk, chunk_t *hash)
209: {
210: if (hash)
211: {
212: *hash = chunk_alloc(this->size);
213: return get_hash(this, chunk, hash->ptr);
214: }
215: return get_hash(this, chunk, NULL);
216: }
217:
218: METHOD(hasher_t, destroy, void,
219: private_pkcs11_hasher_t *this)
220: {
221: this->lib->f->C_CloseSession(this->session);
222: this->mutex->destroy(this->mutex);
223: free(this);
224: }
225:
226: /**
227: * Get the Cryptoki mechanism for a hash algorithm
228: */
229: static CK_MECHANISM_PTR algo_to_mechanism(hash_algorithm_t algo, size_t *size)
230: {
231: static struct {
232: hash_algorithm_t algo;
233: CK_MECHANISM mechanism;
234: size_t size;
235: } mappings[] = {
236: {HASH_MD2, {CKM_MD2, NULL, 0}, HASH_SIZE_MD2},
237: {HASH_MD5, {CKM_MD5, NULL, 0}, HASH_SIZE_MD5},
238: {HASH_SHA1, {CKM_SHA_1, NULL, 0}, HASH_SIZE_SHA1},
239: {HASH_SHA256, {CKM_SHA256, NULL, 0}, HASH_SIZE_SHA256},
240: {HASH_SHA384, {CKM_SHA384, NULL, 0}, HASH_SIZE_SHA384},
241: {HASH_SHA512, {CKM_SHA512, NULL, 0}, HASH_SIZE_SHA512},
242: };
243: int i;
244:
245: for (i = 0; i < countof(mappings); i++)
246: {
247: if (mappings[i].algo == algo)
248: {
249: *size = mappings[i].size;
250: return &mappings[i].mechanism;
251: }
252: }
253: return NULL;
254: }
255:
256: /**
257: * Find a token we can use for a hash algorithm
258: */
259: static pkcs11_library_t* find_token(hash_algorithm_t algo,
260: CK_SESSION_HANDLE *session, CK_MECHANISM_PTR *mout, size_t *size)
261: {
262: enumerator_t *tokens, *mechs;
263: pkcs11_manager_t *manager;
264: pkcs11_library_t *current, *found = NULL;
265: CK_MECHANISM_TYPE type;
266: CK_MECHANISM_PTR mech;
267: CK_SLOT_ID slot;
268:
269: mech = algo_to_mechanism(algo, size);
270: if (!mech)
271: {
272: return NULL;
273: }
274: manager = lib->get(lib, "pkcs11-manager");
275: if (!manager)
276: {
277: return NULL;
278: }
279: tokens = manager->create_token_enumerator(manager);
280: while (tokens->enumerate(tokens, ¤t, &slot))
281: {
282: mechs = current->create_mechanism_enumerator(current, slot);
283: while (mechs->enumerate(mechs, &type, NULL))
284: {
285: if (type == mech->mechanism)
286: {
287: if (current->f->C_OpenSession(slot, CKF_SERIAL_SESSION,
288: NULL, NULL, session) == CKR_OK)
289: {
290: found = current;
291: *mout = mech;
292: break;
293: }
294: }
295: }
296: mechs->destroy(mechs);
297: if (found)
298: {
299: break;
300: }
301: }
302: tokens->destroy(tokens);
303: return found;
304: }
305:
306: /**
307: * See header
308: */
309: pkcs11_hasher_t *pkcs11_hasher_create(hash_algorithm_t algo)
310: {
311: private_pkcs11_hasher_t *this;
312:
313: INIT(this,
314: .public = {
315: .hasher = {
316: .get_hash_size = _get_hash_size,
317: .reset = _reset,
318: .get_hash = _get_hash,
319: .allocate_hash = _allocate_hash,
320: .destroy = _destroy,
321: },
322: },
323: .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
324: );
325:
326: this->lib = find_token(algo, &this->session, &this->mech, &this->size);
327: if (!this->lib)
328: {
329: this->mutex->destroy(this->mutex);
330: free(this);
331: return NULL;
332: }
333:
334: return &this->public;
335: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>