Protocol version 1.2 integrations
[silc.git] / lib / silccrypt / silcpkcs.c
1 /*
2
3   silcpkcs.c 
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2002 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; version 2 of the License.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18 */
19 /* $Id$ */
20
21 #include "silcincludes.h"
22
23 #include "rsa.h"
24 #include "pkcs1.h"
25
26 /* The main SILC PKCS structure. */
27 struct SilcPKCSStruct {
28   void *context;                /* Algorithm internal context */
29   SilcPKCSObject *pkcs;         /* Algorithm implementation */
30   SilcUInt32 key_len;           /* Key length in bits */
31 };
32
33 #ifndef SILC_EPOC
34 /* Dynamically registered list of PKCS. */
35 SilcDList silc_pkcs_list = NULL;
36 #define SILC_PKCS_LIST silc_pkcs_list
37 #else
38 #define SILC_PKCS_LIST TRUE
39 #endif /* SILC_EPOC */
40
41 /* Static list of PKCS for silc_pkcs_register_default(). */
42 const SilcPKCSObject silc_default_pkcs[] =
43 {
44   /* RSA with PKCS #1 (Uses directly routines from Raw RSA operations) */
45   { "rsa", 
46     silc_rsa_init, silc_rsa_clear_keys, silc_rsa_get_public_key,
47     silc_rsa_get_private_key, silc_rsa_set_public_key,
48     silc_rsa_set_private_key, silc_rsa_context_len,
49     silc_pkcs1_encrypt, silc_pkcs1_decrypt,
50     silc_pkcs1_sign, silc_pkcs1_verify },
51
52   /* Raw RSA operations */
53   { "rsa-raw", 
54     silc_rsa_init, silc_rsa_clear_keys, silc_rsa_get_public_key,
55     silc_rsa_get_private_key, silc_rsa_set_public_key,
56     silc_rsa_set_private_key, silc_rsa_context_len,
57     silc_rsa_encrypt, silc_rsa_decrypt,
58     silc_rsa_sign, silc_rsa_verify },
59
60   { NULL, NULL, NULL, NULL, NULL,
61     NULL, NULL, NULL, NULL, NULL, NULL }
62 };
63
64 /* Register a new PKCS into SILC. This is used at the initialization of
65    the SILC. */
66
67 bool silc_pkcs_register(const SilcPKCSObject *pkcs)
68 {
69 #ifndef SILC_EPOC
70   SilcPKCSObject *new;
71
72   SILC_LOG_DEBUG(("Registering new PKCS `%s'", pkcs->name));
73
74   /* Check if exists already */
75   if (silc_pkcs_list) {
76     SilcPKCSObject *entry;
77     silc_dlist_start(silc_pkcs_list);
78     while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
79       if (!strcmp(entry->name, pkcs->name))
80         return FALSE;
81     }
82   }
83
84   new = silc_calloc(1, sizeof(*new));
85   new->name = strdup(pkcs->name);
86   new->init = pkcs->init;
87   new->clear_keys = pkcs->clear_keys;
88   new->get_public_key = pkcs->get_public_key;
89   new->get_private_key = pkcs->get_private_key;
90   new->set_public_key = pkcs->set_public_key;
91   new->set_private_key = pkcs->set_private_key;
92   new->context_len = pkcs->context_len;
93   new->encrypt = pkcs->encrypt;
94   new->decrypt = pkcs->decrypt;
95   new->sign = pkcs->sign;
96   new->verify = pkcs->verify;
97
98   /* Add to list */
99   if (silc_pkcs_list == NULL)
100     silc_pkcs_list = silc_dlist_init();
101   silc_dlist_add(silc_pkcs_list, new);
102
103 #endif /* SILC_EPOC */
104   return TRUE;
105 }
106
107 /* Unregister a PKCS from the SILC. */
108
109 bool silc_pkcs_unregister(SilcPKCSObject *pkcs)
110 {
111 #ifndef SILC_EPOC
112   SilcPKCSObject *entry;
113
114   SILC_LOG_DEBUG(("Unregistering PKCS"));
115
116   if (!silc_pkcs_list)
117     return FALSE;
118
119   silc_dlist_start(silc_pkcs_list);
120   while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
121     if (pkcs == SILC_ALL_PKCS || entry == pkcs) {
122       silc_dlist_del(silc_pkcs_list, entry);
123       silc_free(entry->name);
124       silc_free(entry);
125
126       if (silc_dlist_count(silc_pkcs_list) == 0) {
127         silc_dlist_uninit(silc_pkcs_list);
128         silc_pkcs_list = NULL;
129       }
130
131       return TRUE;
132     }
133   }
134
135 #endif /* SILC_EPOC */
136   return FALSE;
137 }
138
139 /* Function that registers all the default PKCS (all builtin PKCS). 
140    The application may use this to register the default PKCS if specific
141    PKCS in any specific order is not wanted. */
142
143 bool silc_pkcs_register_default(void)
144 {
145 #ifndef SILC_EPOC
146   int i;
147
148   for (i = 0; silc_default_pkcs[i].name; i++)
149     silc_pkcs_register(&(silc_default_pkcs[i]));
150
151 #endif /* SILC_EPOC */
152   return TRUE;
153 }
154
155 bool silc_pkcs_unregister_all(void)
156 {
157 #ifndef SILC_EPOC
158   SilcPKCSObject *entry;
159
160   if (!silc_pkcs_list)
161     return FALSE;
162
163   silc_dlist_start(silc_pkcs_list);
164   while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
165     silc_pkcs_unregister(entry);
166     if (!silc_pkcs_list)
167       break;
168   }
169 #endif /* SILC_EPOC */
170   return TRUE;
171 }
172
173 /* Allocates a new SilcPKCS object. The new allocated object is returned
174    to the 'new_pkcs' argument. */
175
176 bool silc_pkcs_alloc(const unsigned char *name, SilcPKCS *new_pkcs)
177 {
178   SilcPKCSObject *entry = NULL;
179
180   SILC_LOG_DEBUG(("Allocating new PKCS object"));
181
182 #ifndef SILC_EPOC
183   if (silc_pkcs_list) {
184     silc_dlist_start(silc_pkcs_list);
185     while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
186       if (!strcmp(entry->name, name))
187         break;
188     }
189   }
190 #else
191   {
192     /* On EPOC which don't have globals we check our constant hash list. */
193     int i;
194     for (i = 0; silc_default_pkcs[i].name; i++) {
195       if (!strcmp(silc_default_pkcs[i].name, name)) {
196         entry = (SilcPKCSObject *)&(silc_default_pkcs[i]);
197         break;
198       }
199     }
200   }
201 #endif /* SILC_EPOC */
202
203   if (entry) {
204     *new_pkcs = silc_calloc(1, sizeof(**new_pkcs));
205     (*new_pkcs)->pkcs = entry;
206     (*new_pkcs)->context = silc_calloc(1, entry->context_len());
207     return TRUE;
208   }
209
210   return FALSE;
211 }
212
213 /* Free's the PKCS object */
214
215 void silc_pkcs_free(SilcPKCS pkcs)
216 {
217   if (pkcs) {
218     pkcs->pkcs->clear_keys(pkcs->context);
219     silc_free(pkcs->context);
220   }
221   silc_free(pkcs);
222 }
223
224 /* Return TRUE if PKCS algorithm `name' is supported. */
225
226 bool silc_pkcs_is_supported(const unsigned char *name)
227 {
228 #ifndef SILC_EPOC
229   SilcPKCSObject *entry;
230
231   if (silc_pkcs_list) {
232     silc_dlist_start(silc_pkcs_list);
233     while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
234       if (!strcmp(entry->name, name))
235         return TRUE;
236     }
237   }
238 #else
239   {
240     int i;
241     for (i = 0; silc_default_pkcs[i].name; i++)
242       if (!strcmp(silc_default_pkcs[i].name, name))
243         return TRUE;
244   }
245 #endif /* SILC_EPOC */
246   return FALSE;
247 }
248
249 /* Returns comma separated list of supported PKCS algorithms */
250
251 char *silc_pkcs_get_supported(void)
252 {
253   SilcPKCSObject *entry;
254   char *list = NULL;
255   int len = 0;
256
257 #ifndef SILC_EPOC
258   if (silc_pkcs_list) {
259     silc_dlist_start(silc_pkcs_list);
260     while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
261       len += strlen(entry->name);
262       list = silc_realloc(list, len + 1);
263       
264       memcpy(list + (len - strlen(entry->name)), 
265              entry->name, strlen(entry->name));
266       memcpy(list + len, ",", 1);
267       len++;
268     }
269   }
270 #else
271   {
272     int i;
273     for (i = 0; silc_default_pkcs[i].name; i++) {
274       entry = (SilcPKCSObject *)&(silc_default_pkcs[i]);
275       len += strlen(entry->name);
276       list = silc_realloc(list, len + 1);
277       
278       memcpy(list + (len - strlen(entry->name)), 
279              entry->name, strlen(entry->name));
280       memcpy(list + len, ",", 1);
281       len++;
282     }
283   }
284 #endif /* SILC_EPOC */
285
286   list[len - 1] = 0;
287
288   return list;
289 }
290
291 /* Generate new key pair into the `pkcs' context. */
292
293 bool silc_pkcs_generate_key(SilcPKCS pkcs, SilcUInt32 bits_key_len,
294                             SilcRng rng)
295 {
296   return pkcs->pkcs->init(pkcs->context, bits_key_len, rng);
297 }
298
299 /* Returns the length of the key */
300
301 SilcUInt32 silc_pkcs_get_key_len(SilcPKCS pkcs)
302 {
303   return pkcs->key_len;
304 }
305
306 const char *silc_pkcs_get_name(SilcPKCS pkcs)
307 {
308   return pkcs->pkcs->name;
309 }
310
311 /* Returns SILC style public key */
312
313 unsigned char *silc_pkcs_get_public_key(SilcPKCS pkcs, SilcUInt32 *len)
314 {
315   return pkcs->pkcs->get_public_key(pkcs->context, len);
316 }
317
318 /* Returns SILC style private key */
319
320 unsigned char *silc_pkcs_get_private_key(SilcPKCS pkcs, SilcUInt32 *len)
321 {
322   return pkcs->pkcs->get_private_key(pkcs->context, len);
323 }
324
325 /* Sets public key from SilcPublicKey. */
326
327 SilcUInt32 silc_pkcs_public_key_set(SilcPKCS pkcs, SilcPublicKey public_key)
328 {
329   pkcs->key_len = pkcs->pkcs->set_public_key(pkcs->context, public_key->pk, 
330                                              public_key->pk_len);
331   return pkcs->key_len;
332 }
333
334 /* Sets public key from data. */
335
336 SilcUInt32 silc_pkcs_public_key_data_set(SilcPKCS pkcs, unsigned char *pk,
337                                      SilcUInt32 pk_len)
338 {
339   pkcs->key_len = pkcs->pkcs->set_public_key(pkcs->context, pk, pk_len);
340   return pkcs->key_len;
341 }
342
343 /* Sets private key from SilcPrivateKey. */
344
345 SilcUInt32 silc_pkcs_private_key_set(SilcPKCS pkcs, SilcPrivateKey private_key)
346 {
347   SilcUInt32 key_len;
348   key_len = pkcs->pkcs->set_private_key(pkcs->context, private_key->prv, 
349                                         private_key->prv_len);
350   if (!pkcs->key_len)
351     pkcs->key_len = key_len;
352   return pkcs->key_len;
353 }
354
355 /* Sets private key from data. */
356
357 SilcUInt32 silc_pkcs_private_key_data_set(SilcPKCS pkcs, unsigned char *prv,
358                                           SilcUInt32 prv_len)
359 {
360   SilcUInt32 key_len;
361   key_len = pkcs->pkcs->set_private_key(pkcs->context, prv, prv_len);
362   if (!pkcs->key_len)
363     pkcs->key_len = key_len;
364   return pkcs->key_len;
365 }
366
367 /* Encrypts */
368
369 bool silc_pkcs_encrypt(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len,
370                        unsigned char *dst, SilcUInt32 *dst_len)
371 {
372   return pkcs->pkcs->encrypt(pkcs->context, src, src_len, dst, dst_len);
373 }
374
375 /* Decrypts */
376
377 bool silc_pkcs_decrypt(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len,
378                        unsigned char *dst, SilcUInt32 *dst_len)
379 {
380   return pkcs->pkcs->decrypt(pkcs->context, src, src_len, dst, dst_len);
381 }
382
383 /* Generates signature */
384
385 bool silc_pkcs_sign(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len,
386                     unsigned char *dst, SilcUInt32 *dst_len)
387 {
388   return pkcs->pkcs->sign(pkcs->context, src, src_len, dst, dst_len);
389 }
390
391 /* Verifies signature */
392
393 bool silc_pkcs_verify(SilcPKCS pkcs, unsigned char *signature, 
394                       SilcUInt32 signature_len, unsigned char *data, 
395                       SilcUInt32 data_len)
396 {
397   return pkcs->pkcs->verify(pkcs->context, signature, signature_len, 
398                             data, data_len);
399 }
400
401 /* Generates signature with hash. The hash is signed. */
402
403 bool silc_pkcs_sign_with_hash(SilcPKCS pkcs, SilcHash hash,
404                               unsigned char *src, SilcUInt32 src_len,
405                               unsigned char *dst, SilcUInt32 *dst_len)
406 {
407   unsigned char hashr[32];
408   SilcUInt32 hash_len;
409   int ret;
410
411   silc_hash_make(hash, src, src_len, hashr);
412   hash_len = silc_hash_len(hash);
413
414   SILC_LOG_HEXDUMP(("Hash"), hashr, hash_len);
415
416   ret = pkcs->pkcs->sign(pkcs->context, hashr, hash_len, dst, dst_len);
417   memset(hashr, 0, sizeof(hashr));
418
419   return ret;
420 }
421
422 /* Verifies signature with hash. The `data' is hashed and verified against
423    the `signature'. */
424
425 bool silc_pkcs_verify_with_hash(SilcPKCS pkcs, SilcHash hash, 
426                                 unsigned char *signature, 
427                                 SilcUInt32 signature_len, 
428                                 unsigned char *data, 
429                                 SilcUInt32 data_len)
430 {
431   unsigned char hashr[32];
432   SilcUInt32 hash_len;
433   int ret;
434
435   silc_hash_make(hash, data, data_len, hashr);
436   hash_len = silc_hash_len(hash);
437
438   SILC_LOG_HEXDUMP(("Hash"), hashr, hash_len);
439
440   ret = pkcs->pkcs->verify(pkcs->context, signature, signature_len, 
441                            hashr, hash_len);
442   memset(hashr, 0, sizeof(hashr));
443
444   return ret;
445 }
446
447 /* Encodes and returns SILC public key identifier. If some of the 
448    arguments is NULL those are not encoded into the identifier string.
449    Protocol says that at least username and host must be provided. */
450
451 char *silc_pkcs_encode_identifier(char *username, char *host, char *realname,
452                                   char *email, char *org, char *country)
453 {
454   SilcBuffer buf;
455   char *identifier;
456   SilcUInt32 len, tlen = 0;
457
458   if (!username || !host)
459     return NULL;
460
461   len = (username ? strlen(username) : 0) +
462         (host     ? strlen(host)     : 0) +
463         (realname ? strlen(realname) : 0) +
464         (email    ? strlen(email)    : 0) +
465         (org      ? strlen(org)      : 0) +
466         (country  ? strlen(country)  : 0);
467   
468   if (len < 3)
469     return NULL;
470
471   len += 3 + 5 + 5 + 4 + 4 + 4;
472   buf = silc_buffer_alloc(len);
473   silc_buffer_pull_tail(buf, len);
474
475   if (username) {
476     silc_buffer_format(buf,
477                        SILC_STR_UI32_STRING("UN="),
478                        SILC_STR_UI32_STRING(username),
479                        SILC_STR_END);
480     silc_buffer_pull(buf, 3 + strlen(username));
481     tlen = 3 + strlen(username); 
482   }
483     
484   if (host) {
485     silc_buffer_format(buf,
486                        SILC_STR_UI32_STRING(", "),
487                        SILC_STR_UI32_STRING("HN="),
488                        SILC_STR_UI32_STRING(host),
489                        SILC_STR_END);
490     silc_buffer_pull(buf, 5 + strlen(host));
491     tlen += 5 + strlen(host); 
492   }
493
494   if (realname) {
495     silc_buffer_format(buf,
496                        SILC_STR_UI32_STRING(", "),
497                        SILC_STR_UI32_STRING("RN="),
498                        SILC_STR_UI32_STRING(realname),
499                        SILC_STR_END);
500     silc_buffer_pull(buf, 5 + strlen(realname));
501     tlen += 5 + strlen(realname); 
502   }
503
504   if (email) {
505     silc_buffer_format(buf,
506                        SILC_STR_UI32_STRING(", "),
507                        SILC_STR_UI32_STRING("E="),
508                        SILC_STR_UI32_STRING(email),
509                        SILC_STR_END);
510     silc_buffer_pull(buf, 4 + strlen(email));
511     tlen += 4 + strlen(email); 
512   }
513
514   if (org) {
515     silc_buffer_format(buf,
516                        SILC_STR_UI32_STRING(", "),
517                        SILC_STR_UI32_STRING("O="),
518                        SILC_STR_UI32_STRING(org),
519                        SILC_STR_END);
520     silc_buffer_pull(buf, 4 + strlen(org));
521     tlen += 4 + strlen(org); 
522   }
523
524   if (country) {
525     silc_buffer_format(buf,
526                        SILC_STR_UI32_STRING(", "),
527                        SILC_STR_UI32_STRING("C="),
528                        SILC_STR_UI32_STRING(country),
529                        SILC_STR_END);
530     silc_buffer_pull(buf, 4 + strlen(country));
531     tlen += 4 + strlen(country); 
532   }
533
534   silc_buffer_push(buf, buf->data - buf->head);
535   identifier = silc_calloc(tlen + 1, sizeof(*identifier));
536   memcpy(identifier, buf->data, tlen);
537   silc_buffer_free(buf);
538
539   return identifier;
540 }
541
542 /* Decodes the provided `identifier' and returns allocated context for
543    the identifier. */
544
545 SilcPublicKeyIdentifier silc_pkcs_decode_identifier(char *identifier)
546 {
547   SilcPublicKeyIdentifier ident;
548   char *cp, *item;
549   int len;
550
551   ident = silc_calloc(1, sizeof(*ident));
552
553   cp = identifier;
554   while (cp) {
555     len = strcspn(cp, ",");
556     if (len - 1 >= 0 && cp[len - 1] == '\\') {
557       while (cp) {
558         cp += len + 1;
559         len = strcspn(cp, ",") + len;
560         if (len - 1 >= 0 && cp[len - 1] != '\\')
561           break;
562       }
563     }
564
565     item = silc_calloc(len + 1, sizeof(char));
566     memcpy(item, cp, len);
567
568     if (strstr(item, "UN="))
569       ident->username = strdup(item + strcspn(cp, "=") + 1);
570     else if (strstr(item, "HN="))
571       ident->host = strdup(item + strcspn(cp, "=") + 1);
572     else if (strstr(item, "RN="))
573       ident->realname = strdup(item + strcspn(cp, "=") + 1);
574     else if (strstr(item, "E="))
575       ident->email = strdup(item + strcspn(cp, "=") + 1);
576     else if (strstr(item, "O="))
577       ident->org = strdup(item + strcspn(cp, "=") + 1);
578     else if (strstr(item, "C="))
579       ident->country = strdup(item + strcspn(cp, "=") + 1);
580     
581     cp += len;
582     if (strlen(cp) == 0)
583       cp = NULL;
584     else
585       cp += 1;
586     
587     if (item)
588       silc_free(item);
589   }
590
591   return ident;
592 }
593
594 /* Free's decoded public key identifier context. Call this to free the
595    context returned by the silc_pkcs_decode_identifier. */
596
597 void silc_pkcs_free_identifier(SilcPublicKeyIdentifier identifier)
598 {
599   silc_free(identifier->username);
600   silc_free(identifier->host);
601   silc_free(identifier->realname);
602   silc_free(identifier->email);
603   silc_free(identifier->org);
604   silc_free(identifier->country);
605   silc_free(identifier);
606 }
607
608 /* Allocates SILC style public key formed from sent arguments. All data
609    is duplicated. */
610
611 SilcPublicKey silc_pkcs_public_key_alloc(const char *name, 
612                                          const char *identifier,
613                                          const unsigned char *pk, 
614                                          SilcUInt32 pk_len)
615 {
616   SilcPublicKey public_key;
617   char *tmp = NULL;
618
619   public_key = silc_calloc(1, sizeof(*public_key));
620   public_key->name = strdup(name);
621   public_key->pk_len = pk_len;
622   public_key->pk = silc_calloc(pk_len, sizeof(*public_key->pk));
623   public_key->pk_type = SILC_SKE_PK_TYPE_SILC;
624   memcpy(public_key->pk, pk, pk_len);
625
626   if (!silc_utf8_valid(identifier, strlen(identifier))) {
627     int len = silc_utf8_encoded_len(identifier, strlen(identifier), 0);
628     tmp = silc_calloc(len + 1, sizeof(*tmp));
629     silc_utf8_encode(identifier, strlen(identifier), 0, tmp, len);
630     identifier = tmp;
631   }
632
633   public_key->identifier = strdup(identifier);
634   public_key->len = 4 + 2 + strlen(name) + 2 + strlen(identifier) + pk_len;
635   silc_free(tmp);
636
637   return public_key;
638 }
639
640 /* Free's public key */
641
642 void silc_pkcs_public_key_free(SilcPublicKey public_key)
643 {
644   if (public_key) {
645     silc_free(public_key->name);
646     silc_free(public_key->identifier);
647     silc_free(public_key->pk);
648     silc_free(public_key);
649   }
650 }
651
652 /* Allocates SILC private key formed from sent arguments. All data is
653    duplicated. */
654
655 SilcPrivateKey silc_pkcs_private_key_alloc(const char *name,
656                                            const unsigned char *prv,
657                                            SilcUInt32 prv_len)
658 {
659   SilcPrivateKey private_key;
660
661   private_key = silc_calloc(1, sizeof(*private_key));
662   private_key->name = strdup(name);
663   private_key->prv_len = prv_len;
664   private_key->prv = silc_calloc(prv_len, sizeof(*private_key->prv));
665   memcpy(private_key->prv, prv, prv_len);
666
667   return private_key;
668 }
669
670 /* Free's private key */
671
672 void silc_pkcs_private_key_free(SilcPrivateKey private_key)
673 {
674   if (private_key) {
675     silc_free(private_key->name);
676     silc_free(private_key->prv);
677     silc_free(private_key);
678   }
679 }
680
681 /* Encodes SILC style public key from SilcPublicKey. Returns the encoded
682    data. */
683
684 unsigned char *
685 silc_pkcs_public_key_encode(SilcPublicKey public_key, SilcUInt32 *len)
686 {
687   SilcBuffer buf;
688   unsigned char *ret;
689
690   buf = silc_buffer_alloc(public_key->len);
691   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
692
693   silc_buffer_format(buf,
694                      SILC_STR_UI_INT(public_key->len),
695                      SILC_STR_UI_SHORT(strlen(public_key->name)),
696                      SILC_STR_UI32_STRING(public_key->name),
697                      SILC_STR_UI_SHORT(strlen(public_key->identifier)),
698                      SILC_STR_UI32_STRING(public_key->identifier),
699                      SILC_STR_UI_XNSTRING(public_key->pk, 
700                                           public_key->pk_len),
701                      SILC_STR_END);
702   if (len)
703     *len = public_key->len;
704
705   ret = silc_calloc(buf->len, sizeof(*ret));
706   memcpy(ret, buf->data, buf->len);
707   silc_buffer_free(buf);
708
709   return ret;
710 }
711
712 /* Encodes SILC style public key. Returns the encoded data. */
713
714 unsigned char *
715 silc_pkcs_public_key_data_encode(unsigned char *pk, SilcUInt32 pk_len,
716                                  char *pkcs, char *identifier, 
717                                  SilcUInt32 *len)
718 {
719   SilcBuffer buf;
720   unsigned char *ret;
721   SilcUInt32 totlen;
722
723   totlen = 4 + 2 + strlen(pkcs) + 2 + strlen(identifier) + pk_len;
724   buf = silc_buffer_alloc(totlen);
725   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
726
727   silc_buffer_format(buf,
728                      SILC_STR_UI_INT(totlen),
729                      SILC_STR_UI_SHORT(strlen(pkcs)),
730                      SILC_STR_UI32_STRING(pkcs),
731                      SILC_STR_UI_SHORT(strlen(identifier)),
732                      SILC_STR_UI32_STRING(identifier),
733                      SILC_STR_UI_XNSTRING(pk, pk_len),
734                      SILC_STR_END);
735   if (len)
736     *len = totlen;
737
738   ret = silc_calloc(buf->len, sizeof(*ret));
739   memcpy(ret, buf->data, buf->len);
740   silc_buffer_free(buf);
741
742   return ret;
743 }
744
745 /* Decodes SILC style public key. Returns TRUE if the decoding was
746    successful. Allocates new public key as well. */
747
748 bool silc_pkcs_public_key_decode(unsigned char *data, SilcUInt32 data_len,
749                                  SilcPublicKey *public_key)
750 {
751   SilcBuffer buf;
752   SilcPKCS alg;
753   SilcUInt16 pkcs_len, identifier_len;
754   SilcUInt32 totlen, key_len;
755   unsigned char *pkcs_name = NULL, *ident = NULL, *key_data = NULL;
756   int ret;
757
758   buf = silc_buffer_alloc(data_len);
759   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
760   silc_buffer_put(buf, data, data_len);
761
762   /* Get length */
763   ret = silc_buffer_unformat(buf,
764                              SILC_STR_UI_INT(&totlen),
765                              SILC_STR_END);
766   if (ret == -1) {
767     silc_buffer_free(buf);
768     return FALSE;
769   }
770
771   if (totlen != data_len) {
772     silc_buffer_free(buf);
773     return FALSE;
774   }
775
776   /* Get algorithm name and identifier */
777   silc_buffer_pull(buf, 4);
778   ret =
779     silc_buffer_unformat(buf,
780                          SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
781                          SILC_STR_UI16_NSTRING_ALLOC(&ident, &identifier_len),
782                          SILC_STR_END);
783   if (ret == -1)
784     goto err;
785
786   if (pkcs_len < 1 || identifier_len < 3 || 
787       pkcs_len + identifier_len > totlen)
788     goto err;
789
790   /* See if we support this algorithm (check only if PKCS are registered) */
791   if (SILC_PKCS_LIST && !silc_pkcs_is_supported(pkcs_name)) {
792     SILC_LOG_DEBUG(("Unknown PKCS %s", pkcs_name));
793     goto err;
794   }
795
796   /* Protocol says that at least UN and HN must be provided as identifier,
797      check for these. */
798   if (!strstr(ident, "UN=") && !strstr(ident, "HN=")) {
799     SILC_LOG_DEBUG(("The public does not have the required UN= and HN= "
800                     "identifiers"));
801     goto err;
802   }
803
804   /* Get key data. We assume that rest of the buffer is key data. */
805   silc_buffer_pull(buf, 2 + pkcs_len + 2 + identifier_len);
806   key_len = buf->len;
807   ret = silc_buffer_unformat(buf,
808                              SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
809                              SILC_STR_END);
810   if (ret == -1)
811     goto err;
812
813   /* Try to set the key. If this fails the key must be malformed. This
814      code assumes that the PKCS routine checks the format of the key. 
815      (check only if PKCS are registered) */
816   if (SILC_PKCS_LIST) {
817     silc_pkcs_alloc(pkcs_name, &alg);
818     if (!alg->pkcs->set_public_key(alg->context, key_data, key_len))
819       goto err;
820     silc_pkcs_free(alg);
821   }
822   
823   if (public_key) {
824     *public_key = silc_calloc(1, sizeof(**public_key));
825     (*public_key)->len = totlen;
826     (*public_key)->name = pkcs_name;
827     (*public_key)->identifier = ident;
828     (*public_key)->pk = key_data;
829     (*public_key)->pk_len = key_len;
830     (*public_key)->pk_type = SILC_SKE_PK_TYPE_SILC;
831   }
832
833   silc_buffer_free(buf);
834   return TRUE;
835
836  err:
837   if (pkcs_name)
838     silc_free(pkcs_name);
839   if (ident)
840     silc_free(ident);
841   if (key_data)
842     silc_free(key_data);
843   silc_buffer_free(buf);
844   return FALSE;
845 }
846
847 /* Encodes Public Key Payload for transmitting public keys and certificates. */
848
849 SilcBuffer silc_pkcs_public_key_payload_encode(SilcPublicKey public_key)
850 {
851   SilcBuffer buffer;
852   unsigned char *pk;
853   SilcUInt32 pk_len;
854
855   if (!public_key)
856     return NULL;
857
858   pk = silc_pkcs_public_key_encode(public_key, &pk_len);
859   if (!pk)
860     return NULL;
861
862   buffer = silc_buffer_alloc_size(4 + pk_len);
863   if (!buffer) {
864     silc_free(pk);
865     return NULL;
866   }
867
868   silc_buffer_format(buffer,
869                      SILC_STR_UI_SHORT(pk_len),
870                      SILC_STR_UI_SHORT(public_key->pk_type),
871                      SILC_STR_UI_XNSTRING(pk, pk_len),
872                      SILC_STR_END);
873
874   silc_free(pk);
875   return buffer;
876 }
877
878 /* Decode Public Key Payload and decodes the public key inside it to
879    to `payload'. */
880
881 bool silc_pkcs_public_key_payload_decode(unsigned char *data,
882                                          SilcUInt32 data_len,
883                                          SilcPublicKey *public_key)
884 {
885   SilcBufferStruct buf;
886   SilcUInt16 pk_len, pk_type;
887   unsigned char *pk;
888   int ret;
889
890   if (!public_key)
891     return FALSE;
892
893 #if 1
894   /* XXX 1.1 version support.  Check whether the data is actually raw
895      public key and attempt to decode.  Remove this later! */
896   if (silc_pkcs_public_key_decode(data, data_len, public_key)) {
897     (*public_key)->pk_type = SILC_SKE_PK_TYPE_SILC;
898     return TRUE;
899   }
900 #endif
901
902   silc_buffer_set(&buf, data, data_len);
903   ret = silc_buffer_unformat(&buf,
904                              SILC_STR_UI_SHORT(&pk_len),
905                              SILC_STR_UI_SHORT(&pk_type),
906                              SILC_STR_END);
907   if (ret < 0 || pk_len > data_len - 4)
908     return FALSE;
909
910   /* For now we support only SILC public keys */
911   if (pk_type != SILC_SKE_PK_TYPE_SILC)
912     return FALSE;
913
914   silc_buffer_pull(&buf, 4);
915   ret = silc_buffer_unformat(&buf,
916                              SILC_STR_UI_XNSTRING(&pk, pk_len),
917                              SILC_STR_END);
918   silc_buffer_push(&buf, 4);
919   if (ret < 0)
920     return FALSE;
921
922   if (!silc_pkcs_public_key_decode(pk, pk_len, public_key))
923     return FALSE;
924   (*public_key)->pk_type = SILC_SKE_PK_TYPE_SILC;
925
926   return TRUE;
927 }
928
929 /* Compares two public keys and returns TRUE if they are same key, and
930    FALSE if they are not same. */
931
932 bool silc_pkcs_public_key_compare(SilcPublicKey key1, SilcPublicKey key2)
933 {
934   if (key1 == key2)
935     return TRUE;
936
937   if (key1->len == key2->len &&
938       key1->name && key2->name && key1->identifier && key2->identifier &&
939       !strcmp(key1->name, key2->name) &&
940       !strcmp(key1->identifier, key2->identifier) &&
941       !memcmp(key1->pk, key2->pk, key1->pk_len) &&
942       key1->pk_len == key2->pk_len)
943     return TRUE;
944
945   return FALSE;
946 }
947
948 /* Copies the public key indicated by `public_key' and returns new allocated
949    public key which is indentical to the `public_key'. */
950
951 SilcPublicKey silc_pkcs_public_key_copy(SilcPublicKey public_key)
952 {
953   SilcPublicKey key = silc_calloc(1, sizeof(*key));
954   if (!key)
955     return NULL;
956
957   key->len = public_key->len;
958   key->name = silc_memdup(public_key->name, strlen(public_key->name));
959   key->identifier = silc_memdup(public_key->identifier,
960                                 strlen(public_key->identifier));
961   key->pk = silc_memdup(public_key->pk, public_key->pk_len);
962   key->pk_len = public_key->pk_len;
963   key->pk_type = public_key->pk_type;
964
965   return key;
966 }
967
968 /* Encodes SILC private key from SilcPrivateKey. Returns the encoded data. */
969
970 unsigned char *
971 silc_pkcs_private_key_encode(SilcPrivateKey private_key, SilcUInt32 *len)
972 {
973   SilcBuffer buf;
974   unsigned char *ret;
975   SilcUInt32 totlen;
976
977   totlen = 2 + strlen(private_key->name) + private_key->prv_len;
978   buf = silc_buffer_alloc(totlen);
979   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
980
981   silc_buffer_format(buf,
982                      SILC_STR_UI_SHORT(strlen(private_key->name)),
983                      SILC_STR_UI32_STRING(private_key->name),
984                      SILC_STR_UI_XNSTRING(private_key->prv, 
985                                           private_key->prv_len),
986                      SILC_STR_END);
987   if (len)
988     *len = totlen;
989
990   ret = silc_calloc(buf->len, sizeof(*ret));
991   memcpy(ret, buf->data, buf->len);
992   silc_buffer_clear(buf);
993   silc_buffer_free(buf);
994
995   return ret;
996 }
997
998 /* Encodes SILC private key. Returns the encoded data. */
999
1000 unsigned char *
1001 silc_pkcs_private_key_data_encode(unsigned char *prv, SilcUInt32 prv_len,
1002                                   char *pkcs, SilcUInt32 *len)
1003 {
1004   SilcBuffer buf;
1005   unsigned char *ret;
1006   SilcUInt32 totlen;
1007
1008   totlen = 2 + strlen(pkcs) + prv_len;
1009   buf = silc_buffer_alloc(totlen);
1010   silc_buffer_pull_tail(buf, totlen);
1011
1012   silc_buffer_format(buf,
1013                      SILC_STR_UI_SHORT(strlen(pkcs)),
1014                      SILC_STR_UI32_STRING(pkcs),
1015                      SILC_STR_UI_XNSTRING(prv, prv_len),
1016                      SILC_STR_END);
1017   if (len)
1018     *len = totlen;
1019
1020   ret = silc_calloc(buf->len, sizeof(*ret));
1021   memcpy(ret, buf->data, buf->len);
1022   silc_buffer_clear(buf);
1023   silc_buffer_free(buf);
1024
1025   return ret;
1026 }
1027
1028 /* Decodes SILC style private key. Returns TRUE if the decoding was
1029    successful. Allocates new private key as well. */
1030
1031 bool silc_pkcs_private_key_decode(unsigned char *data, SilcUInt32 data_len,
1032                                   SilcPrivateKey *private_key)
1033 {
1034   SilcBuffer buf;
1035   SilcPKCS alg;
1036   SilcUInt16 pkcs_len;
1037   SilcUInt32 key_len;
1038   unsigned char *pkcs_name = NULL, *key_data = NULL;
1039   int ret;
1040
1041   buf = silc_buffer_alloc(data_len);
1042   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1043   silc_buffer_put(buf, data, data_len);
1044
1045   /* Get algorithm name and identifier */
1046   ret = 
1047     silc_buffer_unformat(buf,
1048                          SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
1049                          SILC_STR_END);
1050   if (ret == -1) {
1051     SILC_LOG_DEBUG(("Cannot decode private key buffer"));
1052     goto err;
1053   }
1054
1055   if (pkcs_len < 1 || pkcs_len > buf->truelen) {
1056     SILC_LOG_DEBUG(("Malformed private key buffer"));
1057     goto err;
1058   }
1059
1060   /* See if we support this algorithm (check only if PKCS are registered). */
1061   if (SILC_PKCS_LIST && !silc_pkcs_is_supported(pkcs_name)) {
1062     SILC_LOG_DEBUG(("Unknown PKCS `%s'", pkcs_name));
1063     goto err;
1064   }
1065
1066   /* Get key data. We assume that rest of the buffer is key data. */
1067   silc_buffer_pull(buf, 2 + pkcs_len);
1068   key_len = buf->len;
1069   ret = silc_buffer_unformat(buf,
1070                              SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
1071                              SILC_STR_END);
1072   if (ret == -1)
1073     goto err;
1074
1075   /* Try to set the key. If this fails the key must be malformed. This
1076      code assumes that the PKCS routine checks the format of the key. 
1077      (check only if PKCS are registered) */
1078   if (SILC_PKCS_LIST) {
1079     silc_pkcs_alloc(pkcs_name, &alg);
1080     if (!alg->pkcs->set_private_key(alg->context, key_data, key_len)) {
1081       SILC_LOG_DEBUG(("Could not set private key data"));
1082       goto err;
1083     }
1084     silc_pkcs_free(alg);
1085   }
1086   
1087   if (private_key) {
1088     *private_key = silc_calloc(1, sizeof(**private_key));
1089     (*private_key)->name = pkcs_name;
1090     (*private_key)->prv = key_data;
1091     (*private_key)->prv_len = key_len;
1092   }
1093
1094   silc_buffer_clear(buf);
1095   silc_buffer_free(buf);
1096   return TRUE;
1097
1098  err:
1099   if (pkcs_name)
1100     silc_free(pkcs_name);
1101   if (key_data)
1102     silc_free(key_data);
1103   silc_buffer_clear(buf);
1104   silc_buffer_free(buf);
1105   return FALSE;
1106 }
1107
1108 /* Internal routine to save public key */
1109
1110 static bool silc_pkcs_save_public_key_internal(char *filename,
1111                                                unsigned char *data,
1112                                                SilcUInt32 data_len,
1113                                                SilcUInt32 encoding)
1114 {
1115   SilcBuffer buf;
1116   SilcUInt32 len;
1117
1118   switch(encoding) {
1119   case SILC_PKCS_FILE_BIN:
1120     break;
1121   case SILC_PKCS_FILE_PEM:
1122     data = silc_pem_encode_file(data, data_len);
1123     data_len = strlen(data);
1124     break;
1125   }
1126
1127   len = data_len + (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
1128                     strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
1129   buf = silc_buffer_alloc(len);
1130   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1131
1132   silc_buffer_format(buf,
1133                      SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
1134                      SILC_STR_UI_XNSTRING(data, data_len),
1135                      SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END),
1136                      SILC_STR_END);
1137
1138   /* Save into file */
1139   if (silc_file_writefile(filename, buf->data, buf->len)) {
1140     silc_buffer_free(buf);
1141     return FALSE;
1142   }
1143
1144   silc_buffer_free(buf);
1145   return TRUE;
1146 }
1147
1148 /* Saves public key into file */
1149
1150 bool silc_pkcs_save_public_key(char *filename, SilcPublicKey public_key,
1151                                SilcUInt32 encoding)
1152 {
1153   unsigned char *data;
1154   SilcUInt32 data_len;
1155   bool ret;
1156
1157   data = silc_pkcs_public_key_encode(public_key, &data_len);
1158   ret = silc_pkcs_save_public_key_internal(filename, data, data_len,
1159                                            encoding);
1160   silc_free(data);
1161   return ret;
1162 }
1163
1164 /* Saves public key into file */
1165
1166 bool silc_pkcs_save_public_key_data(char *filename, unsigned char *data,
1167                                     SilcUInt32 data_len,
1168                                     SilcUInt32 encoding)
1169 {
1170   return silc_pkcs_save_public_key_internal(filename, data, data_len,
1171                                             encoding);
1172 }
1173
1174 #define SILC_PKCS_PRIVATE_KEY_MAGIC 0x738df531
1175
1176 /* Internal routine to save private key. */
1177
1178 static bool silc_pkcs_save_private_key_internal(char *filename,
1179                                                 unsigned char *data,
1180                                                 SilcUInt32 data_len,
1181                                                 unsigned char *key,
1182                                                 SilcUInt32 key_len,
1183                                                 SilcUInt32 encoding)
1184 {
1185   SilcCipher aes;
1186   SilcHash md5;
1187   SilcHmac sha1hmac;
1188   SilcBuffer buf, enc;
1189   SilcUInt32 len, blocklen;
1190   unsigned char tmp[32], keymat[32];
1191   int i;
1192
1193   memset(tmp, 0, sizeof(tmp));
1194   memset(keymat, 0, sizeof(keymat));
1195
1196   /* Allocate the AES cipher */
1197   if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
1198     SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
1199     return FALSE;
1200   }
1201   blocklen = silc_cipher_get_block_len(aes);
1202   if (blocklen * 2 > sizeof(tmp))
1203     return FALSE;
1204
1205   /* Allocate MD5 hash */
1206   if (!silc_hash_alloc("md5", &md5)) {
1207     SILC_LOG_ERROR(("Could not allocate MD5 hash, probably not registered"));
1208     silc_cipher_free(aes);
1209     return FALSE;
1210   }
1211
1212   /* Allocate HMAC */
1213   if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
1214     SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
1215     silc_hash_free(md5);
1216     silc_cipher_free(aes);
1217     return FALSE;
1218   }
1219
1220   /* Derive the encryption key from the provided key material.  The key
1221      is 256 bits length, and derived by taking hash of the data, then 
1222      re-hashing the data and the previous digest, and using the first and
1223      second digest as the key. */
1224   silc_hash_init(md5);
1225   silc_hash_update(md5, key, key_len);
1226   silc_hash_final(md5, keymat);
1227   silc_hash_init(md5);
1228   silc_hash_update(md5, key, key_len);
1229   silc_hash_update(md5, keymat, 16);
1230   silc_hash_final(md5, keymat + 16);
1231
1232   /* Set the key to the cipher */
1233   silc_cipher_set_key(aes, keymat, sizeof(keymat) * 8);
1234
1235   /* Encode the buffer to be encrypted.  Add padding to it too, at least
1236      block size of the cipher. */
1237
1238   /* Allocate buffer for encryption */
1239   len = silc_hmac_len(sha1hmac);
1240   enc = silc_buffer_alloc_size(data_len + 4 + 4 +
1241                                (blocklen + (data_len % blocklen)) + len);
1242   if (!enc) {
1243     silc_hmac_free(sha1hmac);
1244     silc_hash_free(md5);
1245     silc_cipher_free(aes);
1246     return FALSE;
1247   }
1248
1249   /* Generate padding */
1250   for (i = 0; i < blocklen + (data_len % blocklen); i++)
1251     tmp[i] = silc_rng_global_get_byte_fast();
1252
1253   /* Put magic number */
1254   SILC_PUT32_MSB(SILC_PKCS_PRIVATE_KEY_MAGIC, enc->data);
1255   silc_buffer_pull(enc, 4);
1256
1257   /* Encode the buffer */
1258   silc_buffer_format(enc,
1259                      SILC_STR_UI_INT(data_len),
1260                      SILC_STR_UI_XNSTRING(data, data_len),
1261                      SILC_STR_UI_XNSTRING(tmp, blocklen + (data_len %
1262                                                            blocklen)),
1263                      SILC_STR_END);
1264
1265   /* Encrypt. */
1266   silc_cipher_encrypt(aes, enc->data, enc->data, enc->len - len,
1267                       silc_cipher_get_iv(aes));
1268
1269   silc_buffer_push(enc, 4);
1270
1271   /* Compute HMAC over the encrypted data and append the MAC to data.
1272      The key is the first digest of the original key material. */
1273   data_len = enc->len - len;
1274   silc_hmac_init_with_key(sha1hmac, keymat, 16);
1275   silc_hmac_update(sha1hmac, enc->data, data_len);
1276   silc_buffer_pull(enc, data_len);
1277   silc_hmac_final(sha1hmac, enc->data, NULL);
1278   silc_buffer_push(enc, data_len);
1279
1280   /* Cleanup */
1281   memset(keymat, 0, sizeof(keymat));
1282   memset(tmp, 0, sizeof(tmp));
1283   silc_hmac_free(sha1hmac);
1284   silc_hash_free(md5);
1285   silc_cipher_free(aes);
1286
1287   data = enc->data;
1288   data_len = enc->len;
1289
1290   switch (encoding) {
1291   case SILC_PKCS_FILE_BIN:
1292     break;
1293   case SILC_PKCS_FILE_PEM:
1294     data = silc_pem_encode_file(data, data_len);
1295     data_len = strlen(data);
1296     break;
1297   }
1298
1299   /* Encode the data and save to file */
1300   len = data_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
1301                     strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
1302   buf = silc_buffer_alloc_size(len);
1303   silc_buffer_format(buf,
1304                      SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
1305                      SILC_STR_UI_XNSTRING(data, data_len),
1306                      SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
1307                      SILC_STR_END);
1308
1309   /* Save into a file */
1310   if (silc_file_writefile_mode(filename, buf->data, buf->len, 0600)) {
1311     silc_buffer_clear(buf);
1312     silc_buffer_free(buf);
1313     silc_buffer_clear(enc);
1314     silc_buffer_free(enc);
1315     return FALSE;
1316   }
1317
1318   silc_buffer_clear(buf);
1319   silc_buffer_free(buf);
1320   silc_buffer_clear(enc);
1321   silc_buffer_free(enc);
1322   return TRUE;
1323 }
1324
1325 /* Saves private key into file. */
1326
1327 bool silc_pkcs_save_private_key(char *filename, SilcPrivateKey private_key, 
1328                                 unsigned char *passphrase,
1329                                 SilcUInt32 passphrase_len,
1330                                 SilcUInt32 encoding)
1331 {
1332   unsigned char *data;
1333   SilcUInt32 data_len;
1334   bool ret;
1335
1336   data = silc_pkcs_private_key_encode(private_key, &data_len);
1337   ret = silc_pkcs_save_private_key_internal(filename, data, data_len,
1338                                             passphrase, passphrase_len,
1339                                             encoding);
1340   memset(data, 0, data_len);
1341   silc_free(data);
1342   return ret;
1343 }
1344
1345 /* Loads public key from file and allocates new public key. Returns TRUE
1346    if loading was successful. */
1347
1348 bool silc_pkcs_load_public_key(char *filename, SilcPublicKey *public_key,
1349                                SilcUInt32 encoding)
1350 {
1351   unsigned char *cp, *old, *data, byte;
1352   SilcUInt32 i, data_len, len;
1353
1354   old = data = silc_file_readfile(filename, &data_len);
1355   if (!data)
1356     return FALSE;
1357
1358   /* Check start of file and remove header from the data. */
1359   len = strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN);
1360   cp = data;
1361   for (i = 0; i < len; i++) {
1362     byte = cp[0];
1363     cp++;
1364     if (byte != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i]) {
1365       memset(old, 0, data_len);
1366       silc_free(old);
1367       return FALSE;
1368     }
1369   }
1370   data = cp;
1371
1372   /* Decode public key */
1373   if (public_key) {
1374     len = data_len - (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
1375                       strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
1376
1377     switch(encoding) {
1378     case SILC_PKCS_FILE_BIN:
1379       break;
1380     case SILC_PKCS_FILE_PEM:
1381       data = silc_pem_decode(data, len, &len);
1382       memset(old, 0, data_len);
1383       silc_free(old);
1384       old = data; 
1385       data_len = len;
1386       break;
1387     }
1388
1389     if (!data || !silc_pkcs_public_key_decode(data, len, public_key)) {
1390       memset(old, 0, data_len);
1391       silc_free(old);
1392       return FALSE;
1393     }
1394   }
1395
1396   memset(old, 0, data_len);
1397   silc_free(old);
1398   return TRUE;
1399 }
1400
1401 /* Load private key from file and allocates new private key. Returns TRUE
1402    if loading was successful. */
1403
1404 bool silc_pkcs_load_private_key(char *filename, SilcPrivateKey *private_key,
1405                                 unsigned char *passphrase,
1406                                 SilcUInt32 passphrase_len,
1407                                 SilcUInt32 encoding)
1408 {
1409   SilcCipher aes;
1410   SilcHash md5;
1411   SilcHmac sha1hmac;
1412   SilcUInt32 blocklen;
1413   unsigned char tmp[32], keymat[32];
1414   unsigned char *cp, *old, *data, byte;
1415   SilcUInt32 i, data_len, len, magic, mac_len;
1416
1417   old = data = silc_file_readfile(filename, &data_len);
1418   if (!data)
1419     return FALSE;
1420
1421   /* Check start of file and remove header from the data. */
1422   len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
1423   cp = data;
1424   for (i = 0; i < len; i++) {
1425     byte = cp[0];
1426     cp++;
1427     if (byte != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i]) {
1428       memset(old, 0, data_len);
1429       silc_free(old);
1430       return FALSE;
1431     }
1432   }
1433   data = cp;
1434
1435   /* Decode private key */
1436   len = data_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
1437                     strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
1438
1439   switch(encoding) {
1440   case SILC_PKCS_FILE_BIN:
1441     break;
1442   case SILC_PKCS_FILE_PEM:
1443     data = silc_pem_decode(data, len, &len);
1444     if (!data) {
1445       memset(old, 0, data_len);
1446       silc_free(old);
1447       return FALSE;
1448     }
1449     break;
1450   }
1451
1452   memset(tmp, 0, sizeof(tmp));
1453   memset(keymat, 0, sizeof(keymat));
1454
1455   /* Private key files without the specific magic number are assumed
1456      to be the old-style private keys that are not encrypted. */
1457   SILC_GET32_MSB(magic, data);
1458   if (magic != SILC_PKCS_PRIVATE_KEY_MAGIC) {
1459     SILC_LOG_DEBUG(("Private key does not have correct magic!"));
1460
1461     /* Now decode the actual private key */
1462     if (!silc_pkcs_private_key_decode(data, len, private_key)) {
1463       memset(old, 0, data_len);
1464       silc_free(old);
1465       return FALSE;
1466     }
1467
1468     memset(old, 0, data_len);
1469     silc_free(old);
1470     return TRUE;
1471   }
1472
1473   /* Allocate the AES cipher */
1474   if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
1475     SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
1476     memset(old, 0, data_len);
1477     silc_free(old);
1478     return FALSE;
1479   }
1480   blocklen = silc_cipher_get_block_len(aes);
1481   if (blocklen * 2 > sizeof(tmp)) {
1482     memset(old, 0, data_len);
1483     silc_free(old);
1484     return FALSE;
1485   }
1486
1487   /* Allocate MD5 hash */
1488   if (!silc_hash_alloc("md5", &md5)) {
1489     SILC_LOG_ERROR(("Could not allocate MD5 hash, probably not registered"));
1490     silc_cipher_free(aes);
1491     memset(old, 0, data_len);
1492     silc_free(old);
1493     return FALSE;
1494   }
1495
1496   /* Allocate HMAC */
1497   if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
1498     SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
1499     silc_hash_free(md5);
1500     silc_cipher_free(aes);
1501     memset(old, 0, data_len);
1502     silc_free(old);
1503     return FALSE;
1504   }
1505
1506   /* Derive the decryption key from the provided key material.  The key
1507      is 256 bits length, and derived by taking hash of the data, then 
1508      re-hashing the data and the previous digest, and using the first and
1509      second digest as the key. */
1510   silc_hash_init(md5);
1511   silc_hash_update(md5, passphrase, passphrase_len);
1512   silc_hash_final(md5, keymat);
1513   silc_hash_init(md5);
1514   silc_hash_update(md5, passphrase, passphrase_len);
1515   silc_hash_update(md5, keymat, 16);
1516   silc_hash_final(md5, keymat + 16);
1517
1518   /* Set the key to the cipher */
1519   silc_cipher_set_key(aes, keymat, sizeof(keymat) * 8);
1520
1521   /* First, verify the MAC of the private key data */
1522   mac_len = silc_hmac_len(sha1hmac);
1523   silc_hmac_init_with_key(sha1hmac, keymat, 16);
1524   silc_hmac_update(sha1hmac, data, len - mac_len);
1525   silc_hmac_final(sha1hmac, tmp, NULL);
1526   if (memcmp(tmp, data + (len - mac_len), mac_len)) {
1527     SILC_LOG_DEBUG(("Integrity check for private key failed"));
1528     memset(keymat, 0, sizeof(keymat));
1529     memset(tmp, 0, sizeof(tmp));
1530     silc_hmac_free(sha1hmac);
1531     silc_hash_free(md5);
1532     silc_cipher_free(aes);
1533     memset(old, 0, data_len);
1534     silc_free(old);
1535     return FALSE;
1536   }
1537   data += 4;
1538   len -= 4;
1539
1540   /* Decrypt the private key buffer */
1541   silc_cipher_decrypt(aes, data, data, len - mac_len, silc_cipher_get_iv(aes));
1542   SILC_GET32_MSB(i, data);
1543   if (i > len) {
1544     SILC_LOG_DEBUG(("Bad private key length in buffer!"));
1545     memset(keymat, 0, sizeof(keymat));
1546     memset(tmp, 0, sizeof(tmp));
1547     silc_hmac_free(sha1hmac);
1548     silc_hash_free(md5);
1549     silc_cipher_free(aes);
1550     memset(old, 0, data_len);
1551     silc_free(old);
1552     return FALSE;
1553   }
1554   data += 4;
1555   len = i;
1556
1557   /* Cleanup */
1558   memset(keymat, 0, sizeof(keymat));
1559   memset(tmp, 0, sizeof(tmp));
1560   silc_hmac_free(sha1hmac);
1561   silc_hash_free(md5);
1562   silc_cipher_free(aes);
1563
1564   /* Now decode the actual private key */
1565   if (!silc_pkcs_private_key_decode(data, len, private_key)) {
1566     memset(old, 0, data_len);
1567     silc_free(old);
1568     return FALSE;
1569   }
1570
1571   memset(old, 0, data_len);
1572   silc_free(old);
1573   return TRUE;
1574 }