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     if (len - 1 >= 0 && cp[len - 1] == '\\') {
449       while (cp) {
450         cp += len + 1;
451         len = strcspn(cp, ",") + len;
452         if (len - 1 >= 0 && cp[len - 1] != '\\')
453           break;
454       }
455     }
456
457     item = silc_calloc(len + 1, sizeof(char));
458     memcpy(item, cp, len);
459
460     if (strstr(item, "UN="))
461       ident->username = strdup(item + strcspn(cp, "=") + 1);
462     else if (strstr(item, "HN="))
463       ident->host = strdup(item + strcspn(cp, "=") + 1);
464     else if (strstr(item, "RN="))
465       ident->realname = strdup(item + strcspn(cp, "=") + 1);
466     else if (strstr(item, "E="))
467       ident->email = strdup(item + strcspn(cp, "=") + 1);
468     else if (strstr(item, "O="))
469       ident->org = strdup(item + strcspn(cp, "=") + 1);
470     else if (strstr(item, "C="))
471       ident->country = strdup(item + strcspn(cp, "=") + 1);
472     
473     cp += len;
474     if (strlen(cp) == 0)
475       cp = NULL;
476     else
477       cp += 1;
478     
479     if (item)
480       silc_free(item);
481   }
482
483   return ident;
484 }
485
486 /* Free's decoded public key identifier context. Call this to free the
487    context returned by the silc_pkcs_decode_identifier. */
488
489 void silc_pkcs_free_identifier(SilcPublicKeyIdentifier identifier)
490 {
491   silc_free(identifier->username);
492   silc_free(identifier->host);
493   silc_free(identifier->realname);
494   silc_free(identifier->email);
495   silc_free(identifier->org);
496   silc_free(identifier->country);
497   silc_free(identifier);
498 }
499
500 /* Allocates SILC style public key formed from sent arguments. All data
501    is duplicated. */
502
503 SilcPublicKey silc_pkcs_public_key_alloc(char *name, char *identifier,
504                                          unsigned char *pk, 
505                                          uint32 pk_len)
506 {
507   SilcPublicKey public_key;
508
509   public_key = silc_calloc(1, sizeof(*public_key));
510   public_key->len = 4 + 2 + strlen(name) + 2 + strlen(identifier) + pk_len;
511   public_key->name = strdup(name);
512   public_key->identifier = strdup(identifier);
513   public_key->pk_len = pk_len;
514   public_key->pk = silc_calloc(pk_len, sizeof(*public_key->pk));
515   memcpy(public_key->pk, pk, pk_len);
516
517   return public_key;
518 }
519
520 /* Free's public key */
521
522 void silc_pkcs_public_key_free(SilcPublicKey public_key)
523 {
524   if (public_key) {
525     silc_free(public_key->name);
526     silc_free(public_key->identifier);
527     silc_free(public_key->pk);
528     silc_free(public_key);
529   }
530 }
531
532 /* Allocates SILC private key formed from sent arguments. All data is
533    duplicated. */
534
535 SilcPrivateKey silc_pkcs_private_key_alloc(char *name, unsigned char *prv,
536                                            uint32 prv_len)
537 {
538   SilcPrivateKey private_key;
539
540   private_key = silc_calloc(1, sizeof(*private_key));
541   private_key->name = strdup(name);
542   private_key->prv_len = prv_len;
543   private_key->prv = silc_calloc(prv_len, sizeof(*private_key->prv));
544   memcpy(private_key->prv, prv, prv_len);
545
546   return private_key;
547 }
548
549 /* Free's private key */
550
551 void silc_pkcs_private_key_free(SilcPrivateKey private_key)
552 {
553   if (private_key) {
554     silc_free(private_key->name);
555     silc_free(private_key->prv);
556     silc_free(private_key);
557   }
558 }
559
560 /* Encodes SILC style public key from SilcPublicKey. Returns the encoded
561    data. */
562
563 unsigned char *
564 silc_pkcs_public_key_encode(SilcPublicKey public_key, uint32 *len)
565 {
566   SilcBuffer buf;
567   unsigned char *ret;
568
569   buf = silc_buffer_alloc(public_key->len);
570   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
571
572   silc_buffer_format(buf,
573                      SILC_STR_UI_INT(public_key->len),
574                      SILC_STR_UI_SHORT(strlen(public_key->name)),
575                      SILC_STR_UI32_STRING(public_key->name),
576                      SILC_STR_UI_SHORT(strlen(public_key->identifier)),
577                      SILC_STR_UI32_STRING(public_key->identifier),
578                      SILC_STR_UI_XNSTRING(public_key->pk, 
579                                           public_key->pk_len),
580                      SILC_STR_END);
581   if (len)
582     *len = public_key->len;
583
584   ret = silc_calloc(buf->len, sizeof(*ret));
585   memcpy(ret, buf->data, buf->len);
586   silc_buffer_free(buf);
587
588   return ret;
589 }
590
591 /* Encodes SILC style public key. Returns the encoded data. */
592
593 unsigned char *
594 silc_pkcs_public_key_data_encode(unsigned char *pk, uint32 pk_len,
595                                  char *pkcs, char *identifier, 
596                                  uint32 *len)
597 {
598   SilcBuffer buf;
599   unsigned char *ret;
600   uint32 totlen;
601
602   totlen = 4 + 2 + strlen(pkcs) + 2 + strlen(identifier) + pk_len;
603   buf = silc_buffer_alloc(totlen);
604   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
605
606   silc_buffer_format(buf,
607                      SILC_STR_UI_INT(totlen),
608                      SILC_STR_UI_SHORT(strlen(pkcs)),
609                      SILC_STR_UI32_STRING(pkcs),
610                      SILC_STR_UI_SHORT(strlen(identifier)),
611                      SILC_STR_UI32_STRING(identifier),
612                      SILC_STR_UI_XNSTRING(pk, pk_len),
613                      SILC_STR_END);
614   if (len)
615     *len = totlen;
616
617   ret = silc_calloc(buf->len, sizeof(*ret));
618   memcpy(ret, buf->data, buf->len);
619   silc_buffer_free(buf);
620
621   return ret;
622 }
623
624 /* Decodes SILC style public key. Returns TRUE if the decoding was
625    successful. Allocates new public key as well. */
626
627 int silc_pkcs_public_key_decode(unsigned char *data, uint32 data_len,
628                                 SilcPublicKey *public_key)
629 {
630   SilcBuffer buf;
631   SilcPKCS alg;
632   uint16 pkcs_len, identifier_len;
633   uint32 totlen, key_len;
634   unsigned char *pkcs_name = NULL, *ident = NULL, *key_data = NULL;
635   int ret;
636
637   buf = silc_buffer_alloc(data_len);
638   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
639   silc_buffer_put(buf, data, data_len);
640
641   /* Get length */
642   ret = silc_buffer_unformat(buf,
643                              SILC_STR_UI_INT(&totlen),
644                              SILC_STR_END);
645   if (ret == -1) {
646     silc_buffer_free(buf);
647     return FALSE;
648   }
649
650   if (totlen != data_len) {
651     silc_buffer_free(buf);
652     return FALSE;
653   }
654
655   /* Get algorithm name and identifier */
656   silc_buffer_pull(buf, 4);
657   ret =
658     silc_buffer_unformat(buf,
659                          SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
660                          SILC_STR_UI16_NSTRING_ALLOC(&ident, &identifier_len),
661                          SILC_STR_END);
662   if (ret == -1)
663     goto err;
664
665   if (pkcs_len < 1 || identifier_len < 3 || 
666       pkcs_len + identifier_len > totlen)
667     goto err;
668
669   /* See if we support this algorithm (check only if PKCS are registered) */
670   if (silc_pkcs_list && !silc_pkcs_is_supported(pkcs_name)) {
671     SILC_LOG_DEBUG(("Unknown PKCS %s", pkcs_name));
672     goto err;
673   }
674
675   /* Protocol says that at least UN and HN must be provided as identifier,
676      check for these. */
677   if (!strstr(ident, "UN=") && !strstr(ident, "HN=")) {
678     SILC_LOG_DEBUG(("The public does not have the required UN= and HN= "
679                     "identifiers"));
680     goto err;
681   }
682
683   /* Get key data. We assume that rest of the buffer is key data. */
684   silc_buffer_pull(buf, 2 + pkcs_len + 2 + identifier_len);
685   key_len = buf->len;
686   ret = silc_buffer_unformat(buf,
687                              SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
688                              SILC_STR_END);
689   if (ret == -1)
690     goto err;
691
692   /* Try to set the key. If this fails the key must be malformed. This
693      code assumes that the PKCS routine checks the format of the key. 
694      (check only if PKCS are registered) */
695   if (silc_pkcs_list) {
696     silc_pkcs_alloc(pkcs_name, &alg);
697     if (!alg->pkcs->set_public_key(alg->context, key_data, key_len))
698       goto err;
699     silc_pkcs_free(alg);
700   }
701   
702   if (public_key) {
703     *public_key = silc_calloc(1, sizeof(**public_key));
704     (*public_key)->len = totlen;
705     (*public_key)->name = pkcs_name;
706     (*public_key)->identifier = ident;
707     (*public_key)->pk = key_data;
708     (*public_key)->pk_len = key_len;
709   }
710
711   silc_buffer_free(buf);
712   return TRUE;
713
714  err:
715   if (pkcs_name)
716     silc_free(pkcs_name);
717   if (ident)
718     silc_free(ident);
719   if (key_data)
720     silc_free(key_data);
721   silc_buffer_free(buf);
722   return FALSE;
723 }
724
725 /* Encodes SILC private key from SilcPrivateKey. Returns the encoded data. */
726
727 unsigned char *
728 silc_pkcs_private_key_encode(SilcPrivateKey private_key, uint32 *len)
729 {
730   SilcBuffer buf;
731   unsigned char *ret;
732   uint32 totlen;
733
734   totlen = 2 + strlen(private_key->name) + private_key->prv_len;
735   buf = silc_buffer_alloc(totlen);
736   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
737
738   silc_buffer_format(buf,
739                      SILC_STR_UI_SHORT(strlen(private_key->name)),
740                      SILC_STR_UI32_STRING(private_key->name),
741                      SILC_STR_UI_XNSTRING(private_key->prv, 
742                                           private_key->prv_len),
743                      SILC_STR_END);
744   if (len)
745     *len = totlen;
746
747   ret = silc_calloc(buf->len, sizeof(*ret));
748   memcpy(ret, buf->data, buf->len);
749   silc_buffer_free(buf);
750
751   return ret;
752 }
753
754 /* Encodes SILC private key. Returns the encoded data. */
755
756 unsigned char *
757 silc_pkcs_private_key_data_encode(unsigned char *prv, uint32 prv_len,
758                                   char *pkcs, uint32 *len)
759 {
760   SilcBuffer buf;
761   unsigned char *ret;
762   uint32 totlen;
763
764   totlen = 2 + strlen(pkcs) + prv_len;
765   buf = silc_buffer_alloc(totlen);
766   silc_buffer_pull_tail(buf, totlen);
767
768   silc_buffer_format(buf,
769                      SILC_STR_UI_SHORT(strlen(pkcs)),
770                      SILC_STR_UI32_STRING(pkcs),
771                      SILC_STR_UI_XNSTRING(prv, prv_len),
772                      SILC_STR_END);
773   if (len)
774     *len = totlen;
775
776   ret = silc_calloc(buf->len, sizeof(*ret));
777   memcpy(ret, buf->data, buf->len);
778   silc_buffer_free(buf);
779
780   return ret;
781 }
782
783 /* Decodes SILC style public key. Returns TRUE if the decoding was
784    successful. Allocates new private key as well. */
785
786 int silc_pkcs_private_key_decode(unsigned char *data, uint32 data_len,
787                                  SilcPrivateKey *private_key)
788 {
789   SilcBuffer buf;
790   SilcPKCS alg;
791   uint16 pkcs_len;
792   uint32 key_len;
793   unsigned char *pkcs_name = NULL, *key_data = NULL;
794   int ret;
795
796   buf = silc_buffer_alloc(data_len);
797   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
798   silc_buffer_put(buf, data, data_len);
799
800   /* Get algorithm name and identifier */
801   ret = 
802     silc_buffer_unformat(buf,
803                          SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
804                          SILC_STR_END);
805   if (ret == -1)
806     goto err;
807
808   if (pkcs_len < 1 || pkcs_len > buf->truelen)
809     goto err;
810
811   /* See if we support this algorithm (check only if PKCS are registered). */
812   if (silc_pkcs_list && !silc_pkcs_is_supported(pkcs_name)) {
813     SILC_LOG_DEBUG(("Unknown PKCS `%s'", pkcs_name));
814     goto err;
815   }
816
817   /* Get key data. We assume that rest of the buffer is key data. */
818   silc_buffer_pull(buf, 2 + pkcs_len);
819   key_len = buf->len;
820   ret = silc_buffer_unformat(buf,
821                              SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
822                              SILC_STR_END);
823   if (ret == -1)
824     goto err;
825
826   /* Try to set the key. If this fails the key must be malformed. This
827      code assumes that the PKCS routine checks the format of the key. 
828      (check only if PKCS are registered) */
829   if (silc_pkcs_list) {
830     silc_pkcs_alloc(pkcs_name, &alg);
831     if (!alg->pkcs->set_private_key(alg->context, key_data, key_len))
832       goto err;
833     silc_pkcs_free(alg);
834   }
835   
836   if (private_key) {
837     *private_key = silc_calloc(1, sizeof(**private_key));
838     (*private_key)->name = pkcs_name;
839     (*private_key)->prv = key_data;
840     (*private_key)->prv_len = key_len;
841   }
842
843   silc_buffer_free(buf);
844   return TRUE;
845
846  err:
847   if (pkcs_name)
848     silc_free(pkcs_name);
849   if (key_data)
850     silc_free(key_data);
851   silc_buffer_free(buf);
852   return FALSE;
853 }
854
855 /* Internal routine to save public key */
856
857 static int silc_pkcs_save_public_key_internal(char *filename,
858                                               unsigned char *data,
859                                               uint32 data_len,
860                                               uint32 encoding)
861 {
862   SilcBuffer buf;
863   uint32 len;
864
865   switch(encoding) {
866   case SILC_PKCS_FILE_BIN:
867     break;
868   case SILC_PKCS_FILE_PEM:
869     data = silc_encode_pem_file(data, data_len);
870     data_len = strlen(data);
871     break;
872   }
873
874   len = data_len + (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
875                     strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
876   buf = silc_buffer_alloc(len);
877   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
878
879   silc_buffer_format(buf,
880                      SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
881                      SILC_STR_UI_XNSTRING(data, data_len),
882                      SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END),
883                      SILC_STR_END);
884
885   /* Save into file */
886   if (silc_file_write(filename, buf->data, buf->len)) {
887     silc_buffer_free(buf);
888     return FALSE;
889   }
890
891   silc_buffer_free(buf);
892   return TRUE;
893 }
894
895 /* Saves public key into file */
896
897 int silc_pkcs_save_public_key(char *filename, SilcPublicKey public_key,
898                               uint32 encoding)
899 {
900   unsigned char *data;
901   uint32 data_len;
902
903   data = silc_pkcs_public_key_encode(public_key, &data_len);
904   return silc_pkcs_save_public_key_internal(filename, data, data_len,
905                                             encoding);
906 }
907
908 /* Saves public key into file */
909
910 int silc_pkcs_save_public_key_data(char *filename, unsigned char *data,
911                                    uint32 data_len,
912                                    uint32 encoding)
913 {
914   return silc_pkcs_save_public_key_internal(filename, data, data_len,
915                                             encoding);
916 }
917
918 /* Internal routine to save private key. */
919
920 static int silc_pkcs_save_private_key_internal(char *filename,
921                                                unsigned char *data,
922                                                uint32 data_len,
923                                                uint32 encoding)
924 {
925   SilcBuffer buf;
926   uint32 len;
927
928   switch(encoding) {
929   case SILC_PKCS_FILE_BIN:
930     break;
931   case SILC_PKCS_FILE_PEM:
932     data = silc_encode_pem_file(data, data_len);
933     data_len = strlen(data);
934     break;
935   }
936
937   len = data_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
938                     strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
939   buf = silc_buffer_alloc(len);
940   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
941
942   silc_buffer_format(buf,
943                      SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
944                      SILC_STR_UI_XNSTRING(data, data_len),
945                      SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
946                      SILC_STR_END);
947
948   /* Save into a file */
949   if (silc_file_write_mode(filename, buf->data, buf->len, 0600)) {
950     silc_buffer_free(buf);
951     return FALSE;
952   }
953
954   silc_buffer_free(buf);
955   return TRUE;
956 }
957
958 /* Saves private key into file. */
959 /* XXX The buffer should be encrypted if passphrase is provided. */
960
961 int silc_pkcs_save_private_key(char *filename, SilcPrivateKey private_key, 
962                                unsigned char *passphrase,
963                                uint32 encoding)
964 {
965   unsigned char *data;
966   uint32 data_len;
967
968   data = silc_pkcs_private_key_encode(private_key, &data_len);
969   return silc_pkcs_save_private_key_internal(filename, data, data_len,
970                                              encoding);
971 }
972
973 /* Saves private key into file. */
974 /* XXX The buffer should be encrypted if passphrase is provided. */
975
976 int silc_pkcs_save_private_key_data(char *filename, unsigned char *data, 
977                                     uint32 data_len,
978                                     unsigned char *passphrase,
979                                     uint32 encoding)
980 {
981   return silc_pkcs_save_private_key_internal(filename, data, data_len,
982                                              encoding);
983 }
984
985 /* Loads public key from file and allocates new public key. Returns TRUE
986    is loading was successful. */
987
988 int silc_pkcs_load_public_key(char *filename, SilcPublicKey *public_key,
989                               uint32 encoding)
990 {
991   unsigned char *cp, *old, *data, byte;
992   uint32 i, data_len, len;
993
994   old = data = silc_file_read(filename, &data_len);
995   if (!data)
996     return FALSE;
997
998   /* Check start of file and remove header from the data. */
999   len = strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN);
1000   cp = data;
1001   for (i = 0; i < len; i++) {
1002     byte = cp[0];
1003     cp++;
1004     if (byte != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i]) {
1005       memset(old, 0, data_len);
1006       silc_free(old);
1007       return FALSE;
1008     }
1009   }
1010   data = cp;
1011
1012   /* Decode public key */
1013   if (public_key) {
1014     len = data_len - (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
1015                       strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
1016
1017     switch(encoding) {
1018     case SILC_PKCS_FILE_BIN:
1019       break;
1020     case SILC_PKCS_FILE_PEM:
1021       data = silc_decode_pem(data, len, &len);
1022       break;
1023     }
1024
1025     if (!data || !silc_pkcs_public_key_decode(data, len, public_key)) {
1026       memset(old, 0, data_len);
1027       silc_free(old);
1028       return FALSE;
1029     }
1030   }
1031
1032   memset(old, 0, data_len);
1033   silc_free(old);
1034   return TRUE;
1035 }
1036
1037 /* Load private key from file and allocates new private key. Returns TRUE
1038    if loading was successful. */
1039 /* XXX Should support encrypted private key files */
1040
1041 int silc_pkcs_load_private_key(char *filename, SilcPrivateKey *private_key,
1042                                uint32 encoding)
1043 {
1044   unsigned char *cp, *old, *data, byte;
1045   uint32 i, data_len, len;
1046
1047   old = data = silc_file_read(filename, &data_len);
1048   if (!data)
1049     return FALSE;
1050
1051   /* Check start of file and remove header from the data. */
1052   len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
1053   cp = data;
1054   for (i = 0; i < len; i++) {
1055     byte = cp[0];
1056     cp++;
1057     if (byte != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i]) {
1058       memset(old, 0, data_len);
1059       silc_free(old);
1060       return FALSE;
1061     }
1062   }
1063   data = cp;
1064
1065   /* Decode private key */
1066   if (private_key) {
1067     len = data_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
1068                       strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
1069
1070     switch(encoding) {
1071     case SILC_PKCS_FILE_BIN:
1072       break;
1073     case SILC_PKCS_FILE_PEM:
1074       data = silc_decode_pem(data, len, &len);
1075       break;
1076     }
1077
1078     if (!data || !silc_pkcs_private_key_decode(data, len, private_key)) {
1079       memset(old, 0, data_len);
1080       silc_free(old);
1081       return FALSE;
1082     }
1083   }
1084
1085   memset(old, 0, data_len);
1086   silc_free(old);
1087   return TRUE;
1088 }