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