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