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