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