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