Added synchronous and asynchronous PKCS calls.
[crypto.git] / lib / silcacc / softacc_pkcs.c
1 /*
2
3   softacc_pkcs.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2007 - 2008 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; version 2 of the License.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18 */
19
20 #include "silccrypto.h"
21 #include "softacc.h"
22 #include "softacc_i.h"
23
24 /* The public and private key accelerator.  We perform the public key and
25    private key operations in threads.  Threads are run in the thread pool. */
26
27 /************************** Types and definitions ***************************/
28
29 /* Software accelerator PKCS algorithm operations */
30 const SilcPKCSAlgorithm softacc_pkcs[] =
31 {
32   {
33     "any", "any", NULL, NULL,
34     silc_softacc_acc_public_key,
35     NULL, NULL, NULL, NULL,
36     silc_softacc_free_public_key,
37     silc_softacc_acc_private_key,
38     NULL, NULL,
39     silc_softacc_free_private_key,
40     silc_softacc_encrypt,
41     silc_softacc_decrypt,
42     silc_softacc_sign,
43     silc_softacc_verify,
44   },
45
46   {
47     NULL, NULL, NULL, NULL,
48     NULL, NULL, NULL, NULL,
49     NULL, NULL, NULL, NULL,
50     NULL, NULL
51   }
52 };
53
54 /* Software accelerator public key */
55 typedef struct {
56   SilcPublicKey key;                     /* Accelerated public key */
57 } *SilcSoftaccPublicKey;
58
59 /* Software accelerator private key */
60 typedef struct {
61   SilcPrivateKey key;                    /* Accelerated private key */
62 } *SilcSoftaccPrivateKey;
63
64 /* Execution types */
65 typedef enum {
66   SILC_SOFTACC_ENCRYPT,
67   SILC_SOFTACC_DECRYPT,
68   SILC_SOFTACC_SIGN,
69   SILC_SOFTACC_VERIFY,
70 } SilcSoftaccType;
71
72 /* Executor context */
73 typedef struct {
74   SilcStack stack;                       /* Executor stack */
75   void *context;                         /* Callback context */
76   SilcSoftaccType type;                  /* Execution type */
77   SilcAsyncOperationStruct op;           /* Operation for aborting */
78
79   unsigned char *src;                    /* Source data */
80   unsigned char *data;                   /* More source data */
81   SilcUInt32 src_len;
82   SilcUInt32 data_len;
83   SilcHash hash;                         /* Hash function to use */
84   SilcRng rng;                           /* RNG, may be NULL */
85
86   union {
87     SilcPublicKey public_key;
88     SilcPrivateKey private_key;
89   } key;
90
91   union {
92     SilcPKCSEncryptCb encrypt_cb;
93     SilcPKCSDecryptCb decrypt_cb;
94     SilcPKCSSignCb sign_cb;
95     SilcPKCSVerifyCb verify_cb;
96   } cb;
97
98   unsigned char *result_data;
99   SilcUInt32 result_len;
100
101   unsigned int result       : 1;
102   unsigned int compute_hash : 1;
103   unsigned int aborted      : 1;
104 } *SilcSoftaccExec;
105
106 /****************************** PKCS ALG API ********************************/
107
108 /* Abort operation */
109
110 void silc_softacc_pkcs_abort(SilcAsyncOperation op, void *context)
111 {
112   SilcSoftaccExec e = context;
113   e->aborted = TRUE;
114 }
115
116 /* Accelerator completion, executed in main thread. */
117
118 SILC_TASK_CALLBACK(silc_softacc_pkcs_completion)
119 {
120   SilcSoftaccExec e = context;
121   SilcStack stack = e->stack;
122
123   /* At the latest, abort is catched here in the main thread.  Don't
124      deliver callback if we were aborted */
125   if (e->aborted)
126     goto out;
127
128   SILC_LOG_DEBUG(("Call completion, result=%s", e->result ? "Ok" : "failed"));
129
130   /* Call completion callback */
131   switch (e->type) {
132   case SILC_SOFTACC_ENCRYPT:
133     e->cb.encrypt_cb(e->result, e->result_data, e->result_len, e->context);
134     break;
135
136   case SILC_SOFTACC_DECRYPT:
137     e->cb.decrypt_cb(e->result, e->result_data, e->result_len, e->context);
138     break;
139
140   case SILC_SOFTACC_SIGN:
141     e->cb.sign_cb(e->result, e->result_data, e->result_len, e->context);
142     break;
143
144   case SILC_SOFTACC_VERIFY:
145     e->cb.verify_cb(e->result, e->context);
146     break;
147   }
148
149  out:
150   silc_sfree(stack, e->src);
151   silc_sfree(stack, e->data);
152   silc_sfree(stack, e->result_data);
153   silc_sfree(stack, e);
154   silc_stack_free(stack);
155 }
156
157 /* Callback for encrypt, decrypt and signature */
158
159 void silc_softacc_pkcs_data_cb(SilcBool success, const unsigned char *data,
160                                SilcUInt32 data_len, void *context)
161 {
162   SilcSoftaccExec e = context;
163   SilcStack stack = e->stack;
164
165   /* Pop e->src */
166   silc_stack_pop(stack);
167
168   if (success)
169     e->result_data = silc_smemdup(stack, data, data_len);
170   e->result_len = data_len;
171   e->result = success;
172 }
173
174 /* Verification callback */
175
176 void silc_softacc_pkcs_verify_cb(SilcBool success, void *context)
177 {
178   SilcSoftaccExec e = context;
179   SilcStack stack = e->stack;
180
181   /* Pop e->src and e->data from memory */
182   silc_stack_pop(stack);
183
184   e->result = success;
185 }
186
187 /* Accelerator thread */
188
189 void silc_softacc_pkcs_thread(SilcSchedule schedule, void *context)
190 {
191   SilcSoftaccExec e = context;
192
193   if (e->aborted)
194     return;
195
196   SILC_LOG_DEBUG(("Execute type %d", e->type));
197
198   /* Call the operation */
199   switch (e->type) {
200   case SILC_SOFTACC_ENCRYPT:
201     silc_pkcs_encrypt_async(e->key.public_key, e->src, e->src_len, e->rng,
202                             silc_softacc_pkcs_data_cb, e);
203     break;
204
205   case SILC_SOFTACC_DECRYPT:
206     silc_pkcs_decrypt_async(e->key.private_key, e->src, e->src_len,
207                             silc_softacc_pkcs_data_cb, e);
208     break;
209
210   case SILC_SOFTACC_SIGN:
211     silc_pkcs_sign_async(e->key.private_key, e->src, e->src_len,
212                          e->compute_hash, e->hash, e->rng,
213                          silc_softacc_pkcs_data_cb, e);
214     break;
215
216   case SILC_SOFTACC_VERIFY:
217     silc_pkcs_verify_async(e->key.public_key, e->src, e->src_len, e->data,
218                            e->data_len, e->compute_hash, e->hash,
219                            silc_softacc_pkcs_verify_cb, e);
220     break;
221   }
222 }
223
224 /* Accelerate public key */
225
226 SILC_PKCS_ALG_IMPORT_PUBLIC_KEY(silc_softacc_acc_public_key)
227 {
228   SilcSoftaccPublicKey pubkey;
229   SilcSoftacc sa;
230
231   sa = silc_global_get_var("softacc", FALSE);
232   if (!sa || !sa->schedule) {
233     SILC_LOG_ERROR(("Software accelerator not initialized"));
234     return FALSE;
235   }
236
237   pubkey = silc_calloc(1, sizeof(*pubkey));
238   if (!pubkey)
239     return FALSE;
240   pubkey->key = key;
241
242   *ret_public_key = pubkey;
243
244   return TRUE;
245 }
246
247 /* Accelerate private key */
248
249 SILC_PKCS_ALG_IMPORT_PRIVATE_KEY(silc_softacc_acc_private_key)
250 {
251   SilcSoftaccPrivateKey privkey;
252   SilcSoftacc sa;
253
254   sa = silc_global_get_var("softacc", FALSE);
255   if (!sa || !sa->schedule) {
256     SILC_LOG_ERROR(("Software accelerator not initialized"));
257     return FALSE;
258   }
259
260   privkey = silc_calloc(1, sizeof(*privkey));
261   if (!privkey)
262     return FALSE;
263   privkey->key = key;
264
265   *ret_private_key = privkey;
266
267   return TRUE;
268 }
269
270 /* Free public key */
271
272 SILC_PKCS_ALG_PUBLIC_KEY_FREE(silc_softacc_free_public_key)
273 {
274   silc_free(public_key);
275 }
276
277 /* Free private key */
278
279 SILC_PKCS_ALG_PRIVATE_KEY_FREE(silc_softacc_free_private_key)
280 {
281   silc_free(private_key);
282 }
283
284 /* Accelerated encrypt */
285
286 SILC_PKCS_ALG_ENCRYPT(silc_softacc_encrypt)
287 {
288   SilcSoftaccPublicKey pubkey = public_key;
289   SilcStack stack;
290   SilcSoftaccExec e;
291   SilcSoftacc sa;
292
293   SILC_LOG_DEBUG(("Encrypt"));
294
295   sa = silc_global_get_var("softacc", FALSE);
296   if (!sa || !sa->schedule) {
297     SILC_LOG_ERROR(("Software accelerator not initialized"));
298     encrypt_cb(FALSE, NULL, 0, context);
299     return NULL;
300   }
301
302   stack = silc_stack_alloc(2048, silc_crypto_stack());
303
304   e = silc_scalloc(stack, 1, sizeof(*e));
305   if (!e) {
306     silc_stack_free(stack);
307     encrypt_cb(FALSE, NULL, 0, context);
308     return NULL;
309   }
310
311   silc_stack_push(stack, NULL);
312
313   e->stack = stack;
314   e->type = SILC_SOFTACC_ENCRYPT;
315   e->src = silc_smemdup(stack, src, src_len);
316   e->src_len = src_len;
317   e->rng = rng;
318   e->key.public_key = pubkey->key;
319   e->cb.encrypt_cb = encrypt_cb;
320   e->context = context;
321   silc_async_init(&e->op, silc_softacc_pkcs_abort, NULL, e);
322
323   /* Run */
324   silc_thread_pool_run(sa->tp, TRUE, sa->schedule, silc_softacc_pkcs_thread, e,
325                        silc_softacc_pkcs_completion, e);
326
327   return &e->op;
328 }
329
330 /* Acceleted decrypt */
331
332 SILC_PKCS_ALG_DECRYPT(silc_softacc_decrypt)
333 {
334   SilcSoftaccPrivateKey privkey = private_key;
335   SilcStack stack;
336   SilcSoftaccExec e;
337   SilcSoftacc sa;
338
339   SILC_LOG_DEBUG(("Decrypt"));
340
341   sa = silc_global_get_var("softacc", FALSE);
342   if (!sa || !sa->schedule) {
343     SILC_LOG_ERROR(("Software accelerator not initialized"));
344     decrypt_cb(FALSE, NULL, 0, context);
345     return NULL;
346   }
347
348   stack = silc_stack_alloc(2048, silc_crypto_stack());
349
350   e = silc_scalloc(stack, 1, sizeof(*e));
351   if (!e) {
352     silc_stack_free(stack);
353     decrypt_cb(FALSE, NULL, 0, context);
354     return NULL;
355   }
356
357   silc_stack_push(stack, NULL);
358
359   e->stack = stack;
360   e->type = SILC_SOFTACC_DECRYPT;
361   e->src = silc_smemdup(stack, src, src_len);
362   e->src_len = src_len;
363   e->key.private_key = privkey->key;
364   e->cb.decrypt_cb = decrypt_cb;
365   e->context = context;
366   silc_async_init(&e->op, silc_softacc_pkcs_abort, NULL, e);
367
368   /* Run */
369   silc_thread_pool_run(sa->tp, TRUE, sa->schedule, silc_softacc_pkcs_thread, e,
370                        silc_softacc_pkcs_completion, e);
371
372   return &e->op;
373 }
374
375 /* Accelerated signature */
376
377 SILC_PKCS_ALG_SIGN(silc_softacc_sign)
378 {
379   SilcSoftaccPrivateKey privkey = private_key;
380   SilcStack stack;
381   SilcSoftaccExec e;
382   SilcSoftacc sa;
383
384   SILC_LOG_DEBUG(("Sign"));
385
386   sa = silc_global_get_var("softacc", FALSE);
387   if (!sa || !sa->schedule) {
388     SILC_LOG_ERROR(("Software accelerator not initialized"));
389     sign_cb(FALSE, NULL, 0, context);
390     return NULL;
391   }
392
393   stack = silc_stack_alloc(2048, silc_crypto_stack());
394
395   e = silc_scalloc(stack, 1, sizeof(*e));
396   if (!e) {
397     silc_stack_free(stack);
398     sign_cb(FALSE, NULL, 0, context);
399     return NULL;
400   }
401
402   silc_stack_push(stack, NULL);
403
404   e->stack = stack;
405   e->type = SILC_SOFTACC_SIGN;
406   e->rng = rng;
407   e->src = silc_smemdup(stack, src, src_len);
408   e->src_len = src_len;
409   e->compute_hash = compute_hash;
410   e->hash = hash;
411   e->key.private_key = privkey->key;
412   e->cb.sign_cb = sign_cb;
413   e->context = context;
414   silc_async_init(&e->op, silc_softacc_pkcs_abort, NULL, e);
415
416   /* Run */
417   silc_thread_pool_run(sa->tp, TRUE, sa->schedule, silc_softacc_pkcs_thread, e,
418                        silc_softacc_pkcs_completion, e);
419
420   return &e->op;
421 }
422
423 /* Accelerated verification */
424
425 SILC_PKCS_ALG_VERIFY(silc_softacc_verify)
426 {
427   SilcSoftaccPublicKey pubkey = public_key;
428   SilcStack stack;
429   SilcSoftaccExec e;
430   SilcSoftacc sa;
431
432   SILC_LOG_DEBUG(("Verify"));
433
434   sa = silc_global_get_var("softacc", FALSE);
435   if (!sa || !sa->schedule) {
436     SILC_LOG_ERROR(("Software accelerator not initialized"));
437     verify_cb(FALSE, context);
438     return NULL;
439   }
440
441   stack = silc_stack_alloc(2048, silc_crypto_stack());
442
443   e = silc_scalloc(stack, 1, sizeof(*e));
444   if (!e) {
445     silc_stack_free(stack);
446     verify_cb(FALSE, context);
447     return NULL;
448   }
449
450   silc_stack_push(stack, NULL);
451
452   e->stack = stack;
453   e->type = SILC_SOFTACC_VERIFY;
454   e->src = silc_smemdup(stack, signature, signature_len);
455   e->src_len = signature_len;
456   e->data = silc_smemdup(stack, data, data_len);
457   e->data_len = data_len;
458   e->compute_hash = compute_hash;
459   e->hash = hash;
460   e->key.public_key = pubkey->key;
461   e->cb.verify_cb = verify_cb;
462   e->context = context;
463   silc_async_init(&e->op, silc_softacc_pkcs_abort, NULL, e);
464
465   /* Run */
466   silc_thread_pool_run(sa->tp, TRUE, sa->schedule, silc_softacc_pkcs_thread, e,
467                        silc_softacc_pkcs_completion, e);
468
469   return &e->op;
470 }