Public and private key setting now takes SilcPublicKey and
[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     memset(data, 0, data_len);
615     silc_free(data);
616     silc_buffer_free(buf);
617     return FALSE;
618   }
619
620   memset(data, 0, data_len);
621   silc_free(data);
622   silc_buffer_free(buf);
623   return TRUE;
624 }
625
626 /* Saves public key into file */
627 /* XXX encoding should be defined (PEM or binary). */
628
629 int silc_pkcs_save_public_key(char *filename, SilcPublicKey public_key)
630 {
631   unsigned char *data;
632   unsigned int data_len;
633
634   data = silc_pkcs_public_key_encode(public_key, &data_len);
635   return silc_pkcs_save_public_key_internal(filename, data, data_len);
636 }
637
638 /* Saves public key into file */
639 /* XXX encoding should be defined (PEM or binary). */
640
641 int silc_pkcs_save_public_key_data(char *filename, unsigned char *data,
642                                    unsigned int data_len)
643 {
644   return silc_pkcs_save_public_key_internal(filename, data, data_len);
645 }
646
647 /* Internal routine to save private key. */
648
649 static int silc_pkcs_save_private_key_internal(char *filename,
650                                                unsigned char *data,
651                                                unsigned int data_len)
652 {
653   SilcBuffer buf;
654   unsigned int len;
655
656   len = data_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
657                     strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
658   buf = silc_buffer_alloc(len);
659   silc_buffer_pull_tail(buf, len);
660
661   silc_buffer_format(buf,
662                      SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
663                      SILC_STR_UI_XNSTRING(data, data_len),
664                      SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
665                      SILC_STR_END);
666
667   /* Save into a file */
668   if (silc_file_write_mode(filename, buf->data, buf->len, 0600)) {
669     memset(data, 0, data_len);
670     silc_free(data);
671     silc_buffer_free(buf);
672     return FALSE;
673   }
674
675   memset(data, 0, data_len);
676   silc_free(data);
677   silc_buffer_free(buf);
678   return TRUE;
679 }
680
681 /* Saves private key into file. */
682 /* XXX The buffer should be encrypted if passphrase is provided. */
683 /* XXX encoding should be defined (PEM or binary). */
684
685 int silc_pkcs_save_private_key(char *filename, SilcPrivateKey private_key, 
686                                unsigned char *passphrase)
687 {
688   unsigned char *data;
689   unsigned int data_len;
690
691   data = silc_pkcs_private_key_encode(private_key, &data_len);
692   return silc_pkcs_save_private_key_internal(filename, data, data_len);
693 }
694
695 /* Saves private key into file. */
696 /* XXX The buffer should be encrypted if passphrase is provided. */
697 /* XXX encoding should be defined (PEM or binary). */
698
699 int silc_pkcs_save_private_key_data(char *filename, unsigned char *data, 
700                                     unsigned int data_len,
701                                     unsigned char *passphrase)
702 {
703   return silc_pkcs_save_private_key_internal(filename, data, data_len);
704 }
705
706 /* Loads public key from file and allocates new public key. Returns TRUE
707    is loading was successful. */
708 /* XXX Encoding should be defined. */
709
710 int silc_pkcs_load_public_key(char *filename, SilcPublicKey *public_key)
711 {
712   unsigned char *cp, *old, *data, byte;
713   unsigned int i, data_len, len;
714
715   old = data = silc_file_read(filename, &data_len);
716   if (!data)
717     return FALSE;
718
719   /* Check start of file and remove header from the data. */
720   len = strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN);
721   cp = data;
722   for (i = 0; i < len; i++) {
723     byte = cp[0];
724     cp++;
725     if (byte != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i]) {
726       memset(old, 0, data_len);
727       silc_free(old);
728     }
729   }
730   data = cp;
731
732   /* Decode public key */
733   if (public_key) {
734     len = data_len - (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
735                       strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
736     if (!silc_pkcs_public_key_decode(data, len, public_key)) {
737       memset(old, 0, data_len);
738       silc_free(old);
739       return FALSE;
740     }
741   }
742
743   memset(old, 0, data_len);
744   silc_free(old);
745   return TRUE;
746 }
747
748 /* Load private key from file and allocates new private key. Returns TRUE
749    if loading was successful. */
750 /* XXX Encoding should be defined. */
751 /* XXX Should support encrypted private key files */
752
753 int silc_pkcs_load_private_key(char *filename, SilcPrivateKey *private_key)
754 {
755   unsigned char *cp, *old, *data, byte;
756   unsigned int i, data_len, len;
757
758   old = data = silc_file_read(filename, &data_len);
759   if (!data)
760     return FALSE;
761
762   /* Check start of file and remove header from the data. */
763   len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
764   cp = data;
765   for (i = 0; i < len; i++) {
766     byte = cp[0];
767     cp++;
768     if (byte != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i]) {
769       memset(old, 0, data_len);
770       silc_free(old);
771     }
772   }
773   data = cp;
774
775   /* Decode private key */
776   if (private_key) {
777     len = data_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
778                       strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
779     if (!silc_pkcs_private_key_decode(data, len, private_key)) {
780       memset(old, 0, data_len);
781       silc_free(old);
782       return FALSE;
783     }
784   }
785
786   memset(old, 0, data_len);
787   silc_free(old);
788   return TRUE;
789 }