Bug fixes on public/private key saving.
[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 from SilcPublicKey. */
140
141 int silc_pkcs_public_key_set(SilcPKCS pkcs, SilcPublicKey public_key)
142 {
143   return pkcs->pkcs->set_public_key(pkcs->context, public_key->pk, 
144                                     public_key->pk_len);
145 }
146
147 /* Sets public key from data. */
148
149 int silc_pkcs_public_key_data_set(SilcPKCS pkcs, unsigned char *pk,
150                                   unsigned int pk_len)
151 {
152   return pkcs->pkcs->set_public_key(pkcs->context, pk, pk_len);
153 }
154
155 /* Sets private key from SilcPrivateKey. */
156
157 int silc_pkcs_private_key_set(SilcPKCS pkcs, SilcPrivateKey private_key)
158 {
159   return pkcs->pkcs->set_private_key(pkcs->context, private_key->prv, 
160                                      private_key->prv_len);
161 }
162
163 /* Sets private key from data. */
164
165 int silc_pkcs_private_key_data_set(SilcPKCS pkcs, unsigned char *prv,
166                                    unsigned int prv_len)
167 {
168   return pkcs->pkcs->set_private_key(pkcs->context, prv, prv_len);
169 }
170
171 /* Encodes and returns SILC public key identifier. If some of the 
172    arguments is NULL those are not encoded into the identifier string.
173    Protocol says that at least username and host must be provided. */
174
175 char *silc_pkcs_encode_identifier(char *username, char *host, char *realname,
176                                   char *email, char *org, char *country)
177 {
178   SilcBuffer buf;
179   char *identifier;
180   unsigned int len, tlen = 0;
181
182   if (!username || !host)
183     return NULL;
184
185   len = (username ? strlen(username) : 0) +
186         (host     ? strlen(host)     : 0) +
187         (realname ? strlen(realname) : 0) +
188         (email    ? strlen(email)    : 0) +
189         (org      ? strlen(org)      : 0) +
190         (country  ? strlen(country)  : 0);
191   
192   if (len < 3)
193     return NULL;
194
195   len += 3 + 5 + 5 + 4 + 4 + 4;
196   buf = silc_buffer_alloc(len);
197   silc_buffer_pull_tail(buf, len);
198
199   if (username) {
200     silc_buffer_format(buf,
201                        SILC_STR_UI32_STRING("UN="),
202                        SILC_STR_UI32_STRING(username),
203                        SILC_STR_END);
204     silc_buffer_pull(buf, 3 + strlen(username));
205     tlen = 3 + strlen(username); 
206   }
207     
208   if (host) {
209     silc_buffer_format(buf,
210                        SILC_STR_UI32_STRING(", "),
211                        SILC_STR_UI32_STRING("HN="),
212                        SILC_STR_UI32_STRING(host),
213                        SILC_STR_END);
214     silc_buffer_pull(buf, 5 + strlen(host));
215     tlen += 5 + strlen(host); 
216   }
217
218   if (realname) {
219     silc_buffer_format(buf,
220                        SILC_STR_UI32_STRING(", "),
221                        SILC_STR_UI32_STRING("RN="),
222                        SILC_STR_UI32_STRING(realname),
223                        SILC_STR_END);
224     silc_buffer_pull(buf, 5 + strlen(realname));
225     tlen += 5 + strlen(realname); 
226   }
227
228   if (email) {
229     silc_buffer_format(buf,
230                        SILC_STR_UI32_STRING(", "),
231                        SILC_STR_UI32_STRING("E="),
232                        SILC_STR_UI32_STRING(email),
233                        SILC_STR_END);
234     silc_buffer_pull(buf, 4 + strlen(email));
235     tlen += 4 + strlen(email); 
236   }
237
238   if (org) {
239     silc_buffer_format(buf,
240                        SILC_STR_UI32_STRING(", "),
241                        SILC_STR_UI32_STRING("O="),
242                        SILC_STR_UI32_STRING(org),
243                        SILC_STR_END);
244     silc_buffer_pull(buf, 4 + strlen(org));
245     tlen += 4 + strlen(org); 
246   }
247
248   if (country) {
249     silc_buffer_format(buf,
250                        SILC_STR_UI32_STRING(", "),
251                        SILC_STR_UI32_STRING("C="),
252                        SILC_STR_UI32_STRING(country),
253                        SILC_STR_END);
254     silc_buffer_pull(buf, 4 + strlen(country));
255     tlen += 4 + strlen(country); 
256   }
257
258   silc_buffer_push(buf, buf->data - buf->head);
259   identifier = silc_calloc(tlen, sizeof(*identifier));
260   memcpy(identifier, buf->data, tlen);
261   silc_buffer_free(buf);
262
263   return identifier;
264 }
265
266 /* Allocates SILC style public key formed from sent arguments. All data
267    is duplicated. */
268
269 SilcPublicKey silc_pkcs_public_key_alloc(char *name, char *identifier,
270                                          unsigned char *pk, 
271                                          unsigned int pk_len)
272 {
273   SilcPublicKey public_key;
274
275   public_key = silc_calloc(1, sizeof(*public_key));
276   public_key->len = 4 + 2 + strlen(name) + 2 + strlen(identifier) + pk_len;
277   public_key->name = strdup(name);
278   public_key->identifier = strdup(identifier);
279   public_key->pk_len = pk_len;
280   public_key->pk = silc_calloc(pk_len, sizeof(*public_key->pk));
281   memcpy(public_key->pk, pk, pk_len);
282
283   return public_key;
284 }
285
286 /* Free's public key */
287
288 void silc_pkcs_public_key_free(SilcPublicKey public_key)
289 {
290   if (public_key) {
291     silc_free(public_key->name);
292     silc_free(public_key->identifier);
293     silc_free(public_key->pk);
294     silc_free(public_key);
295   }
296 }
297
298 /* Allocates SILC private key formed from sent arguments. All data is
299    duplicated. */
300
301 SilcPrivateKey silc_pkcs_private_key_alloc(char *name, unsigned char *prv,
302                                            unsigned int prv_len)
303 {
304   SilcPrivateKey private_key;
305
306   private_key = silc_calloc(1, sizeof(*private_key));
307   private_key->name = strdup(name);
308   private_key->prv_len = prv_len;
309   private_key->prv = silc_calloc(prv_len, sizeof(*private_key->prv));
310   memcpy(private_key->prv, prv, prv_len);
311
312   return private_key;
313 }
314
315 /* Free's private key */
316
317 void silc_pkcs_private_key_free(SilcPrivateKey private_key)
318 {
319   if (private_key) {
320     silc_free(private_key->name);
321     silc_free(private_key->prv);
322     silc_free(private_key);
323   }
324 }
325
326 /* Encodes SILC style public key from SilcPublicKey. Returns the encoded
327    data. */
328
329 unsigned char *
330 silc_pkcs_public_key_encode(SilcPublicKey public_key, unsigned int *len)
331 {
332   SilcBuffer buf;
333   unsigned char *ret;
334
335   buf = silc_buffer_alloc(public_key->len);
336   silc_buffer_pull_tail(buf, public_key->len);
337
338   silc_buffer_format(buf,
339                      SILC_STR_UI_INT(public_key->len),
340                      SILC_STR_UI_SHORT(strlen(public_key->name)),
341                      SILC_STR_UI32_STRING(public_key->name),
342                      SILC_STR_UI_SHORT(strlen(public_key->identifier)),
343                      SILC_STR_UI32_STRING(public_key->identifier),
344                      SILC_STR_UI_XNSTRING(public_key->pk, 
345                                             public_key->pk_len),
346                      SILC_STR_END);
347   if (len)
348     *len = public_key->len;
349
350   ret = silc_calloc(buf->len, sizeof(*ret));
351   memcpy(ret, buf->data, buf->len);
352   silc_buffer_free(buf);
353
354   return ret;
355 }
356
357 /* Encodes SILC style public key. Returns the encoded data. */
358
359 unsigned char *
360 silc_pkcs_public_key_data_encode(unsigned char *pk, unsigned int pk_len,
361                                  char *pkcs, char *identifier, 
362                                  unsigned int *len)
363 {
364   SilcBuffer buf;
365   unsigned char *ret;
366   unsigned int totlen;
367
368   totlen = 4 + 2 + strlen(pkcs) + 2 + strlen(identifier) + pk_len;
369   buf = silc_buffer_alloc(totlen);
370   silc_buffer_pull_tail(buf, totlen);
371
372   silc_buffer_format(buf,
373                      SILC_STR_UI_INT(totlen),
374                      SILC_STR_UI_SHORT(strlen(pkcs)),
375                      SILC_STR_UI32_STRING(pkcs),
376                      SILC_STR_UI_SHORT(strlen(identifier)),
377                      SILC_STR_UI32_STRING(identifier),
378                      SILC_STR_UI_XNSTRING(pk, pk_len),
379                      SILC_STR_END);
380   if (len)
381     *len = totlen;
382
383   ret = silc_calloc(buf->len, sizeof(*ret));
384   memcpy(ret, buf->data, buf->len);
385   silc_buffer_free(buf);
386
387   return ret;
388 }
389
390 /* Decodes SILC style public key. Returns TRUE if the decoding was
391    successful. Allocates new public key as well. */
392
393 int silc_pkcs_public_key_decode(unsigned char *data, unsigned int data_len,
394                                 SilcPublicKey *public_key)
395 {
396   SilcBuffer buf;
397   SilcPKCS alg;
398   unsigned short pkcs_len, identifier_len;
399   unsigned int totlen, key_len;
400   unsigned char *pkcs_name = NULL, *ident = NULL, *key_data = NULL;
401
402   buf = silc_buffer_alloc(data_len);
403   silc_buffer_pull_tail(buf, data_len);
404   silc_buffer_put(buf, data, data_len);
405
406   /* Get length */
407   silc_buffer_unformat(buf,
408                        SILC_STR_UI_INT(&totlen),
409                        SILC_STR_END);
410
411   if (totlen != data_len) {
412     silc_buffer_free(buf);
413     return FALSE;
414   }
415
416   /* Get algorithm name and identifier */
417   silc_buffer_pull(buf, 4);
418   silc_buffer_unformat(buf,
419                        SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
420                        SILC_STR_UI16_NSTRING_ALLOC(&ident, &identifier_len),
421                        SILC_STR_END);
422
423   if (pkcs_len < 1 || identifier_len < 3 || 
424       pkcs_len + identifier_len > totlen)
425     goto err;
426
427   /* See if we support this algorithm */
428   if (!silc_pkcs_is_supported(pkcs_name))
429     goto err;
430
431   /* Protocol says that at least UN and HN must be provided as identifier,
432      check for these. */
433   if (!strstr(ident, "UN=") && !strstr(ident, "HN="))
434     goto err;
435
436   /* Get key data. We assume that rest of the buffer is key data. */
437   silc_buffer_pull(buf, 2 + pkcs_len + 2 + identifier_len);
438   key_len = buf->len;
439   silc_buffer_unformat(buf,
440                        SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
441                        SILC_STR_END);
442
443   /* Try to set the key. If this fails the key must be malformed. This
444      code assumes that the PKCS routine checks the format of the key. */
445   silc_pkcs_alloc(pkcs_name, &alg);
446   if (!alg->pkcs->set_public_key(alg->context, key_data, key_len))
447     goto err;
448   silc_pkcs_free(alg);
449   
450   if (public_key) {
451     *public_key = silc_calloc(1, sizeof(**public_key));
452     (*public_key)->len = totlen;
453     (*public_key)->name = pkcs_name;
454     (*public_key)->identifier = ident;
455     (*public_key)->pk = key_data;
456     (*public_key)->pk_len = key_len;
457   }
458
459   silc_buffer_free(buf);
460   return TRUE;
461
462  err:
463   if (pkcs_name)
464     silc_free(pkcs_name);
465   if (ident)
466     silc_free(ident);
467   if (key_data)
468     silc_free(key_data);
469   silc_buffer_free(buf);
470   return FALSE;
471 }
472
473 /* Encodes SILC private key from SilcPrivateKey. Returns the encoded data. */
474
475 unsigned char *
476 silc_pkcs_private_key_encode(SilcPrivateKey private_key, unsigned int *len)
477 {
478   SilcBuffer buf;
479   unsigned char *ret;
480   unsigned int totlen;
481
482   totlen = 2 + strlen(private_key->name) + private_key->prv_len;
483   buf = silc_buffer_alloc(totlen);
484   silc_buffer_pull_tail(buf, totlen);
485
486   silc_buffer_format(buf,
487                      SILC_STR_UI_SHORT(strlen(private_key->name)),
488                      SILC_STR_UI32_STRING(private_key->name),
489                      SILC_STR_UI_XNSTRING(private_key->prv, 
490                                           private_key->prv_len),
491                      SILC_STR_END);
492   if (len)
493     *len = totlen;
494
495   ret = silc_calloc(buf->len, sizeof(*ret));
496   memcpy(ret, buf->data, buf->len);
497   silc_buffer_free(buf);
498
499   return ret;
500 }
501
502 /* Encodes SILC private key. Returns the encoded data. */
503
504 unsigned char *
505 silc_pkcs_private_key_data_encode(unsigned char *prv, unsigned int prv_len,
506                                   char *pkcs, unsigned int *len)
507 {
508   SilcBuffer buf;
509   unsigned char *ret;
510   unsigned int totlen;
511
512   totlen = 2 + strlen(pkcs) + prv_len;
513   buf = silc_buffer_alloc(totlen);
514   silc_buffer_pull_tail(buf, totlen);
515
516   silc_buffer_format(buf,
517                      SILC_STR_UI_SHORT(strlen(pkcs)),
518                      SILC_STR_UI32_STRING(pkcs),
519                      SILC_STR_UI_XNSTRING(prv, prv_len),
520                      SILC_STR_END);
521   if (len)
522     *len = totlen;
523
524   ret = silc_calloc(buf->len, sizeof(*ret));
525   memcpy(ret, buf->data, buf->len);
526   silc_buffer_free(buf);
527
528   return ret;
529 }
530
531 /* Decodes SILC style public key. Returns TRUE if the decoding was
532    successful. Allocates new private key as well. */
533
534 int silc_pkcs_private_key_decode(unsigned char *data, unsigned int data_len,
535                                  SilcPrivateKey *private_key)
536 {
537   SilcBuffer buf;
538   SilcPKCS alg;
539   unsigned short pkcs_len;
540   unsigned int key_len;
541   unsigned char *pkcs_name = NULL, *key_data = NULL;
542
543   buf = silc_buffer_alloc(data_len);
544   silc_buffer_pull_tail(buf, data_len);
545   silc_buffer_put(buf, data, data_len);
546
547   /* Get algorithm name and identifier */
548   silc_buffer_unformat(buf,
549                        SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
550                        SILC_STR_END);
551
552   if (pkcs_len < 1 || pkcs_len > buf->truelen)
553     goto err;
554
555   /* See if we support this algorithm */
556   if (!silc_pkcs_is_supported(pkcs_name))
557     goto err;
558
559   /* Get key data. We assume that rest of the buffer is key data. */
560   silc_buffer_pull(buf, 2 + pkcs_len);
561   key_len = buf->len;
562   silc_buffer_unformat(buf,
563                        SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
564                        SILC_STR_END);
565
566   /* Try to set the key. If this fails the key must be malformed. This
567      code assumes that the PKCS routine checks the format of the key. */
568   silc_pkcs_alloc(pkcs_name, &alg);
569   if (!alg->pkcs->set_private_key(alg->context, key_data, key_len))
570     goto err;
571   silc_pkcs_free(alg);
572   
573   if (private_key) {
574     *private_key = silc_calloc(1, sizeof(**private_key));
575     (*private_key)->name = pkcs_name;
576     (*private_key)->prv = key_data;
577     (*private_key)->prv_len = key_len;
578   }
579
580   silc_buffer_free(buf);
581   return TRUE;
582
583  err:
584   if (pkcs_name)
585     silc_free(pkcs_name);
586   if (key_data)
587     silc_free(key_data);
588   silc_buffer_free(buf);
589   return FALSE;
590 }
591
592 /* Internal routine to save public key */
593
594 static int silc_pkcs_save_public_key_internal(char *filename,
595                                               unsigned char *data,
596                                               unsigned int data_len)
597 {
598   SilcBuffer buf;
599   unsigned int len;
600
601   len = data_len + (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
602                     strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
603   buf = silc_buffer_alloc(len);
604   silc_buffer_pull_tail(buf, len);
605
606   silc_buffer_format(buf,
607                      SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
608                      SILC_STR_UI_XNSTRING(data, data_len),
609                      SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END),
610                      SILC_STR_END);
611
612   /* Save into a file */
613   if (silc_file_write(filename, buf->data, buf->len)) {
614     silc_buffer_free(buf);
615     return FALSE;
616   }
617
618   silc_buffer_free(buf);
619   return TRUE;
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(char *filename, SilcPublicKey public_key)
626 {
627   unsigned char *data;
628   unsigned int data_len;
629
630   data = silc_pkcs_public_key_encode(public_key, &data_len);
631   return silc_pkcs_save_public_key_internal(filename, data, data_len);
632 }
633
634 /* Saves public key into file */
635 /* XXX encoding should be defined (PEM or binary). */
636
637 int silc_pkcs_save_public_key_data(char *filename, unsigned char *data,
638                                    unsigned int data_len)
639 {
640   return silc_pkcs_save_public_key_internal(filename, data, data_len);
641 }
642
643 /* Internal routine to save private key. */
644
645 static int silc_pkcs_save_private_key_internal(char *filename,
646                                                unsigned char *data,
647                                                unsigned int data_len)
648 {
649   SilcBuffer buf;
650   unsigned int len;
651
652   len = data_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
653                     strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
654   buf = silc_buffer_alloc(len);
655   silc_buffer_pull_tail(buf, len);
656
657   silc_buffer_format(buf,
658                      SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
659                      SILC_STR_UI_XNSTRING(data, data_len),
660                      SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
661                      SILC_STR_END);
662
663   /* Save into a file */
664   if (silc_file_write_mode(filename, buf->data, buf->len, 0600)) {
665     silc_buffer_free(buf);
666     return FALSE;
667   }
668
669   silc_buffer_free(buf);
670   return TRUE;
671 }
672
673 /* Saves private key into file. */
674 /* XXX The buffer should be encrypted if passphrase is provided. */
675 /* XXX encoding should be defined (PEM or binary). */
676
677 int silc_pkcs_save_private_key(char *filename, SilcPrivateKey private_key, 
678                                unsigned char *passphrase)
679 {
680   unsigned char *data;
681   unsigned int data_len;
682
683   data = silc_pkcs_private_key_encode(private_key, &data_len);
684   return silc_pkcs_save_private_key_internal(filename, data, data_len);
685 }
686
687 /* Saves private key into file. */
688 /* XXX The buffer should be encrypted if passphrase is provided. */
689 /* XXX encoding should be defined (PEM or binary). */
690
691 int silc_pkcs_save_private_key_data(char *filename, unsigned char *data, 
692                                     unsigned int data_len,
693                                     unsigned char *passphrase)
694 {
695   return silc_pkcs_save_private_key_internal(filename, data, data_len);
696 }
697
698 /* Loads public key from file and allocates new public key. Returns TRUE
699    is loading was successful. */
700 /* XXX Encoding should be defined. */
701
702 int silc_pkcs_load_public_key(char *filename, SilcPublicKey *public_key)
703 {
704   unsigned char *cp, *old, *data, byte;
705   unsigned int i, data_len, len;
706
707   old = data = silc_file_read(filename, &data_len);
708   if (!data)
709     return FALSE;
710
711   /* Check start of file and remove header from the data. */
712   len = strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN);
713   cp = data;
714   for (i = 0; i < len; i++) {
715     byte = cp[0];
716     cp++;
717     if (byte != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i]) {
718       memset(old, 0, data_len);
719       silc_free(old);
720     }
721   }
722   data = cp;
723
724   /* Decode public key */
725   if (public_key) {
726     len = data_len - (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
727                       strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
728     if (!silc_pkcs_public_key_decode(data, len, public_key)) {
729       memset(old, 0, data_len);
730       silc_free(old);
731       return FALSE;
732     }
733   }
734
735   memset(old, 0, data_len);
736   silc_free(old);
737   return TRUE;
738 }
739
740 /* Load private key from file and allocates new private key. Returns TRUE
741    if loading was successful. */
742 /* XXX Encoding should be defined. */
743 /* XXX Should support encrypted private key files */
744
745 int silc_pkcs_load_private_key(char *filename, SilcPrivateKey *private_key)
746 {
747   unsigned char *cp, *old, *data, byte;
748   unsigned int i, data_len, len;
749
750   old = data = silc_file_read(filename, &data_len);
751   if (!data)
752     return FALSE;
753
754   /* Check start of file and remove header from the data. */
755   len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
756   cp = data;
757   for (i = 0; i < len; i++) {
758     byte = cp[0];
759     cp++;
760     if (byte != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i]) {
761       memset(old, 0, data_len);
762       silc_free(old);
763     }
764   }
765   data = cp;
766
767   /* Decode private key */
768   if (private_key) {
769     len = data_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
770                       strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
771     if (!silc_pkcs_private_key_decode(data, len, private_key)) {
772       memset(old, 0, data_len);
773       silc_free(old);
774       return FALSE;
775     }
776   }
777
778   memset(old, 0, data_len);
779   silc_free(old);
780   return TRUE;
781 }