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