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 #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) {
557       cp = NULL;
558       break;
559     }
560     if (len - 1 >= 0 && cp[len - 1] == '\\') {
561       while (cp) {
562         if (len + 1 > strlen(cp)) {
563           cp = NULL;
564           break;
565         }
566         cp += len + 1;
567         len = strcspn(cp, ",") + len;
568         if (len < 1) {
569           cp = NULL;
570           break;
571         }
572         if (len - 1 >= 0 && cp[len - 1] != '\\')
573           break;
574       }
575     }
576
577     if (!cp)
578       break;
579
580     item = silc_calloc(len + 1, sizeof(char));
581     if (len > strlen(cp))
582       break;
583     memcpy(item, cp, len);
584
585     if (strstr(item, "UN="))
586       ident->username = strdup(item + strcspn(cp, "=") + 1);
587     else if (strstr(item, "HN="))
588       ident->host = strdup(item + strcspn(cp, "=") + 1);
589     else if (strstr(item, "RN="))
590       ident->realname = strdup(item + strcspn(cp, "=") + 1);
591     else if (strstr(item, "E="))
592       ident->email = strdup(item + strcspn(cp, "=") + 1);
593     else if (strstr(item, "O="))
594       ident->org = strdup(item + strcspn(cp, "=") + 1);
595     else if (strstr(item, "C="))
596       ident->country = strdup(item + strcspn(cp, "=") + 1);
597
598     cp += len;
599     if (strlen(cp) < 1)
600       cp = NULL;
601     else
602       cp += 1;
603
604     if (item)
605       silc_free(item);
606   }
607
608   return ident;
609 }
610
611 /* Free's decoded public key identifier context. Call this to free the
612    context returned by the silc_pkcs_decode_identifier. */
613
614 void silc_pkcs_free_identifier(SilcPublicKeyIdentifier identifier)
615 {
616   silc_free(identifier->username);
617   silc_free(identifier->host);
618   silc_free(identifier->realname);
619   silc_free(identifier->email);
620   silc_free(identifier->org);
621   silc_free(identifier->country);
622   silc_free(identifier);
623 }
624
625 /* Allocates SILC style public key formed from sent arguments. All data
626    is duplicated. */
627
628 SilcPublicKey silc_pkcs_public_key_alloc(const char *name,
629                                          const char *identifier,
630                                          const unsigned char *pk,
631                                          SilcUInt32 pk_len)
632 {
633   SilcPublicKey public_key;
634   char *tmp = NULL;
635
636   public_key = silc_calloc(1, sizeof(*public_key));
637   public_key->name = strdup(name);
638   public_key->pk_len = pk_len;
639   public_key->pk = silc_calloc(pk_len, sizeof(*public_key->pk));
640   public_key->pk_type = SILC_SKE_PK_TYPE_SILC;
641   memcpy(public_key->pk, pk, pk_len);
642
643   if (!silc_utf8_valid(identifier, strlen(identifier))) {
644     int len = silc_utf8_encoded_len(identifier, strlen(identifier), 0);
645     tmp = silc_calloc(len + 1, sizeof(*tmp));
646     silc_utf8_encode(identifier, strlen(identifier), 0, tmp, len);
647     identifier = tmp;
648   }
649
650   public_key->identifier = strdup(identifier);
651   public_key->len = 2 + strlen(name) + 2 + strlen(identifier) + pk_len;
652   silc_free(tmp);
653
654   return public_key;
655 }
656
657 /* Free's public key */
658
659 void silc_pkcs_public_key_free(SilcPublicKey public_key)
660 {
661   if (public_key) {
662     silc_free(public_key->name);
663     silc_free(public_key->identifier);
664     silc_free(public_key->pk);
665     silc_free(public_key);
666   }
667 }
668
669 /* Allocates SILC private key formed from sent arguments. All data is
670    duplicated. */
671
672 SilcPrivateKey silc_pkcs_private_key_alloc(const char *name,
673                                            const unsigned char *prv,
674                                            SilcUInt32 prv_len)
675 {
676   SilcPrivateKey private_key;
677
678   private_key = silc_calloc(1, sizeof(*private_key));
679   private_key->name = strdup(name);
680   private_key->prv_len = prv_len;
681   private_key->prv = silc_calloc(prv_len, sizeof(*private_key->prv));
682   memcpy(private_key->prv, 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     silc_free(private_key->prv);
694     silc_free(private_key);
695   }
696 }
697
698 /* Encodes SILC style public key from SilcPublicKey. Returns the encoded
699    data. */
700
701 unsigned char *
702 silc_pkcs_public_key_encode(SilcPublicKey public_key, SilcUInt32 *len)
703 {
704   SilcBuffer buf;
705   unsigned char *ret;
706
707   buf = silc_buffer_alloc_size(public_key->len + 4);
708   if (!buf)
709     return NULL;
710
711   silc_buffer_format(buf,
712                      SILC_STR_UI_INT(public_key->len),
713                      SILC_STR_UI_SHORT(strlen(public_key->name)),
714                      SILC_STR_UI32_STRING(public_key->name),
715                      SILC_STR_UI_SHORT(strlen(public_key->identifier)),
716                      SILC_STR_UI32_STRING(public_key->identifier),
717                      SILC_STR_UI_XNSTRING(public_key->pk,
718                                           public_key->pk_len),
719                      SILC_STR_END);
720
721   ret = silc_buffer_steal(buf, len);
722   silc_buffer_free(buf);
723   return ret;
724 }
725
726 /* Encodes SILC style public key. Returns the encoded data. */
727
728 unsigned char *
729 silc_pkcs_public_key_data_encode(unsigned char *pk, SilcUInt32 pk_len,
730                                  char *pkcs, char *identifier,
731                                  SilcUInt32 *len)
732 {
733   SilcBuffer buf;
734   unsigned char *ret;
735   SilcUInt32 totlen;
736
737   totlen = 2 + strlen(pkcs) + 2 + strlen(identifier) + pk_len;
738   buf = silc_buffer_alloc_size(totlen + 4);
739   if (!buf)
740     return NULL;
741
742   silc_buffer_format(buf,
743                      SILC_STR_UI_INT(totlen),
744                      SILC_STR_UI_SHORT(strlen(pkcs)),
745                      SILC_STR_UI32_STRING(pkcs),
746                      SILC_STR_UI_SHORT(strlen(identifier)),
747                      SILC_STR_UI32_STRING(identifier),
748                      SILC_STR_UI_XNSTRING(pk, pk_len),
749                      SILC_STR_END);
750
751   ret = silc_buffer_steal(buf, len);
752   silc_buffer_free(buf);
753   return ret;
754 }
755
756 /* Decodes SILC style public key. Returns TRUE if the decoding was
757    successful. Allocates new public key as well. */
758
759 bool silc_pkcs_public_key_decode(unsigned char *data, SilcUInt32 data_len,
760                                  SilcPublicKey *public_key)
761 {
762   SilcBufferStruct buf;
763   SilcPKCS alg;
764   SilcUInt16 pkcs_len, identifier_len;
765   SilcUInt32 totlen, key_len;
766   unsigned char *pkcs_name = NULL, *ident = NULL, *key_data = NULL;
767   int ret;
768
769   silc_buffer_set(&buf, data, data_len);
770
771   /* Get length */
772   ret = silc_buffer_unformat(&buf,
773                              SILC_STR_UI_INT(&totlen),
774                              SILC_STR_END);
775   if (ret == -1)
776     return FALSE;
777
778 #if 1 /* Backwards support, remove! */
779   if (totlen == data_len)
780     totlen -= 4;
781 #endif
782
783   if (totlen + 4 != data_len)
784     return FALSE;
785
786   /* Get algorithm name and identifier */
787   silc_buffer_pull(&buf, 4);
788   ret =
789     silc_buffer_unformat(&buf,
790                          SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
791                          SILC_STR_UI16_NSTRING_ALLOC(&ident, &identifier_len),
792                          SILC_STR_END);
793   if (ret == -1)
794     goto err;
795
796   if (pkcs_len < 1 || identifier_len < 3 ||
797       pkcs_len + identifier_len > totlen)
798     goto err;
799
800   /* See if we support this algorithm (check only if PKCS are registered) */
801   if (SILC_PKCS_LIST && !silc_pkcs_is_supported(pkcs_name)) {
802     SILC_LOG_DEBUG(("Unknown PKCS %s", pkcs_name));
803     goto err;
804   }
805
806   /* Protocol says that at least UN and HN must be provided as identifier,
807      check for these. */
808   if (!strstr(ident, "UN=") && !strstr(ident, "HN=")) {
809     SILC_LOG_DEBUG(("The public does not have the required UN= and HN= "
810                     "identifiers"));
811     goto err;
812   }
813
814   /* Get key data. We assume that rest of the buffer is key data. */
815   silc_buffer_pull(&buf, 2 + pkcs_len + 2 + identifier_len);
816   key_len = buf.len;
817   ret = silc_buffer_unformat(&buf,
818                              SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
819                              SILC_STR_END);
820   if (ret == -1)
821     goto err;
822
823   /* Try to set the key. If this fails the key must be malformed. This
824      code assumes that the PKCS routine checks the format of the key.
825      (check only if PKCS are registered) */
826   if (SILC_PKCS_LIST) {
827     silc_pkcs_alloc(pkcs_name, &alg);
828     if (!alg->pkcs->set_public_key(alg->context, key_data, key_len))
829       goto err;
830     silc_pkcs_free(alg);
831   }
832
833   if (public_key) {
834     *public_key = silc_calloc(1, sizeof(**public_key));
835     (*public_key)->len = totlen;
836     (*public_key)->name = pkcs_name;
837     (*public_key)->identifier = ident;
838     (*public_key)->pk = key_data;
839     (*public_key)->pk_len = key_len;
840     (*public_key)->pk_type = SILC_SKE_PK_TYPE_SILC;
841   }
842
843   return TRUE;
844
845  err:
846   silc_free(pkcs_name);
847   silc_free(ident);
848   silc_free(key_data);
849   return FALSE;
850 }
851
852 /* Encodes Public Key Payload for transmitting public keys and certificates. */
853
854 SilcBuffer silc_pkcs_public_key_payload_encode(SilcPublicKey public_key)
855 {
856   SilcBuffer buffer;
857   unsigned char *pk;
858   SilcUInt32 pk_len;
859
860   if (!public_key)
861     return NULL;
862
863   pk = silc_pkcs_public_key_encode(public_key, &pk_len);
864   if (!pk)
865     return NULL;
866
867   buffer = silc_buffer_alloc_size(4 + pk_len);
868   if (!buffer) {
869     silc_free(pk);
870     return NULL;
871   }
872
873   silc_buffer_format(buffer,
874                      SILC_STR_UI_SHORT(pk_len),
875                      SILC_STR_UI_SHORT(public_key->pk_type),
876                      SILC_STR_UI_XNSTRING(pk, pk_len),
877                      SILC_STR_END);
878
879   silc_free(pk);
880   return buffer;
881 }
882
883 /* Decode Public Key Payload and decodes the public key inside it to
884    to `payload'. */
885
886 bool silc_pkcs_public_key_payload_decode(unsigned char *data,
887                                          SilcUInt32 data_len,
888                                          SilcPublicKey *public_key)
889 {
890   SilcBufferStruct buf;
891   SilcUInt16 pk_len, pk_type;
892   unsigned char *pk;
893   int ret;
894
895   if (!public_key)
896     return FALSE;
897
898   silc_buffer_set(&buf, data, data_len);
899   ret = silc_buffer_unformat(&buf,
900                              SILC_STR_UI_SHORT(&pk_len),
901                              SILC_STR_UI_SHORT(&pk_type),
902                              SILC_STR_END);
903   if (ret < 0 || pk_len > data_len - 4)
904     return FALSE;
905
906   /* For now we support only SILC public keys */
907   if (pk_type != SILC_SKE_PK_TYPE_SILC)
908     return FALSE;
909
910   silc_buffer_pull(&buf, 4);
911   ret = silc_buffer_unformat(&buf,
912                              SILC_STR_UI_XNSTRING(&pk, pk_len),
913                              SILC_STR_END);
914   silc_buffer_push(&buf, 4);
915   if (ret < 0)
916     return FALSE;
917
918   if (!silc_pkcs_public_key_decode(pk, pk_len, public_key))
919     return FALSE;
920   (*public_key)->pk_type = SILC_SKE_PK_TYPE_SILC;
921
922   return TRUE;
923 }
924
925 /* Compares two public keys and returns TRUE if they are same key, and
926    FALSE if they are not same. */
927
928 bool silc_pkcs_public_key_compare(SilcPublicKey key1, SilcPublicKey key2)
929 {
930   if (key1 == key2)
931     return TRUE;
932
933   if (key1->len == key2->len &&
934       key1->name && key2->name && key1->identifier && key2->identifier &&
935       !strcmp(key1->name, key2->name) &&
936       !strcmp(key1->identifier, key2->identifier) &&
937       !memcmp(key1->pk, key2->pk, key1->pk_len) &&
938       key1->pk_len == key2->pk_len)
939     return TRUE;
940
941   return FALSE;
942 }
943
944 /* Copies the public key indicated by `public_key' and returns new allocated
945    public key which is indentical to the `public_key'. */
946
947 SilcPublicKey silc_pkcs_public_key_copy(SilcPublicKey public_key)
948 {
949   SilcPublicKey key = silc_calloc(1, sizeof(*key));
950   if (!key)
951     return NULL;
952
953   key->len = public_key->len;
954   key->name = silc_memdup(public_key->name, strlen(public_key->name));
955   key->identifier = silc_memdup(public_key->identifier,
956                                 strlen(public_key->identifier));
957   key->pk = silc_memdup(public_key->pk, public_key->pk_len);
958   key->pk_len = public_key->pk_len;
959   key->pk_type = public_key->pk_type;
960
961   return key;
962 }
963
964 /* Encodes SILC private key from SilcPrivateKey. Returns the encoded data. */
965
966 unsigned char *
967 silc_pkcs_private_key_encode(SilcPrivateKey private_key, SilcUInt32 *len)
968 {
969   SilcBuffer buf;
970   unsigned char *ret;
971   SilcUInt32 totlen;
972
973   totlen = 2 + strlen(private_key->name) + private_key->prv_len;
974   buf = silc_buffer_alloc_size(totlen);
975   if (!buf)
976     return NULL;
977
978   silc_buffer_format(buf,
979                      SILC_STR_UI_SHORT(strlen(private_key->name)),
980                      SILC_STR_UI32_STRING(private_key->name),
981                      SILC_STR_UI_XNSTRING(private_key->prv,
982                                           private_key->prv_len),
983                      SILC_STR_END);
984
985   ret = silc_buffer_steal(buf, len);
986   silc_buffer_free(buf);
987   return ret;
988 }
989
990 /* Encodes SILC private key. Returns the encoded data. */
991
992 unsigned char *
993 silc_pkcs_private_key_data_encode(unsigned char *prv, SilcUInt32 prv_len,
994                                   char *pkcs, SilcUInt32 *len)
995 {
996   SilcBuffer buf;
997   unsigned char *ret;
998   SilcUInt32 totlen;
999
1000   totlen = 2 + strlen(pkcs) + prv_len;
1001   buf = silc_buffer_alloc_size(totlen);
1002   if (!buf)
1003     return NULL;
1004
1005   silc_buffer_format(buf,
1006                      SILC_STR_UI_SHORT(strlen(pkcs)),
1007                      SILC_STR_UI32_STRING(pkcs),
1008                      SILC_STR_UI_XNSTRING(prv, prv_len),
1009                      SILC_STR_END);
1010
1011   ret = silc_buffer_steal(buf, len);
1012   silc_buffer_free(buf);
1013   return ret;
1014 }
1015
1016 /* Decodes SILC style private key. Returns TRUE if the decoding was
1017    successful. Allocates new private key as well. */
1018
1019 bool silc_pkcs_private_key_decode(unsigned char *data, SilcUInt32 data_len,
1020                                   SilcPrivateKey *private_key)
1021 {
1022   SilcBufferStruct buf;
1023   SilcPKCS alg;
1024   SilcUInt16 pkcs_len;
1025   SilcUInt32 key_len;
1026   unsigned char *pkcs_name = NULL, *key_data = NULL;
1027   int ret;
1028
1029   silc_buffer_set(&buf, data, data_len);
1030
1031   /* Get algorithm name and identifier */
1032   ret =
1033     silc_buffer_unformat(&buf,
1034                          SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
1035                          SILC_STR_END);
1036   if (ret == -1) {
1037     SILC_LOG_DEBUG(("Cannot decode private key buffer"));
1038     goto err;
1039   }
1040
1041   if (pkcs_len < 1 || pkcs_len > buf.truelen) {
1042     SILC_LOG_DEBUG(("Malformed private key buffer"));
1043     goto err;
1044   }
1045
1046   /* See if we support this algorithm (check only if PKCS are registered). */
1047   if (SILC_PKCS_LIST && !silc_pkcs_is_supported(pkcs_name)) {
1048     SILC_LOG_DEBUG(("Unknown PKCS `%s'", pkcs_name));
1049     goto err;
1050   }
1051
1052   /* Get key data. We assume that rest of the buffer is key data. */
1053   silc_buffer_pull(&buf, 2 + pkcs_len);
1054   key_len = buf.len;
1055   ret = silc_buffer_unformat(&buf,
1056                              SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
1057                              SILC_STR_END);
1058   if (ret == -1)
1059     goto err;
1060
1061   /* Try to set the key. If this fails the key must be malformed. This
1062      code assumes that the PKCS routine checks the format of the key.
1063      (check only if PKCS are registered) */
1064   if (SILC_PKCS_LIST) {
1065     silc_pkcs_alloc(pkcs_name, &alg);
1066     if (!alg->pkcs->set_private_key(alg->context, key_data, key_len)) {
1067       SILC_LOG_DEBUG(("Could not set private key data"));
1068       goto err;
1069     }
1070     silc_pkcs_free(alg);
1071   }
1072
1073   if (private_key) {
1074     *private_key = silc_calloc(1, sizeof(**private_key));
1075     (*private_key)->name = pkcs_name;
1076     (*private_key)->prv = key_data;
1077     (*private_key)->prv_len = key_len;
1078   }
1079
1080   return TRUE;
1081
1082  err:
1083   silc_free(pkcs_name);
1084   silc_free(key_data);
1085   return FALSE;
1086 }
1087
1088 /* Internal routine to save public key */
1089
1090 static bool silc_pkcs_save_public_key_internal(const char *filename,
1091                                                unsigned char *data,
1092                                                SilcUInt32 data_len,
1093                                                SilcUInt32 encoding)
1094 {
1095   SilcBuffer buf;
1096   SilcUInt32 len;
1097   unsigned char *tmp = NULL;
1098
1099   switch(encoding) {
1100   case SILC_PKCS_FILE_BIN:
1101     break;
1102   case SILC_PKCS_FILE_PEM:
1103     tmp = data = silc_pem_encode_file(data, data_len);
1104     data_len = strlen(data);
1105     break;
1106   }
1107
1108   len = data_len + (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
1109                     strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
1110   buf = silc_buffer_alloc_size(len);
1111   if (!buf) {
1112     silc_free(tmp);
1113     return FALSE;
1114   }
1115
1116   silc_buffer_format(buf,
1117                      SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
1118                      SILC_STR_UI_XNSTRING(data, data_len),
1119                      SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END),
1120                      SILC_STR_END);
1121
1122   /* Save into file */
1123   if (silc_file_writefile(filename, buf->data, buf->len)) {
1124     silc_free(tmp);
1125     silc_buffer_free(buf);
1126     return FALSE;
1127   }
1128
1129   silc_free(tmp);
1130   silc_buffer_free(buf);
1131   return TRUE;
1132 }
1133
1134 /* Saves public key into file */
1135
1136 bool silc_pkcs_save_public_key(const char *filename, SilcPublicKey public_key,
1137                                SilcUInt32 encoding)
1138 {
1139   unsigned char *data;
1140   SilcUInt32 data_len;
1141   bool ret;
1142
1143   data = silc_pkcs_public_key_encode(public_key, &data_len);
1144   ret = silc_pkcs_save_public_key_internal(filename, data, data_len,
1145                                            encoding);
1146   silc_free(data);
1147   return ret;
1148 }
1149
1150 /* Saves public key into file */
1151
1152 bool silc_pkcs_save_public_key_data(const char *filename, unsigned char *data,
1153                                     SilcUInt32 data_len, SilcUInt32 encoding)
1154 {
1155   return silc_pkcs_save_public_key_internal(filename, data, data_len,
1156                                             encoding);
1157 }
1158
1159 #define SILC_PKCS_PRIVATE_KEY_MAGIC 0x738df531
1160
1161 /* Internal routine to save private key. */
1162
1163 static bool silc_pkcs_save_private_key_internal(const char *filename,
1164                                                 unsigned char *data,
1165                                                 SilcUInt32 data_len,
1166                                                 unsigned char *key,
1167                                                 SilcUInt32 key_len,
1168                                                 SilcUInt32 encoding)
1169 {
1170   SilcCipher aes;
1171   SilcHash sha1;
1172   SilcHmac sha1hmac;
1173   SilcBuffer buf, enc;
1174   SilcUInt32 len, blocklen, padlen;
1175   unsigned char tmp[32], keymat[64];
1176   int i;
1177
1178   memset(tmp, 0, sizeof(tmp));
1179   memset(keymat, 0, sizeof(keymat));
1180
1181   /* Allocate the AES cipher */
1182   if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
1183     SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
1184     return FALSE;
1185   }
1186   blocklen = silc_cipher_get_block_len(aes);
1187   if (blocklen * 2 > sizeof(tmp))
1188     return FALSE;
1189
1190   /* Allocate SHA1 hash */
1191   if (!silc_hash_alloc("sha1", &sha1)) {
1192     SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered"));
1193     silc_cipher_free(aes);
1194     return FALSE;
1195   }
1196
1197   /* Allocate HMAC */
1198   if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
1199     SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
1200     silc_hash_free(sha1);
1201     silc_cipher_free(aes);
1202     return FALSE;
1203   }
1204
1205   /* Derive the encryption key from the provided key material.  The key
1206      is 256 bits length, and derived by taking hash of the data, then
1207      re-hashing the data and the previous digest, and using the first and
1208      second digest as the key. */
1209   silc_hash_init(sha1);
1210   silc_hash_update(sha1, key, key_len);
1211   silc_hash_final(sha1, keymat);
1212   silc_hash_init(sha1);
1213   silc_hash_update(sha1, key, key_len);
1214   silc_hash_update(sha1, keymat, 16);
1215   silc_hash_final(sha1, keymat + 16);
1216
1217   /* Set the key to the cipher */
1218   silc_cipher_set_key(aes, keymat, 256);
1219
1220   /* Encode the buffer to be encrypted.  Add padding to it too, at least
1221      block size of the cipher. */
1222
1223   /* Allocate buffer for encryption */
1224   len = silc_hmac_len(sha1hmac);
1225   padlen = 16 + (16 - ((data_len + 4) % blocklen));
1226   enc = silc_buffer_alloc_size(4 + 4 + data_len + padlen + len);
1227   if (!enc) {
1228     silc_hmac_free(sha1hmac);
1229     silc_hash_free(sha1);
1230     silc_cipher_free(aes);
1231     return FALSE;
1232   }
1233
1234   /* Generate padding */
1235   for (i = 0; i < padlen; i++)
1236     tmp[i] = silc_rng_global_get_byte_fast();
1237
1238   /* Put magic number */
1239   SILC_PUT32_MSB(SILC_PKCS_PRIVATE_KEY_MAGIC, enc->data);
1240   silc_buffer_pull(enc, 4);
1241
1242   /* Encode the buffer */
1243   silc_buffer_format(enc,
1244                      SILC_STR_UI_INT(data_len),
1245                      SILC_STR_UI_XNSTRING(data, data_len),
1246                      SILC_STR_UI_XNSTRING(tmp, padlen),
1247                      SILC_STR_END);
1248
1249   /* Encrypt. */
1250   silc_cipher_encrypt(aes, enc->data, enc->data, enc->len - len,
1251                       silc_cipher_get_iv(aes));
1252
1253   silc_buffer_push(enc, 4);
1254
1255   /* Compute HMAC over the encrypted data and append the MAC to data.
1256      The key is the first digest of the original key material. */
1257   data_len = enc->len - len;
1258   silc_hmac_init_with_key(sha1hmac, keymat, 16);
1259   silc_hmac_update(sha1hmac, enc->data, data_len);
1260   silc_buffer_pull(enc, data_len);
1261   silc_hmac_final(sha1hmac, enc->data, NULL);
1262   silc_buffer_push(enc, data_len);
1263
1264   /* Cleanup */
1265   memset(keymat, 0, sizeof(keymat));
1266   memset(tmp, 0, sizeof(tmp));
1267   silc_hmac_free(sha1hmac);
1268   silc_hash_free(sha1);
1269   silc_cipher_free(aes);
1270
1271   data = enc->data;
1272   data_len = enc->len;
1273
1274   switch (encoding) {
1275   case SILC_PKCS_FILE_BIN:
1276     break;
1277   case SILC_PKCS_FILE_PEM:
1278     data = silc_pem_encode_file(data, data_len);
1279     data_len = strlen(data);
1280     break;
1281   }
1282
1283   /* Encode the data and save to file */
1284   len = data_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
1285                     strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
1286   buf = silc_buffer_alloc_size(len);
1287   silc_buffer_format(buf,
1288                      SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
1289                      SILC_STR_UI_XNSTRING(data, data_len),
1290                      SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
1291                      SILC_STR_END);
1292
1293   /* Save into a file */
1294   if (silc_file_writefile_mode(filename, buf->data, buf->len, 0600)) {
1295     silc_buffer_clear(buf);
1296     silc_buffer_free(buf);
1297     silc_buffer_clear(enc);
1298     silc_buffer_free(enc);
1299     return FALSE;
1300   }
1301
1302   silc_buffer_clear(buf);
1303   silc_buffer_free(buf);
1304   silc_buffer_clear(enc);
1305   silc_buffer_free(enc);
1306   return TRUE;
1307 }
1308
1309 /* Saves private key into file. */
1310
1311 bool silc_pkcs_save_private_key(const char *filename,
1312                                 SilcPrivateKey private_key,
1313                                 unsigned char *passphrase,
1314                                 SilcUInt32 passphrase_len,
1315                                 SilcUInt32 encoding)
1316 {
1317   unsigned char *data;
1318   SilcUInt32 data_len;
1319   bool ret;
1320
1321   data = silc_pkcs_private_key_encode(private_key, &data_len);
1322   ret = silc_pkcs_save_private_key_internal(filename, data, data_len,
1323                                             passphrase, passphrase_len,
1324                                             encoding);
1325   memset(data, 0, data_len);
1326   silc_free(data);
1327   return ret;
1328 }
1329
1330 /* Loads public key from file and allocates new public key. Returns TRUE
1331    if loading was successful. */
1332
1333 bool silc_pkcs_load_public_key(const char *filename, SilcPublicKey *public_key,
1334                                SilcUInt32 encoding)
1335 {
1336   unsigned char *cp, *old, *data, byte;
1337   SilcUInt32 i, data_len, len;
1338
1339   SILC_LOG_DEBUG(("Loading public key `%s' with %s encoding", filename,
1340                   encoding == SILC_PKCS_FILE_PEM ? "Base64" :
1341                   encoding == SILC_PKCS_FILE_BIN ? "Binary" : "Unkonwn"));
1342
1343   old = data = silc_file_readfile(filename, &data_len);
1344   if (!data)
1345     return FALSE;
1346
1347   /* Check start of file and remove header from the data. */
1348   len = strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN);
1349   cp = data;
1350   for (i = 0; i < len; i++) {
1351     byte = cp[0];
1352     cp++;
1353     if (byte != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i]) {
1354       memset(old, 0, data_len);
1355       silc_free(old);
1356       return FALSE;
1357     }
1358   }
1359   data = cp;
1360
1361   /* Decode public key */
1362   if (public_key) {
1363     len = data_len - (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
1364                       strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
1365
1366     switch(encoding) {
1367     case SILC_PKCS_FILE_BIN:
1368       break;
1369     case SILC_PKCS_FILE_PEM:
1370       data = silc_pem_decode(data, len, &len);
1371       memset(old, 0, data_len);
1372       silc_free(old);
1373       old = data;
1374       data_len = len;
1375       break;
1376     }
1377
1378     if (!data || !silc_pkcs_public_key_decode(data, len, public_key)) {
1379       memset(old, 0, data_len);
1380       silc_free(old);
1381       return FALSE;
1382     }
1383   }
1384
1385   memset(old, 0, data_len);
1386   silc_free(old);
1387   return TRUE;
1388 }
1389
1390 /* Load private key from file and allocates new private key. Returns TRUE
1391    if loading was successful. */
1392
1393 bool silc_pkcs_load_private_key(const char *filename,
1394                                 SilcPrivateKey *private_key,
1395                                 unsigned char *passphrase,
1396                                 SilcUInt32 passphrase_len,
1397                                 SilcUInt32 encoding)
1398 {
1399   SilcCipher aes;
1400   SilcHash sha1;
1401   SilcHmac sha1hmac;
1402   SilcUInt32 blocklen;
1403   unsigned char tmp[32], keymat[64];
1404   unsigned char *cp, *old, *data, byte;
1405   SilcUInt32 i, data_len, len, magic, mac_len;
1406
1407   SILC_LOG_DEBUG(("Loading private key `%s' with %s encoding", filename,
1408                   encoding == SILC_PKCS_FILE_PEM ? "Base64" :
1409                   encoding == SILC_PKCS_FILE_BIN ? "Binary" : "Unkonwn"));
1410
1411   old = data = silc_file_readfile(filename, &data_len);
1412   if (!data)
1413     return FALSE;
1414
1415   /* Check start of file and remove header from the data. */
1416   len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
1417   cp = data;
1418   for (i = 0; i < len; i++) {
1419     byte = cp[0];
1420     cp++;
1421     if (byte != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i]) {
1422       memset(old, 0, data_len);
1423       silc_free(old);
1424       return FALSE;
1425     }
1426   }
1427   data = cp;
1428
1429   /* Decode private key */
1430   len = data_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
1431                     strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
1432
1433   switch(encoding) {
1434   case SILC_PKCS_FILE_BIN:
1435     break;
1436   case SILC_PKCS_FILE_PEM:
1437     data = silc_pem_decode(data, len, &len);
1438     if (!data) {
1439       memset(old, 0, data_len);
1440       silc_free(old);
1441       return FALSE;
1442     }
1443     break;
1444   }
1445
1446   memset(tmp, 0, sizeof(tmp));
1447   memset(keymat, 0, sizeof(keymat));
1448
1449   /* Private key files without the specific magic number are assumed
1450      to be the old-style private keys that are not encrypted. */
1451   SILC_GET32_MSB(magic, data);
1452   if (magic != SILC_PKCS_PRIVATE_KEY_MAGIC) {
1453     SILC_LOG_DEBUG(("Private key does not have correct magic!"));
1454
1455     /* Now decode the actual private key */
1456     if (!silc_pkcs_private_key_decode(data, len, private_key)) {
1457       memset(old, 0, data_len);
1458       silc_free(old);
1459       return FALSE;
1460     }
1461
1462     memset(old, 0, data_len);
1463     silc_free(old);
1464     return TRUE;
1465   }
1466
1467   /* Allocate the AES cipher */
1468   if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
1469     SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
1470     memset(old, 0, data_len);
1471     silc_free(old);
1472     return FALSE;
1473   }
1474   blocklen = silc_cipher_get_block_len(aes);
1475   if (blocklen * 2 > sizeof(tmp)) {
1476     memset(old, 0, data_len);
1477     silc_free(old);
1478     return FALSE;
1479   }
1480
1481   /* Allocate SHA1 hash */
1482   if (!silc_hash_alloc("sha1", &sha1)) {
1483     SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered"));
1484     silc_cipher_free(aes);
1485     memset(old, 0, data_len);
1486     silc_free(old);
1487     return FALSE;
1488   }
1489
1490   /* Allocate HMAC */
1491   if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
1492     SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
1493     silc_hash_free(sha1);
1494     silc_cipher_free(aes);
1495     memset(old, 0, data_len);
1496     silc_free(old);
1497     return FALSE;
1498   }
1499
1500   /* Derive the decryption key from the provided key material.  The key
1501      is 256 bits length, and derived by taking hash of the data, then
1502      re-hashing the data and the previous digest, and using the first and
1503      second digest as the key. */
1504   silc_hash_init(sha1);
1505   silc_hash_update(sha1, passphrase, passphrase_len);
1506   silc_hash_final(sha1, keymat);
1507   silc_hash_init(sha1);
1508   silc_hash_update(sha1, passphrase, passphrase_len);
1509   silc_hash_update(sha1, keymat, 16);
1510   silc_hash_final(sha1, keymat + 16);
1511
1512   /* Set the key to the cipher */
1513   silc_cipher_set_key(aes, keymat, 256);
1514
1515   /* First, verify the MAC of the private key data */
1516   mac_len = silc_hmac_len(sha1hmac);
1517   silc_hmac_init_with_key(sha1hmac, keymat, 16);
1518   silc_hmac_update(sha1hmac, data, len - mac_len);
1519   silc_hmac_final(sha1hmac, tmp, NULL);
1520   if (memcmp(tmp, data + (len - mac_len), mac_len)) {
1521     SILC_LOG_DEBUG(("Integrity check for private key failed"));
1522     memset(keymat, 0, sizeof(keymat));
1523     memset(tmp, 0, sizeof(tmp));
1524     silc_hmac_free(sha1hmac);
1525     silc_hash_free(sha1);
1526     silc_cipher_free(aes);
1527     memset(old, 0, data_len);
1528     silc_free(old);
1529     return FALSE;
1530   }
1531   data += 4;
1532   len -= 4;
1533
1534   /* Decrypt the private key buffer */
1535   silc_cipher_decrypt(aes, data, data, len - mac_len, NULL);
1536   SILC_GET32_MSB(i, data);
1537   if (i > len) {
1538     SILC_LOG_DEBUG(("Bad private key length in buffer!"));
1539     memset(keymat, 0, sizeof(keymat));
1540     memset(tmp, 0, sizeof(tmp));
1541     silc_hmac_free(sha1hmac);
1542     silc_hash_free(sha1);
1543     silc_cipher_free(aes);
1544     memset(old, 0, data_len);
1545     silc_free(old);
1546     return FALSE;
1547   }
1548   data += 4;
1549   len = i;
1550
1551   /* Cleanup */
1552   memset(keymat, 0, sizeof(keymat));
1553   memset(tmp, 0, sizeof(tmp));
1554   silc_hmac_free(sha1hmac);
1555   silc_hash_free(sha1);
1556   silc_cipher_free(aes);
1557
1558   /* Now decode the actual private key */
1559   if (!silc_pkcs_private_key_decode(data, len, private_key)) {
1560     memset(old, 0, data_len);
1561     silc_free(old);
1562     return FALSE;
1563   }
1564
1565   memset(old, 0, data_len);
1566   silc_free(old);
1567   return TRUE;
1568 }