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