Implemented SILC protocol compliant public key. Added public
[silc.git] / lib / silccrypt / silcpkcs.c
1 /*
2
3   silcpkcs.c
4
5   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
6
7   Copyright (C) 1997 - 2000 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; either version 2 of the License, or
12   (at your option) any later version.
13   
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19 */
20
21 #include "silcincludes.h"
22
23 #include "rsa.h"
24
25 /* List of all PKCS's in SILC. PKCS's don't support SIM's thus
26    only static declarations are possible. XXX: I hope this to change
27    real soon. */
28 SilcPKCSObject silc_pkcs_list[] =
29 {
30   { "rsa", &silc_rsa_data_context, 
31     silc_rsa_init, silc_rsa_clear_keys, silc_rsa_get_public_key,
32     silc_rsa_get_private_key, silc_rsa_set_public_key,
33     silc_rsa_set_private_key, silc_rsa_context_len,
34     silc_rsa_data_context_len, silc_rsa_set_arg,
35     silc_rsa_encrypt, silc_rsa_decrypt,
36     silc_rsa_sign, silc_rsa_verify },
37
38   { NULL, NULL, NULL, NULL, NULL,
39     NULL, NULL, NULL, NULL, NULL, NULL }
40 };
41
42 /* Allocates a new SilcPKCS object. The new allocated object is returned
43    to the 'new_pkcs' argument. This function also initializes the data
44    context structure. Function returns 1 on success and 0 on error.
45
46 */
47 int silc_pkcs_alloc(const unsigned char *name, SilcPKCS *new_pkcs)
48 {
49   int i;
50
51   SILC_LOG_DEBUG(("Allocating new PKCS object"));
52
53   for (i = 0; silc_pkcs_list[i].name; i++) {
54     if (!strcmp(silc_pkcs_list[i].name, name))
55       break;
56   }
57
58   if (silc_pkcs_list[i].name == NULL)
59     return FALSE;
60
61   *new_pkcs = silc_calloc(1, sizeof(**new_pkcs));
62
63   /* Set the pointers */
64   (*new_pkcs)->pkcs = &silc_pkcs_list[i];
65   (*new_pkcs)->pkcs->data_context = 
66     silc_calloc(1, (*new_pkcs)->pkcs->data_context_len());
67   (*new_pkcs)->context = silc_calloc(1, (*new_pkcs)->pkcs->context_len());
68   (*new_pkcs)->get_key_len = silc_pkcs_get_key_len;
69
70   return TRUE;
71 }
72
73 /* Free's the PKCS object */
74
75 void silc_pkcs_free(SilcPKCS pkcs)
76 {
77   if (pkcs)
78     silc_free(pkcs->context);
79 }
80
81 /* Return TRUE if PKCS algorithm `name' is supported. */
82
83 int silc_pkcs_is_supported(const unsigned char *name)
84 {
85   int i;
86
87   for (i = 0; silc_pkcs_list[i].name; i++) {
88     if (!strcmp(silc_pkcs_list[i].name, name))
89       return TRUE;
90   }
91
92   return FALSE;
93 }
94
95 /* Returns comma separated list of supported PKCS algorithms */
96
97 char *silc_pkcs_get_supported()
98 {
99   char *list = NULL;
100   int i, len;
101
102   len = 0;
103   for (i = 0; silc_pkcs_list[i].name; i++) {
104     len += strlen(silc_pkcs_list[i].name);
105     list = silc_realloc(list, len + 1);
106
107     memcpy(list + (len - strlen(silc_pkcs_list[i].name)), 
108            silc_pkcs_list[i].name, strlen(silc_pkcs_list[i].name));
109     memcpy(list + len, ",", 1);
110     len++;
111   }
112
113   list[len - 1] = 0;
114
115   return list;
116 }
117
118 /* Returns the length of the key */
119
120 unsigned int silc_pkcs_get_key_len(SilcPKCS self)
121 {
122   return self->key_len;
123 }
124
125 /* Returns SILC style public key */
126
127 unsigned char *silc_pkcs_get_public_key(SilcPKCS pkcs, unsigned int *len)
128 {
129   return pkcs->pkcs->get_public_key(pkcs->context, len);
130 }
131
132 /* Returns SILC style private key */
133
134 unsigned char *silc_pkcs_get_private_key(SilcPKCS pkcs, unsigned int *len)
135 {
136   return pkcs->pkcs->get_private_key(pkcs->context, len);
137 }
138
139 /* Sets public key */
140
141 int silc_pkcs_set_public_key(SilcPKCS pkcs, unsigned char *pk, 
142                              unsigned int pk_len)
143 {
144   return pkcs->pkcs->set_public_key(pkcs->context, pk, pk_len);
145 }
146
147 /* Sets private key */
148
149 int silc_pkcs_set_private_key(SilcPKCS pkcs, unsigned char *prv, 
150                               unsigned int prv_len)
151 {
152   return pkcs->pkcs->set_private_key(pkcs->context, prv, prv_len);
153 }
154
155 /* Encodes and returns SILC public key identifier. If some of the 
156    arguments as NULL those are not encoded into the identifier string.
157    Protocol says that at least username and host must be provided. */
158
159 char *silc_pkcs_encode_identifier(char *username, char *host, char *realname,
160                                   char *email, char *org, char *country)
161 {
162   SilcBuffer buf;
163   char *identifier;
164   unsigned int len, tlen = 0;
165
166   if (!username || !host)
167     return NULL;
168
169   len = (username ? strlen(username) : 0) +
170         (host     ? strlen(host)     : 0) +
171         (realname ? strlen(realname) : 0) +
172         (email    ? strlen(email)    : 0) +
173         (org      ? strlen(org)      : 0) +
174         (country  ? strlen(country)  : 0);
175   
176   if (len < 3)
177     return NULL;
178
179   len += 3 + 5 + 5 + 4 + 4 + 4;
180   buf = silc_buffer_alloc(len);
181   silc_buffer_pull_tail(buf, len);
182
183   if (username) {
184     silc_buffer_format(buf,
185                        SILC_STR_UI32_STRING("UN="),
186                        SILC_STR_UI32_STRING(username),
187                        SILC_STR_END);
188     silc_buffer_pull(buf, 3 + strlen(username));
189     tlen = 3 + strlen(username); 
190   }
191     
192   if (host) {
193     silc_buffer_format(buf,
194                        SILC_STR_UI32_STRING(", "),
195                        SILC_STR_UI32_STRING("HN="),
196                        SILC_STR_UI32_STRING(host),
197                        SILC_STR_END);
198     silc_buffer_pull(buf, 5 + strlen(host));
199     tlen += 5 + strlen(host); 
200   }
201
202   if (realname) {
203     silc_buffer_format(buf,
204                        SILC_STR_UI32_STRING(", "),
205                        SILC_STR_UI32_STRING("RN="),
206                        SILC_STR_UI32_STRING(realname),
207                        SILC_STR_END);
208     silc_buffer_pull(buf, 5 + strlen(realname));
209     tlen += 5 + strlen(realname); 
210   }
211
212   if (email) {
213     silc_buffer_format(buf,
214                        SILC_STR_UI32_STRING(", "),
215                        SILC_STR_UI32_STRING("E="),
216                        SILC_STR_UI32_STRING(email),
217                        SILC_STR_END);
218     silc_buffer_pull(buf, 4 + strlen(email));
219     tlen += 4 + strlen(email); 
220   }
221
222   if (org) {
223     silc_buffer_format(buf,
224                        SILC_STR_UI32_STRING(", "),
225                        SILC_STR_UI32_STRING("O="),
226                        SILC_STR_UI32_STRING(org),
227                        SILC_STR_END);
228     silc_buffer_pull(buf, 4 + strlen(org));
229     tlen += 4 + strlen(org); 
230   }
231
232   if (country) {
233     silc_buffer_format(buf,
234                        SILC_STR_UI32_STRING(", "),
235                        SILC_STR_UI32_STRING("C="),
236                        SILC_STR_UI32_STRING(country),
237                        SILC_STR_END);
238     silc_buffer_pull(buf, 4 + strlen(country));
239     tlen += 4 + strlen(country); 
240   }
241
242   silc_buffer_push(buf, buf->data - buf->head);
243   identifier = silc_calloc(tlen, sizeof(*identifier));
244   memcpy(identifier, buf->data, tlen);
245   silc_buffer_free(buf);
246
247   return identifier;
248 }
249
250 /* Allocates SILC style public key formed from sent arguments. All data
251    is duplicated. */
252
253 SilcPublicKey silc_pkcs_public_key_alloc(char *name, char *identifier,
254                                          unsigned char *pk, 
255                                          unsigned int pk_len)
256 {
257   SilcPublicKey public_key;
258
259   public_key = silc_calloc(1, sizeof(*public_key));
260   public_key->len = 4 + 2 + strlen(name) + 2 + strlen(identifier) + pk_len;
261   public_key->name = strdup(name);
262   public_key->identifier = strdup(identifier);
263   public_key->pk_len = pk_len;
264   public_key->pk = silc_calloc(pk_len, sizeof(*public_key->pk));
265   memcpy(public_key->pk, pk, pk_len);
266
267   return public_key;
268 }
269
270 /* Free's public key */
271
272 void silc_pkcs_public_key_free(SilcPublicKey public_key)
273 {
274   if (public_key) {
275     silc_free(public_key->name);
276     silc_free(public_key->identifier);
277     silc_free(public_key->pk);
278     silc_free(public_key);
279   }
280 }
281
282 /* Allocates SILC private key formed from sent arguments. All data is
283    duplicated. */
284
285 SilcPrivateKey silc_pkcs_private_key_alloc(char *name, unsigned char *prv,
286                                            unsigned int prv_len)
287 {
288   SilcPrivateKey private_key;
289
290   private_key = silc_calloc(1, sizeof(*private_key));
291   private_key->name = strdup(name);
292   private_key->prv_len = prv_len;
293   private_key->prv = silc_calloc(prv_len, sizeof(*private_key->prv));
294   memcpy(private_key->prv, prv, prv_len);
295
296   return private_key;
297 }
298
299 /* Free's private key */
300
301 void silc_pkcs_private_key_free(SilcPrivateKey private_key)
302 {
303   if (private_key) {
304     silc_free(private_key->name);
305     silc_free(private_key->prv);
306     silc_free(private_key);
307   }
308 }
309
310 /* Encodes SILC style public key from SilcPublicKey. Returns the encoded
311    data. */
312
313 unsigned char *
314 silc_pkcs_public_key_encode(SilcPublicKey public_key, unsigned int *len)
315 {
316   SilcBuffer buf;
317   unsigned char *ret;
318
319   buf = silc_buffer_alloc(public_key->len);
320   silc_buffer_pull_tail(buf, public_key->len);
321
322   silc_buffer_format(buf,
323                      SILC_STR_UI_INT(public_key->len),
324                      SILC_STR_UI_SHORT(strlen(public_key->name)),
325                      SILC_STR_UI32_STRING(public_key->name),
326                      SILC_STR_UI_SHORT(strlen(public_key->identifier)),
327                      SILC_STR_UI32_STRING(public_key->identifier),
328                      SILC_STR_UI_XNSTRING(public_key->pk, 
329                                             public_key->pk_len),
330                      SILC_STR_END);
331   if (len)
332     *len = public_key->len;
333
334   ret = silc_calloc(buf->len, sizeof(*ret));
335   memcpy(ret, buf->data, buf->len);
336   silc_buffer_free(buf);
337
338   return ret;
339 }
340
341 /* Encodes SILC style public key. Returns the encoded data. */
342
343 unsigned char *
344 silc_pkcs_public_key_data_encode(unsigned char *pk, unsigned int pk_len,
345                                  char *pkcs, char *identifier, 
346                                  unsigned int *len)
347 {
348   SilcBuffer buf;
349   unsigned char *ret;
350   unsigned int totlen;
351
352   totlen = 4 + 2 + strlen(pkcs) + 2 + strlen(identifier) + pk_len;
353   buf = silc_buffer_alloc(totlen);
354   silc_buffer_pull_tail(buf, totlen);
355
356   silc_buffer_format(buf,
357                      SILC_STR_UI_INT(totlen),
358                      SILC_STR_UI_SHORT(strlen(pkcs)),
359                      SILC_STR_UI32_STRING(pkcs),
360                      SILC_STR_UI_SHORT(strlen(identifier)),
361                      SILC_STR_UI32_STRING(identifier),
362                      SILC_STR_UI_XNSTRING(pk, pk_len),
363                      SILC_STR_END);
364   if (len)
365     *len = totlen;
366
367   ret = silc_calloc(buf->len, sizeof(*ret));
368   memcpy(ret, buf->data, buf->len);
369   silc_buffer_free(buf);
370
371   return ret;
372 }
373
374 /* Decodes SILC style public key. Returns TRUE if the decoding was
375    successful. Allocates new public key as well. */
376
377 int silc_pkcs_public_key_decode(unsigned char *data, unsigned int data_len,
378                                 SilcPublicKey *public_key)
379 {
380   SilcBuffer buf;
381   SilcPKCS alg;
382   unsigned short pkcs_len, identifier_len;
383   unsigned int totlen, key_len;
384   unsigned char *pkcs_name = NULL, *ident = NULL, *key_data = NULL;
385
386   buf = silc_buffer_alloc(data_len);
387   silc_buffer_pull_tail(buf, data_len);
388   silc_buffer_put(buf, data, data_len);
389
390   /* Get length */
391   silc_buffer_unformat(buf,
392                        SILC_STR_UI_INT(&totlen),
393                        SILC_STR_END);
394
395   if (totlen != data_len) {
396     silc_buffer_free(buf);
397     return FALSE;
398   }
399
400   /* Get algorithm name and identifier */
401   silc_buffer_pull(buf, 4);
402   silc_buffer_unformat(buf,
403                        SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
404                        SILC_STR_UI16_NSTRING_ALLOC(&ident, &identifier_len),
405                        SILC_STR_END);
406
407   if (pkcs_len < 1 || identifier_len < 3 || 
408       pkcs_len + identifier_len > totlen)
409     goto err;
410
411   /* See if we support this algorithm */
412   if (!silc_pkcs_is_supported(pkcs_name))
413     goto err;
414
415   /* Protocol says that at least UN and HN must be provided as identifier,
416      check for these. */
417   if (!strstr(ident, "UN=") && !strstr(ident, "HN="))
418     goto err;
419
420   /* Get key data. We assume that rest of the buffer is key data. */
421   silc_buffer_pull(buf, 2 + pkcs_len + 2 + identifier_len);
422   key_len = buf->len;
423   silc_buffer_unformat(buf,
424                        SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
425                        SILC_STR_END);
426
427   /* Try to set the key. If this fails the key must be malformed. This
428      code assumes that the PKCS routine checks the format of the key. */
429   silc_pkcs_alloc(pkcs_name, &alg);
430   if (!alg->pkcs->set_public_key(alg->context, key_data, key_len))
431     goto err;
432   silc_pkcs_free(alg);
433   
434   if (public_key) {
435     *public_key = silc_calloc(1, sizeof(**public_key));
436     (*public_key)->len = totlen;
437     (*public_key)->name = pkcs_name;
438     (*public_key)->identifier = ident;
439     (*public_key)->pk = key_data;
440     (*public_key)->pk_len = key_len;
441   }
442
443   silc_buffer_free(buf);
444   return TRUE;
445
446  err:
447   if (pkcs_name)
448     silc_free(pkcs_name);
449   if (ident)
450     silc_free(ident);
451   if (key_data)
452     silc_free(key_data);
453   silc_buffer_free(buf);
454   return FALSE;
455 }
456
457 /* Encodes SILC private key from SilcPrivateKey. Returns the encoded data. */
458
459 unsigned char *
460 silc_pkcs_private_key_encode(SilcPrivateKey private_key, unsigned int *len)
461 {
462   SilcBuffer buf;
463   unsigned char *ret;
464   unsigned int totlen;
465
466   totlen = 2 + strlen(private_key->name) + private_key->prv_len;
467   buf = silc_buffer_alloc(totlen);
468   silc_buffer_pull_tail(buf, totlen);
469
470   silc_buffer_format(buf,
471                      SILC_STR_UI_SHORT(strlen(private_key->name)),
472                      SILC_STR_UI32_STRING(private_key->name),
473                      SILC_STR_UI_XNSTRING(private_key->prv, 
474                                           private_key->prv_len),
475                      SILC_STR_END);
476   if (len)
477     *len = totlen;
478
479   ret = silc_calloc(buf->len, sizeof(*ret));
480   memcpy(ret, buf->data, buf->len);
481   silc_buffer_free(buf);
482
483   return ret;
484 }
485
486 /* Encodes SILC private key. Returns the encoded data. */
487
488 unsigned char *
489 silc_pkcs_private_key_data_encode(unsigned char *prv, unsigned int prv_len,
490                                   char *pkcs, unsigned int *len)
491 {
492   SilcBuffer buf;
493   unsigned char *ret;
494   unsigned int totlen;
495
496   totlen = 2 + strlen(pkcs) + prv_len;
497   buf = silc_buffer_alloc(totlen);
498   silc_buffer_pull_tail(buf, totlen);
499
500   silc_buffer_format(buf,
501                      SILC_STR_UI_SHORT(strlen(pkcs)),
502                      SILC_STR_UI32_STRING(pkcs),
503                      SILC_STR_UI_XNSTRING(prv, prv_len),
504                      SILC_STR_END);
505   if (len)
506     *len = totlen;
507
508   ret = silc_calloc(buf->len, sizeof(*ret));
509   memcpy(ret, buf->data, buf->len);
510   silc_buffer_free(buf);
511
512   return ret;
513 }
514
515 /* Decodes SILC style public key. Returns TRUE if the decoding was
516    successful. Allocates new private key as well. */
517
518 int silc_pkcs_private_key_decode(unsigned char *data, unsigned int data_len,
519                                  SilcPrivateKey *private_key)
520 {
521   SilcBuffer buf;
522   SilcPKCS alg;
523   unsigned short pkcs_len;
524   unsigned int key_len;
525   unsigned char *pkcs_name = NULL, *key_data = NULL;
526
527   buf = silc_buffer_alloc(data_len);
528   silc_buffer_pull_tail(buf, data_len);
529   silc_buffer_put(buf, data, data_len);
530
531   /* Get algorithm name and identifier */
532   silc_buffer_unformat(buf,
533                        SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
534                        SILC_STR_END);
535
536   if (pkcs_len < 1 || pkcs_len > buf->truelen)
537     goto err;
538
539   /* See if we support this algorithm */
540   if (!silc_pkcs_is_supported(pkcs_name))
541     goto err;
542
543   /* Get key data. We assume that rest of the buffer is key data. */
544   silc_buffer_pull(buf, 2 + pkcs_len);
545   key_len = buf->len;
546   silc_buffer_unformat(buf,
547                        SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
548                        SILC_STR_END);
549
550   /* Try to set the key. If this fails the key must be malformed. This
551      code assumes that the PKCS routine checks the format of the key. */
552   silc_pkcs_alloc(pkcs_name, &alg);
553   if (!alg->pkcs->set_private_key(alg->context, key_data, key_len))
554     goto err;
555   silc_pkcs_free(alg);
556   
557   if (private_key) {
558     *private_key = silc_calloc(1, sizeof(**private_key));
559     (*private_key)->name = pkcs_name;
560     (*private_key)->prv = key_data;
561     (*private_key)->prv_len = key_len;
562   }
563
564   silc_buffer_free(buf);
565   return TRUE;
566
567  err:
568   if (pkcs_name)
569     silc_free(pkcs_name);
570   if (key_data)
571     silc_free(key_data);
572   silc_buffer_free(buf);
573   return FALSE;
574 }
575
576 /* Internal routine to save public key */
577
578 static int silc_pkcs_save_public_key_internal(char *filename,
579                                               unsigned char *data,
580                                               unsigned int data_len)
581 {
582   SilcBuffer buf;
583   unsigned int len;
584
585   len = data_len + (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
586                     strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
587   buf = silc_buffer_alloc(len);
588   silc_buffer_pull_tail(buf, len);
589
590   silc_buffer_format(buf,
591                      SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
592                      SILC_STR_UI_XNSTRING(data, data_len),
593                      SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END),
594                      SILC_STR_END);
595
596   /* Save into a file */
597   if (silc_file_write(filename, buf->data, buf->len)) {
598     memset(data, 0, data_len);
599     silc_free(data);
600     silc_buffer_free(buf);
601     return FALSE;
602   }
603
604   memset(data, 0, data_len);
605   silc_free(data);
606   silc_buffer_free(buf);
607   return TRUE;
608 }
609
610 /* Saves public key into file */
611 /* XXX encoding should be defined (PEM or binary). */
612
613 int silc_pkcs_save_public_key(char *filename, SilcPublicKey public_key)
614 {
615   unsigned char *data;
616   unsigned int data_len;
617
618   data = silc_pkcs_public_key_encode(public_key, &data_len);
619   return silc_pkcs_save_public_key_internal(filename, data, data_len);
620 }
621
622 /* Saves public key into file */
623 /* XXX encoding should be defined (PEM or binary). */
624
625 int silc_pkcs_save_public_key_data(char *filename, unsigned char *data,
626                                    unsigned int data_len)
627 {
628   return silc_pkcs_save_public_key_internal(filename, data, data_len);
629 }
630
631 /* Internal routine to save private key. */
632
633 static int silc_pkcs_save_private_key_internal(char *filename,
634                                                unsigned char *data,
635                                                unsigned int data_len)
636 {
637   SilcBuffer buf;
638   unsigned int len;
639
640   len = data_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
641                     strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
642   buf = silc_buffer_alloc(len);
643   silc_buffer_pull_tail(buf, len);
644
645   silc_buffer_format(buf,
646                      SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
647                      SILC_STR_UI_XNSTRING(data, data_len),
648                      SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
649                      SILC_STR_END);
650
651   /* Save into a file */
652   if (silc_file_write_mode(filename, buf->data, buf->len, 0600)) {
653     memset(data, 0, data_len);
654     silc_free(data);
655     silc_buffer_free(buf);
656     return FALSE;
657   }
658
659   memset(data, 0, data_len);
660   silc_free(data);
661   silc_buffer_free(buf);
662   return TRUE;
663 }
664
665 /* Saves private key into file. */
666 /* XXX The buffer should be encrypted if passphrase is provided. */
667 /* XXX encoding should be defined (PEM or binary). */
668
669 int silc_pkcs_save_private_key(char *filename, SilcPrivateKey private_key, 
670                                unsigned char *passphrase)
671 {
672   unsigned char *data;
673   unsigned int data_len;
674
675   data = silc_pkcs_private_key_encode(private_key, &data_len);
676   return silc_pkcs_save_private_key_internal(filename, data, data_len);
677 }
678
679 /* Saves private key into file. */
680 /* XXX The buffer should be encrypted if passphrase is provided. */
681 /* XXX encoding should be defined (PEM or binary). */
682
683 int silc_pkcs_save_private_key_data(char *filename, unsigned char *data, 
684                                     unsigned int data_len,
685                                     unsigned char *passphrase)
686 {
687   return silc_pkcs_save_private_key_internal(filename, data, data_len);
688 }
689
690 /* Loads public key from file and allocates new public key. Returns TRUE
691    is loading was successful. */
692 /* XXX Encoding should be defined. */
693
694 int silc_pkcs_load_public_key(char *filename, SilcPublicKey *public_key)
695 {
696   unsigned char *cp, *old, *data, byte;
697   unsigned int i, data_len, len;
698
699   old = data = silc_file_read(filename, &data_len);
700   if (!data)
701     return FALSE;
702
703   /* Check start of file and remove header from the data. */
704   len = strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN);
705   cp = data;
706   for (i = 0; i < len; i++) {
707     byte = cp[0];
708     cp++;
709     if (byte != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i]) {
710       memset(old, 0, data_len);
711       silc_free(old);
712     }
713   }
714   data = cp;
715
716   /* Decode public key */
717   if (public_key) {
718     len = data_len - (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
719                       strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
720     if (!silc_pkcs_public_key_decode(data, len, public_key)) {
721       memset(old, 0, data_len);
722       silc_free(old);
723       return FALSE;
724     }
725   }
726
727   memset(old, 0, data_len);
728   silc_free(old);
729   return TRUE;
730 }
731
732 /* Load private key from file and allocates new private key. Returns TRUE
733    if loading was successful. */
734 /* XXX Encoding should be defined. */
735 /* XXX Should support encrypted private key files */
736
737 int silc_pkcs_load_private_key(char *filename, SilcPrivateKey *private_key)
738 {
739   unsigned char *cp, *old, *data, byte;
740   unsigned int i, data_len, len;
741
742   old = data = silc_file_read(filename, &data_len);
743   if (!data)
744     return FALSE;
745
746   /* Check start of file and remove header from the data. */
747   len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
748   cp = data;
749   for (i = 0; i < len; i++) {
750     byte = cp[0];
751     cp++;
752     if (byte != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i]) {
753       memset(old, 0, data_len);
754       silc_free(old);
755     }
756   }
757   data = cp;
758
759   /* Decode private key */
760   if (private_key) {
761     len = data_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
762                       strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
763     if (!silc_pkcs_private_key_decode(data, len, private_key)) {
764       memset(old, 0, data_len);
765       silc_free(old);
766       return FALSE;
767     }
768   }
769
770   memset(old, 0, data_len);
771   silc_free(old);
772   return TRUE;
773 }