Added full PKCS API wrapper.
[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 SILC_PKCS_PUBLIC_KEY_FREE(silc_acc_pkcs_public_key_free)
203 {
204   SilcAcceleratorPublicKey pub = public_key;
205   pub->acc->pkcs[pub->pkcs_index].
206     public_key_free(&pub->acc->pkcs[pub->pkcs_index], pub->context);
207 }
208
209 SILC_PKCS_PRIVATE_KEY_FREE(silc_acc_pkcs_private_key_free)
210 {
211   SilcAcceleratorPrivateKey prv = private_key;
212   prv->acc->pkcs[prv->pkcs_index].
213     private_key_free(&prv->acc->pkcs[prv->pkcs_index], prv->context);
214 }
215
216 SILC_PKCS_ENCRYPT(silc_acc_pkcs_encrypt)
217 {
218   SilcAcceleratorPublicKey pub = public_key;
219
220   /* Accelerate */
221   return pub->acc->pkcs[pub->pkcs_index].encrypt(
222                        &pub->acc->pkcs[pub->pkcs_index], pub->context, src,
223                        src_len, rng, encrypt_cb, context);
224 }
225
226 SILC_PKCS_DECRYPT(silc_acc_pkcs_decrypt)
227 {
228   SilcAcceleratorPrivateKey prv = private_key;
229
230   /* Accelerate */
231   return prv->acc->pkcs[prv->pkcs_index].decrypt(
232                        &prv->acc->pkcs[prv->pkcs_index], prv->context, src,
233                        src_len, decrypt_cb, context);
234 }
235
236 SILC_PKCS_SIGN(silc_acc_pkcs_sign)
237 {
238   SilcAcceleratorPrivateKey prv = private_key;
239
240   /* Accelerate */
241   return prv->acc->pkcs[prv->pkcs_index].sign(
242                        &prv->acc->pkcs[prv->pkcs_index], prv->context, src,
243                        src_len, compute_hash, hash, sign_cb, context);
244 }
245
246 SILC_PKCS_VERIFY(silc_acc_pkcs_verify)
247 {
248   SilcAcceleratorPublicKey pub = public_key;
249
250   /* Accelerate */
251   return pub->acc->pkcs[pub->pkcs_index].verify(
252                        &pub->acc->pkcs[pub->pkcs_index], pub->context,
253                        signature, signature_len, data, data_len, hash,
254                        verify_cb, context);
255 }
256
257 /*************************** SILC Accelerator API ***************************/
258
259 /* Accelerate public key */
260
261 SilcPublicKey silc_acc_public_key(SilcAccelerator acc,
262                                   SilcPublicKey public_key)
263 {
264   SilcPublicKey pubkey;
265   SilcAcceleratorPublicKey acc_pubkey;
266   const SilcPKCSAlgorithm *alg;
267   int i;
268
269   if (!acc || !public_key)
270     return NULL;
271
272   SILC_LOG_DEBUG(("Accelerate public key %p with accelerator %s",
273                   public_key, acc->name));
274
275   if (!acc->pkcs) {
276     SILC_LOG_ERROR(("Accelerator '%s' does not support public key "
277                     "acceleration", acc->name));
278     return NULL;
279   }
280
281   /* Check that accelerator supports this public key algorithm */
282   alg = silc_pkcs_get_algorithm(public_key);
283   if (!alg)
284     return NULL;
285   for (i = 0; acc->pkcs[i].name; i++) {
286     if ((!strcmp(acc->pkcs[i].name, alg->name) &&
287          !strcmp(acc->pkcs[i].scheme, alg->scheme)) ||
288         !strcmp(acc->pkcs[i].name, "any")) {
289       alg = NULL;
290       break;
291     }
292   }
293   if (alg) {
294     SILC_LOG_DEBUG(("Accelerator %s does not support %s/%s acceleration",
295                     alg->name, alg->scheme));
296     return NULL;
297   }
298
299   pubkey = silc_calloc(1, sizeof(*pubkey));
300   if (!pubkey)
301     return NULL;
302
303   /* Allocate PKCS operations */
304   pubkey->pkcs = silc_calloc(1, sizeof(*pubkey->pkcs));
305   if (!pubkey->pkcs) {
306     silc_free(pubkey);
307     return NULL;
308   }
309   *pubkey->pkcs = silc_acc_pkcs;
310   pubkey->pkcs->type = silc_pkcs_get_type(public_key);
311   pubkey->alg = silc_pkcs_get_algorithm(public_key);
312
313   /* Allocate accelerator public key */
314   acc_pubkey = silc_calloc(1, sizeof(*acc_pubkey));
315   if (!acc_pubkey) {
316     silc_free(pubkey->pkcs);
317     silc_free(pubkey);
318     return NULL;
319   }
320   acc_pubkey->magic = SILC_ACC_KEY_MAGIC;
321   acc_pubkey->accelerated = public_key;
322   acc_pubkey->acc = acc;
323   acc_pubkey->pkcs_index = i;
324
325   /* Accelerate the public key.  Returns accelerator context. */
326   if (!acc->pkcs->import_public_key(&acc->pkcs[i], public_key, 0,
327                                     &acc_pubkey->context)) {
328     SILC_LOG_ERROR(("Error accelerating public key with accelerator '%s'",
329                     acc->name));
330     silc_free(acc_pubkey);
331     silc_free(pubkey->pkcs);
332     silc_free(pubkey);
333     return NULL;
334   }
335   pubkey->public_key = acc_pubkey;
336
337   SILC_LOG_DEBUG(("New accelerated public key %p", pubkey));
338
339   return pubkey;
340 }
341
342 /* Accelerate private key */
343
344 SilcPrivateKey silc_acc_private_key(SilcAccelerator acc,
345                                     SilcPrivateKey private_key)
346 {
347   SilcPrivateKey privkey;
348   SilcAcceleratorPrivateKey acc_privkey;
349   const SilcPKCSAlgorithm *alg;
350   int i;
351
352   if (!acc || !private_key)
353     return NULL;
354
355   SILC_LOG_DEBUG(("Accelerate private key %p with accelerator %s",
356                   private_key, acc->name));
357
358   if (!acc->pkcs) {
359     SILC_LOG_ERROR(("Accelerator '%s' does not support private key "
360                     "acceleration", acc->name));
361     return NULL;
362   }
363
364   /* Check that accelerator supports this private key algorithm */
365   alg = silc_pkcs_get_algorithm(private_key);
366   if (!alg)
367     return NULL;
368   for (i = 0; acc->pkcs[i].name; i++) {
369     if ((!strcmp(acc->pkcs[i].name, alg->name) &&
370          !strcmp(acc->pkcs[i].scheme, alg->scheme)) ||
371         !strcmp(acc->pkcs[i].name, "any")) {
372       alg = NULL;
373       break;
374     }
375   }
376   if (alg) {
377     SILC_LOG_DEBUG(("Accelerator %s does not support %s/%s acceleration",
378                     alg->name, alg->scheme));
379     return NULL;
380   }
381
382   privkey = silc_calloc(1, sizeof(*privkey));
383   if (!privkey)
384     return NULL;
385
386   /* Allocate PKCS operations */
387   privkey->pkcs = silc_calloc(1, sizeof(*privkey->pkcs));
388   if (!privkey->pkcs) {
389     silc_free(privkey);
390     return NULL;
391   }
392   *privkey->pkcs = silc_acc_pkcs;
393   privkey->pkcs->type = silc_pkcs_get_type(private_key);
394   privkey->alg = silc_pkcs_get_algorithm(private_key);
395
396   /* Allocate accelerator public key */
397   acc_privkey = silc_calloc(1, sizeof(*acc_privkey));
398   if (!acc_privkey) {
399     silc_free(privkey->pkcs);
400     silc_free(privkey);
401     return NULL;
402   }
403   acc_privkey->magic = SILC_ACC_KEY_MAGIC;
404   acc_privkey->accelerated = private_key;
405   acc_privkey->acc = acc;
406   acc_privkey->pkcs_index = i;
407
408   /* Accelerate the public key.  Returns accelerator context. */
409   if (!acc->pkcs->import_private_key(&acc->pkcs[i], private_key, 0,
410                                      &acc_privkey->context)) {
411     SILC_LOG_ERROR(("Error accelerating private key with accelerator '%s'",
412                     acc->name));
413     silc_free(acc_privkey);
414     silc_free(privkey->pkcs);
415     silc_free(privkey);
416     return NULL;
417   }
418   privkey->private_key = acc_privkey;
419
420   SILC_LOG_DEBUG(("New accelerated private key %p", privkey));
421
422   return privkey;
423 }
424
425 /* Get associated public key */
426
427 SilcPublicKey silc_acc_get_public_key(SilcAccelerator acc,
428                                       SilcPublicKey public_key)
429 {
430   SilcAcceleratorPublicKey pubkey;
431
432   if (!public_key)
433     return NULL;
434
435   if (public_key->pkcs->get_algorithm != silc_acc_pkcs_get_algorithm)
436     return NULL;
437
438   pubkey = public_key->public_key;
439
440   return pubkey->accelerated;
441 }
442
443 /* Get associated private key */
444
445 SilcPrivateKey silc_acc_get_private_key(SilcAccelerator acc,
446                                         SilcPrivateKey private_key)
447 {
448   SilcAcceleratorPrivateKey privkey;
449
450   if (!private_key)
451     return NULL;
452
453   if (private_key->pkcs->get_algorithm != silc_acc_pkcs_get_algorithm)
454     return NULL;
455
456   privkey = private_key->private_key;
457
458   return privkey->accelerated;
459 }