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