5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 1997 - 2001 Pekka Riikonen
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.
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.
22 #include "silcincludes.h"
28 /* Dynamically registered list of PKCS. */
29 SilcDList silc_pkcs_list = NULL;
30 #define SILC_PKCS_LIST silc_pkcs_list
32 #define SILC_PKCS_LIST TRUE
33 #endif /* SILC_EPOC */
35 /* Static list of PKCS for silc_pkcs_register_default(). */
36 const SilcPKCSObject silc_default_pkcs[] =
38 /* RSA with PKCS #1 (Uses directly routines from Raw RSA operations) */
40 silc_rsa_init, silc_rsa_clear_keys, silc_rsa_get_public_key,
41 silc_rsa_get_private_key, silc_rsa_set_public_key,
42 silc_rsa_set_private_key, silc_rsa_context_len,
43 silc_pkcs1_encrypt, silc_pkcs1_decrypt,
44 silc_pkcs1_sign, silc_pkcs1_verify },
46 /* Raw RSA operations */
48 silc_rsa_init, silc_rsa_clear_keys, silc_rsa_get_public_key,
49 silc_rsa_get_private_key, silc_rsa_set_public_key,
50 silc_rsa_set_private_key, silc_rsa_context_len,
51 silc_rsa_encrypt, silc_rsa_decrypt,
52 silc_rsa_sign, silc_rsa_verify },
54 { NULL, NULL, NULL, NULL, NULL,
55 NULL, NULL, NULL, NULL, NULL, NULL }
58 /* Register a new PKCS into SILC. This is used at the initialization of
61 bool silc_pkcs_register(const SilcPKCSObject *pkcs)
66 SILC_LOG_DEBUG(("Registering new PKCS `%s'", pkcs->name));
68 new = silc_calloc(1, sizeof(*new));
69 new->name = strdup(pkcs->name);
70 new->init = pkcs->init;
71 new->clear_keys = pkcs->clear_keys;
72 new->get_public_key = pkcs->get_public_key;
73 new->get_private_key = pkcs->get_private_key;
74 new->set_public_key = pkcs->set_public_key;
75 new->set_private_key = pkcs->set_private_key;
76 new->context_len = pkcs->context_len;
77 new->encrypt = pkcs->encrypt;
78 new->decrypt = pkcs->decrypt;
79 new->sign = pkcs->sign;
80 new->verify = pkcs->verify;
83 if (silc_pkcs_list == NULL)
84 silc_pkcs_list = silc_dlist_init();
85 silc_dlist_add(silc_pkcs_list, new);
87 #endif /* SILC_EPOC */
91 /* Unregister a PKCS from the SILC. */
93 bool silc_pkcs_unregister(SilcPKCSObject *pkcs)
96 SilcPKCSObject *entry;
98 SILC_LOG_DEBUG(("Unregistering PKCS"));
103 silc_dlist_start(silc_pkcs_list);
104 while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
105 if (pkcs == SILC_ALL_PKCS || entry == pkcs) {
106 silc_dlist_del(silc_pkcs_list, entry);
108 if (silc_dlist_count(silc_pkcs_list) == 0) {
109 silc_dlist_uninit(silc_pkcs_list);
110 silc_pkcs_list = NULL;
117 #endif /* SILC_EPOC */
121 /* Function that registers all the default PKCS (all builtin PKCS).
122 The application may use this to register the default PKCS if specific
123 PKCS in any specific order is not wanted. */
125 bool silc_pkcs_register_default(void)
130 for (i = 0; silc_default_pkcs[i].name; i++)
131 silc_pkcs_register(&(silc_default_pkcs[i]));
133 #endif /* SILC_EPOC */
137 /* Allocates a new SilcPKCS object. The new allocated object is returned
138 to the 'new_pkcs' argument. */
140 bool silc_pkcs_alloc(const unsigned char *name, SilcPKCS *new_pkcs)
142 SilcPKCSObject *entry = NULL;
144 SILC_LOG_DEBUG(("Allocating new PKCS object"));
147 if (silc_pkcs_list) {
148 silc_dlist_start(silc_pkcs_list);
149 while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
150 if (!strcmp(entry->name, name))
156 /* On EPOC which don't have globals we check our constant hash list. */
158 for (i = 0; silc_default_pkcs[i].name; i++) {
159 if (!strcmp(silc_default_pkcs[i].name, name)) {
160 entry = (SilcPKCSObject *)&(silc_default_pkcs[i]);
165 #endif /* SILC_EPOC */
168 *new_pkcs = silc_calloc(1, sizeof(**new_pkcs));
169 (*new_pkcs)->pkcs = entry;
170 (*new_pkcs)->context = silc_calloc(1, entry->context_len());
171 (*new_pkcs)->get_key_len = silc_pkcs_get_key_len;
178 /* Free's the PKCS object */
180 void silc_pkcs_free(SilcPKCS pkcs)
183 pkcs->pkcs->clear_keys(pkcs->context);
184 silc_free(pkcs->context);
189 /* Return TRUE if PKCS algorithm `name' is supported. */
191 int silc_pkcs_is_supported(const unsigned char *name)
194 SilcPKCSObject *entry;
196 if (silc_pkcs_list) {
197 silc_dlist_start(silc_pkcs_list);
198 while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
199 if (!strcmp(entry->name, name))
206 for (i = 0; silc_default_pkcs[i].name; i++)
207 if (!strcmp(silc_default_pkcs[i].name, name))
210 #endif /* SILC_EPOC */
214 /* Returns comma separated list of supported PKCS algorithms */
216 char *silc_pkcs_get_supported(void)
218 SilcPKCSObject *entry;
223 if (silc_pkcs_list) {
224 silc_dlist_start(silc_pkcs_list);
225 while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
226 len += strlen(entry->name);
227 list = silc_realloc(list, len + 1);
229 memcpy(list + (len - strlen(entry->name)),
230 entry->name, strlen(entry->name));
231 memcpy(list + len, ",", 1);
238 for (i = 0; silc_default_pkcs[i].name; i++) {
239 entry = (SilcPKCSObject *)&(silc_default_pkcs[i]);
240 len += strlen(entry->name);
241 list = silc_realloc(list, len + 1);
243 memcpy(list + (len - strlen(entry->name)),
244 entry->name, strlen(entry->name));
245 memcpy(list + len, ",", 1);
249 #endif /* SILC_EPOC */
256 /* Generate new key pair into the `pkcs' context. */
258 int silc_pkcs_generate_key(SilcPKCS pkcs, SilcUInt32 bits_key_len,
261 return pkcs->pkcs->init(pkcs->context, bits_key_len, rng);
264 /* Returns the length of the key */
266 SilcUInt32 silc_pkcs_get_key_len(SilcPKCS pkcs)
268 return pkcs->key_len;
271 /* Returns SILC style public key */
273 unsigned char *silc_pkcs_get_public_key(SilcPKCS pkcs, SilcUInt32 *len)
275 return pkcs->pkcs->get_public_key(pkcs->context, len);
278 /* Returns SILC style private key */
280 unsigned char *silc_pkcs_get_private_key(SilcPKCS pkcs, SilcUInt32 *len)
282 return pkcs->pkcs->get_private_key(pkcs->context, len);
285 /* Sets public key from SilcPublicKey. */
287 SilcUInt32 silc_pkcs_public_key_set(SilcPKCS pkcs, SilcPublicKey public_key)
289 pkcs->key_len = pkcs->pkcs->set_public_key(pkcs->context, public_key->pk,
291 return pkcs->key_len;
294 /* Sets public key from data. */
296 SilcUInt32 silc_pkcs_public_key_data_set(SilcPKCS pkcs, unsigned char *pk,
299 pkcs->key_len = pkcs->pkcs->set_public_key(pkcs->context, pk, pk_len);
300 return pkcs->key_len;
303 /* Sets private key from SilcPrivateKey. */
305 int silc_pkcs_private_key_set(SilcPKCS pkcs, SilcPrivateKey private_key)
307 return pkcs->pkcs->set_private_key(pkcs->context, private_key->prv,
308 private_key->prv_len);
311 /* Sets private key from data. */
313 int silc_pkcs_private_key_data_set(SilcPKCS pkcs, unsigned char *prv,
316 return pkcs->pkcs->set_private_key(pkcs->context, prv, prv_len);
321 int silc_pkcs_encrypt(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len,
322 unsigned char *dst, SilcUInt32 *dst_len)
324 return pkcs->pkcs->encrypt(pkcs->context, src, src_len, dst, dst_len);
329 int silc_pkcs_decrypt(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len,
330 unsigned char *dst, SilcUInt32 *dst_len)
332 return pkcs->pkcs->decrypt(pkcs->context, src, src_len, dst, dst_len);
335 /* Generates signature */
337 int silc_pkcs_sign(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len,
338 unsigned char *dst, SilcUInt32 *dst_len)
340 return pkcs->pkcs->sign(pkcs->context, src, src_len, dst, dst_len);
343 /* Verifies signature */
345 int silc_pkcs_verify(SilcPKCS pkcs, unsigned char *signature,
346 SilcUInt32 signature_len, unsigned char *data,
349 return pkcs->pkcs->verify(pkcs->context, signature, signature_len,
353 /* Generates signature with hash. The hash is signed. */
355 int silc_pkcs_sign_with_hash(SilcPKCS pkcs, SilcHash hash,
356 unsigned char *src, SilcUInt32 src_len,
357 unsigned char *dst, SilcUInt32 *dst_len)
359 unsigned char hashr[32];
363 silc_hash_make(hash, src, src_len, hashr);
364 hash_len = silc_hash_len(hash);
366 SILC_LOG_HEXDUMP(("Hash"), hashr, hash_len);
368 ret = pkcs->pkcs->sign(pkcs->context, hashr, hash_len, dst, dst_len);
369 memset(hashr, 0, sizeof(hashr));
374 /* Verifies signature with hash. The `data' is hashed and verified against
377 int silc_pkcs_verify_with_hash(SilcPKCS pkcs, SilcHash hash,
378 unsigned char *signature,
379 SilcUInt32 signature_len,
383 unsigned char hashr[32];
387 silc_hash_make(hash, data, data_len, hashr);
388 hash_len = silc_hash_len(hash);
390 SILC_LOG_HEXDUMP(("Hash"), hashr, hash_len);
392 ret = pkcs->pkcs->verify(pkcs->context, signature, signature_len,
394 memset(hashr, 0, sizeof(hashr));
399 /* Encodes and returns SILC public key identifier. If some of the
400 arguments is NULL those are not encoded into the identifier string.
401 Protocol says that at least username and host must be provided. */
403 char *silc_pkcs_encode_identifier(char *username, char *host, char *realname,
404 char *email, char *org, char *country)
408 SilcUInt32 len, tlen = 0;
410 if (!username || !host)
413 len = (username ? strlen(username) : 0) +
414 (host ? strlen(host) : 0) +
415 (realname ? strlen(realname) : 0) +
416 (email ? strlen(email) : 0) +
417 (org ? strlen(org) : 0) +
418 (country ? strlen(country) : 0);
423 len += 3 + 5 + 5 + 4 + 4 + 4;
424 buf = silc_buffer_alloc(len);
425 silc_buffer_pull_tail(buf, len);
428 silc_buffer_format(buf,
429 SILC_STR_UI32_STRING("UN="),
430 SILC_STR_UI32_STRING(username),
432 silc_buffer_pull(buf, 3 + strlen(username));
433 tlen = 3 + strlen(username);
437 silc_buffer_format(buf,
438 SILC_STR_UI32_STRING(", "),
439 SILC_STR_UI32_STRING("HN="),
440 SILC_STR_UI32_STRING(host),
442 silc_buffer_pull(buf, 5 + strlen(host));
443 tlen += 5 + strlen(host);
447 silc_buffer_format(buf,
448 SILC_STR_UI32_STRING(", "),
449 SILC_STR_UI32_STRING("RN="),
450 SILC_STR_UI32_STRING(realname),
452 silc_buffer_pull(buf, 5 + strlen(realname));
453 tlen += 5 + strlen(realname);
457 silc_buffer_format(buf,
458 SILC_STR_UI32_STRING(", "),
459 SILC_STR_UI32_STRING("E="),
460 SILC_STR_UI32_STRING(email),
462 silc_buffer_pull(buf, 4 + strlen(email));
463 tlen += 4 + strlen(email);
467 silc_buffer_format(buf,
468 SILC_STR_UI32_STRING(", "),
469 SILC_STR_UI32_STRING("O="),
470 SILC_STR_UI32_STRING(org),
472 silc_buffer_pull(buf, 4 + strlen(org));
473 tlen += 4 + strlen(org);
477 silc_buffer_format(buf,
478 SILC_STR_UI32_STRING(", "),
479 SILC_STR_UI32_STRING("C="),
480 SILC_STR_UI32_STRING(country),
482 silc_buffer_pull(buf, 4 + strlen(country));
483 tlen += 4 + strlen(country);
486 silc_buffer_push(buf, buf->data - buf->head);
487 identifier = silc_calloc(tlen + 1, sizeof(*identifier));
488 memcpy(identifier, buf->data, tlen);
489 silc_buffer_free(buf);
494 /* Decodes the provided `identifier' and returns allocated context for
497 SilcPublicKeyIdentifier silc_pkcs_decode_identifier(char *identifier)
499 SilcPublicKeyIdentifier ident;
503 ident = silc_calloc(1, sizeof(*ident));
507 len = strcspn(cp, ",");
508 if (len - 1 >= 0 && cp[len - 1] == '\\') {
511 len = strcspn(cp, ",") + len;
512 if (len - 1 >= 0 && cp[len - 1] != '\\')
517 item = silc_calloc(len + 1, sizeof(char));
518 memcpy(item, cp, len);
520 if (strstr(item, "UN="))
521 ident->username = strdup(item + strcspn(cp, "=") + 1);
522 else if (strstr(item, "HN="))
523 ident->host = strdup(item + strcspn(cp, "=") + 1);
524 else if (strstr(item, "RN="))
525 ident->realname = strdup(item + strcspn(cp, "=") + 1);
526 else if (strstr(item, "E="))
527 ident->email = strdup(item + strcspn(cp, "=") + 1);
528 else if (strstr(item, "O="))
529 ident->org = strdup(item + strcspn(cp, "=") + 1);
530 else if (strstr(item, "C="))
531 ident->country = strdup(item + strcspn(cp, "=") + 1);
546 /* Free's decoded public key identifier context. Call this to free the
547 context returned by the silc_pkcs_decode_identifier. */
549 void silc_pkcs_free_identifier(SilcPublicKeyIdentifier identifier)
551 silc_free(identifier->username);
552 silc_free(identifier->host);
553 silc_free(identifier->realname);
554 silc_free(identifier->email);
555 silc_free(identifier->org);
556 silc_free(identifier->country);
557 silc_free(identifier);
560 /* Allocates SILC style public key formed from sent arguments. All data
563 SilcPublicKey silc_pkcs_public_key_alloc(char *name, char *identifier,
567 SilcPublicKey public_key;
570 public_key = silc_calloc(1, sizeof(*public_key));
571 public_key->name = strdup(name);
572 public_key->pk_len = pk_len;
573 public_key->pk = silc_calloc(pk_len, sizeof(*public_key->pk));
574 memcpy(public_key->pk, pk, pk_len);
576 if (!silc_utf8_valid(identifier, strlen(identifier))) {
577 int len = silc_utf8_encoded_len(identifier, strlen(identifier), 0);
578 tmp = silc_calloc(len + 1, sizeof(*tmp));
579 silc_utf8_encode(identifier, strlen(identifier), 0, tmp, len);
583 public_key->identifier = strdup(identifier);
584 public_key->len = 4 + 2 + strlen(name) + 2 + strlen(identifier) + pk_len;
590 /* Free's public key */
592 void silc_pkcs_public_key_free(SilcPublicKey public_key)
595 silc_free(public_key->name);
596 silc_free(public_key->identifier);
597 silc_free(public_key->pk);
598 silc_free(public_key);
602 /* Allocates SILC private key formed from sent arguments. All data is
605 SilcPrivateKey silc_pkcs_private_key_alloc(char *name, unsigned char *prv,
608 SilcPrivateKey private_key;
610 private_key = silc_calloc(1, sizeof(*private_key));
611 private_key->name = strdup(name);
612 private_key->prv_len = prv_len;
613 private_key->prv = silc_calloc(prv_len, sizeof(*private_key->prv));
614 memcpy(private_key->prv, prv, prv_len);
619 /* Free's private key */
621 void silc_pkcs_private_key_free(SilcPrivateKey private_key)
624 silc_free(private_key->name);
625 silc_free(private_key->prv);
626 silc_free(private_key);
630 /* Encodes SILC style public key from SilcPublicKey. Returns the encoded
634 silc_pkcs_public_key_encode(SilcPublicKey public_key, SilcUInt32 *len)
639 buf = silc_buffer_alloc(public_key->len);
640 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
642 silc_buffer_format(buf,
643 SILC_STR_UI_INT(public_key->len),
644 SILC_STR_UI_SHORT(strlen(public_key->name)),
645 SILC_STR_UI32_STRING(public_key->name),
646 SILC_STR_UI_SHORT(strlen(public_key->identifier)),
647 SILC_STR_UI32_STRING(public_key->identifier),
648 SILC_STR_UI_XNSTRING(public_key->pk,
652 *len = public_key->len;
654 ret = silc_calloc(buf->len, sizeof(*ret));
655 memcpy(ret, buf->data, buf->len);
656 silc_buffer_free(buf);
661 /* Encodes SILC style public key. Returns the encoded data. */
664 silc_pkcs_public_key_data_encode(unsigned char *pk, SilcUInt32 pk_len,
665 char *pkcs, char *identifier,
672 totlen = 4 + 2 + strlen(pkcs) + 2 + strlen(identifier) + pk_len;
673 buf = silc_buffer_alloc(totlen);
674 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
676 silc_buffer_format(buf,
677 SILC_STR_UI_INT(totlen),
678 SILC_STR_UI_SHORT(strlen(pkcs)),
679 SILC_STR_UI32_STRING(pkcs),
680 SILC_STR_UI_SHORT(strlen(identifier)),
681 SILC_STR_UI32_STRING(identifier),
682 SILC_STR_UI_XNSTRING(pk, pk_len),
687 ret = silc_calloc(buf->len, sizeof(*ret));
688 memcpy(ret, buf->data, buf->len);
689 silc_buffer_free(buf);
694 /* Decodes SILC style public key. Returns TRUE if the decoding was
695 successful. Allocates new public key as well. */
697 int silc_pkcs_public_key_decode(unsigned char *data, SilcUInt32 data_len,
698 SilcPublicKey *public_key)
702 SilcUInt16 pkcs_len, identifier_len;
703 SilcUInt32 totlen, key_len;
704 unsigned char *pkcs_name = NULL, *ident = NULL, *key_data = NULL;
707 buf = silc_buffer_alloc(data_len);
708 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
709 silc_buffer_put(buf, data, data_len);
712 ret = silc_buffer_unformat(buf,
713 SILC_STR_UI_INT(&totlen),
716 silc_buffer_free(buf);
720 if (totlen != data_len) {
721 silc_buffer_free(buf);
725 /* Get algorithm name and identifier */
726 silc_buffer_pull(buf, 4);
728 silc_buffer_unformat(buf,
729 SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
730 SILC_STR_UI16_NSTRING_ALLOC(&ident, &identifier_len),
735 if (pkcs_len < 1 || identifier_len < 3 ||
736 pkcs_len + identifier_len > totlen)
739 /* See if we support this algorithm (check only if PKCS are registered) */
740 if (SILC_PKCS_LIST && !silc_pkcs_is_supported(pkcs_name)) {
741 SILC_LOG_DEBUG(("Unknown PKCS %s", pkcs_name));
745 /* Protocol says that at least UN and HN must be provided as identifier,
747 if (!strstr(ident, "UN=") && !strstr(ident, "HN=")) {
748 SILC_LOG_DEBUG(("The public does not have the required UN= and HN= "
753 /* Get key data. We assume that rest of the buffer is key data. */
754 silc_buffer_pull(buf, 2 + pkcs_len + 2 + identifier_len);
756 ret = silc_buffer_unformat(buf,
757 SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
762 /* Try to set the key. If this fails the key must be malformed. This
763 code assumes that the PKCS routine checks the format of the key.
764 (check only if PKCS are registered) */
765 if (SILC_PKCS_LIST) {
766 silc_pkcs_alloc(pkcs_name, &alg);
767 if (!alg->pkcs->set_public_key(alg->context, key_data, key_len))
773 *public_key = silc_calloc(1, sizeof(**public_key));
774 (*public_key)->len = totlen;
775 (*public_key)->name = pkcs_name;
776 (*public_key)->identifier = ident;
777 (*public_key)->pk = key_data;
778 (*public_key)->pk_len = key_len;
781 silc_buffer_free(buf);
786 silc_free(pkcs_name);
791 silc_buffer_free(buf);
795 /* Compares two public keys and returns TRUE if they are same key, and
796 FALSE if they are not same. */
798 bool silc_pkcs_public_key_compare(SilcPublicKey key1, SilcPublicKey key2)
803 if (key1->len == key2->len &&
804 key1->name && key2->name && key1->identifier && key2->identifier &&
805 !strcmp(key1->name, key2->name) &&
806 !strcmp(key1->identifier, key2->identifier) &&
807 !memcmp(key1->pk, key2->pk, key1->pk_len) &&
808 key1->pk_len == key2->pk_len)
814 /* Copies the public key indicated by `public_key' and returns new allocated
815 public key which is indentical to the `public_key'. */
817 SilcPublicKey silc_pkcs_public_key_copy(SilcPublicKey public_key)
819 SilcPublicKey key = silc_calloc(1, sizeof(*key));
823 key->len = public_key->len;
824 key->name = silc_memdup(public_key->name, strlen(public_key->name));
825 key->identifier = silc_memdup(public_key->identifier,
826 strlen(public_key->identifier));
827 key->pk = silc_memdup(public_key->pk, public_key->pk_len);
828 key->pk_len = public_key->pk_len;
833 /* Encodes SILC private key from SilcPrivateKey. Returns the encoded data. */
836 silc_pkcs_private_key_encode(SilcPrivateKey private_key, SilcUInt32 *len)
842 totlen = 2 + strlen(private_key->name) + private_key->prv_len;
843 buf = silc_buffer_alloc(totlen);
844 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
846 silc_buffer_format(buf,
847 SILC_STR_UI_SHORT(strlen(private_key->name)),
848 SILC_STR_UI32_STRING(private_key->name),
849 SILC_STR_UI_XNSTRING(private_key->prv,
850 private_key->prv_len),
855 ret = silc_calloc(buf->len, sizeof(*ret));
856 memcpy(ret, buf->data, buf->len);
857 silc_buffer_free(buf);
862 /* Encodes SILC private key. Returns the encoded data. */
865 silc_pkcs_private_key_data_encode(unsigned char *prv, SilcUInt32 prv_len,
866 char *pkcs, SilcUInt32 *len)
872 totlen = 2 + strlen(pkcs) + prv_len;
873 buf = silc_buffer_alloc(totlen);
874 silc_buffer_pull_tail(buf, totlen);
876 silc_buffer_format(buf,
877 SILC_STR_UI_SHORT(strlen(pkcs)),
878 SILC_STR_UI32_STRING(pkcs),
879 SILC_STR_UI_XNSTRING(prv, prv_len),
884 ret = silc_calloc(buf->len, sizeof(*ret));
885 memcpy(ret, buf->data, buf->len);
886 silc_buffer_free(buf);
891 /* Decodes SILC style public key. Returns TRUE if the decoding was
892 successful. Allocates new private key as well. */
894 int silc_pkcs_private_key_decode(unsigned char *data, SilcUInt32 data_len,
895 SilcPrivateKey *private_key)
901 unsigned char *pkcs_name = NULL, *key_data = NULL;
904 buf = silc_buffer_alloc(data_len);
905 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
906 silc_buffer_put(buf, data, data_len);
908 /* Get algorithm name and identifier */
910 silc_buffer_unformat(buf,
911 SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
916 if (pkcs_len < 1 || pkcs_len > buf->truelen)
919 /* See if we support this algorithm (check only if PKCS are registered). */
920 if (SILC_PKCS_LIST && !silc_pkcs_is_supported(pkcs_name)) {
921 SILC_LOG_DEBUG(("Unknown PKCS `%s'", pkcs_name));
925 /* Get key data. We assume that rest of the buffer is key data. */
926 silc_buffer_pull(buf, 2 + pkcs_len);
928 ret = silc_buffer_unformat(buf,
929 SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
934 /* Try to set the key. If this fails the key must be malformed. This
935 code assumes that the PKCS routine checks the format of the key.
936 (check only if PKCS are registered) */
937 if (SILC_PKCS_LIST) {
938 silc_pkcs_alloc(pkcs_name, &alg);
939 if (!alg->pkcs->set_private_key(alg->context, key_data, key_len))
945 *private_key = silc_calloc(1, sizeof(**private_key));
946 (*private_key)->name = pkcs_name;
947 (*private_key)->prv = key_data;
948 (*private_key)->prv_len = key_len;
951 silc_buffer_free(buf);
956 silc_free(pkcs_name);
959 silc_buffer_free(buf);
963 /* Internal routine to save public key */
965 static int silc_pkcs_save_public_key_internal(char *filename,
974 case SILC_PKCS_FILE_BIN:
976 case SILC_PKCS_FILE_PEM:
977 data = silc_pem_encode_file(data, data_len);
978 data_len = strlen(data);
982 len = data_len + (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
983 strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
984 buf = silc_buffer_alloc(len);
985 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
987 silc_buffer_format(buf,
988 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
989 SILC_STR_UI_XNSTRING(data, data_len),
990 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END),
994 if (silc_file_writefile(filename, buf->data, buf->len)) {
995 silc_buffer_free(buf);
999 silc_buffer_free(buf);
1003 /* Saves public key into file */
1005 int silc_pkcs_save_public_key(char *filename, SilcPublicKey public_key,
1006 SilcUInt32 encoding)
1008 unsigned char *data;
1009 SilcUInt32 data_len;
1011 data = silc_pkcs_public_key_encode(public_key, &data_len);
1012 return silc_pkcs_save_public_key_internal(filename, data, data_len,
1016 /* Saves public key into file */
1018 int silc_pkcs_save_public_key_data(char *filename, unsigned char *data,
1019 SilcUInt32 data_len,
1020 SilcUInt32 encoding)
1022 return silc_pkcs_save_public_key_internal(filename, data, data_len,
1026 /* Internal routine to save private key. */
1028 static int silc_pkcs_save_private_key_internal(char *filename,
1029 unsigned char *data,
1030 SilcUInt32 data_len,
1031 SilcUInt32 encoding)
1037 case SILC_PKCS_FILE_BIN:
1039 case SILC_PKCS_FILE_PEM:
1040 data = silc_pem_encode_file(data, data_len);
1041 data_len = strlen(data);
1045 len = data_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
1046 strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
1047 buf = silc_buffer_alloc(len);
1048 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1050 silc_buffer_format(buf,
1051 SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
1052 SILC_STR_UI_XNSTRING(data, data_len),
1053 SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
1056 /* Save into a file */
1057 if (silc_file_writefile_mode(filename, buf->data, buf->len, 0600)) {
1058 silc_buffer_free(buf);
1062 silc_buffer_free(buf);
1066 /* Saves private key into file. */
1067 /* XXX The buffer should be encrypted if passphrase is provided. */
1069 int silc_pkcs_save_private_key(char *filename, SilcPrivateKey private_key,
1070 unsigned char *passphrase,
1071 SilcUInt32 encoding)
1073 unsigned char *data;
1074 SilcUInt32 data_len;
1076 data = silc_pkcs_private_key_encode(private_key, &data_len);
1077 return silc_pkcs_save_private_key_internal(filename, data, data_len,
1081 /* Saves private key into file. */
1082 /* XXX The buffer should be encrypted if passphrase is provided. */
1084 int silc_pkcs_save_private_key_data(char *filename, unsigned char *data,
1085 SilcUInt32 data_len,
1086 unsigned char *passphrase,
1087 SilcUInt32 encoding)
1089 return silc_pkcs_save_private_key_internal(filename, data, data_len,
1093 /* Loads public key from file and allocates new public key. Returns TRUE
1094 is loading was successful. */
1096 int silc_pkcs_load_public_key(char *filename, SilcPublicKey *public_key,
1097 SilcUInt32 encoding)
1099 unsigned char *cp, *old, *data, byte;
1100 SilcUInt32 i, data_len, len;
1102 old = data = silc_file_readfile(filename, &data_len);
1106 /* Check start of file and remove header from the data. */
1107 len = strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN);
1109 for (i = 0; i < len; i++) {
1112 if (byte != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i]) {
1113 memset(old, 0, data_len);
1120 /* Decode public key */
1122 len = data_len - (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
1123 strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
1126 case SILC_PKCS_FILE_BIN:
1128 case SILC_PKCS_FILE_PEM:
1129 data = silc_pem_decode(data, len, &len);
1130 memset(old, 0, data_len);
1137 if (!data || !silc_pkcs_public_key_decode(data, len, public_key)) {
1138 memset(old, 0, data_len);
1144 memset(old, 0, data_len);
1149 /* Load private key from file and allocates new private key. Returns TRUE
1150 if loading was successful. */
1151 /* XXX Should support encrypted private key files */
1153 int silc_pkcs_load_private_key(char *filename, SilcPrivateKey *private_key,
1154 SilcUInt32 encoding)
1156 unsigned char *cp, *old, *data, byte;
1157 SilcUInt32 i, data_len, len;
1159 old = data = silc_file_readfile(filename, &data_len);
1163 /* Check start of file and remove header from the data. */
1164 len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
1166 for (i = 0; i < len; i++) {
1169 if (byte != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i]) {
1170 memset(old, 0, data_len);
1177 /* Decode private key */
1179 len = data_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
1180 strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
1183 case SILC_PKCS_FILE_BIN:
1185 case SILC_PKCS_FILE_PEM:
1186 data = silc_pem_decode(data, len, &len);
1190 if (!data || !silc_pkcs_private_key_decode(data, len, private_key)) {
1191 memset(old, 0, data_len);
1197 memset(old, 0, data_len);