Started ROBOdoc documenting. Added silc_pkcs_get_name function.
[silc.git] / lib / silccrypt / silcpkcs.c
1 /*
2
3   silcpkcs.c 
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2002 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; version 2 of the License.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18 */
19 /* $Id$ */
20
21 #include "silcincludes.h"
22
23 #include "rsa.h"
24 #include "pkcs1.h"
25
26 /* The main SILC PKCS structure. */
27 struct SilcPKCSStruct {
28   void *context;
29   SilcPKCSObject *pkcs;
30   SilcUInt32 key_len;
31 };
32
33 #ifndef SILC_EPOC
34 /* Dynamically registered list of PKCS. */
35 SilcDList silc_pkcs_list = NULL;
36 #define SILC_PKCS_LIST silc_pkcs_list
37 #else
38 #define SILC_PKCS_LIST TRUE
39 #endif /* SILC_EPOC */
40
41 /* Static list of PKCS for silc_pkcs_register_default(). */
42 const SilcPKCSObject silc_default_pkcs[] =
43 {
44   /* RSA with PKCS #1 (Uses directly routines from Raw RSA operations) */
45   { "rsa", 
46     silc_rsa_init, silc_rsa_clear_keys, silc_rsa_get_public_key,
47     silc_rsa_get_private_key, silc_rsa_set_public_key,
48     silc_rsa_set_private_key, silc_rsa_context_len,
49     silc_pkcs1_encrypt, silc_pkcs1_decrypt,
50     silc_pkcs1_sign, silc_pkcs1_verify },
51
52   /* Raw RSA operations */
53   { "rsa-raw", 
54     silc_rsa_init, silc_rsa_clear_keys, silc_rsa_get_public_key,
55     silc_rsa_get_private_key, silc_rsa_set_public_key,
56     silc_rsa_set_private_key, silc_rsa_context_len,
57     silc_rsa_encrypt, silc_rsa_decrypt,
58     silc_rsa_sign, silc_rsa_verify },
59
60   { NULL, NULL, NULL, NULL, NULL,
61     NULL, NULL, NULL, NULL, NULL, NULL }
62 };
63
64 /* Register a new PKCS into SILC. This is used at the initialization of
65    the SILC. */
66
67 bool silc_pkcs_register(const SilcPKCSObject *pkcs)
68 {
69 #ifndef SILC_EPOC
70   SilcPKCSObject *new;
71
72   SILC_LOG_DEBUG(("Registering new PKCS `%s'", pkcs->name));
73
74   new = silc_calloc(1, sizeof(*new));
75   new->name = strdup(pkcs->name);
76   new->init = pkcs->init;
77   new->clear_keys = pkcs->clear_keys;
78   new->get_public_key = pkcs->get_public_key;
79   new->get_private_key = pkcs->get_private_key;
80   new->set_public_key = pkcs->set_public_key;
81   new->set_private_key = pkcs->set_private_key;
82   new->context_len = pkcs->context_len;
83   new->encrypt = pkcs->encrypt;
84   new->decrypt = pkcs->decrypt;
85   new->sign = pkcs->sign;
86   new->verify = pkcs->verify;
87
88   /* Add to list */
89   if (silc_pkcs_list == NULL)
90     silc_pkcs_list = silc_dlist_init();
91   silc_dlist_add(silc_pkcs_list, new);
92
93 #endif /* SILC_EPOC */
94   return TRUE;
95 }
96
97 /* Unregister a PKCS from the SILC. */
98
99 bool silc_pkcs_unregister(SilcPKCSObject *pkcs)
100 {
101 #ifndef SILC_EPOC
102   SilcPKCSObject *entry;
103
104   SILC_LOG_DEBUG(("Unregistering PKCS"));
105
106   if (!silc_pkcs_list)
107     return FALSE;
108
109   silc_dlist_start(silc_pkcs_list);
110   while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
111     if (pkcs == SILC_ALL_PKCS || entry == pkcs) {
112       silc_dlist_del(silc_pkcs_list, entry);
113
114       if (silc_dlist_count(silc_pkcs_list) == 0) {
115         silc_dlist_uninit(silc_pkcs_list);
116         silc_pkcs_list = NULL;
117       }
118
119       return TRUE;
120     }
121   }
122
123 #endif /* SILC_EPOC */
124   return FALSE;
125 }
126
127 /* Function that registers all the default PKCS (all builtin PKCS). 
128    The application may use this to register the default PKCS if specific
129    PKCS in any specific order is not wanted. */
130
131 bool silc_pkcs_register_default(void)
132 {
133 #ifndef SILC_EPOC
134   int i;
135
136   for (i = 0; silc_default_pkcs[i].name; i++)
137     silc_pkcs_register(&(silc_default_pkcs[i]));
138
139 #endif /* SILC_EPOC */
140   return TRUE;
141 }
142
143 /* Allocates a new SilcPKCS object. The new allocated object is returned
144    to the 'new_pkcs' argument. */
145
146 bool silc_pkcs_alloc(const unsigned char *name, SilcPKCS *new_pkcs)
147 {
148   SilcPKCSObject *entry = NULL;
149
150   SILC_LOG_DEBUG(("Allocating new PKCS object"));
151
152 #ifndef SILC_EPOC
153   if (silc_pkcs_list) {
154     silc_dlist_start(silc_pkcs_list);
155     while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
156       if (!strcmp(entry->name, name))
157         break;
158     }
159   }
160 #else
161   {
162     /* On EPOC which don't have globals we check our constant hash list. */
163     int i;
164     for (i = 0; silc_default_pkcs[i].name; i++) {
165       if (!strcmp(silc_default_pkcs[i].name, name)) {
166         entry = (SilcPKCSObject *)&(silc_default_pkcs[i]);
167         break;
168       }
169     }
170   }
171 #endif /* SILC_EPOC */
172
173   if (entry) {
174     *new_pkcs = silc_calloc(1, sizeof(**new_pkcs));
175     (*new_pkcs)->pkcs = entry;
176     (*new_pkcs)->context = silc_calloc(1, entry->context_len());
177     return TRUE;
178   }
179
180   return FALSE;
181 }
182
183 /* Free's the PKCS object */
184
185 void silc_pkcs_free(SilcPKCS pkcs)
186 {
187   if (pkcs) {
188     pkcs->pkcs->clear_keys(pkcs->context);
189     silc_free(pkcs->context);
190   }
191   silc_free(pkcs);
192 }
193
194 /* Return TRUE if PKCS algorithm `name' is supported. */
195
196 int silc_pkcs_is_supported(const unsigned char *name)
197 {
198 #ifndef SILC_EPOC
199   SilcPKCSObject *entry;
200
201   if (silc_pkcs_list) {
202     silc_dlist_start(silc_pkcs_list);
203     while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
204       if (!strcmp(entry->name, name))
205         return TRUE;
206     }
207   }
208 #else
209   {
210     int i;
211     for (i = 0; silc_default_pkcs[i].name; i++)
212       if (!strcmp(silc_default_pkcs[i].name, name))
213         return TRUE;
214   }
215 #endif /* SILC_EPOC */
216   return FALSE;
217 }
218
219 /* Returns comma separated list of supported PKCS algorithms */
220
221 char *silc_pkcs_get_supported(void)
222 {
223   SilcPKCSObject *entry;
224   char *list = NULL;
225   int len = 0;
226
227 #ifndef SILC_EPOC
228   if (silc_pkcs_list) {
229     silc_dlist_start(silc_pkcs_list);
230     while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
231       len += strlen(entry->name);
232       list = silc_realloc(list, len + 1);
233       
234       memcpy(list + (len - strlen(entry->name)), 
235              entry->name, strlen(entry->name));
236       memcpy(list + len, ",", 1);
237       len++;
238     }
239   }
240 #else
241   {
242     int i;
243     for (i = 0; silc_default_pkcs[i].name; i++) {
244       entry = (SilcPKCSObject *)&(silc_default_pkcs[i]);
245       len += strlen(entry->name);
246       list = silc_realloc(list, len + 1);
247       
248       memcpy(list + (len - strlen(entry->name)), 
249              entry->name, strlen(entry->name));
250       memcpy(list + len, ",", 1);
251       len++;
252     }
253   }
254 #endif /* SILC_EPOC */
255
256   list[len - 1] = 0;
257
258   return list;
259 }
260
261 /* Generate new key pair into the `pkcs' context. */
262
263 int silc_pkcs_generate_key(SilcPKCS pkcs, SilcUInt32 bits_key_len,
264                            SilcRng rng)
265 {
266   return pkcs->pkcs->init(pkcs->context, bits_key_len, rng);
267 }
268
269 /* Returns the length of the key */
270
271 SilcUInt32 silc_pkcs_get_key_len(SilcPKCS pkcs)
272 {
273   return pkcs->key_len;
274 }
275
276 const char *silc_pkcs_get_name(SilcPKCS pkcs)
277 {
278   return pkcs->pkcs->name;
279 }
280
281 /* Returns SILC style public key */
282
283 unsigned char *silc_pkcs_get_public_key(SilcPKCS pkcs, SilcUInt32 *len)
284 {
285   return pkcs->pkcs->get_public_key(pkcs->context, len);
286 }
287
288 /* Returns SILC style private key */
289
290 unsigned char *silc_pkcs_get_private_key(SilcPKCS pkcs, SilcUInt32 *len)
291 {
292   return pkcs->pkcs->get_private_key(pkcs->context, len);
293 }
294
295 /* Sets public key from SilcPublicKey. */
296
297 SilcUInt32 silc_pkcs_public_key_set(SilcPKCS pkcs, SilcPublicKey public_key)
298 {
299   pkcs->key_len = pkcs->pkcs->set_public_key(pkcs->context, public_key->pk, 
300                                              public_key->pk_len);
301   return pkcs->key_len;
302 }
303
304 /* Sets public key from data. */
305
306 SilcUInt32 silc_pkcs_public_key_data_set(SilcPKCS pkcs, unsigned char *pk,
307                                      SilcUInt32 pk_len)
308 {
309   pkcs->key_len = pkcs->pkcs->set_public_key(pkcs->context, pk, pk_len);
310   return pkcs->key_len;
311 }
312
313 /* Sets private key from SilcPrivateKey. */
314
315 int silc_pkcs_private_key_set(SilcPKCS pkcs, SilcPrivateKey private_key)
316 {
317   return pkcs->pkcs->set_private_key(pkcs->context, private_key->prv, 
318                                      private_key->prv_len);
319 }
320
321 /* Sets private key from data. */
322
323 int silc_pkcs_private_key_data_set(SilcPKCS pkcs, unsigned char *prv,
324                                    SilcUInt32 prv_len)
325 {
326   return pkcs->pkcs->set_private_key(pkcs->context, prv, prv_len);
327 }
328
329 /* Encrypts */
330
331 int silc_pkcs_encrypt(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len,
332                       unsigned char *dst, SilcUInt32 *dst_len)
333 {
334   return pkcs->pkcs->encrypt(pkcs->context, src, src_len, dst, dst_len);
335 }
336
337 /* Decrypts */
338
339 int silc_pkcs_decrypt(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len,
340                       unsigned char *dst, SilcUInt32 *dst_len)
341 {
342   return pkcs->pkcs->decrypt(pkcs->context, src, src_len, dst, dst_len);
343 }
344
345 /* Generates signature */
346
347 int silc_pkcs_sign(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len,
348                    unsigned char *dst, SilcUInt32 *dst_len)
349 {
350   return pkcs->pkcs->sign(pkcs->context, src, src_len, dst, dst_len);
351 }
352
353 /* Verifies signature */
354
355 int silc_pkcs_verify(SilcPKCS pkcs, unsigned char *signature, 
356                      SilcUInt32 signature_len, unsigned char *data, 
357                      SilcUInt32 data_len)
358 {
359   return pkcs->pkcs->verify(pkcs->context, signature, signature_len, 
360                             data, data_len);
361 }
362
363 /* Generates signature with hash. The hash is signed. */
364
365 int silc_pkcs_sign_with_hash(SilcPKCS pkcs, SilcHash hash,
366                              unsigned char *src, SilcUInt32 src_len,
367                              unsigned char *dst, SilcUInt32 *dst_len)
368 {
369   unsigned char hashr[32];
370   SilcUInt32 hash_len;
371   int ret;
372
373   silc_hash_make(hash, src, src_len, hashr);
374   hash_len = silc_hash_len(hash);
375
376   SILC_LOG_HEXDUMP(("Hash"), hashr, hash_len);
377
378   ret = pkcs->pkcs->sign(pkcs->context, hashr, hash_len, dst, dst_len);
379   memset(hashr, 0, sizeof(hashr));
380
381   return ret;
382 }
383
384 /* Verifies signature with hash. The `data' is hashed and verified against
385    the `signature'. */
386
387 int silc_pkcs_verify_with_hash(SilcPKCS pkcs, SilcHash hash, 
388                                unsigned char *signature, 
389                                SilcUInt32 signature_len, 
390                                unsigned char *data, 
391                                SilcUInt32 data_len)
392 {
393   unsigned char hashr[32];
394   SilcUInt32 hash_len;
395   int ret;
396
397   silc_hash_make(hash, data, data_len, hashr);
398   hash_len = silc_hash_len(hash);
399
400   SILC_LOG_HEXDUMP(("Hash"), hashr, hash_len);
401
402   ret = pkcs->pkcs->verify(pkcs->context, signature, signature_len, 
403                            hashr, hash_len);
404   memset(hashr, 0, sizeof(hashr));
405
406   return ret;
407 }
408
409 /* Encodes and returns SILC public key identifier. If some of the 
410    arguments is NULL those are not encoded into the identifier string.
411    Protocol says that at least username and host must be provided. */
412
413 char *silc_pkcs_encode_identifier(char *username, char *host, char *realname,
414                                   char *email, char *org, char *country)
415 {
416   SilcBuffer buf;
417   char *identifier;
418   SilcUInt32 len, tlen = 0;
419
420   if (!username || !host)
421     return NULL;
422
423   len = (username ? strlen(username) : 0) +
424         (host     ? strlen(host)     : 0) +
425         (realname ? strlen(realname) : 0) +
426         (email    ? strlen(email)    : 0) +
427         (org      ? strlen(org)      : 0) +
428         (country  ? strlen(country)  : 0);
429   
430   if (len < 3)
431     return NULL;
432
433   len += 3 + 5 + 5 + 4 + 4 + 4;
434   buf = silc_buffer_alloc(len);
435   silc_buffer_pull_tail(buf, len);
436
437   if (username) {
438     silc_buffer_format(buf,
439                        SILC_STR_UI32_STRING("UN="),
440                        SILC_STR_UI32_STRING(username),
441                        SILC_STR_END);
442     silc_buffer_pull(buf, 3 + strlen(username));
443     tlen = 3 + strlen(username); 
444   }
445     
446   if (host) {
447     silc_buffer_format(buf,
448                        SILC_STR_UI32_STRING(", "),
449                        SILC_STR_UI32_STRING("HN="),
450                        SILC_STR_UI32_STRING(host),
451                        SILC_STR_END);
452     silc_buffer_pull(buf, 5 + strlen(host));
453     tlen += 5 + strlen(host); 
454   }
455
456   if (realname) {
457     silc_buffer_format(buf,
458                        SILC_STR_UI32_STRING(", "),
459                        SILC_STR_UI32_STRING("RN="),
460                        SILC_STR_UI32_STRING(realname),
461                        SILC_STR_END);
462     silc_buffer_pull(buf, 5 + strlen(realname));
463     tlen += 5 + strlen(realname); 
464   }
465
466   if (email) {
467     silc_buffer_format(buf,
468                        SILC_STR_UI32_STRING(", "),
469                        SILC_STR_UI32_STRING("E="),
470                        SILC_STR_UI32_STRING(email),
471                        SILC_STR_END);
472     silc_buffer_pull(buf, 4 + strlen(email));
473     tlen += 4 + strlen(email); 
474   }
475
476   if (org) {
477     silc_buffer_format(buf,
478                        SILC_STR_UI32_STRING(", "),
479                        SILC_STR_UI32_STRING("O="),
480                        SILC_STR_UI32_STRING(org),
481                        SILC_STR_END);
482     silc_buffer_pull(buf, 4 + strlen(org));
483     tlen += 4 + strlen(org); 
484   }
485
486   if (country) {
487     silc_buffer_format(buf,
488                        SILC_STR_UI32_STRING(", "),
489                        SILC_STR_UI32_STRING("C="),
490                        SILC_STR_UI32_STRING(country),
491                        SILC_STR_END);
492     silc_buffer_pull(buf, 4 + strlen(country));
493     tlen += 4 + strlen(country); 
494   }
495
496   silc_buffer_push(buf, buf->data - buf->head);
497   identifier = silc_calloc(tlen + 1, sizeof(*identifier));
498   memcpy(identifier, buf->data, tlen);
499   silc_buffer_free(buf);
500
501   return identifier;
502 }
503
504 /* Decodes the provided `identifier' and returns allocated context for
505    the identifier. */
506
507 SilcPublicKeyIdentifier silc_pkcs_decode_identifier(char *identifier)
508 {
509   SilcPublicKeyIdentifier ident;
510   char *cp, *item;
511   int len;
512
513   ident = silc_calloc(1, sizeof(*ident));
514
515   cp = identifier;
516   while (cp) {
517     len = strcspn(cp, ",");
518     if (len - 1 >= 0 && cp[len - 1] == '\\') {
519       while (cp) {
520         cp += len + 1;
521         len = strcspn(cp, ",") + len;
522         if (len - 1 >= 0 && cp[len - 1] != '\\')
523           break;
524       }
525     }
526
527     item = silc_calloc(len + 1, sizeof(char));
528     memcpy(item, cp, len);
529
530     if (strstr(item, "UN="))
531       ident->username = strdup(item + strcspn(cp, "=") + 1);
532     else if (strstr(item, "HN="))
533       ident->host = strdup(item + strcspn(cp, "=") + 1);
534     else if (strstr(item, "RN="))
535       ident->realname = strdup(item + strcspn(cp, "=") + 1);
536     else if (strstr(item, "E="))
537       ident->email = strdup(item + strcspn(cp, "=") + 1);
538     else if (strstr(item, "O="))
539       ident->org = strdup(item + strcspn(cp, "=") + 1);
540     else if (strstr(item, "C="))
541       ident->country = strdup(item + strcspn(cp, "=") + 1);
542     
543     cp += len;
544     if (strlen(cp) == 0)
545       cp = NULL;
546     else
547       cp += 1;
548     
549     if (item)
550       silc_free(item);
551   }
552
553   return ident;
554 }
555
556 /* Free's decoded public key identifier context. Call this to free the
557    context returned by the silc_pkcs_decode_identifier. */
558
559 void silc_pkcs_free_identifier(SilcPublicKeyIdentifier identifier)
560 {
561   silc_free(identifier->username);
562   silc_free(identifier->host);
563   silc_free(identifier->realname);
564   silc_free(identifier->email);
565   silc_free(identifier->org);
566   silc_free(identifier->country);
567   silc_free(identifier);
568 }
569
570 /* Allocates SILC style public key formed from sent arguments. All data
571    is duplicated. */
572
573 SilcPublicKey silc_pkcs_public_key_alloc(const char *name, 
574                                          const char *identifier,
575                                          const unsigned char *pk, 
576                                          SilcUInt32 pk_len)
577 {
578   SilcPublicKey public_key;
579   char *tmp = NULL;
580
581   public_key = silc_calloc(1, sizeof(*public_key));
582   public_key->name = strdup(name);
583   public_key->pk_len = pk_len;
584   public_key->pk = silc_calloc(pk_len, sizeof(*public_key->pk));
585   memcpy(public_key->pk, pk, pk_len);
586
587   if (!silc_utf8_valid(identifier, strlen(identifier))) {
588     int len = silc_utf8_encoded_len(identifier, strlen(identifier), 0);
589     tmp = silc_calloc(len + 1, sizeof(*tmp));
590     silc_utf8_encode(identifier, strlen(identifier), 0, tmp, len);
591     identifier = tmp;
592   }
593
594   public_key->identifier = strdup(identifier);
595   public_key->len = 4 + 2 + strlen(name) + 2 + strlen(identifier) + pk_len;
596   silc_free(tmp);
597
598   return public_key;
599 }
600
601 /* Free's public key */
602
603 void silc_pkcs_public_key_free(SilcPublicKey public_key)
604 {
605   if (public_key) {
606     silc_free(public_key->name);
607     silc_free(public_key->identifier);
608     silc_free(public_key->pk);
609     silc_free(public_key);
610   }
611 }
612
613 /* Allocates SILC private key formed from sent arguments. All data is
614    duplicated. */
615
616 SilcPrivateKey silc_pkcs_private_key_alloc(const char *name,
617                                            const unsigned char *prv,
618                                            SilcUInt32 prv_len)
619 {
620   SilcPrivateKey private_key;
621
622   private_key = silc_calloc(1, sizeof(*private_key));
623   private_key->name = strdup(name);
624   private_key->prv_len = prv_len;
625   private_key->prv = silc_calloc(prv_len, sizeof(*private_key->prv));
626   memcpy(private_key->prv, prv, prv_len);
627
628   return private_key;
629 }
630
631 /* Free's private key */
632
633 void silc_pkcs_private_key_free(SilcPrivateKey private_key)
634 {
635   if (private_key) {
636     silc_free(private_key->name);
637     silc_free(private_key->prv);
638     silc_free(private_key);
639   }
640 }
641
642 /* Encodes SILC style public key from SilcPublicKey. Returns the encoded
643    data. */
644
645 unsigned char *
646 silc_pkcs_public_key_encode(SilcPublicKey public_key, SilcUInt32 *len)
647 {
648   SilcBuffer buf;
649   unsigned char *ret;
650
651   buf = silc_buffer_alloc(public_key->len);
652   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
653
654   silc_buffer_format(buf,
655                      SILC_STR_UI_INT(public_key->len),
656                      SILC_STR_UI_SHORT(strlen(public_key->name)),
657                      SILC_STR_UI32_STRING(public_key->name),
658                      SILC_STR_UI_SHORT(strlen(public_key->identifier)),
659                      SILC_STR_UI32_STRING(public_key->identifier),
660                      SILC_STR_UI_XNSTRING(public_key->pk, 
661                                           public_key->pk_len),
662                      SILC_STR_END);
663   if (len)
664     *len = public_key->len;
665
666   ret = silc_calloc(buf->len, sizeof(*ret));
667   memcpy(ret, buf->data, buf->len);
668   silc_buffer_free(buf);
669
670   return ret;
671 }
672
673 /* Encodes SILC style public key. Returns the encoded data. */
674
675 unsigned char *
676 silc_pkcs_public_key_data_encode(unsigned char *pk, SilcUInt32 pk_len,
677                                  char *pkcs, char *identifier, 
678                                  SilcUInt32 *len)
679 {
680   SilcBuffer buf;
681   unsigned char *ret;
682   SilcUInt32 totlen;
683
684   totlen = 4 + 2 + strlen(pkcs) + 2 + strlen(identifier) + pk_len;
685   buf = silc_buffer_alloc(totlen);
686   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
687
688   silc_buffer_format(buf,
689                      SILC_STR_UI_INT(totlen),
690                      SILC_STR_UI_SHORT(strlen(pkcs)),
691                      SILC_STR_UI32_STRING(pkcs),
692                      SILC_STR_UI_SHORT(strlen(identifier)),
693                      SILC_STR_UI32_STRING(identifier),
694                      SILC_STR_UI_XNSTRING(pk, pk_len),
695                      SILC_STR_END);
696   if (len)
697     *len = totlen;
698
699   ret = silc_calloc(buf->len, sizeof(*ret));
700   memcpy(ret, buf->data, buf->len);
701   silc_buffer_free(buf);
702
703   return ret;
704 }
705
706 /* Decodes SILC style public key. Returns TRUE if the decoding was
707    successful. Allocates new public key as well. */
708
709 int silc_pkcs_public_key_decode(unsigned char *data, SilcUInt32 data_len,
710                                 SilcPublicKey *public_key)
711 {
712   SilcBuffer buf;
713   SilcPKCS alg;
714   SilcUInt16 pkcs_len, identifier_len;
715   SilcUInt32 totlen, key_len;
716   unsigned char *pkcs_name = NULL, *ident = NULL, *key_data = NULL;
717   int ret;
718
719   buf = silc_buffer_alloc(data_len);
720   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
721   silc_buffer_put(buf, data, data_len);
722
723   /* Get length */
724   ret = silc_buffer_unformat(buf,
725                              SILC_STR_UI_INT(&totlen),
726                              SILC_STR_END);
727   if (ret == -1) {
728     silc_buffer_free(buf);
729     return FALSE;
730   }
731
732   if (totlen != data_len) {
733     silc_buffer_free(buf);
734     return FALSE;
735   }
736
737   /* Get algorithm name and identifier */
738   silc_buffer_pull(buf, 4);
739   ret =
740     silc_buffer_unformat(buf,
741                          SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
742                          SILC_STR_UI16_NSTRING_ALLOC(&ident, &identifier_len),
743                          SILC_STR_END);
744   if (ret == -1)
745     goto err;
746
747   if (pkcs_len < 1 || identifier_len < 3 || 
748       pkcs_len + identifier_len > totlen)
749     goto err;
750
751   /* See if we support this algorithm (check only if PKCS are registered) */
752   if (SILC_PKCS_LIST && !silc_pkcs_is_supported(pkcs_name)) {
753     SILC_LOG_DEBUG(("Unknown PKCS %s", pkcs_name));
754     goto err;
755   }
756
757   /* Protocol says that at least UN and HN must be provided as identifier,
758      check for these. */
759   if (!strstr(ident, "UN=") && !strstr(ident, "HN=")) {
760     SILC_LOG_DEBUG(("The public does not have the required UN= and HN= "
761                     "identifiers"));
762     goto err;
763   }
764
765   /* Get key data. We assume that rest of the buffer is key data. */
766   silc_buffer_pull(buf, 2 + pkcs_len + 2 + identifier_len);
767   key_len = buf->len;
768   ret = silc_buffer_unformat(buf,
769                              SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
770                              SILC_STR_END);
771   if (ret == -1)
772     goto err;
773
774   /* Try to set the key. If this fails the key must be malformed. This
775      code assumes that the PKCS routine checks the format of the key. 
776      (check only if PKCS are registered) */
777   if (SILC_PKCS_LIST) {
778     silc_pkcs_alloc(pkcs_name, &alg);
779     if (!alg->pkcs->set_public_key(alg->context, key_data, key_len))
780       goto err;
781     silc_pkcs_free(alg);
782   }
783   
784   if (public_key) {
785     *public_key = silc_calloc(1, sizeof(**public_key));
786     (*public_key)->len = totlen;
787     (*public_key)->name = pkcs_name;
788     (*public_key)->identifier = ident;
789     (*public_key)->pk = key_data;
790     (*public_key)->pk_len = key_len;
791   }
792
793   silc_buffer_free(buf);
794   return TRUE;
795
796  err:
797   if (pkcs_name)
798     silc_free(pkcs_name);
799   if (ident)
800     silc_free(ident);
801   if (key_data)
802     silc_free(key_data);
803   silc_buffer_free(buf);
804   return FALSE;
805 }
806
807 /* Compares two public keys and returns TRUE if they are same key, and
808    FALSE if they are not same. */
809
810 bool silc_pkcs_public_key_compare(SilcPublicKey key1, SilcPublicKey key2)
811 {
812   if (key1 == key2)
813     return TRUE;
814
815   if (key1->len == key2->len &&
816       key1->name && key2->name && key1->identifier && key2->identifier &&
817       !strcmp(key1->name, key2->name) &&
818       !strcmp(key1->identifier, key2->identifier) &&
819       !memcmp(key1->pk, key2->pk, key1->pk_len) &&
820       key1->pk_len == key2->pk_len)
821     return TRUE;
822
823   return FALSE;
824 }
825
826 /* Copies the public key indicated by `public_key' and returns new allocated
827    public key which is indentical to the `public_key'. */
828
829 SilcPublicKey silc_pkcs_public_key_copy(SilcPublicKey public_key)
830 {
831   SilcPublicKey key = silc_calloc(1, sizeof(*key));
832   if (!key)
833     return NULL;
834
835   key->len = public_key->len;
836   key->name = silc_memdup(public_key->name, strlen(public_key->name));
837   key->identifier = silc_memdup(public_key->identifier,
838                                 strlen(public_key->identifier));
839   key->pk = silc_memdup(public_key->pk, public_key->pk_len);
840   key->pk_len = public_key->pk_len;
841
842   return key;
843 }
844
845 /* Encodes SILC private key from SilcPrivateKey. Returns the encoded data. */
846
847 unsigned char *
848 silc_pkcs_private_key_encode(SilcPrivateKey private_key, SilcUInt32 *len)
849 {
850   SilcBuffer buf;
851   unsigned char *ret;
852   SilcUInt32 totlen;
853
854   totlen = 2 + strlen(private_key->name) + private_key->prv_len;
855   buf = silc_buffer_alloc(totlen);
856   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
857
858   silc_buffer_format(buf,
859                      SILC_STR_UI_SHORT(strlen(private_key->name)),
860                      SILC_STR_UI32_STRING(private_key->name),
861                      SILC_STR_UI_XNSTRING(private_key->prv, 
862                                           private_key->prv_len),
863                      SILC_STR_END);
864   if (len)
865     *len = totlen;
866
867   ret = silc_calloc(buf->len, sizeof(*ret));
868   memcpy(ret, buf->data, buf->len);
869   silc_buffer_free(buf);
870
871   return ret;
872 }
873
874 /* Encodes SILC private key. Returns the encoded data. */
875
876 unsigned char *
877 silc_pkcs_private_key_data_encode(unsigned char *prv, SilcUInt32 prv_len,
878                                   char *pkcs, SilcUInt32 *len)
879 {
880   SilcBuffer buf;
881   unsigned char *ret;
882   SilcUInt32 totlen;
883
884   totlen = 2 + strlen(pkcs) + prv_len;
885   buf = silc_buffer_alloc(totlen);
886   silc_buffer_pull_tail(buf, totlen);
887
888   silc_buffer_format(buf,
889                      SILC_STR_UI_SHORT(strlen(pkcs)),
890                      SILC_STR_UI32_STRING(pkcs),
891                      SILC_STR_UI_XNSTRING(prv, prv_len),
892                      SILC_STR_END);
893   if (len)
894     *len = totlen;
895
896   ret = silc_calloc(buf->len, sizeof(*ret));
897   memcpy(ret, buf->data, buf->len);
898   silc_buffer_free(buf);
899
900   return ret;
901 }
902
903 /* Decodes SILC style public key. Returns TRUE if the decoding was
904    successful. Allocates new private key as well. */
905
906 int silc_pkcs_private_key_decode(unsigned char *data, SilcUInt32 data_len,
907                                  SilcPrivateKey *private_key)
908 {
909   SilcBuffer buf;
910   SilcPKCS alg;
911   SilcUInt16 pkcs_len;
912   SilcUInt32 key_len;
913   unsigned char *pkcs_name = NULL, *key_data = NULL;
914   int ret;
915
916   buf = silc_buffer_alloc(data_len);
917   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
918   silc_buffer_put(buf, data, data_len);
919
920   /* Get algorithm name and identifier */
921   ret = 
922     silc_buffer_unformat(buf,
923                          SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
924                          SILC_STR_END);
925   if (ret == -1)
926     goto err;
927
928   if (pkcs_len < 1 || pkcs_len > buf->truelen)
929     goto err;
930
931   /* See if we support this algorithm (check only if PKCS are registered). */
932   if (SILC_PKCS_LIST && !silc_pkcs_is_supported(pkcs_name)) {
933     SILC_LOG_DEBUG(("Unknown PKCS `%s'", pkcs_name));
934     goto err;
935   }
936
937   /* Get key data. We assume that rest of the buffer is key data. */
938   silc_buffer_pull(buf, 2 + pkcs_len);
939   key_len = buf->len;
940   ret = silc_buffer_unformat(buf,
941                              SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
942                              SILC_STR_END);
943   if (ret == -1)
944     goto err;
945
946   /* Try to set the key. If this fails the key must be malformed. This
947      code assumes that the PKCS routine checks the format of the key. 
948      (check only if PKCS are registered) */
949   if (SILC_PKCS_LIST) {
950     silc_pkcs_alloc(pkcs_name, &alg);
951     if (!alg->pkcs->set_private_key(alg->context, key_data, key_len))
952       goto err;
953     silc_pkcs_free(alg);
954   }
955   
956   if (private_key) {
957     *private_key = silc_calloc(1, sizeof(**private_key));
958     (*private_key)->name = pkcs_name;
959     (*private_key)->prv = key_data;
960     (*private_key)->prv_len = key_len;
961   }
962
963   silc_buffer_free(buf);
964   return TRUE;
965
966  err:
967   if (pkcs_name)
968     silc_free(pkcs_name);
969   if (key_data)
970     silc_free(key_data);
971   silc_buffer_free(buf);
972   return FALSE;
973 }
974
975 /* Internal routine to save public key */
976
977 static int silc_pkcs_save_public_key_internal(char *filename,
978                                               unsigned char *data,
979                                               SilcUInt32 data_len,
980                                               SilcUInt32 encoding)
981 {
982   SilcBuffer buf;
983   SilcUInt32 len;
984
985   switch(encoding) {
986   case SILC_PKCS_FILE_BIN:
987     break;
988   case SILC_PKCS_FILE_PEM:
989     data = silc_pem_encode_file(data, data_len);
990     data_len = strlen(data);
991     break;
992   }
993
994   len = data_len + (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
995                     strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
996   buf = silc_buffer_alloc(len);
997   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
998
999   silc_buffer_format(buf,
1000                      SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
1001                      SILC_STR_UI_XNSTRING(data, data_len),
1002                      SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END),
1003                      SILC_STR_END);
1004
1005   /* Save into file */
1006   if (silc_file_writefile(filename, buf->data, buf->len)) {
1007     silc_buffer_free(buf);
1008     return FALSE;
1009   }
1010
1011   silc_buffer_free(buf);
1012   return TRUE;
1013 }
1014
1015 /* Saves public key into file */
1016
1017 int silc_pkcs_save_public_key(char *filename, SilcPublicKey public_key,
1018                               SilcUInt32 encoding)
1019 {
1020   unsigned char *data;
1021   SilcUInt32 data_len;
1022
1023   data = silc_pkcs_public_key_encode(public_key, &data_len);
1024   return silc_pkcs_save_public_key_internal(filename, data, data_len,
1025                                             encoding);
1026 }
1027
1028 /* Saves public key into file */
1029
1030 int silc_pkcs_save_public_key_data(char *filename, unsigned char *data,
1031                                    SilcUInt32 data_len,
1032                                    SilcUInt32 encoding)
1033 {
1034   return silc_pkcs_save_public_key_internal(filename, data, data_len,
1035                                             encoding);
1036 }
1037
1038 /* Internal routine to save private key. */
1039
1040 static int silc_pkcs_save_private_key_internal(char *filename,
1041                                                unsigned char *data,
1042                                                SilcUInt32 data_len,
1043                                                SilcUInt32 encoding)
1044 {
1045   SilcBuffer buf;
1046   SilcUInt32 len;
1047
1048   switch(encoding) {
1049   case SILC_PKCS_FILE_BIN:
1050     break;
1051   case SILC_PKCS_FILE_PEM:
1052     data = silc_pem_encode_file(data, data_len);
1053     data_len = strlen(data);
1054     break;
1055   }
1056
1057   len = data_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
1058                     strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
1059   buf = silc_buffer_alloc(len);
1060   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1061
1062   silc_buffer_format(buf,
1063                      SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
1064                      SILC_STR_UI_XNSTRING(data, data_len),
1065                      SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
1066                      SILC_STR_END);
1067
1068   /* Save into a file */
1069   if (silc_file_writefile_mode(filename, buf->data, buf->len, 0600)) {
1070     silc_buffer_free(buf);
1071     return FALSE;
1072   }
1073
1074   silc_buffer_free(buf);
1075   return TRUE;
1076 }
1077
1078 /* Saves private key into file. */
1079 /* XXX The buffer should be encrypted if passphrase is provided. */
1080
1081 int silc_pkcs_save_private_key(char *filename, SilcPrivateKey private_key, 
1082                                unsigned char *passphrase,
1083                                SilcUInt32 encoding)
1084 {
1085   unsigned char *data;
1086   SilcUInt32 data_len;
1087
1088   data = silc_pkcs_private_key_encode(private_key, &data_len);
1089   return silc_pkcs_save_private_key_internal(filename, data, data_len,
1090                                              encoding);
1091 }
1092
1093 /* Saves private key into file. */
1094 /* XXX The buffer should be encrypted if passphrase is provided. */
1095
1096 int silc_pkcs_save_private_key_data(char *filename, unsigned char *data, 
1097                                     SilcUInt32 data_len,
1098                                     unsigned char *passphrase,
1099                                     SilcUInt32 encoding)
1100 {
1101   return silc_pkcs_save_private_key_internal(filename, data, data_len,
1102                                              encoding);
1103 }
1104
1105 /* Loads public key from file and allocates new public key. Returns TRUE
1106    is loading was successful. */
1107
1108 int silc_pkcs_load_public_key(char *filename, SilcPublicKey *public_key,
1109                               SilcUInt32 encoding)
1110 {
1111   unsigned char *cp, *old, *data, byte;
1112   SilcUInt32 i, data_len, len;
1113
1114   old = data = silc_file_readfile(filename, &data_len);
1115   if (!data)
1116     return FALSE;
1117
1118   /* Check start of file and remove header from the data. */
1119   len = strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN);
1120   cp = data;
1121   for (i = 0; i < len; i++) {
1122     byte = cp[0];
1123     cp++;
1124     if (byte != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i]) {
1125       memset(old, 0, data_len);
1126       silc_free(old);
1127       return FALSE;
1128     }
1129   }
1130   data = cp;
1131
1132   /* Decode public key */
1133   if (public_key) {
1134     len = data_len - (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
1135                       strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
1136
1137     switch(encoding) {
1138     case SILC_PKCS_FILE_BIN:
1139       break;
1140     case SILC_PKCS_FILE_PEM:
1141       data = silc_pem_decode(data, len, &len);
1142       memset(old, 0, data_len);
1143       silc_free(old);
1144       old = data; 
1145       data_len = len;
1146       break;
1147     }
1148
1149     if (!data || !silc_pkcs_public_key_decode(data, len, public_key)) {
1150       memset(old, 0, data_len);
1151       silc_free(old);
1152       return FALSE;
1153     }
1154   }
1155
1156   memset(old, 0, data_len);
1157   silc_free(old);
1158   return TRUE;
1159 }
1160
1161 /* Load private key from file and allocates new private key. Returns TRUE
1162    if loading was successful. */
1163 /* XXX Should support encrypted private key files */
1164
1165 int silc_pkcs_load_private_key(char *filename, SilcPrivateKey *private_key,
1166                                SilcUInt32 encoding)
1167 {
1168   unsigned char *cp, *old, *data, byte;
1169   SilcUInt32 i, data_len, len;
1170
1171   old = data = silc_file_readfile(filename, &data_len);
1172   if (!data)
1173     return FALSE;
1174
1175   /* Check start of file and remove header from the data. */
1176   len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
1177   cp = data;
1178   for (i = 0; i < len; i++) {
1179     byte = cp[0];
1180     cp++;
1181     if (byte != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i]) {
1182       memset(old, 0, data_len);
1183       silc_free(old);
1184       return FALSE;
1185     }
1186   }
1187   data = cp;
1188
1189   /* Decode private key */
1190   if (private_key) {
1191     len = data_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
1192                       strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
1193
1194     switch(encoding) {
1195     case SILC_PKCS_FILE_BIN:
1196       break;
1197     case SILC_PKCS_FILE_PEM:
1198       data = silc_pem_decode(data, len, &len);
1199       break;
1200     }
1201
1202     if (!data || !silc_pkcs_private_key_decode(data, len, private_key)) {
1203       memset(old, 0, data_len);
1204       silc_free(old);
1205       return FALSE;
1206     }
1207   }
1208
1209   memset(old, 0, data_len);
1210   silc_free(old);
1211   return TRUE;
1212 }