Added SILC Thread Queue API
[silc.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 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 "silc.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, hash, rng,
256                        verify_cb, context);
257 }
258
259 /*************************** SILC Accelerator API ***************************/
260
261 /* Accelerate public key */
262
263 SilcPublicKey silc_acc_public_key(SilcAccelerator acc,
264                                   SilcPublicKey public_key)
265 {
266   SilcPublicKey pubkey;
267   SilcAcceleratorPublicKey acc_pubkey;
268   const SilcPKCSAlgorithm *alg;
269   int i;
270
271   if (!acc || !public_key)
272     return NULL;
273
274   SILC_LOG_DEBUG(("Accelerate public key %p with accelerator %s",
275                   public_key, acc->name));
276
277   if (!acc->pkcs) {
278     SILC_LOG_ERROR(("Accelerator '%s' does not support public key "
279                     "acceleration", acc->name));
280     return NULL;
281   }
282
283   if (silc_acc_get_public_key(NULL, public_key)) {
284     SILC_LOG_DEBUG(("Pubilc key %p is already accelerated", public_key));
285     return NULL;
286   }
287
288   /* Check that accelerator supports this public key algorithm */
289   alg = silc_pkcs_get_algorithm(public_key);
290   if (!alg)
291     return NULL;
292   for (i = 0; acc->pkcs[i].name; i++) {
293     if ((!strcmp(acc->pkcs[i].name, alg->name) &&
294          !strcmp(acc->pkcs[i].scheme, alg->scheme)) ||
295         !strcmp(acc->pkcs[i].name, "any")) {
296       alg = NULL;
297       break;
298     }
299   }
300   if (alg) {
301     SILC_LOG_DEBUG(("Accelerator %s does not support %s/%s acceleration",
302                     acc->name, alg->name, alg->scheme));
303     return NULL;
304   }
305
306   pubkey = silc_calloc(1, sizeof(*pubkey));
307   if (!pubkey)
308     return NULL;
309
310   /* Allocate PKCS operations */
311   pubkey->pkcs = silc_calloc(1, sizeof(*pubkey->pkcs));
312   if (!pubkey->pkcs) {
313     silc_free(pubkey);
314     return NULL;
315   }
316   *pubkey->pkcs = silc_acc_pkcs;
317   pubkey->pkcs->type = silc_pkcs_get_type(public_key);
318   pubkey->alg = silc_pkcs_get_algorithm(public_key);
319
320   /* Allocate accelerator public key */
321   acc_pubkey = silc_calloc(1, sizeof(*acc_pubkey));
322   if (!acc_pubkey) {
323     silc_free(pubkey->pkcs);
324     silc_free(pubkey);
325     return NULL;
326   }
327   acc_pubkey->magic = SILC_ACC_KEY_MAGIC;
328   acc_pubkey->accelerated = public_key;
329   acc_pubkey->acc = acc;
330   acc_pubkey->pkcs_index = i;
331
332   /* Accelerate the public key.  Returns accelerator context. */
333   if (!acc->pkcs[i].import_public_key(&acc->pkcs[i], public_key, 0,
334                                       &acc_pubkey->context)) {
335     SILC_LOG_ERROR(("Error accelerating public key with accelerator '%s'",
336                     acc->name));
337     silc_free(acc_pubkey);
338     silc_free(pubkey->pkcs);
339     silc_free(pubkey);
340     return NULL;
341   }
342   pubkey->public_key = acc_pubkey;
343
344   SILC_LOG_DEBUG(("New accelerated public key %p", pubkey));
345
346   return pubkey;
347 }
348
349 /* Accelerate private key */
350
351 SilcPrivateKey silc_acc_private_key(SilcAccelerator acc,
352                                     SilcPrivateKey private_key)
353 {
354   SilcPrivateKey privkey;
355   SilcAcceleratorPrivateKey acc_privkey;
356   const SilcPKCSAlgorithm *alg;
357   int i;
358
359   if (!acc || !private_key)
360     return NULL;
361
362   SILC_LOG_DEBUG(("Accelerate private key %p with accelerator %s",
363                   private_key, acc->name));
364
365   if (!acc->pkcs) {
366     SILC_LOG_ERROR(("Accelerator '%s' does not support private key "
367                     "acceleration", acc->name));
368     return NULL;
369   }
370
371   if (silc_acc_get_private_key(NULL, private_key)) {
372     SILC_LOG_DEBUG(("Private key %p is already accelerated", private_key));
373     return NULL;
374   }
375
376   /* Check that accelerator supports this private key algorithm */
377   alg = silc_pkcs_get_algorithm(private_key);
378   if (!alg)
379     return NULL;
380   for (i = 0; acc->pkcs[i].name; i++) {
381     if ((!strcmp(acc->pkcs[i].name, alg->name) &&
382          !strcmp(acc->pkcs[i].scheme, alg->scheme)) ||
383         !strcmp(acc->pkcs[i].name, "any")) {
384       alg = NULL;
385       break;
386     }
387   }
388   if (alg) {
389     SILC_LOG_DEBUG(("Accelerator %s does not support %s/%s acceleration",
390                     acc->name, alg->name, alg->scheme));
391     return NULL;
392   }
393
394   privkey = silc_calloc(1, sizeof(*privkey));
395   if (!privkey)
396     return NULL;
397
398   /* Allocate PKCS operations */
399   privkey->pkcs = silc_calloc(1, sizeof(*privkey->pkcs));
400   if (!privkey->pkcs) {
401     silc_free(privkey);
402     return NULL;
403   }
404   *privkey->pkcs = silc_acc_pkcs;
405   privkey->pkcs->type = silc_pkcs_get_type(private_key);
406   privkey->alg = silc_pkcs_get_algorithm(private_key);
407
408   /* Allocate accelerator public key */
409   acc_privkey = silc_calloc(1, sizeof(*acc_privkey));
410   if (!acc_privkey) {
411     silc_free(privkey->pkcs);
412     silc_free(privkey);
413     return NULL;
414   }
415   acc_privkey->magic = SILC_ACC_KEY_MAGIC;
416   acc_privkey->accelerated = private_key;
417   acc_privkey->acc = acc;
418   acc_privkey->pkcs_index = i;
419
420   /* Accelerate the public key.  Returns accelerator context. */
421   if (!acc->pkcs[i].import_private_key(&acc->pkcs[i], private_key, 0,
422                                        &acc_privkey->context)) {
423     SILC_LOG_ERROR(("Error accelerating private key with accelerator '%s'",
424                     acc->name));
425     silc_free(acc_privkey);
426     silc_free(privkey->pkcs);
427     silc_free(privkey);
428     return NULL;
429   }
430   privkey->private_key = acc_privkey;
431
432   SILC_LOG_DEBUG(("New accelerated private key %p", privkey));
433
434   return privkey;
435 }
436
437 /* Get associated public key */
438
439 SilcPublicKey silc_acc_get_public_key(SilcAccelerator acc,
440                                       SilcPublicKey public_key)
441 {
442   SilcAcceleratorPublicKey pubkey;
443
444   if (!public_key)
445     return NULL;
446
447   if (public_key->pkcs->get_algorithm != silc_acc_pkcs_get_algorithm)
448     return NULL;
449
450   pubkey = public_key->public_key;
451
452   return pubkey->accelerated;
453 }
454
455 /* Get associated private key */
456
457 SilcPrivateKey silc_acc_get_private_key(SilcAccelerator acc,
458                                         SilcPrivateKey private_key)
459 {
460   SilcAcceleratorPrivateKey privkey;
461
462   if (!private_key)
463     return NULL;
464
465   if (private_key->pkcs->get_algorithm != silc_acc_pkcs_get_algorithm)
466     return NULL;
467
468   privkey = private_key->private_key;
469
470   return privkey->accelerated;
471 }