updates. New data types.
[silc.git] / lib / silccrypt / silcpkcs.c
1 /*
2
3   silcpkcs.c
4
5   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
6
7   Copyright (C) 1997 - 2001 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; either version 2 of the License, or
12   (at your option) any later version.
13   
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19 */
20 /* $Id$ */
21
22 #include "silcincludes.h"
23
24 #include "rsa.h"
25 #include "pkcs1.h"
26
27 /* List of all PKCS's in SILC. PKCS's don't support SIM's thus
28    only static declarations are possible. XXX: I hope this to change
29    real soon. */
30 SilcPKCSObject silc_pkcs_list[] =
31 {
32   /* RSA with PKCS #1 (Uses directly routines from Raw RSA operations) */
33   { "rsa", &silc_rsa_data_context, 
34     silc_rsa_init, silc_rsa_clear_keys, silc_rsa_get_public_key,
35     silc_rsa_get_private_key, silc_rsa_set_public_key,
36     silc_rsa_set_private_key, silc_rsa_context_len,
37     silc_rsa_data_context_len, silc_rsa_set_arg,
38     silc_pkcs1_encrypt, silc_pkcs1_decrypt,
39     silc_pkcs1_sign, silc_pkcs1_verify },
40
41   /* Raw RSA operations */
42   { "rsa-raw", &silc_rsa_data_context, 
43     silc_rsa_init, silc_rsa_clear_keys, silc_rsa_get_public_key,
44     silc_rsa_get_private_key, silc_rsa_set_public_key,
45     silc_rsa_set_private_key, silc_rsa_context_len,
46     silc_rsa_data_context_len, silc_rsa_set_arg,
47     silc_rsa_encrypt, silc_rsa_decrypt,
48     silc_rsa_sign, silc_rsa_verify },
49
50   { NULL, NULL, NULL, NULL, NULL,
51     NULL, NULL, NULL, NULL, NULL, NULL }
52 };
53
54 /* Allocates a new SilcPKCS object. The new allocated object is returned
55    to the 'new_pkcs' argument. This function also initializes the data
56    context structure. Function returns 1 on success and 0 on error.
57
58 */
59 int silc_pkcs_alloc(const unsigned char *name, SilcPKCS *new_pkcs)
60 {
61   int i;
62
63   SILC_LOG_DEBUG(("Allocating new PKCS object"));
64
65   for (i = 0; silc_pkcs_list[i].name; i++) {
66     if (!strcmp(silc_pkcs_list[i].name, name))
67       break;
68   }
69
70   if (silc_pkcs_list[i].name == NULL)
71     return FALSE;
72
73   *new_pkcs = silc_calloc(1, sizeof(**new_pkcs));
74
75   /* Set the pointers */
76   (*new_pkcs)->pkcs = &silc_pkcs_list[i];
77   (*new_pkcs)->pkcs->data_context = 
78     silc_calloc(1, (*new_pkcs)->pkcs->data_context_len());
79   (*new_pkcs)->context = silc_calloc(1, (*new_pkcs)->pkcs->context_len());
80   (*new_pkcs)->get_key_len = silc_pkcs_get_key_len;
81
82   return TRUE;
83 }
84
85 /* Free's the PKCS object */
86
87 void silc_pkcs_free(SilcPKCS pkcs)
88 {
89   if (pkcs)
90     silc_free(pkcs->context);
91 }
92
93 /* Return TRUE if PKCS algorithm `name' is supported. */
94
95 int silc_pkcs_is_supported(const unsigned char *name)
96 {
97   int i;
98
99   if (!name)
100     return FALSE;
101
102   for (i = 0; silc_pkcs_list[i].name; i++) {
103     if (!strcmp(silc_pkcs_list[i].name, name))
104       return TRUE;
105   }
106
107   return FALSE;
108 }
109
110 /* Returns comma separated list of supported PKCS algorithms */
111
112 char *silc_pkcs_get_supported()
113 {
114   char *list = NULL;
115   int i, len;
116
117   len = 0;
118   for (i = 0; silc_pkcs_list[i].name; i++) {
119     len += strlen(silc_pkcs_list[i].name);
120     list = silc_realloc(list, len + 1);
121
122     memcpy(list + (len - strlen(silc_pkcs_list[i].name)), 
123            silc_pkcs_list[i].name, strlen(silc_pkcs_list[i].name));
124     memcpy(list + len, ",", 1);
125     len++;
126   }
127
128   list[len - 1] = 0;
129
130   return list;
131 }
132
133 /* Returns the length of the key */
134
135 uint32 silc_pkcs_get_key_len(SilcPKCS self)
136 {
137   return self->key_len;
138 }
139
140 /* Returns SILC style public key */
141
142 unsigned char *silc_pkcs_get_public_key(SilcPKCS pkcs, uint32 *len)
143 {
144   return pkcs->pkcs->get_public_key(pkcs->context, len);
145 }
146
147 /* Returns SILC style private key */
148
149 unsigned char *silc_pkcs_get_private_key(SilcPKCS pkcs, uint32 *len)
150 {
151   return pkcs->pkcs->get_private_key(pkcs->context, len);
152 }
153
154 /* Sets public key from SilcPublicKey. */
155
156 int silc_pkcs_public_key_set(SilcPKCS pkcs, SilcPublicKey public_key)
157 {
158   return pkcs->pkcs->set_public_key(pkcs->context, public_key->pk, 
159                                     public_key->pk_len);
160 }
161
162 /* Sets public key from data. */
163
164 int silc_pkcs_public_key_data_set(SilcPKCS pkcs, unsigned char *pk,
165                                   uint32 pk_len)
166 {
167   return pkcs->pkcs->set_public_key(pkcs->context, pk, pk_len);
168 }
169
170 /* Sets private key from SilcPrivateKey. */
171
172 int silc_pkcs_private_key_set(SilcPKCS pkcs, SilcPrivateKey private_key)
173 {
174   return pkcs->pkcs->set_private_key(pkcs->context, private_key->prv, 
175                                      private_key->prv_len);
176 }
177
178 /* Sets private key from data. */
179
180 int silc_pkcs_private_key_data_set(SilcPKCS pkcs, unsigned char *prv,
181                                    uint32 prv_len)
182 {
183   return pkcs->pkcs->set_private_key(pkcs->context, prv, prv_len);
184 }
185
186 /* Encrypts */
187
188 int silc_pkcs_encrypt(SilcPKCS pkcs, unsigned char *src, uint32 src_len,
189                       unsigned char *dst, uint32 *dst_len)
190 {
191   return pkcs->pkcs->encrypt(pkcs->context, src, src_len, dst, dst_len);
192 }
193
194 /* Decrypts */
195
196 int silc_pkcs_decrypt(SilcPKCS pkcs, unsigned char *src, uint32 src_len,
197                       unsigned char *dst, uint32 *dst_len)
198 {
199   return pkcs->pkcs->decrypt(pkcs->context, src, src_len, dst, dst_len);
200 }
201
202 /* Generates signature */
203
204 int silc_pkcs_sign(SilcPKCS pkcs, unsigned char *src, uint32 src_len,
205                    unsigned char *dst, uint32 *dst_len)
206 {
207   return pkcs->pkcs->sign(pkcs->context, src, src_len, dst, dst_len);
208 }
209
210 /* Verifies signature */
211
212 int silc_pkcs_verify(SilcPKCS pkcs, unsigned char *signature, 
213                      uint32 signature_len, unsigned char *data, 
214                      uint32 data_len)
215 {
216   return pkcs->pkcs->verify(pkcs->context, signature, signature_len, 
217                             data, data_len);
218 }
219
220 /* Generates signature with hash. The hash is signed. */
221
222 int silc_pkcs_sign_with_hash(SilcPKCS pkcs, SilcHash hash,
223                              unsigned char *src, uint32 src_len,
224                              unsigned char *dst, uint32 *dst_len)
225 {
226   unsigned char hashr[32];
227   uint32 hash_len;
228   int ret;
229
230   silc_hash_make(hash, src, src_len, hashr);
231   hash_len = hash->hash->hash_len;
232
233   SILC_LOG_HEXDUMP(("Hash"), hashr, hash_len);
234
235   ret = pkcs->pkcs->sign(pkcs->context, hashr, hash_len, dst, dst_len);
236   memset(hashr, 0, sizeof(hashr));
237
238   return ret;
239 }
240
241 /* Verifies signature with hash. The `data' is hashed and verified against
242    the `signature'. */
243
244 int silc_pkcs_verify_with_hash(SilcPKCS pkcs, SilcHash hash, 
245                                unsigned char *signature, 
246                                uint32 signature_len, 
247                                unsigned char *data, 
248                                uint32 data_len)
249 {
250   unsigned char hashr[32];
251   uint32 hash_len;
252   int ret;
253
254   silc_hash_make(hash, data, data_len, hashr);
255   hash_len = hash->hash->hash_len;
256
257   SILC_LOG_HEXDUMP(("Hash"), hashr, hash_len);
258
259   ret = pkcs->pkcs->verify(pkcs->context, signature, signature_len, 
260                            hashr, hash_len);
261   memset(hashr, 0, sizeof(hashr));
262
263   return ret;
264 }
265
266 /* Encodes and returns SILC public key identifier. If some of the 
267    arguments is NULL those are not encoded into the identifier string.
268    Protocol says that at least username and host must be provided. */
269
270 char *silc_pkcs_encode_identifier(char *username, char *host, char *realname,
271                                   char *email, char *org, char *country)
272 {
273   SilcBuffer buf;
274   char *identifier;
275   uint32 len, tlen = 0;
276
277   if (!username || !host)
278     return NULL;
279
280   len = (username ? strlen(username) : 0) +
281         (host     ? strlen(host)     : 0) +
282         (realname ? strlen(realname) : 0) +
283         (email    ? strlen(email)    : 0) +
284         (org      ? strlen(org)      : 0) +
285         (country  ? strlen(country)  : 0);
286   
287   if (len < 3)
288     return NULL;
289
290   len += 3 + 5 + 5 + 4 + 4 + 4;
291   buf = silc_buffer_alloc(len);
292   silc_buffer_pull_tail(buf, len);
293
294   if (username) {
295     silc_buffer_format(buf,
296                        SILC_STR_UI32_STRING("UN="),
297                        SILC_STR_UI32_STRING(username),
298                        SILC_STR_END);
299     silc_buffer_pull(buf, 3 + strlen(username));
300     tlen = 3 + strlen(username); 
301   }
302     
303   if (host) {
304     silc_buffer_format(buf,
305                        SILC_STR_UI32_STRING(", "),
306                        SILC_STR_UI32_STRING("HN="),
307                        SILC_STR_UI32_STRING(host),
308                        SILC_STR_END);
309     silc_buffer_pull(buf, 5 + strlen(host));
310     tlen += 5 + strlen(host); 
311   }
312
313   if (realname) {
314     silc_buffer_format(buf,
315                        SILC_STR_UI32_STRING(", "),
316                        SILC_STR_UI32_STRING("RN="),
317                        SILC_STR_UI32_STRING(realname),
318                        SILC_STR_END);
319     silc_buffer_pull(buf, 5 + strlen(realname));
320     tlen += 5 + strlen(realname); 
321   }
322
323   if (email) {
324     silc_buffer_format(buf,
325                        SILC_STR_UI32_STRING(", "),
326                        SILC_STR_UI32_STRING("E="),
327                        SILC_STR_UI32_STRING(email),
328                        SILC_STR_END);
329     silc_buffer_pull(buf, 4 + strlen(email));
330     tlen += 4 + strlen(email); 
331   }
332
333   if (org) {
334     silc_buffer_format(buf,
335                        SILC_STR_UI32_STRING(", "),
336                        SILC_STR_UI32_STRING("O="),
337                        SILC_STR_UI32_STRING(org),
338                        SILC_STR_END);
339     silc_buffer_pull(buf, 4 + strlen(org));
340     tlen += 4 + strlen(org); 
341   }
342
343   if (country) {
344     silc_buffer_format(buf,
345                        SILC_STR_UI32_STRING(", "),
346                        SILC_STR_UI32_STRING("C="),
347                        SILC_STR_UI32_STRING(country),
348                        SILC_STR_END);
349     silc_buffer_pull(buf, 4 + strlen(country));
350     tlen += 4 + strlen(country); 
351   }
352
353   silc_buffer_push(buf, buf->data - buf->head);
354   identifier = silc_calloc(tlen + 1, sizeof(*identifier));
355   memcpy(identifier, buf->data, tlen);
356   silc_buffer_free(buf);
357
358   return identifier;
359 }
360
361 /* Allocates SILC style public key formed from sent arguments. All data
362    is duplicated. */
363
364 SilcPublicKey silc_pkcs_public_key_alloc(char *name, char *identifier,
365                                          unsigned char *pk, 
366                                          uint32 pk_len)
367 {
368   SilcPublicKey public_key;
369
370   public_key = silc_calloc(1, sizeof(*public_key));
371   public_key->len = 4 + 2 + strlen(name) + 2 + strlen(identifier) + pk_len;
372   public_key->name = strdup(name);
373   public_key->identifier = strdup(identifier);
374   public_key->pk_len = pk_len;
375   public_key->pk = silc_calloc(pk_len, sizeof(*public_key->pk));
376   memcpy(public_key->pk, pk, pk_len);
377
378   return public_key;
379 }
380
381 /* Free's public key */
382
383 void silc_pkcs_public_key_free(SilcPublicKey public_key)
384 {
385   if (public_key) {
386     silc_free(public_key->name);
387     silc_free(public_key->identifier);
388     silc_free(public_key->pk);
389     silc_free(public_key);
390   }
391 }
392
393 /* Allocates SILC private key formed from sent arguments. All data is
394    duplicated. */
395
396 SilcPrivateKey silc_pkcs_private_key_alloc(char *name, unsigned char *prv,
397                                            uint32 prv_len)
398 {
399   SilcPrivateKey private_key;
400
401   private_key = silc_calloc(1, sizeof(*private_key));
402   private_key->name = strdup(name);
403   private_key->prv_len = prv_len;
404   private_key->prv = silc_calloc(prv_len, sizeof(*private_key->prv));
405   memcpy(private_key->prv, prv, prv_len);
406
407   return private_key;
408 }
409
410 /* Free's private key */
411
412 void silc_pkcs_private_key_free(SilcPrivateKey private_key)
413 {
414   if (private_key) {
415     silc_free(private_key->name);
416     silc_free(private_key->prv);
417     silc_free(private_key);
418   }
419 }
420
421 /* Encodes SILC style public key from SilcPublicKey. Returns the encoded
422    data. */
423
424 unsigned char *
425 silc_pkcs_public_key_encode(SilcPublicKey public_key, uint32 *len)
426 {
427   SilcBuffer buf;
428   unsigned char *ret;
429
430   buf = silc_buffer_alloc(public_key->len);
431   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
432
433   silc_buffer_format(buf,
434                      SILC_STR_UI_INT(public_key->len),
435                      SILC_STR_UI_SHORT(strlen(public_key->name)),
436                      SILC_STR_UI32_STRING(public_key->name),
437                      SILC_STR_UI_SHORT(strlen(public_key->identifier)),
438                      SILC_STR_UI32_STRING(public_key->identifier),
439                      SILC_STR_UI_XNSTRING(public_key->pk, 
440                                           public_key->pk_len),
441                      SILC_STR_END);
442   if (len)
443     *len = public_key->len;
444
445   ret = silc_calloc(buf->len, sizeof(*ret));
446   memcpy(ret, buf->data, buf->len);
447   silc_buffer_free(buf);
448
449   return ret;
450 }
451
452 /* Encodes SILC style public key. Returns the encoded data. */
453
454 unsigned char *
455 silc_pkcs_public_key_data_encode(unsigned char *pk, uint32 pk_len,
456                                  char *pkcs, char *identifier, 
457                                  uint32 *len)
458 {
459   SilcBuffer buf;
460   unsigned char *ret;
461   uint32 totlen;
462
463   totlen = 4 + 2 + strlen(pkcs) + 2 + strlen(identifier) + pk_len;
464   buf = silc_buffer_alloc(totlen);
465   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
466
467   silc_buffer_format(buf,
468                      SILC_STR_UI_INT(totlen),
469                      SILC_STR_UI_SHORT(strlen(pkcs)),
470                      SILC_STR_UI32_STRING(pkcs),
471                      SILC_STR_UI_SHORT(strlen(identifier)),
472                      SILC_STR_UI32_STRING(identifier),
473                      SILC_STR_UI_XNSTRING(pk, pk_len),
474                      SILC_STR_END);
475   if (len)
476     *len = totlen;
477
478   ret = silc_calloc(buf->len, sizeof(*ret));
479   memcpy(ret, buf->data, buf->len);
480   silc_buffer_free(buf);
481
482   return ret;
483 }
484
485 /* Decodes SILC style public key. Returns TRUE if the decoding was
486    successful. Allocates new public key as well. */
487
488 int silc_pkcs_public_key_decode(unsigned char *data, uint32 data_len,
489                                 SilcPublicKey *public_key)
490 {
491   SilcBuffer buf;
492   SilcPKCS alg;
493   uint16 pkcs_len, identifier_len;
494   uint32 totlen, key_len;
495   unsigned char *pkcs_name = NULL, *ident = NULL, *key_data = NULL;
496   int ret;
497
498   buf = silc_buffer_alloc(data_len);
499   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
500   silc_buffer_put(buf, data, data_len);
501
502   /* Get length */
503   ret = silc_buffer_unformat(buf,
504                              SILC_STR_UI_INT(&totlen),
505                              SILC_STR_END);
506   if (ret == -1) {
507     silc_buffer_free(buf);
508     return FALSE;
509   }
510
511   if (totlen != data_len) {
512     silc_buffer_free(buf);
513     return FALSE;
514   }
515
516   /* Get algorithm name and identifier */
517   silc_buffer_pull(buf, 4);
518   ret =
519     silc_buffer_unformat(buf,
520                          SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
521                          SILC_STR_UI16_NSTRING_ALLOC(&ident, &identifier_len),
522                          SILC_STR_END);
523   if (ret == -1)
524     goto err;
525
526   if (pkcs_len < 1 || identifier_len < 3 || 
527       pkcs_len + identifier_len > totlen)
528     goto err;
529
530   /* See if we support this algorithm */
531   if (!silc_pkcs_is_supported(pkcs_name))
532     goto err;
533
534   /* Protocol says that at least UN and HN must be provided as identifier,
535      check for these. */
536   if (!strstr(ident, "UN=") && !strstr(ident, "HN="))
537     goto err;
538
539   /* Get key data. We assume that rest of the buffer is key data. */
540   silc_buffer_pull(buf, 2 + pkcs_len + 2 + identifier_len);
541   key_len = buf->len;
542   ret = silc_buffer_unformat(buf,
543                              SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
544                              SILC_STR_END);
545   if (ret == -1)
546     goto err;
547
548   /* Try to set the key. If this fails the key must be malformed. This
549      code assumes that the PKCS routine checks the format of the key. */
550   silc_pkcs_alloc(pkcs_name, &alg);
551   if (!alg->pkcs->set_public_key(alg->context, key_data, key_len))
552     goto err;
553   silc_pkcs_free(alg);
554   
555   if (public_key) {
556     *public_key = silc_calloc(1, sizeof(**public_key));
557     (*public_key)->len = totlen;
558     (*public_key)->name = pkcs_name;
559     (*public_key)->identifier = ident;
560     (*public_key)->pk = key_data;
561     (*public_key)->pk_len = key_len;
562   }
563
564   silc_buffer_free(buf);
565   return TRUE;
566
567  err:
568   if (pkcs_name)
569     silc_free(pkcs_name);
570   if (ident)
571     silc_free(ident);
572   if (key_data)
573     silc_free(key_data);
574   silc_buffer_free(buf);
575   return FALSE;
576 }
577
578 /* Encodes SILC private key from SilcPrivateKey. Returns the encoded data. */
579
580 unsigned char *
581 silc_pkcs_private_key_encode(SilcPrivateKey private_key, uint32 *len)
582 {
583   SilcBuffer buf;
584   unsigned char *ret;
585   uint32 totlen;
586
587   totlen = 2 + strlen(private_key->name) + private_key->prv_len;
588   buf = silc_buffer_alloc(totlen);
589   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
590
591   silc_buffer_format(buf,
592                      SILC_STR_UI_SHORT(strlen(private_key->name)),
593                      SILC_STR_UI32_STRING(private_key->name),
594                      SILC_STR_UI_XNSTRING(private_key->prv, 
595                                           private_key->prv_len),
596                      SILC_STR_END);
597   if (len)
598     *len = totlen;
599
600   ret = silc_calloc(buf->len, sizeof(*ret));
601   memcpy(ret, buf->data, buf->len);
602   silc_buffer_free(buf);
603
604   return ret;
605 }
606
607 /* Encodes SILC private key. Returns the encoded data. */
608
609 unsigned char *
610 silc_pkcs_private_key_data_encode(unsigned char *prv, uint32 prv_len,
611                                   char *pkcs, uint32 *len)
612 {
613   SilcBuffer buf;
614   unsigned char *ret;
615   uint32 totlen;
616
617   totlen = 2 + strlen(pkcs) + prv_len;
618   buf = silc_buffer_alloc(totlen);
619   silc_buffer_pull_tail(buf, totlen);
620
621   silc_buffer_format(buf,
622                      SILC_STR_UI_SHORT(strlen(pkcs)),
623                      SILC_STR_UI32_STRING(pkcs),
624                      SILC_STR_UI_XNSTRING(prv, prv_len),
625                      SILC_STR_END);
626   if (len)
627     *len = totlen;
628
629   ret = silc_calloc(buf->len, sizeof(*ret));
630   memcpy(ret, buf->data, buf->len);
631   silc_buffer_free(buf);
632
633   return ret;
634 }
635
636 /* Decodes SILC style public key. Returns TRUE if the decoding was
637    successful. Allocates new private key as well. */
638
639 int silc_pkcs_private_key_decode(unsigned char *data, uint32 data_len,
640                                  SilcPrivateKey *private_key)
641 {
642   SilcBuffer buf;
643   SilcPKCS alg;
644   uint16 pkcs_len;
645   uint32 key_len;
646   unsigned char *pkcs_name = NULL, *key_data = NULL;
647   int ret;
648
649   buf = silc_buffer_alloc(data_len);
650   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
651   silc_buffer_put(buf, data, data_len);
652
653   /* Get algorithm name and identifier */
654   ret = 
655     silc_buffer_unformat(buf,
656                          SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
657                          SILC_STR_END);
658   if (ret == -1)
659     goto err;
660
661   if (pkcs_len < 1 || pkcs_len > buf->truelen)
662     goto err;
663
664   /* See if we support this algorithm */
665   if (!silc_pkcs_is_supported(pkcs_name))
666     goto err;
667
668   /* Get key data. We assume that rest of the buffer is key data. */
669   silc_buffer_pull(buf, 2 + pkcs_len);
670   key_len = buf->len;
671   ret = silc_buffer_unformat(buf,
672                              SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
673                              SILC_STR_END);
674   if (ret == -1)
675     goto err;
676
677   /* Try to set the key. If this fails the key must be malformed. This
678      code assumes that the PKCS routine checks the format of the key. */
679   silc_pkcs_alloc(pkcs_name, &alg);
680   if (!alg->pkcs->set_private_key(alg->context, key_data, key_len))
681     goto err;
682   silc_pkcs_free(alg);
683   
684   if (private_key) {
685     *private_key = silc_calloc(1, sizeof(**private_key));
686     (*private_key)->name = pkcs_name;
687     (*private_key)->prv = key_data;
688     (*private_key)->prv_len = key_len;
689   }
690
691   silc_buffer_free(buf);
692   return TRUE;
693
694  err:
695   if (pkcs_name)
696     silc_free(pkcs_name);
697   if (key_data)
698     silc_free(key_data);
699   silc_buffer_free(buf);
700   return FALSE;
701 }
702
703 /* Internal routine to save public key */
704
705 static int silc_pkcs_save_public_key_internal(char *filename,
706                                               unsigned char *data,
707                                               uint32 data_len,
708                                               uint32 encoding)
709 {
710   SilcBuffer buf;
711   uint32 len;
712
713   switch(encoding) {
714   case SILC_PKCS_FILE_BIN:
715     break;
716   case SILC_PKCS_FILE_PEM:
717     data = silc_encode_pem_file(data, data_len);
718     data_len = strlen(data);
719     break;
720   }
721
722   len = data_len + (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
723                     strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
724   buf = silc_buffer_alloc(len);
725   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
726
727   silc_buffer_format(buf,
728                      SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
729                      SILC_STR_UI_XNSTRING(data, data_len),
730                      SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END),
731                      SILC_STR_END);
732
733   /* Save into file */
734   if (silc_file_write(filename, buf->data, buf->len)) {
735     silc_buffer_free(buf);
736     return FALSE;
737   }
738
739   silc_buffer_free(buf);
740   return TRUE;
741 }
742
743 /* Saves public key into file */
744
745 int silc_pkcs_save_public_key(char *filename, SilcPublicKey public_key,
746                               uint32 encoding)
747 {
748   unsigned char *data;
749   uint32 data_len;
750
751   data = silc_pkcs_public_key_encode(public_key, &data_len);
752   return silc_pkcs_save_public_key_internal(filename, data, data_len,
753                                             encoding);
754 }
755
756 /* Saves public key into file */
757
758 int silc_pkcs_save_public_key_data(char *filename, unsigned char *data,
759                                    uint32 data_len,
760                                    uint32 encoding)
761 {
762   return silc_pkcs_save_public_key_internal(filename, data, data_len,
763                                             encoding);
764 }
765
766 /* Internal routine to save private key. */
767
768 static int silc_pkcs_save_private_key_internal(char *filename,
769                                                unsigned char *data,
770                                                uint32 data_len,
771                                                uint32 encoding)
772 {
773   SilcBuffer buf;
774   uint32 len;
775
776   switch(encoding) {
777   case SILC_PKCS_FILE_BIN:
778     break;
779   case SILC_PKCS_FILE_PEM:
780     data = silc_encode_pem_file(data, data_len);
781     data_len = strlen(data);
782     break;
783   }
784
785   len = data_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
786                     strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
787   buf = silc_buffer_alloc(len);
788   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
789
790   silc_buffer_format(buf,
791                      SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
792                      SILC_STR_UI_XNSTRING(data, data_len),
793                      SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
794                      SILC_STR_END);
795
796   /* Save into a file */
797   if (silc_file_write_mode(filename, buf->data, buf->len, 0600)) {
798     silc_buffer_free(buf);
799     return FALSE;
800   }
801
802   silc_buffer_free(buf);
803   return TRUE;
804 }
805
806 /* Saves private key into file. */
807 /* XXX The buffer should be encrypted if passphrase is provided. */
808
809 int silc_pkcs_save_private_key(char *filename, SilcPrivateKey private_key, 
810                                unsigned char *passphrase,
811                                uint32 encoding)
812 {
813   unsigned char *data;
814   uint32 data_len;
815
816   data = silc_pkcs_private_key_encode(private_key, &data_len);
817   return silc_pkcs_save_private_key_internal(filename, data, data_len,
818                                              encoding);
819 }
820
821 /* Saves private key into file. */
822 /* XXX The buffer should be encrypted if passphrase is provided. */
823
824 int silc_pkcs_save_private_key_data(char *filename, unsigned char *data, 
825                                     uint32 data_len,
826                                     unsigned char *passphrase,
827                                     uint32 encoding)
828 {
829   return silc_pkcs_save_private_key_internal(filename, data, data_len,
830                                              encoding);
831 }
832
833 /* Loads public key from file and allocates new public key. Returns TRUE
834    is loading was successful. */
835
836 int silc_pkcs_load_public_key(char *filename, SilcPublicKey *public_key,
837                               uint32 encoding)
838 {
839   unsigned char *cp, *old, *data, byte;
840   uint32 i, data_len, len;
841
842   old = data = silc_file_read(filename, &data_len);
843   if (!data)
844     return FALSE;
845
846   /* Check start of file and remove header from the data. */
847   len = strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN);
848   cp = data;
849   for (i = 0; i < len; i++) {
850     byte = cp[0];
851     cp++;
852     if (byte != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i]) {
853       memset(old, 0, data_len);
854       silc_free(old);
855     }
856   }
857   data = cp;
858
859   /* Decode public key */
860   if (public_key) {
861     len = data_len - (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
862                       strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
863
864     switch(encoding) {
865     case SILC_PKCS_FILE_BIN:
866       break;
867     case SILC_PKCS_FILE_PEM:
868       data = silc_decode_pem(data, len, &len);
869       break;
870     }
871
872     if (!data || !silc_pkcs_public_key_decode(data, len, public_key)) {
873       memset(old, 0, data_len);
874       silc_free(old);
875       return FALSE;
876     }
877   }
878
879   memset(old, 0, data_len);
880   silc_free(old);
881   return TRUE;
882 }
883
884 /* Load private key from file and allocates new private key. Returns TRUE
885    if loading was successful. */
886 /* XXX Should support encrypted private key files */
887
888 int silc_pkcs_load_private_key(char *filename, SilcPrivateKey *private_key,
889                                uint32 encoding)
890 {
891   unsigned char *cp, *old, *data, byte;
892   uint32 i, data_len, len;
893
894   old = data = silc_file_read(filename, &data_len);
895   if (!data)
896     return FALSE;
897
898   /* Check start of file and remove header from the data. */
899   len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
900   cp = data;
901   for (i = 0; i < len; i++) {
902     byte = cp[0];
903     cp++;
904     if (byte != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i]) {
905       memset(old, 0, data_len);
906       silc_free(old);
907     }
908   }
909   data = cp;
910
911   /* Decode private key */
912   if (private_key) {
913     len = data_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
914                       strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
915
916     switch(encoding) {
917     case SILC_PKCS_FILE_BIN:
918       break;
919     case SILC_PKCS_FILE_PEM:
920       data = silc_decode_pem(data, len, &len);
921       break;
922     }
923
924     if (!data || !silc_pkcs_private_key_decode(data, len, private_key)) {
925       memset(old, 0, data_len);
926       silc_free(old);
927       return FALSE;
928     }
929   }
930
931   memset(old, 0, data_len);
932   silc_free(old);
933   return TRUE;
934 }