Added synchronous and asynchronous PKCS calls.
[crypto.git] / lib / silcacc / silcacc_pkcs.c
1 /*
2
3   silcacc_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
22 /************************** Types and definitions ***************************/
23
24 #define SILC_ACC_KEY_MAGIC 0xfde09137
25
26 SILC_PKCS_GET_ALGORITHM(silc_acc_pkcs_get_algorithm);
27 SILC_PKCS_IMPORT_PUBLIC_KEY_FILE(silc_acc_pkcs_import_public_key_file);
28 SILC_PKCS_IMPORT_PUBLIC_KEY(silc_acc_pkcs_import_public_key);
29 SILC_PKCS_EXPORT_PUBLIC_KEY_FILE(silc_acc_pkcs_export_public_key_file);
30 SILC_PKCS_EXPORT_PUBLIC_KEY(silc_acc_pkcs_export_public_key);
31 SILC_PKCS_PUBLIC_KEY_BITLEN(silc_acc_pkcs_public_key_bitlen);
32 SILC_PKCS_PUBLIC_KEY_COPY(silc_acc_pkcs_public_key_copy);
33 SILC_PKCS_PUBLIC_KEY_COMPARE(silc_acc_pkcs_public_key_compare);
34 SILC_PKCS_PUBLIC_KEY_FREE(silc_acc_pkcs_public_key_free);
35 SILC_PKCS_IMPORT_PRIVATE_KEY_FILE(silc_acc_pkcs_import_private_key_file);
36 SILC_PKCS_IMPORT_PRIVATE_KEY(silc_acc_pkcs_import_private_key);
37 SILC_PKCS_EXPORT_PRIVATE_KEY_FILE(silc_acc_pkcs_export_private_key_file);
38 SILC_PKCS_EXPORT_PRIVATE_KEY(silc_acc_pkcs_export_private_key);
39 SILC_PKCS_PRIVATE_KEY_BITLEN(silc_acc_pkcs_private_key_bitlen);
40 SILC_PKCS_PRIVATE_KEY_FREE(silc_acc_pkcs_private_key_free);
41 SILC_PKCS_ENCRYPT(silc_acc_pkcs_encrypt);
42 SILC_PKCS_DECRYPT(silc_acc_pkcs_decrypt);
43 SILC_PKCS_SIGN(silc_acc_pkcs_sign);
44 SILC_PKCS_VERIFY(silc_acc_pkcs_verify);
45
46 /* Accelerator public key */
47 typedef struct {
48   SilcUInt32 magic;
49   int pkcs_index;               /* Accelerator PKCS index */
50   SilcAccelerator acc;          /* The accelerator */
51   void *context;                /* Accelerator context */
52   SilcPublicKey accelerated;    /* Associated public key */
53 } *SilcAcceleratorPublicKey;
54
55 /* Accelerator private key */
56 typedef struct {
57   SilcUInt32 magic;
58   int pkcs_index;               /* Accelerator PKCS index */
59   SilcAccelerator acc;          /* The accelerator */
60   void *context;                /* Accelerator context */
61   SilcPrivateKey accelerated;   /* Associated private key */
62 } *SilcAcceleratorPrivateKey;
63
64 /*************************** Accelerator PKCS API ***************************/
65
66 /* The PKCS API for the accelerated public key and private key is simply
67    a wrapper for the underlaying key.  Encrypt, decrypt, sign and verify
68    operations are accelerated by calling the accelerator operations. */
69
70 const SilcPKCSObject silc_acc_pkcs =
71 {
72   SILC_PKCS_SILC,
73
74   /* Wrappers */
75   silc_acc_pkcs_get_algorithm,
76   silc_acc_pkcs_import_public_key_file,
77   silc_acc_pkcs_import_public_key,
78   silc_acc_pkcs_export_public_key_file,
79   silc_acc_pkcs_export_public_key,
80   silc_acc_pkcs_public_key_bitlen,
81   silc_acc_pkcs_public_key_copy,
82   silc_acc_pkcs_public_key_compare,
83   silc_acc_pkcs_public_key_free,
84   silc_acc_pkcs_import_private_key_file,
85   silc_acc_pkcs_import_private_key,
86   silc_acc_pkcs_export_private_key_file,
87   silc_acc_pkcs_export_private_key,
88   silc_acc_pkcs_private_key_bitlen,
89   silc_acc_pkcs_private_key_free,
90
91   /* Accelerated */
92   silc_acc_pkcs_encrypt,
93   silc_acc_pkcs_decrypt,
94   silc_acc_pkcs_sign,
95   silc_acc_pkcs_verify
96 };
97
98 SILC_PKCS_GET_ALGORITHM(silc_acc_pkcs_get_algorithm)
99 {
100   SilcAcceleratorPublicKey pub = public_key;
101   return pub->accelerated->pkcs->get_algorithm(pub->accelerated->pkcs,
102                                                pub->accelerated->public_key);
103 }
104
105 SILC_PKCS_IMPORT_PUBLIC_KEY_FILE(silc_acc_pkcs_import_public_key_file)
106 {
107   /* Not implemented */
108   return FALSE;
109 }
110
111 SILC_PKCS_IMPORT_PUBLIC_KEY(silc_acc_pkcs_import_public_key)
112 {
113   /* Not implemented */
114   return FALSE;
115 }
116
117 SILC_PKCS_EXPORT_PUBLIC_KEY_FILE(silc_acc_pkcs_export_public_key_file)
118 {
119   SilcAcceleratorPublicKey pub = public_key;
120   return pub->accelerated->pkcs->
121     export_public_key_file(pub->accelerated->pkcs, NULL,
122                            pub->accelerated->public_key,
123                            encoding, ret_len);
124 }
125
126 SILC_PKCS_EXPORT_PUBLIC_KEY(silc_acc_pkcs_export_public_key)
127 {
128   SilcAcceleratorPublicKey pub = public_key;
129   return pub->accelerated->pkcs->export_public_key(pub->accelerated->pkcs,
130                                                    NULL,
131                                                    pub->accelerated->public_key,
132                                                    ret_len);
133 }
134
135 SILC_PKCS_PUBLIC_KEY_BITLEN(silc_acc_pkcs_public_key_bitlen)
136 {
137   SilcAcceleratorPublicKey pub = public_key;
138   return pub->accelerated->pkcs->
139     public_key_bitlen(pub->accelerated->pkcs,
140                       pub->accelerated->public_key);
141 }
142
143 SILC_PKCS_PUBLIC_KEY_COPY(silc_acc_pkcs_public_key_copy)
144 {
145   SilcAcceleratorPublicKey pub = public_key;
146   return pub->accelerated->pkcs->public_key_copy(pub->accelerated->pkcs,
147                                                  pub->accelerated->public_key);
148 }
149
150 SILC_PKCS_PUBLIC_KEY_COMPARE(silc_acc_pkcs_public_key_compare)
151 {
152   SilcAcceleratorPublicKey pub;
153
154   pub = key2;
155   if (pub->magic == SILC_ACC_KEY_MAGIC)
156     key2 = pub->accelerated->public_key;
157
158   pub = key1;
159
160   return pub->accelerated->pkcs->
161     public_key_compare(pub->accelerated->pkcs,
162                        pub->accelerated->public_key, key2);
163 }
164
165 SILC_PKCS_IMPORT_PRIVATE_KEY_FILE(silc_acc_pkcs_import_private_key_file)
166 {
167   /* Not implemented */
168   return FALSE;
169 }
170
171 SILC_PKCS_IMPORT_PRIVATE_KEY(silc_acc_pkcs_import_private_key)
172 {
173   /* Not implemented */
174   return FALSE;
175 }
176
177 SILC_PKCS_EXPORT_PRIVATE_KEY_FILE(silc_acc_pkcs_export_private_key_file)
178 {
179   SilcAcceleratorPrivateKey prv = private_key;
180   return prv->accelerated->pkcs->
181     export_private_key_file(prv->accelerated->pkcs, stack,
182                             prv->accelerated->private_key, passphrase,
183                             passphrase_len, encoding, rng, ret_len);
184 }
185
186 SILC_PKCS_EXPORT_PRIVATE_KEY(silc_acc_pkcs_export_private_key)
187 {
188   SilcAcceleratorPrivateKey prv = private_key;
189   return prv->accelerated->pkcs->
190     export_private_key(prv->accelerated->pkcs, stack,
191                        prv->accelerated->private_key, ret_len);
192 }
193
194 SILC_PKCS_PRIVATE_KEY_BITLEN(silc_acc_pkcs_private_key_bitlen)
195 {
196   SilcAcceleratorPrivateKey prv = private_key;
197   return prv->accelerated->pkcs->
198     private_key_bitlen(prv->accelerated->pkcs,
199                        prv->accelerated->private_key);
200 }
201
202 /* Accelerator routines follow */
203
204 SILC_PKCS_PUBLIC_KEY_FREE(silc_acc_pkcs_public_key_free)
205 {
206   SilcAcceleratorPublicKey pub = public_key;
207   pub->acc->pkcs[pub->pkcs_index].
208     public_key_free(&pub->acc->pkcs[pub->pkcs_index], pub->context);
209 }
210
211 SILC_PKCS_PRIVATE_KEY_FREE(silc_acc_pkcs_private_key_free)
212 {
213   SilcAcceleratorPrivateKey prv = private_key;
214   prv->acc->pkcs[prv->pkcs_index].
215     private_key_free(&prv->acc->pkcs[prv->pkcs_index], prv->context);
216 }
217
218 SILC_PKCS_ENCRYPT(silc_acc_pkcs_encrypt)
219 {
220   SilcAcceleratorPublicKey pub = public_key;
221
222   /* Accelerate */
223   return pub->acc->pkcs[pub->pkcs_index].encrypt(
224                        &pub->acc->pkcs[pub->pkcs_index], pub->context, src,
225                        src_len, rng, encrypt_cb, context);
226 }
227
228 SILC_PKCS_DECRYPT(silc_acc_pkcs_decrypt)
229 {
230   SilcAcceleratorPrivateKey prv = private_key;
231
232   /* Accelerate */
233   return prv->acc->pkcs[prv->pkcs_index].decrypt(
234                        &prv->acc->pkcs[prv->pkcs_index], prv->context, src,
235                        src_len, decrypt_cb, context);
236 }
237
238 SILC_PKCS_SIGN(silc_acc_pkcs_sign)
239 {
240   SilcAcceleratorPrivateKey prv = private_key;
241
242   /* Accelerate */
243   return prv->acc->pkcs[prv->pkcs_index].sign(
244                        &prv->acc->pkcs[prv->pkcs_index], prv->context, src,
245                        src_len, compute_hash, hash, rng, sign_cb, context);
246 }
247
248 SILC_PKCS_VERIFY(silc_acc_pkcs_verify)
249 {
250   SilcAcceleratorPublicKey pub = public_key;
251
252   /* Accelerate */
253   return pub->acc->pkcs[pub->pkcs_index].verify(
254                        &pub->acc->pkcs[pub->pkcs_index], pub->context,
255                        signature, signature_len, data, data_len,
256                        compute_hash, hash, rng,
257                        verify_cb, context);
258 }
259
260 /*************************** SILC Accelerator API ***************************/
261
262 /* Accelerate public key */
263
264 SilcPublicKey silc_acc_public_key(SilcAccelerator acc,
265                                   SilcPublicKey public_key)
266 {
267   SilcPublicKey pubkey;
268   SilcAcceleratorPublicKey acc_pubkey;
269   const SilcPKCSAlgorithm *alg;
270   int i;
271
272   if (!acc || !public_key)
273     return NULL;
274
275   SILC_LOG_DEBUG(("Accelerate public key %p with accelerator %s",
276                   public_key, acc->name));
277
278   if (!acc->pkcs) {
279     SILC_LOG_ERROR(("Accelerator '%s' does not support public key "
280                     "acceleration", acc->name));
281     return NULL;
282   }
283
284   if (silc_acc_get_public_key(NULL, public_key)) {
285     SILC_LOG_DEBUG(("Pubilc key %p is already accelerated", public_key));
286     return NULL;
287   }
288
289   /* Check that accelerator supports this public key algorithm */
290   alg = silc_pkcs_get_algorithm(public_key);
291   if (!alg)
292     return NULL;
293   for (i = 0; acc->pkcs[i].name; i++) {
294     if ((!strcmp(acc->pkcs[i].name, alg->name) &&
295          !strcmp(acc->pkcs[i].scheme, alg->scheme)) ||
296         !strcmp(acc->pkcs[i].name, "any")) {
297       alg = NULL;
298       break;
299     }
300   }
301   if (alg) {
302     SILC_LOG_DEBUG(("Accelerator %s does not support %s/%s acceleration",
303                     acc->name, alg->name, alg->scheme));
304     return NULL;
305   }
306
307   pubkey = silc_calloc(1, sizeof(*pubkey));
308   if (!pubkey)
309     return NULL;
310
311   /* Allocate PKCS operations */
312   pubkey->pkcs = silc_calloc(1, sizeof(*pubkey->pkcs));
313   if (!pubkey->pkcs) {
314     silc_free(pubkey);
315     return NULL;
316   }
317   *pubkey->pkcs = silc_acc_pkcs;
318   pubkey->pkcs->type = silc_pkcs_get_type(public_key);
319   pubkey->alg = silc_pkcs_get_algorithm(public_key);
320
321   /* Allocate accelerator public key */
322   acc_pubkey = silc_calloc(1, sizeof(*acc_pubkey));
323   if (!acc_pubkey) {
324     silc_free(pubkey->pkcs);
325     silc_free(pubkey);
326     return NULL;
327   }
328   acc_pubkey->magic = SILC_ACC_KEY_MAGIC;
329   acc_pubkey->accelerated = public_key;
330   acc_pubkey->acc = acc;
331   acc_pubkey->pkcs_index = i;
332
333   /* Accelerate the public key.  Returns accelerator context. */
334   if (!acc->pkcs[i].import_public_key(&acc->pkcs[i], public_key, 0,
335                                       &acc_pubkey->context)) {
336     SILC_LOG_DEBUG(("Error accelerating public key with accelerator '%s'",
337                     acc->name));
338     silc_free(acc_pubkey);
339     silc_free(pubkey->pkcs);
340     silc_free(pubkey);
341     return NULL;
342   }
343   pubkey->public_key = acc_pubkey;
344
345   SILC_LOG_DEBUG(("New accelerated public key %p", pubkey));
346
347   return pubkey;
348 }
349
350 /* Accelerate private key */
351
352 SilcPrivateKey silc_acc_private_key(SilcAccelerator acc,
353                                     SilcPrivateKey private_key)
354 {
355   SilcPrivateKey privkey;
356   SilcAcceleratorPrivateKey acc_privkey;
357   const SilcPKCSAlgorithm *alg;
358   int i;
359
360   if (!acc || !private_key)
361     return NULL;
362
363   SILC_LOG_DEBUG(("Accelerate private key %p with accelerator %s",
364                   private_key, acc->name));
365
366   if (!acc->pkcs) {
367     SILC_LOG_ERROR(("Accelerator '%s' does not support private key "
368                     "acceleration", acc->name));
369     return NULL;
370   }
371
372   if (silc_acc_get_private_key(NULL, private_key)) {
373     SILC_LOG_DEBUG(("Private key %p is already accelerated", private_key));
374     return NULL;
375   }
376
377   /* Check that accelerator supports this private key algorithm */
378   alg = silc_pkcs_get_algorithm(private_key);
379   if (!alg)
380     return NULL;
381   for (i = 0; acc->pkcs[i].name; i++) {
382     if ((!strcmp(acc->pkcs[i].name, alg->name) &&
383          !strcmp(acc->pkcs[i].scheme, alg->scheme)) ||
384         !strcmp(acc->pkcs[i].name, "any")) {
385       alg = NULL;
386       break;
387     }
388   }
389   if (alg) {
390     SILC_LOG_DEBUG(("Accelerator %s does not support %s/%s acceleration",
391                     acc->name, alg->name, alg->scheme));
392     return NULL;
393   }
394
395   privkey = silc_calloc(1, sizeof(*privkey));
396   if (!privkey)
397     return NULL;
398
399   /* Allocate PKCS operations */
400   privkey->pkcs = silc_calloc(1, sizeof(*privkey->pkcs));
401   if (!privkey->pkcs) {
402     silc_free(privkey);
403     return NULL;
404   }
405   *privkey->pkcs = silc_acc_pkcs;
406   privkey->pkcs->type = silc_pkcs_get_type(private_key);
407   privkey->alg = silc_pkcs_get_algorithm(private_key);
408
409   /* Allocate accelerator public key */
410   acc_privkey = silc_calloc(1, sizeof(*acc_privkey));
411   if (!acc_privkey) {
412     silc_free(privkey->pkcs);
413     silc_free(privkey);
414     return NULL;
415   }
416   acc_privkey->magic = SILC_ACC_KEY_MAGIC;
417   acc_privkey->accelerated = private_key;
418   acc_privkey->acc = acc;
419   acc_privkey->pkcs_index = i;
420
421   /* Accelerate the public key.  Returns accelerator context.  The
422      import_public_key operation is used to accelerate the key. */
423   if (!acc->pkcs[i].import_private_key(&acc->pkcs[i], private_key, 0,
424                                        &acc_privkey->context)) {
425     SILC_LOG_ERROR(("Error accelerating private key with accelerator '%s'",
426                     acc->name));
427     silc_free(acc_privkey);
428     silc_free(privkey->pkcs);
429     silc_free(privkey);
430     return NULL;
431   }
432   privkey->private_key = acc_privkey;
433
434   SILC_LOG_DEBUG(("New accelerated private key %p", privkey));
435
436   return privkey;
437 }
438
439 /* Get associated public key */
440
441 SilcPublicKey silc_acc_get_public_key(SilcAccelerator acc,
442                                       SilcPublicKey public_key)
443 {
444   SilcAcceleratorPublicKey pubkey;
445
446   if (!public_key)
447     return NULL;
448
449   if (public_key->pkcs->get_algorithm != silc_acc_pkcs_get_algorithm)
450     return NULL;
451
452   pubkey = public_key->public_key;
453
454   return pubkey->accelerated;
455 }
456
457 /* Get associated private key */
458
459 SilcPrivateKey silc_acc_get_private_key(SilcAccelerator acc,
460                                         SilcPrivateKey private_key)
461 {
462   SilcAcceleratorPrivateKey privkey;
463
464   if (!private_key)
465     return NULL;
466
467   if (private_key->pkcs->get_algorithm != silc_acc_pkcs_get_algorithm)
468     return NULL;
469
470   privkey = private_key->private_key;
471
472   return privkey->accelerated;
473 }