f8c9e80905c875c2e046cfa341eea633ae3a3013
[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 - 2001 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 /* $Id$ */
21
22 #include "silcincludes.h"
23
24 #include "rsa.h"
25 #include "pkcs1.h"
26
27 /* List of all PKCS's in SILC. PKCS's don't support SIM's thus
28    only static declarations are possible. XXX: I hope this to change
29    real soon. */
30 SilcPKCSObject silc_pkcs_list[] =
31 {
32   /* RSA with PKCS #1 (Uses directly routines from Raw RSA operations) */
33   { "rsa", &silc_rsa_data_context, 
34     silc_rsa_init, silc_rsa_clear_keys, silc_rsa_get_public_key,
35     silc_rsa_get_private_key, silc_rsa_set_public_key,
36     silc_rsa_set_private_key, silc_rsa_context_len,
37     silc_rsa_data_context_len, silc_rsa_set_arg,
38     silc_pkcs1_encrypt, silc_pkcs1_decrypt,
39     silc_pkcs1_sign, silc_pkcs1_verify },
40
41   /* Raw RSA operations */
42   { "rsa-raw", &silc_rsa_data_context, 
43     silc_rsa_init, silc_rsa_clear_keys, silc_rsa_get_public_key,
44     silc_rsa_get_private_key, silc_rsa_set_public_key,
45     silc_rsa_set_private_key, silc_rsa_context_len,
46     silc_rsa_data_context_len, silc_rsa_set_arg,
47     silc_rsa_encrypt, silc_rsa_decrypt,
48     silc_rsa_sign, silc_rsa_verify },
49
50   { NULL, NULL, NULL, NULL, NULL,
51     NULL, NULL, NULL, NULL, NULL, NULL }
52 };
53
54 /* Allocates a new SilcPKCS object. The new allocated object is returned
55    to the 'new_pkcs' argument. This function also initializes the data
56    context structure. Function returns 1 on success and 0 on error.
57
58 */
59 int silc_pkcs_alloc(const unsigned char *name, SilcPKCS *new_pkcs)
60 {
61   int i;
62
63   SILC_LOG_DEBUG(("Allocating new PKCS object"));
64
65   for (i = 0; silc_pkcs_list[i].name; i++) {
66     if (!strcmp(silc_pkcs_list[i].name, name))
67       break;
68   }
69
70   if (silc_pkcs_list[i].name == NULL)
71     return FALSE;
72
73   *new_pkcs = silc_calloc(1, sizeof(**new_pkcs));
74
75   /* Set the pointers */
76   (*new_pkcs)->pkcs = &silc_pkcs_list[i];
77   (*new_pkcs)->pkcs->data_context = 
78     silc_calloc(1, (*new_pkcs)->pkcs->data_context_len());
79   (*new_pkcs)->context = silc_calloc(1, (*new_pkcs)->pkcs->context_len());
80   (*new_pkcs)->get_key_len = silc_pkcs_get_key_len;
81
82   return TRUE;
83 }
84
85 /* Free's the PKCS object */
86
87 void silc_pkcs_free(SilcPKCS pkcs)
88 {
89   if (pkcs)
90     silc_free(pkcs->context);
91 }
92
93 /* Return TRUE if PKCS algorithm `name' is supported. */
94
95 int silc_pkcs_is_supported(const unsigned char *name)
96 {
97   int i;
98
99   if (!name)
100     return FALSE;
101
102   for (i = 0; silc_pkcs_list[i].name; i++) {
103     if (!strcmp(silc_pkcs_list[i].name, name))
104       return TRUE;
105   }
106
107   return FALSE;
108 }
109
110 /* Returns comma separated list of supported PKCS algorithms */
111
112 char *silc_pkcs_get_supported()
113 {
114   char *list = NULL;
115   int i, len;
116
117   len = 0;
118   for (i = 0; silc_pkcs_list[i].name; i++) {
119     len += strlen(silc_pkcs_list[i].name);
120     list = silc_realloc(list, len + 1);
121
122     memcpy(list + (len - strlen(silc_pkcs_list[i].name)), 
123            silc_pkcs_list[i].name, strlen(silc_pkcs_list[i].name));
124     memcpy(list + len, ",", 1);
125     len++;
126   }
127
128   list[len - 1] = 0;
129
130   return list;
131 }
132
133 /* Returns the length of the key */
134
135 uint32 silc_pkcs_get_key_len(SilcPKCS self)
136 {
137   return self->key_len;
138 }
139
140 /* Returns SILC style public key */
141
142 unsigned char *silc_pkcs_get_public_key(SilcPKCS pkcs, uint32 *len)
143 {
144   return pkcs->pkcs->get_public_key(pkcs->context, len);
145 }
146
147 /* Returns SILC style private key */
148
149 unsigned char *silc_pkcs_get_private_key(SilcPKCS pkcs, uint32 *len)
150 {
151   return pkcs->pkcs->get_private_key(pkcs->context, len);
152 }
153
154 /* Sets public key from SilcPublicKey. */
155
156 uint32 silc_pkcs_public_key_set(SilcPKCS pkcs, SilcPublicKey public_key)
157 {
158   pkcs->key_len = pkcs->pkcs->set_public_key(pkcs->context, public_key->pk, 
159                                              public_key->pk_len);
160   return pkcs->key_len;
161 }
162
163 /* Sets public key from data. */
164
165 uint32 silc_pkcs_public_key_data_set(SilcPKCS pkcs, unsigned char *pk,
166                                      uint32 pk_len)
167 {
168   pkcs->key_len = pkcs->pkcs->set_public_key(pkcs->context, pk, pk_len);
169   return pkcs->key_len;
170 }
171
172 /* Sets private key from SilcPrivateKey. */
173
174 int silc_pkcs_private_key_set(SilcPKCS pkcs, SilcPrivateKey private_key)
175 {
176   return pkcs->pkcs->set_private_key(pkcs->context, private_key->prv, 
177                                      private_key->prv_len);
178 }
179
180 /* Sets private key from data. */
181
182 int silc_pkcs_private_key_data_set(SilcPKCS pkcs, unsigned char *prv,
183                                    uint32 prv_len)
184 {
185   return pkcs->pkcs->set_private_key(pkcs->context, prv, prv_len);
186 }
187
188 /* Encrypts */
189
190 int silc_pkcs_encrypt(SilcPKCS pkcs, unsigned char *src, uint32 src_len,
191                       unsigned char *dst, uint32 *dst_len)
192 {
193   return pkcs->pkcs->encrypt(pkcs->context, src, src_len, dst, dst_len);
194 }
195
196 /* Decrypts */
197
198 int silc_pkcs_decrypt(SilcPKCS pkcs, unsigned char *src, uint32 src_len,
199                       unsigned char *dst, uint32 *dst_len)
200 {
201   return pkcs->pkcs->decrypt(pkcs->context, src, src_len, dst, dst_len);
202 }
203
204 /* Generates signature */
205
206 int silc_pkcs_sign(SilcPKCS pkcs, unsigned char *src, uint32 src_len,
207                    unsigned char *dst, uint32 *dst_len)
208 {
209   return pkcs->pkcs->sign(pkcs->context, src, src_len, dst, dst_len);
210 }
211
212 /* Verifies signature */
213
214 int silc_pkcs_verify(SilcPKCS pkcs, unsigned char *signature, 
215                      uint32 signature_len, unsigned char *data, 
216                      uint32 data_len)
217 {
218   return pkcs->pkcs->verify(pkcs->context, signature, signature_len, 
219                             data, data_len);
220 }
221
222 /* Generates signature with hash. The hash is signed. */
223
224 int silc_pkcs_sign_with_hash(SilcPKCS pkcs, SilcHash hash,
225                              unsigned char *src, uint32 src_len,
226                              unsigned char *dst, uint32 *dst_len)
227 {
228   unsigned char hashr[32];
229   uint32 hash_len;
230   int ret;
231
232   silc_hash_make(hash, src, src_len, hashr);
233   hash_len = hash->hash->hash_len;
234
235   SILC_LOG_HEXDUMP(("Hash"), hashr, hash_len);
236
237   ret = pkcs->pkcs->sign(pkcs->context, hashr, hash_len, dst, dst_len);
238   memset(hashr, 0, sizeof(hashr));
239
240   return ret;
241 }
242
243 /* Verifies signature with hash. The `data' is hashed and verified against
244    the `signature'. */
245
246 int silc_pkcs_verify_with_hash(SilcPKCS pkcs, SilcHash hash, 
247                                unsigned char *signature, 
248                                uint32 signature_len, 
249                                unsigned char *data, 
250                                uint32 data_len)
251 {
252   unsigned char hashr[32];
253   uint32 hash_len;
254   int ret;
255
256   silc_hash_make(hash, data, data_len, hashr);
257   hash_len = hash->hash->hash_len;
258
259   SILC_LOG_HEXDUMP(("Hash"), hashr, hash_len);
260
261   ret = pkcs->pkcs->verify(pkcs->context, signature, signature_len, 
262                            hashr, hash_len);
263   memset(hashr, 0, sizeof(hashr));
264
265   return ret;
266 }
267
268 /* Encodes and returns SILC public key identifier. If some of the 
269    arguments is NULL those are not encoded into the identifier string.
270    Protocol says that at least username and host must be provided. */
271
272 char *silc_pkcs_encode_identifier(char *username, char *host, char *realname,
273                                   char *email, char *org, char *country)
274 {
275   SilcBuffer buf;
276   char *identifier;
277   uint32 len, tlen = 0;
278
279   if (!username || !host)
280     return NULL;
281
282   len = (username ? strlen(username) : 0) +
283         (host     ? strlen(host)     : 0) +
284         (realname ? strlen(realname) : 0) +
285         (email    ? strlen(email)    : 0) +
286         (org      ? strlen(org)      : 0) +
287         (country  ? strlen(country)  : 0);
288   
289   if (len < 3)
290     return NULL;
291
292   len += 3 + 5 + 5 + 4 + 4 + 4;
293   buf = silc_buffer_alloc(len);
294   silc_buffer_pull_tail(buf, len);
295
296   if (username) {
297     silc_buffer_format(buf,
298                        SILC_STR_UI32_STRING("UN="),
299                        SILC_STR_UI32_STRING(username),
300                        SILC_STR_END);
301     silc_buffer_pull(buf, 3 + strlen(username));
302     tlen = 3 + strlen(username); 
303   }
304     
305   if (host) {
306     silc_buffer_format(buf,
307                        SILC_STR_UI32_STRING(", "),
308                        SILC_STR_UI32_STRING("HN="),
309                        SILC_STR_UI32_STRING(host),
310                        SILC_STR_END);
311     silc_buffer_pull(buf, 5 + strlen(host));
312     tlen += 5 + strlen(host); 
313   }
314
315   if (realname) {
316     silc_buffer_format(buf,
317                        SILC_STR_UI32_STRING(", "),
318                        SILC_STR_UI32_STRING("RN="),
319                        SILC_STR_UI32_STRING(realname),
320                        SILC_STR_END);
321     silc_buffer_pull(buf, 5 + strlen(realname));
322     tlen += 5 + strlen(realname); 
323   }
324
325   if (email) {
326     silc_buffer_format(buf,
327                        SILC_STR_UI32_STRING(", "),
328                        SILC_STR_UI32_STRING("E="),
329                        SILC_STR_UI32_STRING(email),
330                        SILC_STR_END);
331     silc_buffer_pull(buf, 4 + strlen(email));
332     tlen += 4 + strlen(email); 
333   }
334
335   if (org) {
336     silc_buffer_format(buf,
337                        SILC_STR_UI32_STRING(", "),
338                        SILC_STR_UI32_STRING("O="),
339                        SILC_STR_UI32_STRING(org),
340                        SILC_STR_END);
341     silc_buffer_pull(buf, 4 + strlen(org));
342     tlen += 4 + strlen(org); 
343   }
344
345   if (country) {
346     silc_buffer_format(buf,
347                        SILC_STR_UI32_STRING(", "),
348                        SILC_STR_UI32_STRING("C="),
349                        SILC_STR_UI32_STRING(country),
350                        SILC_STR_END);
351     silc_buffer_pull(buf, 4 + strlen(country));
352     tlen += 4 + strlen(country); 
353   }
354
355   silc_buffer_push(buf, buf->data - buf->head);
356   identifier = silc_calloc(tlen + 1, sizeof(*identifier));
357   memcpy(identifier, buf->data, tlen);
358   silc_buffer_free(buf);
359
360   return identifier;
361 }
362
363 /* Decodes the provided `identifier' and returns allocated context for
364    the identifier. */
365
366 SilcPublicKeyIdentifier silc_pkcs_decode_identifier(char *identifier)
367 {
368   SilcPublicKeyIdentifier ident;
369   char *cp, *item;
370   int len;
371
372   ident = silc_calloc(1, sizeof(*ident));
373
374   cp = identifier;
375   while (cp) {
376     len = strcspn(cp, ",");
377     item = silc_calloc(len + 1, sizeof(char));
378     memcpy(item, cp, len);
379
380     if (strstr(item, "UN="))
381       ident->username = strdup(item + 3);
382     else if (strstr(item, "HN="))
383       ident->host = strdup(item + 3);
384     else if (strstr(item, "RN="))
385       ident->realname = strdup(item + 3);
386     else if (strstr(item, "E="))
387       ident->email = strdup(item + 2);
388     else if (strstr(item, "O="))
389       ident->org = strdup(item + 2);
390     else if (strstr(item, "C="))
391       ident->country = strdup(item + 2);
392     
393     cp += len;
394     if (strlen(cp) == 0)
395       cp = NULL;
396     else
397       cp += 2;
398     
399     if (item)
400       silc_free(item);
401   }
402
403   return ident;
404 }
405
406 /* Free's decoded public key identifier context. Call this to free the
407    context returned by the silc_pkcs_decode_identifier. */
408
409 void silc_pkcs_free_identifier(SilcPublicKeyIdentifier identifier)
410 {
411   silc_free(identifier->username);
412   silc_free(identifier->host);
413   silc_free(identifier->realname);
414   silc_free(identifier->email);
415   silc_free(identifier->org);
416   silc_free(identifier->country);
417   silc_free(identifier);
418 }
419
420 /* Allocates SILC style public key formed from sent arguments. All data
421    is duplicated. */
422
423 SilcPublicKey silc_pkcs_public_key_alloc(char *name, char *identifier,
424                                          unsigned char *pk, 
425                                          uint32 pk_len)
426 {
427   SilcPublicKey public_key;
428
429   public_key = silc_calloc(1, sizeof(*public_key));
430   public_key->len = 4 + 2 + strlen(name) + 2 + strlen(identifier) + pk_len;
431   public_key->name = strdup(name);
432   public_key->identifier = strdup(identifier);
433   public_key->pk_len = pk_len;
434   public_key->pk = silc_calloc(pk_len, sizeof(*public_key->pk));
435   memcpy(public_key->pk, pk, pk_len);
436
437   return public_key;
438 }
439
440 /* Free's public key */
441
442 void silc_pkcs_public_key_free(SilcPublicKey public_key)
443 {
444   if (public_key) {
445     silc_free(public_key->name);
446     silc_free(public_key->identifier);
447     silc_free(public_key->pk);
448     silc_free(public_key);
449   }
450 }
451
452 /* Allocates SILC private key formed from sent arguments. All data is
453    duplicated. */
454
455 SilcPrivateKey silc_pkcs_private_key_alloc(char *name, unsigned char *prv,
456                                            uint32 prv_len)
457 {
458   SilcPrivateKey private_key;
459
460   private_key = silc_calloc(1, sizeof(*private_key));
461   private_key->name = strdup(name);
462   private_key->prv_len = prv_len;
463   private_key->prv = silc_calloc(prv_len, sizeof(*private_key->prv));
464   memcpy(private_key->prv, prv, prv_len);
465
466   return private_key;
467 }
468
469 /* Free's private key */
470
471 void silc_pkcs_private_key_free(SilcPrivateKey private_key)
472 {
473   if (private_key) {
474     silc_free(private_key->name);
475     silc_free(private_key->prv);
476     silc_free(private_key);
477   }
478 }
479
480 /* Encodes SILC style public key from SilcPublicKey. Returns the encoded
481    data. */
482
483 unsigned char *
484 silc_pkcs_public_key_encode(SilcPublicKey public_key, uint32 *len)
485 {
486   SilcBuffer buf;
487   unsigned char *ret;
488
489   buf = silc_buffer_alloc(public_key->len);
490   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
491
492   silc_buffer_format(buf,
493                      SILC_STR_UI_INT(public_key->len),
494                      SILC_STR_UI_SHORT(strlen(public_key->name)),
495                      SILC_STR_UI32_STRING(public_key->name),
496                      SILC_STR_UI_SHORT(strlen(public_key->identifier)),
497                      SILC_STR_UI32_STRING(public_key->identifier),
498                      SILC_STR_UI_XNSTRING(public_key->pk, 
499                                           public_key->pk_len),
500                      SILC_STR_END);
501   if (len)
502     *len = public_key->len;
503
504   ret = silc_calloc(buf->len, sizeof(*ret));
505   memcpy(ret, buf->data, buf->len);
506   silc_buffer_free(buf);
507
508   return ret;
509 }
510
511 /* Encodes SILC style public key. Returns the encoded data. */
512
513 unsigned char *
514 silc_pkcs_public_key_data_encode(unsigned char *pk, uint32 pk_len,
515                                  char *pkcs, char *identifier, 
516                                  uint32 *len)
517 {
518   SilcBuffer buf;
519   unsigned char *ret;
520   uint32 totlen;
521
522   totlen = 4 + 2 + strlen(pkcs) + 2 + strlen(identifier) + pk_len;
523   buf = silc_buffer_alloc(totlen);
524   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
525
526   silc_buffer_format(buf,
527                      SILC_STR_UI_INT(totlen),
528                      SILC_STR_UI_SHORT(strlen(pkcs)),
529                      SILC_STR_UI32_STRING(pkcs),
530                      SILC_STR_UI_SHORT(strlen(identifier)),
531                      SILC_STR_UI32_STRING(identifier),
532                      SILC_STR_UI_XNSTRING(pk, pk_len),
533                      SILC_STR_END);
534   if (len)
535     *len = totlen;
536
537   ret = silc_calloc(buf->len, sizeof(*ret));
538   memcpy(ret, buf->data, buf->len);
539   silc_buffer_free(buf);
540
541   return ret;
542 }
543
544 /* Decodes SILC style public key. Returns TRUE if the decoding was
545    successful. Allocates new public key as well. */
546
547 int silc_pkcs_public_key_decode(unsigned char *data, uint32 data_len,
548                                 SilcPublicKey *public_key)
549 {
550   SilcBuffer buf;
551   SilcPKCS alg;
552   uint16 pkcs_len, identifier_len;
553   uint32 totlen, key_len;
554   unsigned char *pkcs_name = NULL, *ident = NULL, *key_data = NULL;
555   int ret;
556
557   buf = silc_buffer_alloc(data_len);
558   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
559   silc_buffer_put(buf, data, data_len);
560
561   /* Get length */
562   ret = silc_buffer_unformat(buf,
563                              SILC_STR_UI_INT(&totlen),
564                              SILC_STR_END);
565   if (ret == -1) {
566     silc_buffer_free(buf);
567     return FALSE;
568   }
569
570   if (totlen != data_len) {
571     silc_buffer_free(buf);
572     return FALSE;
573   }
574
575   /* Get algorithm name and identifier */
576   silc_buffer_pull(buf, 4);
577   ret =
578     silc_buffer_unformat(buf,
579                          SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
580                          SILC_STR_UI16_NSTRING_ALLOC(&ident, &identifier_len),
581                          SILC_STR_END);
582   if (ret == -1)
583     goto err;
584
585   if (pkcs_len < 1 || identifier_len < 3 || 
586       pkcs_len + identifier_len > totlen)
587     goto err;
588
589   /* See if we support this algorithm */
590   if (!silc_pkcs_is_supported(pkcs_name)) {
591     SILC_LOG_DEBUG(("Unsupported PKCS %s", pkcs_name));
592     goto err;
593   }
594
595   /* Protocol says that at least UN and HN must be provided as identifier,
596      check for these. */
597   if (!strstr(ident, "UN=") && !strstr(ident, "HN=")) {
598     SILC_LOG_DEBUG(("The public does not have the required UN= and HN= "
599                     "identifiers"));
600     goto err;
601   }
602
603   /* Get key data. We assume that rest of the buffer is key data. */
604   silc_buffer_pull(buf, 2 + pkcs_len + 2 + identifier_len);
605   key_len = buf->len;
606   ret = silc_buffer_unformat(buf,
607                              SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
608                              SILC_STR_END);
609   if (ret == -1)
610     goto err;
611
612   /* Try to set the key. If this fails the key must be malformed. This
613      code assumes that the PKCS routine checks the format of the key. */
614   silc_pkcs_alloc(pkcs_name, &alg);
615   if (!alg->pkcs->set_public_key(alg->context, key_data, key_len))
616     goto err;
617   silc_pkcs_free(alg);
618   
619   if (public_key) {
620     *public_key = silc_calloc(1, sizeof(**public_key));
621     (*public_key)->len = totlen;
622     (*public_key)->name = pkcs_name;
623     (*public_key)->identifier = ident;
624     (*public_key)->pk = key_data;
625     (*public_key)->pk_len = key_len;
626   }
627
628   silc_buffer_free(buf);
629   return TRUE;
630
631  err:
632   if (pkcs_name)
633     silc_free(pkcs_name);
634   if (ident)
635     silc_free(ident);
636   if (key_data)
637     silc_free(key_data);
638   silc_buffer_free(buf);
639   return FALSE;
640 }
641
642 /* Encodes SILC private key from SilcPrivateKey. Returns the encoded data. */
643
644 unsigned char *
645 silc_pkcs_private_key_encode(SilcPrivateKey private_key, uint32 *len)
646 {
647   SilcBuffer buf;
648   unsigned char *ret;
649   uint32 totlen;
650
651   totlen = 2 + strlen(private_key->name) + private_key->prv_len;
652   buf = silc_buffer_alloc(totlen);
653   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
654
655   silc_buffer_format(buf,
656                      SILC_STR_UI_SHORT(strlen(private_key->name)),
657                      SILC_STR_UI32_STRING(private_key->name),
658                      SILC_STR_UI_XNSTRING(private_key->prv, 
659                                           private_key->prv_len),
660                      SILC_STR_END);
661   if (len)
662     *len = totlen;
663
664   ret = silc_calloc(buf->len, sizeof(*ret));
665   memcpy(ret, buf->data, buf->len);
666   silc_buffer_free(buf);
667
668   return ret;
669 }
670
671 /* Encodes SILC private key. Returns the encoded data. */
672
673 unsigned char *
674 silc_pkcs_private_key_data_encode(unsigned char *prv, uint32 prv_len,
675                                   char *pkcs, uint32 *len)
676 {
677   SilcBuffer buf;
678   unsigned char *ret;
679   uint32 totlen;
680
681   totlen = 2 + strlen(pkcs) + prv_len;
682   buf = silc_buffer_alloc(totlen);
683   silc_buffer_pull_tail(buf, totlen);
684
685   silc_buffer_format(buf,
686                      SILC_STR_UI_SHORT(strlen(pkcs)),
687                      SILC_STR_UI32_STRING(pkcs),
688                      SILC_STR_UI_XNSTRING(prv, prv_len),
689                      SILC_STR_END);
690   if (len)
691     *len = totlen;
692
693   ret = silc_calloc(buf->len, sizeof(*ret));
694   memcpy(ret, buf->data, buf->len);
695   silc_buffer_free(buf);
696
697   return ret;
698 }
699
700 /* Decodes SILC style public key. Returns TRUE if the decoding was
701    successful. Allocates new private key as well. */
702
703 int silc_pkcs_private_key_decode(unsigned char *data, uint32 data_len,
704                                  SilcPrivateKey *private_key)
705 {
706   SilcBuffer buf;
707   SilcPKCS alg;
708   uint16 pkcs_len;
709   uint32 key_len;
710   unsigned char *pkcs_name = NULL, *key_data = NULL;
711   int ret;
712
713   buf = silc_buffer_alloc(data_len);
714   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
715   silc_buffer_put(buf, data, data_len);
716
717   /* Get algorithm name and identifier */
718   ret = 
719     silc_buffer_unformat(buf,
720                          SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
721                          SILC_STR_END);
722   if (ret == -1)
723     goto err;
724
725   if (pkcs_len < 1 || pkcs_len > buf->truelen)
726     goto err;
727
728   /* See if we support this algorithm */
729   if (!silc_pkcs_is_supported(pkcs_name))
730     goto err;
731
732   /* Get key data. We assume that rest of the buffer is key data. */
733   silc_buffer_pull(buf, 2 + pkcs_len);
734   key_len = buf->len;
735   ret = silc_buffer_unformat(buf,
736                              SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
737                              SILC_STR_END);
738   if (ret == -1)
739     goto err;
740
741   /* Try to set the key. If this fails the key must be malformed. This
742      code assumes that the PKCS routine checks the format of the key. */
743   silc_pkcs_alloc(pkcs_name, &alg);
744   if (!alg->pkcs->set_private_key(alg->context, key_data, key_len))
745     goto err;
746   silc_pkcs_free(alg);
747   
748   if (private_key) {
749     *private_key = silc_calloc(1, sizeof(**private_key));
750     (*private_key)->name = pkcs_name;
751     (*private_key)->prv = key_data;
752     (*private_key)->prv_len = key_len;
753   }
754
755   silc_buffer_free(buf);
756   return TRUE;
757
758  err:
759   if (pkcs_name)
760     silc_free(pkcs_name);
761   if (key_data)
762     silc_free(key_data);
763   silc_buffer_free(buf);
764   return FALSE;
765 }
766
767 /* Internal routine to save public key */
768
769 static int silc_pkcs_save_public_key_internal(char *filename,
770                                               unsigned char *data,
771                                               uint32 data_len,
772                                               uint32 encoding)
773 {
774   SilcBuffer buf;
775   uint32 len;
776
777   switch(encoding) {
778   case SILC_PKCS_FILE_BIN:
779     break;
780   case SILC_PKCS_FILE_PEM:
781     data = silc_encode_pem_file(data, data_len);
782     data_len = strlen(data);
783     break;
784   }
785
786   len = data_len + (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
787                     strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
788   buf = silc_buffer_alloc(len);
789   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
790
791   silc_buffer_format(buf,
792                      SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
793                      SILC_STR_UI_XNSTRING(data, data_len),
794                      SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END),
795                      SILC_STR_END);
796
797   /* Save into file */
798   if (silc_file_write(filename, buf->data, buf->len)) {
799     silc_buffer_free(buf);
800     return FALSE;
801   }
802
803   silc_buffer_free(buf);
804   return TRUE;
805 }
806
807 /* Saves public key into file */
808
809 int silc_pkcs_save_public_key(char *filename, SilcPublicKey public_key,
810                               uint32 encoding)
811 {
812   unsigned char *data;
813   uint32 data_len;
814
815   data = silc_pkcs_public_key_encode(public_key, &data_len);
816   return silc_pkcs_save_public_key_internal(filename, data, data_len,
817                                             encoding);
818 }
819
820 /* Saves public key into file */
821
822 int silc_pkcs_save_public_key_data(char *filename, unsigned char *data,
823                                    uint32 data_len,
824                                    uint32 encoding)
825 {
826   return silc_pkcs_save_public_key_internal(filename, data, data_len,
827                                             encoding);
828 }
829
830 /* Internal routine to save private key. */
831
832 static int silc_pkcs_save_private_key_internal(char *filename,
833                                                unsigned char *data,
834                                                uint32 data_len,
835                                                uint32 encoding)
836 {
837   SilcBuffer buf;
838   uint32 len;
839
840   switch(encoding) {
841   case SILC_PKCS_FILE_BIN:
842     break;
843   case SILC_PKCS_FILE_PEM:
844     data = silc_encode_pem_file(data, data_len);
845     data_len = strlen(data);
846     break;
847   }
848
849   len = data_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
850                     strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
851   buf = silc_buffer_alloc(len);
852   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
853
854   silc_buffer_format(buf,
855                      SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
856                      SILC_STR_UI_XNSTRING(data, data_len),
857                      SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
858                      SILC_STR_END);
859
860   /* Save into a file */
861   if (silc_file_write_mode(filename, buf->data, buf->len, 0600)) {
862     silc_buffer_free(buf);
863     return FALSE;
864   }
865
866   silc_buffer_free(buf);
867   return TRUE;
868 }
869
870 /* Saves private key into file. */
871 /* XXX The buffer should be encrypted if passphrase is provided. */
872
873 int silc_pkcs_save_private_key(char *filename, SilcPrivateKey private_key, 
874                                unsigned char *passphrase,
875                                uint32 encoding)
876 {
877   unsigned char *data;
878   uint32 data_len;
879
880   data = silc_pkcs_private_key_encode(private_key, &data_len);
881   return silc_pkcs_save_private_key_internal(filename, data, data_len,
882                                              encoding);
883 }
884
885 /* Saves private key into file. */
886 /* XXX The buffer should be encrypted if passphrase is provided. */
887
888 int silc_pkcs_save_private_key_data(char *filename, unsigned char *data, 
889                                     uint32 data_len,
890                                     unsigned char *passphrase,
891                                     uint32 encoding)
892 {
893   return silc_pkcs_save_private_key_internal(filename, data, data_len,
894                                              encoding);
895 }
896
897 /* Loads public key from file and allocates new public key. Returns TRUE
898    is loading was successful. */
899
900 int silc_pkcs_load_public_key(char *filename, SilcPublicKey *public_key,
901                               uint32 encoding)
902 {
903   unsigned char *cp, *old, *data, byte;
904   uint32 i, data_len, len;
905
906   old = data = silc_file_read(filename, &data_len);
907   if (!data)
908     return FALSE;
909
910   /* Check start of file and remove header from the data. */
911   len = strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN);
912   cp = data;
913   for (i = 0; i < len; i++) {
914     byte = cp[0];
915     cp++;
916     if (byte != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i]) {
917       memset(old, 0, data_len);
918       silc_free(old);
919       return FALSE;
920     }
921   }
922   data = cp;
923
924   /* Decode public key */
925   if (public_key) {
926     len = data_len - (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
927                       strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
928
929     switch(encoding) {
930     case SILC_PKCS_FILE_BIN:
931       break;
932     case SILC_PKCS_FILE_PEM:
933       data = silc_decode_pem(data, len, &len);
934       break;
935     }
936
937     if (!data || !silc_pkcs_public_key_decode(data, len, public_key)) {
938       memset(old, 0, data_len);
939       silc_free(old);
940       return FALSE;
941     }
942   }
943
944   memset(old, 0, data_len);
945   silc_free(old);
946   return TRUE;
947 }
948
949 /* Load private key from file and allocates new private key. Returns TRUE
950    if loading was successful. */
951 /* XXX Should support encrypted private key files */
952
953 int silc_pkcs_load_private_key(char *filename, SilcPrivateKey *private_key,
954                                uint32 encoding)
955 {
956   unsigned char *cp, *old, *data, byte;
957   uint32 i, data_len, len;
958
959   old = data = silc_file_read(filename, &data_len);
960   if (!data)
961     return FALSE;
962
963   /* Check start of file and remove header from the data. */
964   len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
965   cp = data;
966   for (i = 0; i < len; i++) {
967     byte = cp[0];
968     cp++;
969     if (byte != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i]) {
970       memset(old, 0, data_len);
971       silc_free(old);
972       return FALSE;
973     }
974   }
975   data = cp;
976
977   /* Decode private key */
978   if (private_key) {
979     len = data_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
980                       strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
981
982     switch(encoding) {
983     case SILC_PKCS_FILE_BIN:
984       break;
985     case SILC_PKCS_FILE_PEM:
986       data = silc_decode_pem(data, len, &len);
987       break;
988     }
989
990     if (!data || !silc_pkcs_private_key_decode(data, len, private_key)) {
991       memset(old, 0, data_len);
992       silc_free(old);
993       return FALSE;
994     }
995   }
996
997   memset(old, 0, data_len);
998   silc_free(old);
999   return TRUE;
1000 }