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 /* Copies the public key indicated by `public_key' and returns new allocated
815    public key which is indentical to the `public_key'. */
816
817 SilcPublicKey silc_pkcs_public_key_copy(SilcPublicKey public_key)
818 {
819   SilcPublicKey key = silc_calloc(1, sizeof(*key));
820   if (!key)
821     return NULL;
822
823   key->len = public_key->len;
824   key->name = silc_memdup(public_key->name, strlen(public_key->name));
825   key->identifier = silc_memdup(public_key->identifier,
826                                 strlen(public_key->identifier));
827   key->pk = silc_memdup(public_key->pk, public_key->pk_len);
828   key->pk_len = public_key->pk_len;
829
830   return key;
831 }
832
833 /* Encodes SILC private key from SilcPrivateKey. Returns the encoded data. */
834
835 unsigned char *
836 silc_pkcs_private_key_encode(SilcPrivateKey private_key, SilcUInt32 *len)
837 {
838   SilcBuffer buf;
839   unsigned char *ret;
840   SilcUInt32 totlen;
841
842   totlen = 2 + strlen(private_key->name) + private_key->prv_len;
843   buf = silc_buffer_alloc(totlen);
844   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
845
846   silc_buffer_format(buf,
847                      SILC_STR_UI_SHORT(strlen(private_key->name)),
848                      SILC_STR_UI32_STRING(private_key->name),
849                      SILC_STR_UI_XNSTRING(private_key->prv, 
850                                           private_key->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 /* Encodes SILC private key. Returns the encoded data. */
863
864 unsigned char *
865 silc_pkcs_private_key_data_encode(unsigned char *prv, SilcUInt32 prv_len,
866                                   char *pkcs, SilcUInt32 *len)
867 {
868   SilcBuffer buf;
869   unsigned char *ret;
870   SilcUInt32 totlen;
871
872   totlen = 2 + strlen(pkcs) + prv_len;
873   buf = silc_buffer_alloc(totlen);
874   silc_buffer_pull_tail(buf, totlen);
875
876   silc_buffer_format(buf,
877                      SILC_STR_UI_SHORT(strlen(pkcs)),
878                      SILC_STR_UI32_STRING(pkcs),
879                      SILC_STR_UI_XNSTRING(prv, prv_len),
880                      SILC_STR_END);
881   if (len)
882     *len = totlen;
883
884   ret = silc_calloc(buf->len, sizeof(*ret));
885   memcpy(ret, buf->data, buf->len);
886   silc_buffer_free(buf);
887
888   return ret;
889 }
890
891 /* Decodes SILC style public key. Returns TRUE if the decoding was
892    successful. Allocates new private key as well. */
893
894 int silc_pkcs_private_key_decode(unsigned char *data, SilcUInt32 data_len,
895                                  SilcPrivateKey *private_key)
896 {
897   SilcBuffer buf;
898   SilcPKCS alg;
899   SilcUInt16 pkcs_len;
900   SilcUInt32 key_len;
901   unsigned char *pkcs_name = NULL, *key_data = NULL;
902   int ret;
903
904   buf = silc_buffer_alloc(data_len);
905   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
906   silc_buffer_put(buf, data, data_len);
907
908   /* Get algorithm name and identifier */
909   ret = 
910     silc_buffer_unformat(buf,
911                          SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
912                          SILC_STR_END);
913   if (ret == -1)
914     goto err;
915
916   if (pkcs_len < 1 || pkcs_len > buf->truelen)
917     goto err;
918
919   /* See if we support this algorithm (check only if PKCS are registered). */
920   if (SILC_PKCS_LIST && !silc_pkcs_is_supported(pkcs_name)) {
921     SILC_LOG_DEBUG(("Unknown PKCS `%s'", pkcs_name));
922     goto err;
923   }
924
925   /* Get key data. We assume that rest of the buffer is key data. */
926   silc_buffer_pull(buf, 2 + pkcs_len);
927   key_len = buf->len;
928   ret = silc_buffer_unformat(buf,
929                              SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
930                              SILC_STR_END);
931   if (ret == -1)
932     goto err;
933
934   /* Try to set the key. If this fails the key must be malformed. This
935      code assumes that the PKCS routine checks the format of the key. 
936      (check only if PKCS are registered) */
937   if (SILC_PKCS_LIST) {
938     silc_pkcs_alloc(pkcs_name, &alg);
939     if (!alg->pkcs->set_private_key(alg->context, key_data, key_len))
940       goto err;
941     silc_pkcs_free(alg);
942   }
943   
944   if (private_key) {
945     *private_key = silc_calloc(1, sizeof(**private_key));
946     (*private_key)->name = pkcs_name;
947     (*private_key)->prv = key_data;
948     (*private_key)->prv_len = key_len;
949   }
950
951   silc_buffer_free(buf);
952   return TRUE;
953
954  err:
955   if (pkcs_name)
956     silc_free(pkcs_name);
957   if (key_data)
958     silc_free(key_data);
959   silc_buffer_free(buf);
960   return FALSE;
961 }
962
963 /* Internal routine to save public key */
964
965 static int silc_pkcs_save_public_key_internal(char *filename,
966                                               unsigned char *data,
967                                               SilcUInt32 data_len,
968                                               SilcUInt32 encoding)
969 {
970   SilcBuffer buf;
971   SilcUInt32 len;
972
973   switch(encoding) {
974   case SILC_PKCS_FILE_BIN:
975     break;
976   case SILC_PKCS_FILE_PEM:
977     data = silc_pem_encode_file(data, data_len);
978     data_len = strlen(data);
979     break;
980   }
981
982   len = data_len + (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
983                     strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
984   buf = silc_buffer_alloc(len);
985   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
986
987   silc_buffer_format(buf,
988                      SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
989                      SILC_STR_UI_XNSTRING(data, data_len),
990                      SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END),
991                      SILC_STR_END);
992
993   /* Save into file */
994   if (silc_file_writefile(filename, buf->data, buf->len)) {
995     silc_buffer_free(buf);
996     return FALSE;
997   }
998
999   silc_buffer_free(buf);
1000   return TRUE;
1001 }
1002
1003 /* Saves public key into file */
1004
1005 int silc_pkcs_save_public_key(char *filename, SilcPublicKey public_key,
1006                               SilcUInt32 encoding)
1007 {
1008   unsigned char *data;
1009   SilcUInt32 data_len;
1010
1011   data = silc_pkcs_public_key_encode(public_key, &data_len);
1012   return silc_pkcs_save_public_key_internal(filename, data, data_len,
1013                                             encoding);
1014 }
1015
1016 /* Saves public key into file */
1017
1018 int silc_pkcs_save_public_key_data(char *filename, unsigned char *data,
1019                                    SilcUInt32 data_len,
1020                                    SilcUInt32 encoding)
1021 {
1022   return silc_pkcs_save_public_key_internal(filename, data, data_len,
1023                                             encoding);
1024 }
1025
1026 /* Internal routine to save private key. */
1027
1028 static int silc_pkcs_save_private_key_internal(char *filename,
1029                                                unsigned char *data,
1030                                                SilcUInt32 data_len,
1031                                                SilcUInt32 encoding)
1032 {
1033   SilcBuffer buf;
1034   SilcUInt32 len;
1035
1036   switch(encoding) {
1037   case SILC_PKCS_FILE_BIN:
1038     break;
1039   case SILC_PKCS_FILE_PEM:
1040     data = silc_pem_encode_file(data, data_len);
1041     data_len = strlen(data);
1042     break;
1043   }
1044
1045   len = data_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
1046                     strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
1047   buf = silc_buffer_alloc(len);
1048   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1049
1050   silc_buffer_format(buf,
1051                      SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
1052                      SILC_STR_UI_XNSTRING(data, data_len),
1053                      SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
1054                      SILC_STR_END);
1055
1056   /* Save into a file */
1057   if (silc_file_writefile_mode(filename, buf->data, buf->len, 0600)) {
1058     silc_buffer_free(buf);
1059     return FALSE;
1060   }
1061
1062   silc_buffer_free(buf);
1063   return TRUE;
1064 }
1065
1066 /* Saves private key into file. */
1067 /* XXX The buffer should be encrypted if passphrase is provided. */
1068
1069 int silc_pkcs_save_private_key(char *filename, SilcPrivateKey private_key, 
1070                                unsigned char *passphrase,
1071                                SilcUInt32 encoding)
1072 {
1073   unsigned char *data;
1074   SilcUInt32 data_len;
1075
1076   data = silc_pkcs_private_key_encode(private_key, &data_len);
1077   return silc_pkcs_save_private_key_internal(filename, data, data_len,
1078                                              encoding);
1079 }
1080
1081 /* Saves private key into file. */
1082 /* XXX The buffer should be encrypted if passphrase is provided. */
1083
1084 int silc_pkcs_save_private_key_data(char *filename, unsigned char *data, 
1085                                     SilcUInt32 data_len,
1086                                     unsigned char *passphrase,
1087                                     SilcUInt32 encoding)
1088 {
1089   return silc_pkcs_save_private_key_internal(filename, data, data_len,
1090                                              encoding);
1091 }
1092
1093 /* Loads public key from file and allocates new public key. Returns TRUE
1094    is loading was successful. */
1095
1096 int silc_pkcs_load_public_key(char *filename, SilcPublicKey *public_key,
1097                               SilcUInt32 encoding)
1098 {
1099   unsigned char *cp, *old, *data, byte;
1100   SilcUInt32 i, data_len, len;
1101
1102   old = data = silc_file_readfile(filename, &data_len);
1103   if (!data)
1104     return FALSE;
1105
1106   /* Check start of file and remove header from the data. */
1107   len = strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN);
1108   cp = data;
1109   for (i = 0; i < len; i++) {
1110     byte = cp[0];
1111     cp++;
1112     if (byte != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i]) {
1113       memset(old, 0, data_len);
1114       silc_free(old);
1115       return FALSE;
1116     }
1117   }
1118   data = cp;
1119
1120   /* Decode public key */
1121   if (public_key) {
1122     len = data_len - (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
1123                       strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
1124
1125     switch(encoding) {
1126     case SILC_PKCS_FILE_BIN:
1127       break;
1128     case SILC_PKCS_FILE_PEM:
1129       data = silc_pem_decode(data, len, &len);
1130       memset(old, 0, data_len);
1131       silc_free(old);
1132       old = data; 
1133       data_len = len;
1134       break;
1135     }
1136
1137     if (!data || !silc_pkcs_public_key_decode(data, len, public_key)) {
1138       memset(old, 0, data_len);
1139       silc_free(old);
1140       return FALSE;
1141     }
1142   }
1143
1144   memset(old, 0, data_len);
1145   silc_free(old);
1146   return TRUE;
1147 }
1148
1149 /* Load private key from file and allocates new private key. Returns TRUE
1150    if loading was successful. */
1151 /* XXX Should support encrypted private key files */
1152
1153 int silc_pkcs_load_private_key(char *filename, SilcPrivateKey *private_key,
1154                                SilcUInt32 encoding)
1155 {
1156   unsigned char *cp, *old, *data, byte;
1157   SilcUInt32 i, data_len, len;
1158
1159   old = data = silc_file_readfile(filename, &data_len);
1160   if (!data)
1161     return FALSE;
1162
1163   /* Check start of file and remove header from the data. */
1164   len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
1165   cp = data;
1166   for (i = 0; i < len; i++) {
1167     byte = cp[0];
1168     cp++;
1169     if (byte != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i]) {
1170       memset(old, 0, data_len);
1171       silc_free(old);
1172       return FALSE;
1173     }
1174   }
1175   data = cp;
1176
1177   /* Decode private key */
1178   if (private_key) {
1179     len = data_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
1180                       strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
1181
1182     switch(encoding) {
1183     case SILC_PKCS_FILE_BIN:
1184       break;
1185     case SILC_PKCS_FILE_PEM:
1186       data = silc_pem_decode(data, len, &len);
1187       break;
1188     }
1189
1190     if (!data || !silc_pkcs_private_key_decode(data, len, private_key)) {
1191       memset(old, 0, data_len);
1192       silc_free(old);
1193       return FALSE;
1194     }
1195   }
1196
1197   memset(old, 0, data_len);
1198   silc_free(old);
1199   return TRUE;
1200 }