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   char utf8[256 + 1];
410
411   if (!username || !host)
412     return NULL;
413
414   len = (username ? silc_utf8_encoded_len(username, strlen(username), 0) : 0) +
415         (host     ? silc_utf8_encoded_len(host, strlen(host), 0) : 0) +
416         (realname ? silc_utf8_encoded_len(realname, strlen(realname), 0) : 0) +
417         (email    ? silc_utf8_encoded_len(email, strlen(email), 0) : 0) +
418         (org      ? silc_utf8_encoded_len(org, strlen(org), 0) : 0) +
419         (country  ? silc_utf8_encoded_len(country, strlen(country), 0) : 0);
420   
421   if (len < 3)
422     return NULL;
423
424   len += 3 + 5 + 5 + 4 + 4 + 4;
425   buf = silc_buffer_alloc(len);
426   silc_buffer_pull_tail(buf, len);
427
428   if (username) {
429     memset(utf8, 0, sizeof(utf8));
430     len = silc_utf8_encode(username, strlen(username), 0, utf8,
431                            sizeof(utf8) - 1);
432     silc_buffer_format(buf,
433                        SILC_STR_UI32_STRING("UN="),
434                        SILC_STR_UI32_STRING(utf8),
435                        SILC_STR_END);
436     silc_buffer_pull(buf, 3 + len);
437     tlen = 3 + len; 
438   }
439     
440   if (host) {
441     memset(utf8, 0, sizeof(utf8));
442     len = silc_utf8_encode(host, strlen(host), 0, utf8, sizeof(utf8) - 1);
443     silc_buffer_format(buf,
444                        SILC_STR_UI32_STRING(", "),
445                        SILC_STR_UI32_STRING("HN="),
446                        SILC_STR_UI32_STRING(utf8),
447                        SILC_STR_END);
448     silc_buffer_pull(buf, 5 + len);
449     tlen += 5 + len; 
450   }
451
452   if (realname) {
453     memset(utf8, 0, sizeof(utf8));
454     len = silc_utf8_encode(realname, strlen(realname), 0, utf8,
455                            sizeof(utf8) - 1);
456     silc_buffer_format(buf,
457                        SILC_STR_UI32_STRING(", "),
458                        SILC_STR_UI32_STRING("RN="),
459                        SILC_STR_UI32_STRING(utf8),
460                        SILC_STR_END);
461     silc_buffer_pull(buf, 5 + len);
462     tlen += 5 + len; 
463   }
464
465   if (email) {
466     memset(utf8, 0, sizeof(utf8));
467     len = silc_utf8_encode(email, strlen(email), 0, utf8, sizeof(utf8) - 1);
468     silc_buffer_format(buf,
469                        SILC_STR_UI32_STRING(", "),
470                        SILC_STR_UI32_STRING("E="),
471                        SILC_STR_UI32_STRING(utf8),
472                        SILC_STR_END);
473     silc_buffer_pull(buf, 4 + len);
474     tlen += 4 + len; 
475   }
476
477   if (org) {
478     memset(utf8, 0, sizeof(utf8));
479     len = silc_utf8_encode(org, strlen(org), 0, utf8, sizeof(utf8) - 1);
480     silc_buffer_format(buf,
481                        SILC_STR_UI32_STRING(", "),
482                        SILC_STR_UI32_STRING("O="),
483                        SILC_STR_UI32_STRING(utf8),
484                        SILC_STR_END);
485     silc_buffer_pull(buf, 4 + len);
486     tlen += 4 + len; 
487   }
488
489   if (country) {
490     memset(utf8, 0, sizeof(utf8));
491     len = silc_utf8_encode(country, strlen(country), 0, utf8,
492                            sizeof(utf8) - 1);
493     silc_buffer_format(buf,
494                        SILC_STR_UI32_STRING(", "),
495                        SILC_STR_UI32_STRING("C="),
496                        SILC_STR_UI32_STRING(utf8),
497                        SILC_STR_END);
498     silc_buffer_pull(buf, 4 + len);
499     tlen += 4 + len; 
500   }
501
502   silc_buffer_push(buf, buf->data - buf->head);
503   identifier = silc_calloc(tlen + 1, sizeof(*identifier));
504   memcpy(identifier, buf->data, tlen);
505   silc_buffer_free(buf);
506
507   return identifier;
508 }
509
510 /* Decodes the provided `identifier' and returns allocated context for
511    the identifier. */
512
513 SilcPublicKeyIdentifier silc_pkcs_decode_identifier(char *identifier)
514 {
515   SilcPublicKeyIdentifier ident;
516   char *cp, *item;
517   int len;
518
519   ident = silc_calloc(1, sizeof(*ident));
520
521   cp = identifier;
522   while (cp) {
523     len = strcspn(cp, ",");
524     if (len - 1 >= 0 && cp[len - 1] == '\\') {
525       while (cp) {
526         cp += len + 1;
527         len = strcspn(cp, ",") + len;
528         if (len - 1 >= 0 && cp[len - 1] != '\\')
529           break;
530       }
531     }
532
533     item = silc_calloc(len + 1, sizeof(char));
534     memcpy(item, cp, len);
535
536     if (strstr(item, "UN="))
537       ident->username = strdup(item + strcspn(cp, "=") + 1);
538     else if (strstr(item, "HN="))
539       ident->host = strdup(item + strcspn(cp, "=") + 1);
540     else if (strstr(item, "RN="))
541       ident->realname = strdup(item + strcspn(cp, "=") + 1);
542     else if (strstr(item, "E="))
543       ident->email = strdup(item + strcspn(cp, "=") + 1);
544     else if (strstr(item, "O="))
545       ident->org = strdup(item + strcspn(cp, "=") + 1);
546     else if (strstr(item, "C="))
547       ident->country = strdup(item + strcspn(cp, "=") + 1);
548     
549     cp += len;
550     if (strlen(cp) == 0)
551       cp = NULL;
552     else
553       cp += 1;
554     
555     if (item)
556       silc_free(item);
557   }
558
559   return ident;
560 }
561
562 /* Free's decoded public key identifier context. Call this to free the
563    context returned by the silc_pkcs_decode_identifier. */
564
565 void silc_pkcs_free_identifier(SilcPublicKeyIdentifier identifier)
566 {
567   silc_free(identifier->username);
568   silc_free(identifier->host);
569   silc_free(identifier->realname);
570   silc_free(identifier->email);
571   silc_free(identifier->org);
572   silc_free(identifier->country);
573   silc_free(identifier);
574 }
575
576 /* Allocates SILC style public key formed from sent arguments. All data
577    is duplicated. */
578
579 SilcPublicKey silc_pkcs_public_key_alloc(char *name, char *identifier,
580                                          unsigned char *pk, 
581                                          SilcUInt32 pk_len)
582 {
583   SilcPublicKey public_key;
584
585   public_key = silc_calloc(1, sizeof(*public_key));
586   public_key->len = 4 + 2 + strlen(name) + 2 + strlen(identifier) + pk_len;
587   public_key->name = strdup(name);
588   public_key->identifier = strdup(identifier);
589   public_key->pk_len = pk_len;
590   public_key->pk = silc_calloc(pk_len, sizeof(*public_key->pk));
591   memcpy(public_key->pk, pk, pk_len);
592
593   return public_key;
594 }
595
596 /* Free's public key */
597
598 void silc_pkcs_public_key_free(SilcPublicKey public_key)
599 {
600   if (public_key) {
601     silc_free(public_key->name);
602     silc_free(public_key->identifier);
603     silc_free(public_key->pk);
604     silc_free(public_key);
605   }
606 }
607
608 /* Allocates SILC private key formed from sent arguments. All data is
609    duplicated. */
610
611 SilcPrivateKey silc_pkcs_private_key_alloc(char *name, unsigned char *prv,
612                                            SilcUInt32 prv_len)
613 {
614   SilcPrivateKey private_key;
615
616   private_key = silc_calloc(1, sizeof(*private_key));
617   private_key->name = strdup(name);
618   private_key->prv_len = prv_len;
619   private_key->prv = silc_calloc(prv_len, sizeof(*private_key->prv));
620   memcpy(private_key->prv, prv, prv_len);
621
622   return private_key;
623 }
624
625 /* Free's private key */
626
627 void silc_pkcs_private_key_free(SilcPrivateKey private_key)
628 {
629   if (private_key) {
630     silc_free(private_key->name);
631     silc_free(private_key->prv);
632     silc_free(private_key);
633   }
634 }
635
636 /* Encodes SILC style public key from SilcPublicKey. Returns the encoded
637    data. */
638
639 unsigned char *
640 silc_pkcs_public_key_encode(SilcPublicKey public_key, SilcUInt32 *len)
641 {
642   SilcBuffer buf;
643   unsigned char *ret;
644
645   buf = silc_buffer_alloc(public_key->len);
646   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
647
648   silc_buffer_format(buf,
649                      SILC_STR_UI_INT(public_key->len),
650                      SILC_STR_UI_SHORT(strlen(public_key->name)),
651                      SILC_STR_UI32_STRING(public_key->name),
652                      SILC_STR_UI_SHORT(strlen(public_key->identifier)),
653                      SILC_STR_UI32_STRING(public_key->identifier),
654                      SILC_STR_UI_XNSTRING(public_key->pk, 
655                                           public_key->pk_len),
656                      SILC_STR_END);
657   if (len)
658     *len = public_key->len;
659
660   ret = silc_calloc(buf->len, sizeof(*ret));
661   memcpy(ret, buf->data, buf->len);
662   silc_buffer_free(buf);
663
664   return ret;
665 }
666
667 /* Encodes SILC style public key. Returns the encoded data. */
668
669 unsigned char *
670 silc_pkcs_public_key_data_encode(unsigned char *pk, SilcUInt32 pk_len,
671                                  char *pkcs, char *identifier, 
672                                  SilcUInt32 *len)
673 {
674   SilcBuffer buf;
675   unsigned char *ret;
676   SilcUInt32 totlen;
677
678   totlen = 4 + 2 + strlen(pkcs) + 2 + strlen(identifier) + pk_len;
679   buf = silc_buffer_alloc(totlen);
680   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
681
682   silc_buffer_format(buf,
683                      SILC_STR_UI_INT(totlen),
684                      SILC_STR_UI_SHORT(strlen(pkcs)),
685                      SILC_STR_UI32_STRING(pkcs),
686                      SILC_STR_UI_SHORT(strlen(identifier)),
687                      SILC_STR_UI32_STRING(identifier),
688                      SILC_STR_UI_XNSTRING(pk, pk_len),
689                      SILC_STR_END);
690   if (len)
691     *len = totlen;
692
693   ret = silc_calloc(buf->len, sizeof(*ret));
694   memcpy(ret, buf->data, buf->len);
695   silc_buffer_free(buf);
696
697   return ret;
698 }
699
700 /* Decodes SILC style public key. Returns TRUE if the decoding was
701    successful. Allocates new public key as well. */
702
703 int silc_pkcs_public_key_decode(unsigned char *data, SilcUInt32 data_len,
704                                 SilcPublicKey *public_key)
705 {
706   SilcBuffer buf;
707   SilcPKCS alg;
708   SilcUInt16 pkcs_len, identifier_len;
709   SilcUInt32 totlen, key_len;
710   unsigned char *pkcs_name = NULL, *ident = NULL, *key_data = NULL;
711   int ret;
712
713   buf = silc_buffer_alloc(data_len);
714   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
715   silc_buffer_put(buf, data, data_len);
716
717   /* Get length */
718   ret = silc_buffer_unformat(buf,
719                              SILC_STR_UI_INT(&totlen),
720                              SILC_STR_END);
721   if (ret == -1) {
722     silc_buffer_free(buf);
723     return FALSE;
724   }
725
726   if (totlen != data_len) {
727     silc_buffer_free(buf);
728     return FALSE;
729   }
730
731   /* Get algorithm name and identifier */
732   silc_buffer_pull(buf, 4);
733   ret =
734     silc_buffer_unformat(buf,
735                          SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
736                          SILC_STR_UI16_NSTRING_ALLOC(&ident, &identifier_len),
737                          SILC_STR_END);
738   if (ret == -1)
739     goto err;
740
741   if (pkcs_len < 1 || identifier_len < 3 || 
742       pkcs_len + identifier_len > totlen)
743     goto err;
744
745   /* See if we support this algorithm (check only if PKCS are registered) */
746   if (SILC_PKCS_LIST && !silc_pkcs_is_supported(pkcs_name)) {
747     SILC_LOG_DEBUG(("Unknown PKCS %s", pkcs_name));
748     goto err;
749   }
750
751   /* Protocol says that at least UN and HN must be provided as identifier,
752      check for these. */
753   if (!strstr(ident, "UN=") && !strstr(ident, "HN=")) {
754     SILC_LOG_DEBUG(("The public does not have the required UN= and HN= "
755                     "identifiers"));
756     goto err;
757   }
758
759   /* Get key data. We assume that rest of the buffer is key data. */
760   silc_buffer_pull(buf, 2 + pkcs_len + 2 + identifier_len);
761   key_len = buf->len;
762   ret = silc_buffer_unformat(buf,
763                              SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
764                              SILC_STR_END);
765   if (ret == -1)
766     goto err;
767
768   /* Try to set the key. If this fails the key must be malformed. This
769      code assumes that the PKCS routine checks the format of the key. 
770      (check only if PKCS are registered) */
771   if (SILC_PKCS_LIST) {
772     silc_pkcs_alloc(pkcs_name, &alg);
773     if (!alg->pkcs->set_public_key(alg->context, key_data, key_len))
774       goto err;
775     silc_pkcs_free(alg);
776   }
777   
778   if (public_key) {
779     *public_key = silc_calloc(1, sizeof(**public_key));
780     (*public_key)->len = totlen;
781     (*public_key)->name = pkcs_name;
782     (*public_key)->identifier = ident;
783     (*public_key)->pk = key_data;
784     (*public_key)->pk_len = key_len;
785   }
786
787   silc_buffer_free(buf);
788   return TRUE;
789
790  err:
791   if (pkcs_name)
792     silc_free(pkcs_name);
793   if (ident)
794     silc_free(ident);
795   if (key_data)
796     silc_free(key_data);
797   silc_buffer_free(buf);
798   return FALSE;
799 }
800
801 /* Compares two public keys and returns TRUE if they are same key, and
802    FALSE if they are not same. */
803
804 bool silc_pkcs_public_key_compare(SilcPublicKey key1, SilcPublicKey key2)
805 {
806   if (key1 == key2)
807     return TRUE;
808
809   if (key1->len == key2->len &&
810       key1->name && key2->name && key1->identifier && key2->identifier &&
811       !strcmp(key1->name, key2->name) &&
812       !strcmp(key1->identifier, key2->identifier) &&
813       !memcmp(key1->pk, key2->pk, key1->pk_len) &&
814       key1->pk_len == key2->pk_len)
815     return TRUE;
816
817   return FALSE;
818 }
819
820 /* Encodes SILC private key from SilcPrivateKey. Returns the encoded data. */
821
822 unsigned char *
823 silc_pkcs_private_key_encode(SilcPrivateKey private_key, SilcUInt32 *len)
824 {
825   SilcBuffer buf;
826   unsigned char *ret;
827   SilcUInt32 totlen;
828
829   totlen = 2 + strlen(private_key->name) + private_key->prv_len;
830   buf = silc_buffer_alloc(totlen);
831   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
832
833   silc_buffer_format(buf,
834                      SILC_STR_UI_SHORT(strlen(private_key->name)),
835                      SILC_STR_UI32_STRING(private_key->name),
836                      SILC_STR_UI_XNSTRING(private_key->prv, 
837                                           private_key->prv_len),
838                      SILC_STR_END);
839   if (len)
840     *len = totlen;
841
842   ret = silc_calloc(buf->len, sizeof(*ret));
843   memcpy(ret, buf->data, buf->len);
844   silc_buffer_free(buf);
845
846   return ret;
847 }
848
849 /* Encodes SILC private key. Returns the encoded data. */
850
851 unsigned char *
852 silc_pkcs_private_key_data_encode(unsigned char *prv, SilcUInt32 prv_len,
853                                   char *pkcs, SilcUInt32 *len)
854 {
855   SilcBuffer buf;
856   unsigned char *ret;
857   SilcUInt32 totlen;
858
859   totlen = 2 + strlen(pkcs) + prv_len;
860   buf = silc_buffer_alloc(totlen);
861   silc_buffer_pull_tail(buf, totlen);
862
863   silc_buffer_format(buf,
864                      SILC_STR_UI_SHORT(strlen(pkcs)),
865                      SILC_STR_UI32_STRING(pkcs),
866                      SILC_STR_UI_XNSTRING(prv, prv_len),
867                      SILC_STR_END);
868   if (len)
869     *len = totlen;
870
871   ret = silc_calloc(buf->len, sizeof(*ret));
872   memcpy(ret, buf->data, buf->len);
873   silc_buffer_free(buf);
874
875   return ret;
876 }
877
878 /* Decodes SILC style public key. Returns TRUE if the decoding was
879    successful. Allocates new private key as well. */
880
881 int silc_pkcs_private_key_decode(unsigned char *data, SilcUInt32 data_len,
882                                  SilcPrivateKey *private_key)
883 {
884   SilcBuffer buf;
885   SilcPKCS alg;
886   SilcUInt16 pkcs_len;
887   SilcUInt32 key_len;
888   unsigned char *pkcs_name = NULL, *key_data = NULL;
889   int ret;
890
891   buf = silc_buffer_alloc(data_len);
892   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
893   silc_buffer_put(buf, data, data_len);
894
895   /* Get algorithm name and identifier */
896   ret = 
897     silc_buffer_unformat(buf,
898                          SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
899                          SILC_STR_END);
900   if (ret == -1)
901     goto err;
902
903   if (pkcs_len < 1 || pkcs_len > buf->truelen)
904     goto err;
905
906   /* See if we support this algorithm (check only if PKCS are registered). */
907   if (SILC_PKCS_LIST && !silc_pkcs_is_supported(pkcs_name)) {
908     SILC_LOG_DEBUG(("Unknown PKCS `%s'", pkcs_name));
909     goto err;
910   }
911
912   /* Get key data. We assume that rest of the buffer is key data. */
913   silc_buffer_pull(buf, 2 + pkcs_len);
914   key_len = buf->len;
915   ret = silc_buffer_unformat(buf,
916                              SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
917                              SILC_STR_END);
918   if (ret == -1)
919     goto err;
920
921   /* Try to set the key. If this fails the key must be malformed. This
922      code assumes that the PKCS routine checks the format of the key. 
923      (check only if PKCS are registered) */
924   if (SILC_PKCS_LIST) {
925     silc_pkcs_alloc(pkcs_name, &alg);
926     if (!alg->pkcs->set_private_key(alg->context, key_data, key_len))
927       goto err;
928     silc_pkcs_free(alg);
929   }
930   
931   if (private_key) {
932     *private_key = silc_calloc(1, sizeof(**private_key));
933     (*private_key)->name = pkcs_name;
934     (*private_key)->prv = key_data;
935     (*private_key)->prv_len = key_len;
936   }
937
938   silc_buffer_free(buf);
939   return TRUE;
940
941  err:
942   if (pkcs_name)
943     silc_free(pkcs_name);
944   if (key_data)
945     silc_free(key_data);
946   silc_buffer_free(buf);
947   return FALSE;
948 }
949
950 /* Internal routine to save public key */
951
952 static int silc_pkcs_save_public_key_internal(char *filename,
953                                               unsigned char *data,
954                                               SilcUInt32 data_len,
955                                               SilcUInt32 encoding)
956 {
957   SilcBuffer buf;
958   SilcUInt32 len;
959
960   switch(encoding) {
961   case SILC_PKCS_FILE_BIN:
962     break;
963   case SILC_PKCS_FILE_PEM:
964     data = silc_pem_encode_file(data, data_len);
965     data_len = strlen(data);
966     break;
967   }
968
969   len = data_len + (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
970                     strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
971   buf = silc_buffer_alloc(len);
972   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
973
974   silc_buffer_format(buf,
975                      SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
976                      SILC_STR_UI_XNSTRING(data, data_len),
977                      SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END),
978                      SILC_STR_END);
979
980   /* Save into file */
981   if (silc_file_writefile(filename, buf->data, buf->len)) {
982     silc_buffer_free(buf);
983     return FALSE;
984   }
985
986   silc_buffer_free(buf);
987   return TRUE;
988 }
989
990 /* Saves public key into file */
991
992 int silc_pkcs_save_public_key(char *filename, SilcPublicKey public_key,
993                               SilcUInt32 encoding)
994 {
995   unsigned char *data;
996   SilcUInt32 data_len;
997
998   data = silc_pkcs_public_key_encode(public_key, &data_len);
999   return silc_pkcs_save_public_key_internal(filename, data, data_len,
1000                                             encoding);
1001 }
1002
1003 /* Saves public key into file */
1004
1005 int silc_pkcs_save_public_key_data(char *filename, unsigned char *data,
1006                                    SilcUInt32 data_len,
1007                                    SilcUInt32 encoding)
1008 {
1009   return silc_pkcs_save_public_key_internal(filename, data, data_len,
1010                                             encoding);
1011 }
1012
1013 /* Internal routine to save private key. */
1014
1015 static int silc_pkcs_save_private_key_internal(char *filename,
1016                                                unsigned char *data,
1017                                                SilcUInt32 data_len,
1018                                                SilcUInt32 encoding)
1019 {
1020   SilcBuffer buf;
1021   SilcUInt32 len;
1022
1023   switch(encoding) {
1024   case SILC_PKCS_FILE_BIN:
1025     break;
1026   case SILC_PKCS_FILE_PEM:
1027     data = silc_pem_encode_file(data, data_len);
1028     data_len = strlen(data);
1029     break;
1030   }
1031
1032   len = data_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
1033                     strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
1034   buf = silc_buffer_alloc(len);
1035   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1036
1037   silc_buffer_format(buf,
1038                      SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
1039                      SILC_STR_UI_XNSTRING(data, data_len),
1040                      SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
1041                      SILC_STR_END);
1042
1043   /* Save into a file */
1044   if (silc_file_writefile_mode(filename, buf->data, buf->len, 0600)) {
1045     silc_buffer_free(buf);
1046     return FALSE;
1047   }
1048
1049   silc_buffer_free(buf);
1050   return TRUE;
1051 }
1052
1053 /* Saves private key into file. */
1054 /* XXX The buffer should be encrypted if passphrase is provided. */
1055
1056 int silc_pkcs_save_private_key(char *filename, SilcPrivateKey private_key, 
1057                                unsigned char *passphrase,
1058                                SilcUInt32 encoding)
1059 {
1060   unsigned char *data;
1061   SilcUInt32 data_len;
1062
1063   data = silc_pkcs_private_key_encode(private_key, &data_len);
1064   return silc_pkcs_save_private_key_internal(filename, data, data_len,
1065                                              encoding);
1066 }
1067
1068 /* Saves private key into file. */
1069 /* XXX The buffer should be encrypted if passphrase is provided. */
1070
1071 int silc_pkcs_save_private_key_data(char *filename, unsigned char *data, 
1072                                     SilcUInt32 data_len,
1073                                     unsigned char *passphrase,
1074                                     SilcUInt32 encoding)
1075 {
1076   return silc_pkcs_save_private_key_internal(filename, data, data_len,
1077                                              encoding);
1078 }
1079
1080 /* Loads public key from file and allocates new public key. Returns TRUE
1081    is loading was successful. */
1082
1083 int silc_pkcs_load_public_key(char *filename, SilcPublicKey *public_key,
1084                               SilcUInt32 encoding)
1085 {
1086   unsigned char *cp, *old, *data, byte;
1087   SilcUInt32 i, data_len, len;
1088
1089   old = data = silc_file_readfile(filename, &data_len);
1090   if (!data)
1091     return FALSE;
1092
1093   /* Check start of file and remove header from the data. */
1094   len = strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN);
1095   cp = data;
1096   for (i = 0; i < len; i++) {
1097     byte = cp[0];
1098     cp++;
1099     if (byte != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i]) {
1100       memset(old, 0, data_len);
1101       silc_free(old);
1102       return FALSE;
1103     }
1104   }
1105   data = cp;
1106
1107   /* Decode public key */
1108   if (public_key) {
1109     len = data_len - (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
1110                       strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
1111
1112     switch(encoding) {
1113     case SILC_PKCS_FILE_BIN:
1114       break;
1115     case SILC_PKCS_FILE_PEM:
1116       data = silc_pem_decode(data, len, &len);
1117       memset(old, 0, data_len);
1118       silc_free(old);
1119       old = data; 
1120       data_len = len;
1121       break;
1122     }
1123
1124     if (!data || !silc_pkcs_public_key_decode(data, len, public_key)) {
1125       memset(old, 0, data_len);
1126       silc_free(old);
1127       return FALSE;
1128     }
1129   }
1130
1131   memset(old, 0, data_len);
1132   silc_free(old);
1133   return TRUE;
1134 }
1135
1136 /* Load private key from file and allocates new private key. Returns TRUE
1137    if loading was successful. */
1138 /* XXX Should support encrypted private key files */
1139
1140 int silc_pkcs_load_private_key(char *filename, SilcPrivateKey *private_key,
1141                                SilcUInt32 encoding)
1142 {
1143   unsigned char *cp, *old, *data, byte;
1144   SilcUInt32 i, data_len, len;
1145
1146   old = data = silc_file_readfile(filename, &data_len);
1147   if (!data)
1148     return FALSE;
1149
1150   /* Check start of file and remove header from the data. */
1151   len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
1152   cp = data;
1153   for (i = 0; i < len; i++) {
1154     byte = cp[0];
1155     cp++;
1156     if (byte != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i]) {
1157       memset(old, 0, data_len);
1158       silc_free(old);
1159       return FALSE;
1160     }
1161   }
1162   data = cp;
1163
1164   /* Decode private key */
1165   if (private_key) {
1166     len = data_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
1167                       strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
1168
1169     switch(encoding) {
1170     case SILC_PKCS_FILE_BIN:
1171       break;
1172     case SILC_PKCS_FILE_PEM:
1173       data = silc_pem_decode(data, len, &len);
1174       break;
1175     }
1176
1177     if (!data || !silc_pkcs_private_key_decode(data, len, private_key)) {
1178       memset(old, 0, data_len);
1179       silc_free(old);
1180       return FALSE;
1181     }
1182   }
1183
1184   memset(old, 0, data_len);
1185   silc_free(old);
1186   return TRUE;
1187 }