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