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