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"
27 /* Dynamically registered list of PKCS. */
28 SilcDList silc_pkcs_list = NULL;
30 /* Static list of PKCS for silc_pkcs_register_default(). */
31 SilcPKCSObject silc_default_pkcs[] =
33 /* RSA with PKCS #1 (Uses directly routines from Raw RSA operations) */
35 silc_rsa_init, silc_rsa_clear_keys, silc_rsa_get_public_key,
36 silc_rsa_get_private_key, silc_rsa_set_public_key,
37 silc_rsa_set_private_key, silc_rsa_context_len,
38 silc_pkcs1_encrypt, silc_pkcs1_decrypt,
39 silc_pkcs1_sign, silc_pkcs1_verify },
41 /* Raw RSA operations */
43 silc_rsa_init, silc_rsa_clear_keys, silc_rsa_get_public_key,
44 silc_rsa_get_private_key, silc_rsa_set_public_key,
45 silc_rsa_set_private_key, silc_rsa_context_len,
46 silc_rsa_encrypt, silc_rsa_decrypt,
47 silc_rsa_sign, silc_rsa_verify },
49 { NULL, NULL, NULL, NULL, NULL,
50 NULL, NULL, NULL, NULL, NULL, NULL }
53 /* Register a new PKCS into SILC. This is used at the initialization of
56 bool silc_pkcs_register(SilcPKCSObject *pkcs)
60 SILC_LOG_DEBUG(("Registering new PKCS `%s'", pkcs->name));
62 new = silc_calloc(1, sizeof(*new));
63 new->name = strdup(pkcs->name);
64 new->init = pkcs->init;
65 new->clear_keys = pkcs->clear_keys;
66 new->get_public_key = pkcs->get_public_key;
67 new->get_private_key = pkcs->get_private_key;
68 new->set_public_key = pkcs->set_public_key;
69 new->set_private_key = pkcs->set_private_key;
70 new->context_len = pkcs->context_len;
71 new->encrypt = pkcs->encrypt;
72 new->decrypt = pkcs->decrypt;
73 new->sign = pkcs->sign;
74 new->verify = pkcs->verify;
77 if (silc_pkcs_list == NULL)
78 silc_pkcs_list = silc_dlist_init();
79 silc_dlist_add(silc_pkcs_list, new);
84 /* Unregister a PKCS from the SILC. */
86 bool silc_pkcs_unregister(SilcPKCSObject *pkcs)
88 SilcPKCSObject *entry;
90 SILC_LOG_DEBUG(("Unregistering PKCS"));
95 silc_dlist_start(silc_pkcs_list);
96 while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
97 if (pkcs == SILC_ALL_PKCS || entry == pkcs) {
98 silc_dlist_del(silc_pkcs_list, entry);
100 if (silc_dlist_count(silc_pkcs_list) == 0) {
101 silc_dlist_uninit(silc_pkcs_list);
102 silc_pkcs_list = NULL;
112 /* Function that registers all the default PKCS (all builtin PKCS).
113 The application may use this to register the default PKCS if specific
114 PKCS in any specific order is not wanted. */
116 bool silc_pkcs_register_default(void)
120 for (i = 0; silc_default_pkcs[i].name; i++)
121 silc_pkcs_register(&(silc_default_pkcs[i]));
126 /* Allocates a new SilcPKCS object. The new allocated object is returned
127 to the 'new_pkcs' argument. */
129 bool silc_pkcs_alloc(const unsigned char *name, SilcPKCS *new_pkcs)
131 SilcPKCSObject *entry;
133 SILC_LOG_DEBUG(("Allocating new PKCS object"));
135 if (silc_pkcs_list) {
136 silc_dlist_start(silc_pkcs_list);
137 while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
138 if (!strcmp(entry->name, name)) {
139 *new_pkcs = silc_calloc(1, sizeof(**new_pkcs));
140 (*new_pkcs)->pkcs = entry;
141 (*new_pkcs)->context = silc_calloc(1, entry->context_len());
142 (*new_pkcs)->get_key_len = silc_pkcs_get_key_len;
151 /* Free's the PKCS object */
153 void silc_pkcs_free(SilcPKCS pkcs)
156 silc_free(pkcs->context);
160 /* Return TRUE if PKCS algorithm `name' is supported. */
162 int silc_pkcs_is_supported(const unsigned char *name)
164 SilcPKCSObject *entry;
166 if (silc_pkcs_list) {
167 silc_dlist_start(silc_pkcs_list);
168 while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
169 if (!strcmp(entry->name, name))
177 /* Returns comma separated list of supported PKCS algorithms */
179 char *silc_pkcs_get_supported(void)
181 SilcPKCSObject *entry;
186 if (silc_pkcs_list) {
187 silc_dlist_start(silc_pkcs_list);
188 while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
189 len += strlen(entry->name);
190 list = silc_realloc(list, len + 1);
192 memcpy(list + (len - strlen(entry->name)),
193 entry->name, strlen(entry->name));
194 memcpy(list + len, ",", 1);
203 /* Returns the length of the key */
205 uint32 silc_pkcs_get_key_len(SilcPKCS self)
207 return self->key_len;
210 /* Returns SILC style public key */
212 unsigned char *silc_pkcs_get_public_key(SilcPKCS pkcs, uint32 *len)
214 return pkcs->pkcs->get_public_key(pkcs->context, len);
217 /* Returns SILC style private key */
219 unsigned char *silc_pkcs_get_private_key(SilcPKCS pkcs, uint32 *len)
221 return pkcs->pkcs->get_private_key(pkcs->context, len);
224 /* Sets public key from SilcPublicKey. */
226 uint32 silc_pkcs_public_key_set(SilcPKCS pkcs, SilcPublicKey public_key)
228 pkcs->key_len = pkcs->pkcs->set_public_key(pkcs->context, public_key->pk,
230 return pkcs->key_len;
233 /* Sets public key from data. */
235 uint32 silc_pkcs_public_key_data_set(SilcPKCS pkcs, unsigned char *pk,
238 pkcs->key_len = pkcs->pkcs->set_public_key(pkcs->context, pk, pk_len);
239 return pkcs->key_len;
242 /* Sets private key from SilcPrivateKey. */
244 int silc_pkcs_private_key_set(SilcPKCS pkcs, SilcPrivateKey private_key)
246 return pkcs->pkcs->set_private_key(pkcs->context, private_key->prv,
247 private_key->prv_len);
250 /* Sets private key from data. */
252 int silc_pkcs_private_key_data_set(SilcPKCS pkcs, unsigned char *prv,
255 return pkcs->pkcs->set_private_key(pkcs->context, prv, prv_len);
260 int silc_pkcs_encrypt(SilcPKCS pkcs, unsigned char *src, uint32 src_len,
261 unsigned char *dst, uint32 *dst_len)
263 return pkcs->pkcs->encrypt(pkcs->context, src, src_len, dst, dst_len);
268 int silc_pkcs_decrypt(SilcPKCS pkcs, unsigned char *src, uint32 src_len,
269 unsigned char *dst, uint32 *dst_len)
271 return pkcs->pkcs->decrypt(pkcs->context, src, src_len, dst, dst_len);
274 /* Generates signature */
276 int silc_pkcs_sign(SilcPKCS pkcs, unsigned char *src, uint32 src_len,
277 unsigned char *dst, uint32 *dst_len)
279 return pkcs->pkcs->sign(pkcs->context, src, src_len, dst, dst_len);
282 /* Verifies signature */
284 int silc_pkcs_verify(SilcPKCS pkcs, unsigned char *signature,
285 uint32 signature_len, unsigned char *data,
288 return pkcs->pkcs->verify(pkcs->context, signature, signature_len,
292 /* Generates signature with hash. The hash is signed. */
294 int silc_pkcs_sign_with_hash(SilcPKCS pkcs, SilcHash hash,
295 unsigned char *src, uint32 src_len,
296 unsigned char *dst, uint32 *dst_len)
298 unsigned char hashr[32];
302 silc_hash_make(hash, src, src_len, hashr);
303 hash_len = hash->hash->hash_len;
305 SILC_LOG_HEXDUMP(("Hash"), hashr, hash_len);
307 ret = pkcs->pkcs->sign(pkcs->context, hashr, hash_len, dst, dst_len);
308 memset(hashr, 0, sizeof(hashr));
313 /* Verifies signature with hash. The `data' is hashed and verified against
316 int silc_pkcs_verify_with_hash(SilcPKCS pkcs, SilcHash hash,
317 unsigned char *signature,
318 uint32 signature_len,
322 unsigned char hashr[32];
326 silc_hash_make(hash, data, data_len, hashr);
327 hash_len = hash->hash->hash_len;
329 SILC_LOG_HEXDUMP(("Hash"), hashr, hash_len);
331 ret = pkcs->pkcs->verify(pkcs->context, signature, signature_len,
333 memset(hashr, 0, sizeof(hashr));
338 /* Encodes and returns SILC public key identifier. If some of the
339 arguments is NULL those are not encoded into the identifier string.
340 Protocol says that at least username and host must be provided. */
342 char *silc_pkcs_encode_identifier(char *username, char *host, char *realname,
343 char *email, char *org, char *country)
347 uint32 len, tlen = 0;
349 if (!username || !host)
352 len = (username ? strlen(username) : 0) +
353 (host ? strlen(host) : 0) +
354 (realname ? strlen(realname) : 0) +
355 (email ? strlen(email) : 0) +
356 (org ? strlen(org) : 0) +
357 (country ? strlen(country) : 0);
362 len += 3 + 5 + 5 + 4 + 4 + 4;
363 buf = silc_buffer_alloc(len);
364 silc_buffer_pull_tail(buf, len);
367 silc_buffer_format(buf,
368 SILC_STR_UI32_STRING("UN="),
369 SILC_STR_UI32_STRING(username),
371 silc_buffer_pull(buf, 3 + strlen(username));
372 tlen = 3 + strlen(username);
376 silc_buffer_format(buf,
377 SILC_STR_UI32_STRING(", "),
378 SILC_STR_UI32_STRING("HN="),
379 SILC_STR_UI32_STRING(host),
381 silc_buffer_pull(buf, 5 + strlen(host));
382 tlen += 5 + strlen(host);
386 silc_buffer_format(buf,
387 SILC_STR_UI32_STRING(", "),
388 SILC_STR_UI32_STRING("RN="),
389 SILC_STR_UI32_STRING(realname),
391 silc_buffer_pull(buf, 5 + strlen(realname));
392 tlen += 5 + strlen(realname);
396 silc_buffer_format(buf,
397 SILC_STR_UI32_STRING(", "),
398 SILC_STR_UI32_STRING("E="),
399 SILC_STR_UI32_STRING(email),
401 silc_buffer_pull(buf, 4 + strlen(email));
402 tlen += 4 + strlen(email);
406 silc_buffer_format(buf,
407 SILC_STR_UI32_STRING(", "),
408 SILC_STR_UI32_STRING("O="),
409 SILC_STR_UI32_STRING(org),
411 silc_buffer_pull(buf, 4 + strlen(org));
412 tlen += 4 + strlen(org);
416 silc_buffer_format(buf,
417 SILC_STR_UI32_STRING(", "),
418 SILC_STR_UI32_STRING("C="),
419 SILC_STR_UI32_STRING(country),
421 silc_buffer_pull(buf, 4 + strlen(country));
422 tlen += 4 + strlen(country);
425 silc_buffer_push(buf, buf->data - buf->head);
426 identifier = silc_calloc(tlen + 1, sizeof(*identifier));
427 memcpy(identifier, buf->data, tlen);
428 silc_buffer_free(buf);
433 /* Decodes the provided `identifier' and returns allocated context for
436 SilcPublicKeyIdentifier silc_pkcs_decode_identifier(char *identifier)
438 SilcPublicKeyIdentifier ident;
442 ident = silc_calloc(1, sizeof(*ident));
446 len = strcspn(cp, ",");
447 if (len - 1 >= 0 && cp[len - 1] == '\\') {
450 len = strcspn(cp, ",") + len;
451 if (len - 1 >= 0 && cp[len - 1] != '\\')
456 item = silc_calloc(len + 1, sizeof(char));
457 memcpy(item, cp, len);
459 if (strstr(item, "UN="))
460 ident->username = strdup(item + strcspn(cp, "=") + 1);
461 else if (strstr(item, "HN="))
462 ident->host = strdup(item + strcspn(cp, "=") + 1);
463 else if (strstr(item, "RN="))
464 ident->realname = strdup(item + strcspn(cp, "=") + 1);
465 else if (strstr(item, "E="))
466 ident->email = strdup(item + strcspn(cp, "=") + 1);
467 else if (strstr(item, "O="))
468 ident->org = strdup(item + strcspn(cp, "=") + 1);
469 else if (strstr(item, "C="))
470 ident->country = strdup(item + strcspn(cp, "=") + 1);
485 /* Free's decoded public key identifier context. Call this to free the
486 context returned by the silc_pkcs_decode_identifier. */
488 void silc_pkcs_free_identifier(SilcPublicKeyIdentifier identifier)
490 silc_free(identifier->username);
491 silc_free(identifier->host);
492 silc_free(identifier->realname);
493 silc_free(identifier->email);
494 silc_free(identifier->org);
495 silc_free(identifier->country);
496 silc_free(identifier);
499 /* Allocates SILC style public key formed from sent arguments. All data
502 SilcPublicKey silc_pkcs_public_key_alloc(char *name, char *identifier,
506 SilcPublicKey public_key;
508 public_key = silc_calloc(1, sizeof(*public_key));
509 public_key->len = 4 + 2 + strlen(name) + 2 + strlen(identifier) + pk_len;
510 public_key->name = strdup(name);
511 public_key->identifier = strdup(identifier);
512 public_key->pk_len = pk_len;
513 public_key->pk = silc_calloc(pk_len, sizeof(*public_key->pk));
514 memcpy(public_key->pk, pk, pk_len);
519 /* Free's public key */
521 void silc_pkcs_public_key_free(SilcPublicKey public_key)
524 silc_free(public_key->name);
525 silc_free(public_key->identifier);
526 silc_free(public_key->pk);
527 silc_free(public_key);
531 /* Allocates SILC private key formed from sent arguments. All data is
534 SilcPrivateKey silc_pkcs_private_key_alloc(char *name, unsigned char *prv,
537 SilcPrivateKey private_key;
539 private_key = silc_calloc(1, sizeof(*private_key));
540 private_key->name = strdup(name);
541 private_key->prv_len = prv_len;
542 private_key->prv = silc_calloc(prv_len, sizeof(*private_key->prv));
543 memcpy(private_key->prv, prv, prv_len);
548 /* Free's private key */
550 void silc_pkcs_private_key_free(SilcPrivateKey private_key)
553 silc_free(private_key->name);
554 silc_free(private_key->prv);
555 silc_free(private_key);
559 /* Encodes SILC style public key from SilcPublicKey. Returns the encoded
563 silc_pkcs_public_key_encode(SilcPublicKey public_key, uint32 *len)
568 buf = silc_buffer_alloc(public_key->len);
569 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
571 silc_buffer_format(buf,
572 SILC_STR_UI_INT(public_key->len),
573 SILC_STR_UI_SHORT(strlen(public_key->name)),
574 SILC_STR_UI32_STRING(public_key->name),
575 SILC_STR_UI_SHORT(strlen(public_key->identifier)),
576 SILC_STR_UI32_STRING(public_key->identifier),
577 SILC_STR_UI_XNSTRING(public_key->pk,
581 *len = public_key->len;
583 ret = silc_calloc(buf->len, sizeof(*ret));
584 memcpy(ret, buf->data, buf->len);
585 silc_buffer_free(buf);
590 /* Encodes SILC style public key. Returns the encoded data. */
593 silc_pkcs_public_key_data_encode(unsigned char *pk, uint32 pk_len,
594 char *pkcs, char *identifier,
601 totlen = 4 + 2 + strlen(pkcs) + 2 + strlen(identifier) + pk_len;
602 buf = silc_buffer_alloc(totlen);
603 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
605 silc_buffer_format(buf,
606 SILC_STR_UI_INT(totlen),
607 SILC_STR_UI_SHORT(strlen(pkcs)),
608 SILC_STR_UI32_STRING(pkcs),
609 SILC_STR_UI_SHORT(strlen(identifier)),
610 SILC_STR_UI32_STRING(identifier),
611 SILC_STR_UI_XNSTRING(pk, pk_len),
616 ret = silc_calloc(buf->len, sizeof(*ret));
617 memcpy(ret, buf->data, buf->len);
618 silc_buffer_free(buf);
623 /* Decodes SILC style public key. Returns TRUE if the decoding was
624 successful. Allocates new public key as well. */
626 int silc_pkcs_public_key_decode(unsigned char *data, uint32 data_len,
627 SilcPublicKey *public_key)
631 uint16 pkcs_len, identifier_len;
632 uint32 totlen, key_len;
633 unsigned char *pkcs_name = NULL, *ident = NULL, *key_data = NULL;
636 buf = silc_buffer_alloc(data_len);
637 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
638 silc_buffer_put(buf, data, data_len);
641 ret = silc_buffer_unformat(buf,
642 SILC_STR_UI_INT(&totlen),
645 silc_buffer_free(buf);
649 if (totlen != data_len) {
650 silc_buffer_free(buf);
654 /* Get algorithm name and identifier */
655 silc_buffer_pull(buf, 4);
657 silc_buffer_unformat(buf,
658 SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
659 SILC_STR_UI16_NSTRING_ALLOC(&ident, &identifier_len),
664 if (pkcs_len < 1 || identifier_len < 3 ||
665 pkcs_len + identifier_len > totlen)
668 /* See if we support this algorithm (check only if PKCS are registered) */
669 if (silc_pkcs_list && !silc_pkcs_is_supported(pkcs_name)) {
670 SILC_LOG_DEBUG(("Unknown PKCS %s", pkcs_name));
674 /* Protocol says that at least UN and HN must be provided as identifier,
676 if (!strstr(ident, "UN=") && !strstr(ident, "HN=")) {
677 SILC_LOG_DEBUG(("The public does not have the required UN= and HN= "
682 /* Get key data. We assume that rest of the buffer is key data. */
683 silc_buffer_pull(buf, 2 + pkcs_len + 2 + identifier_len);
685 ret = silc_buffer_unformat(buf,
686 SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
691 /* Try to set the key. If this fails the key must be malformed. This
692 code assumes that the PKCS routine checks the format of the key.
693 (check only if PKCS are registered) */
694 if (silc_pkcs_list) {
695 silc_pkcs_alloc(pkcs_name, &alg);
696 if (!alg->pkcs->set_public_key(alg->context, key_data, key_len))
702 *public_key = silc_calloc(1, sizeof(**public_key));
703 (*public_key)->len = totlen;
704 (*public_key)->name = pkcs_name;
705 (*public_key)->identifier = ident;
706 (*public_key)->pk = key_data;
707 (*public_key)->pk_len = key_len;
710 silc_buffer_free(buf);
715 silc_free(pkcs_name);
720 silc_buffer_free(buf);
724 /* Compares two public keys and returns TRUE if they are same key, and
725 FALSE if they are not same. */
727 bool silc_pkcs_public_key_compare(SilcPublicKey key1, SilcPublicKey key2)
732 if (key1->len == key2->len &&
733 key1->name && key2->name && key1->identifier && key2->identifier &&
734 !strcmp(key1->name, key2->name) &&
735 !strcmp(key1->identifier, key2->identifier) &&
736 !memcmp(key1->pk, key2->pk, key1->pk_len) &&
737 key1->pk_len == key2->pk_len)
743 /* Encodes SILC private key from SilcPrivateKey. Returns the encoded data. */
746 silc_pkcs_private_key_encode(SilcPrivateKey private_key, uint32 *len)
752 totlen = 2 + strlen(private_key->name) + private_key->prv_len;
753 buf = silc_buffer_alloc(totlen);
754 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
756 silc_buffer_format(buf,
757 SILC_STR_UI_SHORT(strlen(private_key->name)),
758 SILC_STR_UI32_STRING(private_key->name),
759 SILC_STR_UI_XNSTRING(private_key->prv,
760 private_key->prv_len),
765 ret = silc_calloc(buf->len, sizeof(*ret));
766 memcpy(ret, buf->data, buf->len);
767 silc_buffer_free(buf);
772 /* Encodes SILC private key. Returns the encoded data. */
775 silc_pkcs_private_key_data_encode(unsigned char *prv, uint32 prv_len,
776 char *pkcs, uint32 *len)
782 totlen = 2 + strlen(pkcs) + prv_len;
783 buf = silc_buffer_alloc(totlen);
784 silc_buffer_pull_tail(buf, totlen);
786 silc_buffer_format(buf,
787 SILC_STR_UI_SHORT(strlen(pkcs)),
788 SILC_STR_UI32_STRING(pkcs),
789 SILC_STR_UI_XNSTRING(prv, prv_len),
794 ret = silc_calloc(buf->len, sizeof(*ret));
795 memcpy(ret, buf->data, buf->len);
796 silc_buffer_free(buf);
801 /* Decodes SILC style public key. Returns TRUE if the decoding was
802 successful. Allocates new private key as well. */
804 int silc_pkcs_private_key_decode(unsigned char *data, uint32 data_len,
805 SilcPrivateKey *private_key)
811 unsigned char *pkcs_name = NULL, *key_data = NULL;
814 buf = silc_buffer_alloc(data_len);
815 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
816 silc_buffer_put(buf, data, data_len);
818 /* Get algorithm name and identifier */
820 silc_buffer_unformat(buf,
821 SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
826 if (pkcs_len < 1 || pkcs_len > buf->truelen)
829 /* See if we support this algorithm (check only if PKCS are registered). */
830 if (silc_pkcs_list && !silc_pkcs_is_supported(pkcs_name)) {
831 SILC_LOG_DEBUG(("Unknown PKCS `%s'", pkcs_name));
835 /* Get key data. We assume that rest of the buffer is key data. */
836 silc_buffer_pull(buf, 2 + pkcs_len);
838 ret = silc_buffer_unformat(buf,
839 SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
844 /* Try to set the key. If this fails the key must be malformed. This
845 code assumes that the PKCS routine checks the format of the key.
846 (check only if PKCS are registered) */
847 if (silc_pkcs_list) {
848 silc_pkcs_alloc(pkcs_name, &alg);
849 if (!alg->pkcs->set_private_key(alg->context, key_data, key_len))
855 *private_key = silc_calloc(1, sizeof(**private_key));
856 (*private_key)->name = pkcs_name;
857 (*private_key)->prv = key_data;
858 (*private_key)->prv_len = key_len;
861 silc_buffer_free(buf);
866 silc_free(pkcs_name);
869 silc_buffer_free(buf);
873 /* Internal routine to save public key */
875 static int silc_pkcs_save_public_key_internal(char *filename,
884 case SILC_PKCS_FILE_BIN:
886 case SILC_PKCS_FILE_PEM:
887 data = silc_encode_pem_file(data, data_len);
888 data_len = strlen(data);
892 len = data_len + (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
893 strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
894 buf = silc_buffer_alloc(len);
895 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
897 silc_buffer_format(buf,
898 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
899 SILC_STR_UI_XNSTRING(data, data_len),
900 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END),
904 if (silc_file_writefile(filename, buf->data, buf->len)) {
905 silc_buffer_free(buf);
909 silc_buffer_free(buf);
913 /* Saves public key into file */
915 int silc_pkcs_save_public_key(char *filename, SilcPublicKey public_key,
921 data = silc_pkcs_public_key_encode(public_key, &data_len);
922 return silc_pkcs_save_public_key_internal(filename, data, data_len,
926 /* Saves public key into file */
928 int silc_pkcs_save_public_key_data(char *filename, unsigned char *data,
932 return silc_pkcs_save_public_key_internal(filename, data, data_len,
936 /* Internal routine to save private key. */
938 static int silc_pkcs_save_private_key_internal(char *filename,
947 case SILC_PKCS_FILE_BIN:
949 case SILC_PKCS_FILE_PEM:
950 data = silc_encode_pem_file(data, data_len);
951 data_len = strlen(data);
955 len = data_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
956 strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
957 buf = silc_buffer_alloc(len);
958 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
960 silc_buffer_format(buf,
961 SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
962 SILC_STR_UI_XNSTRING(data, data_len),
963 SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
966 /* Save into a file */
967 if (silc_file_writefile_mode(filename, buf->data, buf->len, 0600)) {
968 silc_buffer_free(buf);
972 silc_buffer_free(buf);
976 /* Saves private key into file. */
977 /* XXX The buffer should be encrypted if passphrase is provided. */
979 int silc_pkcs_save_private_key(char *filename, SilcPrivateKey private_key,
980 unsigned char *passphrase,
986 data = silc_pkcs_private_key_encode(private_key, &data_len);
987 return silc_pkcs_save_private_key_internal(filename, data, data_len,
991 /* Saves private key into file. */
992 /* XXX The buffer should be encrypted if passphrase is provided. */
994 int silc_pkcs_save_private_key_data(char *filename, unsigned char *data,
996 unsigned char *passphrase,
999 return silc_pkcs_save_private_key_internal(filename, data, data_len,
1003 /* Loads public key from file and allocates new public key. Returns TRUE
1004 is loading was successful. */
1006 int silc_pkcs_load_public_key(char *filename, SilcPublicKey *public_key,
1009 unsigned char *cp, *old, *data, byte;
1010 uint32 i, data_len, len;
1012 old = data = silc_file_readfile(filename, &data_len);
1016 /* Check start of file and remove header from the data. */
1017 len = strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN);
1019 for (i = 0; i < len; i++) {
1022 if (byte != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i]) {
1023 memset(old, 0, data_len);
1030 /* Decode public key */
1032 len = data_len - (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
1033 strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
1036 case SILC_PKCS_FILE_BIN:
1038 case SILC_PKCS_FILE_PEM:
1039 data = silc_decode_pem(data, len, &len);
1043 if (!data || !silc_pkcs_public_key_decode(data, len, public_key)) {
1044 memset(old, 0, data_len);
1050 memset(old, 0, data_len);
1055 /* Load private key from file and allocates new private key. Returns TRUE
1056 if loading was successful. */
1057 /* XXX Should support encrypted private key files */
1059 int silc_pkcs_load_private_key(char *filename, SilcPrivateKey *private_key,
1062 unsigned char *cp, *old, *data, byte;
1063 uint32 i, data_len, len;
1065 old = data = silc_file_readfile(filename, &data_len);
1069 /* Check start of file and remove header from the data. */
1070 len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
1072 for (i = 0; i < len; i++) {
1075 if (byte != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i]) {
1076 memset(old, 0, data_len);
1083 /* Decode private key */
1085 len = data_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
1086 strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
1089 case SILC_PKCS_FILE_BIN:
1091 case SILC_PKCS_FILE_PEM:
1092 data = silc_decode_pem(data, len, &len);
1096 if (!data || !silc_pkcs_private_key_decode(data, len, private_key)) {
1097 memset(old, 0, data_len);
1103 memset(old, 0, data_len);