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