5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2002 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; version 2 of the License.
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.
21 #include "silcincludes.h"
26 /* The main SILC PKCS structure. */
27 struct SilcPKCSStruct {
34 /* Dynamically registered list of PKCS. */
35 SilcDList silc_pkcs_list = NULL;
36 #define SILC_PKCS_LIST silc_pkcs_list
38 #define SILC_PKCS_LIST TRUE
39 #endif /* SILC_EPOC */
41 /* Static list of PKCS for silc_pkcs_register_default(). */
42 const SilcPKCSObject silc_default_pkcs[] =
44 /* RSA with PKCS #1 (Uses directly routines from Raw RSA operations) */
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 },
52 /* Raw RSA operations */
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 },
60 { NULL, NULL, NULL, NULL, NULL,
61 NULL, NULL, NULL, NULL, NULL, NULL }
64 /* Register a new PKCS into SILC. This is used at the initialization of
67 bool silc_pkcs_register(const SilcPKCSObject *pkcs)
72 SILC_LOG_DEBUG(("Registering new PKCS `%s'", pkcs->name));
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;
89 if (silc_pkcs_list == NULL)
90 silc_pkcs_list = silc_dlist_init();
91 silc_dlist_add(silc_pkcs_list, new);
93 #endif /* SILC_EPOC */
97 /* Unregister a PKCS from the SILC. */
99 bool silc_pkcs_unregister(SilcPKCSObject *pkcs)
102 SilcPKCSObject *entry;
104 SILC_LOG_DEBUG(("Unregistering PKCS"));
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);
114 if (silc_dlist_count(silc_pkcs_list) == 0) {
115 silc_dlist_uninit(silc_pkcs_list);
116 silc_pkcs_list = NULL;
123 #endif /* SILC_EPOC */
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. */
131 bool silc_pkcs_register_default(void)
136 for (i = 0; silc_default_pkcs[i].name; i++)
137 silc_pkcs_register(&(silc_default_pkcs[i]));
139 #endif /* SILC_EPOC */
143 /* Allocates a new SilcPKCS object. The new allocated object is returned
144 to the 'new_pkcs' argument. */
146 bool silc_pkcs_alloc(const unsigned char *name, SilcPKCS *new_pkcs)
148 SilcPKCSObject *entry = NULL;
150 SILC_LOG_DEBUG(("Allocating new PKCS object"));
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))
162 /* On EPOC which don't have globals we check our constant hash list. */
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]);
171 #endif /* SILC_EPOC */
174 *new_pkcs = silc_calloc(1, sizeof(**new_pkcs));
175 (*new_pkcs)->pkcs = entry;
176 (*new_pkcs)->context = silc_calloc(1, entry->context_len());
183 /* Free's the PKCS object */
185 void silc_pkcs_free(SilcPKCS pkcs)
188 pkcs->pkcs->clear_keys(pkcs->context);
189 silc_free(pkcs->context);
194 /* Return TRUE if PKCS algorithm `name' is supported. */
196 int silc_pkcs_is_supported(const unsigned char *name)
199 SilcPKCSObject *entry;
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))
211 for (i = 0; silc_default_pkcs[i].name; i++)
212 if (!strcmp(silc_default_pkcs[i].name, name))
215 #endif /* SILC_EPOC */
219 /* Returns comma separated list of supported PKCS algorithms */
221 char *silc_pkcs_get_supported(void)
223 SilcPKCSObject *entry;
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);
234 memcpy(list + (len - strlen(entry->name)),
235 entry->name, strlen(entry->name));
236 memcpy(list + len, ",", 1);
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);
248 memcpy(list + (len - strlen(entry->name)),
249 entry->name, strlen(entry->name));
250 memcpy(list + len, ",", 1);
254 #endif /* SILC_EPOC */
261 /* Generate new key pair into the `pkcs' context. */
263 int silc_pkcs_generate_key(SilcPKCS pkcs, SilcUInt32 bits_key_len,
266 return pkcs->pkcs->init(pkcs->context, bits_key_len, rng);
269 /* Returns the length of the key */
271 SilcUInt32 silc_pkcs_get_key_len(SilcPKCS pkcs)
273 return pkcs->key_len;
276 const char *silc_pkcs_get_name(SilcPKCS pkcs)
278 return pkcs->pkcs->name;
281 /* Returns SILC style public key */
283 unsigned char *silc_pkcs_get_public_key(SilcPKCS pkcs, SilcUInt32 *len)
285 return pkcs->pkcs->get_public_key(pkcs->context, len);
288 /* Returns SILC style private key */
290 unsigned char *silc_pkcs_get_private_key(SilcPKCS pkcs, SilcUInt32 *len)
292 return pkcs->pkcs->get_private_key(pkcs->context, len);
295 /* Sets public key from SilcPublicKey. */
297 SilcUInt32 silc_pkcs_public_key_set(SilcPKCS pkcs, SilcPublicKey public_key)
299 pkcs->key_len = pkcs->pkcs->set_public_key(pkcs->context, public_key->pk,
301 return pkcs->key_len;
304 /* Sets public key from data. */
306 SilcUInt32 silc_pkcs_public_key_data_set(SilcPKCS pkcs, unsigned char *pk,
309 pkcs->key_len = pkcs->pkcs->set_public_key(pkcs->context, pk, pk_len);
310 return pkcs->key_len;
313 /* Sets private key from SilcPrivateKey. */
315 int silc_pkcs_private_key_set(SilcPKCS pkcs, SilcPrivateKey private_key)
317 return pkcs->pkcs->set_private_key(pkcs->context, private_key->prv,
318 private_key->prv_len);
321 /* Sets private key from data. */
323 int silc_pkcs_private_key_data_set(SilcPKCS pkcs, unsigned char *prv,
326 return pkcs->pkcs->set_private_key(pkcs->context, prv, prv_len);
331 int silc_pkcs_encrypt(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len,
332 unsigned char *dst, SilcUInt32 *dst_len)
334 return pkcs->pkcs->encrypt(pkcs->context, src, src_len, dst, dst_len);
339 int silc_pkcs_decrypt(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len,
340 unsigned char *dst, SilcUInt32 *dst_len)
342 return pkcs->pkcs->decrypt(pkcs->context, src, src_len, dst, dst_len);
345 /* Generates signature */
347 int silc_pkcs_sign(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len,
348 unsigned char *dst, SilcUInt32 *dst_len)
350 return pkcs->pkcs->sign(pkcs->context, src, src_len, dst, dst_len);
353 /* Verifies signature */
355 int silc_pkcs_verify(SilcPKCS pkcs, unsigned char *signature,
356 SilcUInt32 signature_len, unsigned char *data,
359 return pkcs->pkcs->verify(pkcs->context, signature, signature_len,
363 /* Generates signature with hash. The hash is signed. */
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)
369 unsigned char hashr[32];
373 silc_hash_make(hash, src, src_len, hashr);
374 hash_len = silc_hash_len(hash);
376 SILC_LOG_HEXDUMP(("Hash"), hashr, hash_len);
378 ret = pkcs->pkcs->sign(pkcs->context, hashr, hash_len, dst, dst_len);
379 memset(hashr, 0, sizeof(hashr));
384 /* Verifies signature with hash. The `data' is hashed and verified against
387 int silc_pkcs_verify_with_hash(SilcPKCS pkcs, SilcHash hash,
388 unsigned char *signature,
389 SilcUInt32 signature_len,
393 unsigned char hashr[32];
397 silc_hash_make(hash, data, data_len, hashr);
398 hash_len = silc_hash_len(hash);
400 SILC_LOG_HEXDUMP(("Hash"), hashr, hash_len);
402 ret = pkcs->pkcs->verify(pkcs->context, signature, signature_len,
404 memset(hashr, 0, sizeof(hashr));
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. */
413 char *silc_pkcs_encode_identifier(char *username, char *host, char *realname,
414 char *email, char *org, char *country)
418 SilcUInt32 len, tlen = 0;
420 if (!username || !host)
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);
433 len += 3 + 5 + 5 + 4 + 4 + 4;
434 buf = silc_buffer_alloc(len);
435 silc_buffer_pull_tail(buf, len);
438 silc_buffer_format(buf,
439 SILC_STR_UI32_STRING("UN="),
440 SILC_STR_UI32_STRING(username),
442 silc_buffer_pull(buf, 3 + strlen(username));
443 tlen = 3 + strlen(username);
447 silc_buffer_format(buf,
448 SILC_STR_UI32_STRING(", "),
449 SILC_STR_UI32_STRING("HN="),
450 SILC_STR_UI32_STRING(host),
452 silc_buffer_pull(buf, 5 + strlen(host));
453 tlen += 5 + strlen(host);
457 silc_buffer_format(buf,
458 SILC_STR_UI32_STRING(", "),
459 SILC_STR_UI32_STRING("RN="),
460 SILC_STR_UI32_STRING(realname),
462 silc_buffer_pull(buf, 5 + strlen(realname));
463 tlen += 5 + strlen(realname);
467 silc_buffer_format(buf,
468 SILC_STR_UI32_STRING(", "),
469 SILC_STR_UI32_STRING("E="),
470 SILC_STR_UI32_STRING(email),
472 silc_buffer_pull(buf, 4 + strlen(email));
473 tlen += 4 + strlen(email);
477 silc_buffer_format(buf,
478 SILC_STR_UI32_STRING(", "),
479 SILC_STR_UI32_STRING("O="),
480 SILC_STR_UI32_STRING(org),
482 silc_buffer_pull(buf, 4 + strlen(org));
483 tlen += 4 + strlen(org);
487 silc_buffer_format(buf,
488 SILC_STR_UI32_STRING(", "),
489 SILC_STR_UI32_STRING("C="),
490 SILC_STR_UI32_STRING(country),
492 silc_buffer_pull(buf, 4 + strlen(country));
493 tlen += 4 + strlen(country);
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);
504 /* Decodes the provided `identifier' and returns allocated context for
507 SilcPublicKeyIdentifier silc_pkcs_decode_identifier(char *identifier)
509 SilcPublicKeyIdentifier ident;
513 ident = silc_calloc(1, sizeof(*ident));
517 len = strcspn(cp, ",");
518 if (len - 1 >= 0 && cp[len - 1] == '\\') {
521 len = strcspn(cp, ",") + len;
522 if (len - 1 >= 0 && cp[len - 1] != '\\')
527 item = silc_calloc(len + 1, sizeof(char));
528 memcpy(item, cp, len);
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);
556 /* Free's decoded public key identifier context. Call this to free the
557 context returned by the silc_pkcs_decode_identifier. */
559 void silc_pkcs_free_identifier(SilcPublicKeyIdentifier identifier)
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);
570 /* Allocates SILC style public key formed from sent arguments. All data
573 SilcPublicKey silc_pkcs_public_key_alloc(const char *name,
574 const char *identifier,
575 const unsigned char *pk,
578 SilcPublicKey public_key;
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);
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);
594 public_key->identifier = strdup(identifier);
595 public_key->len = 4 + 2 + strlen(name) + 2 + strlen(identifier) + pk_len;
601 /* Free's public key */
603 void silc_pkcs_public_key_free(SilcPublicKey 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);
613 /* Allocates SILC private key formed from sent arguments. All data is
616 SilcPrivateKey silc_pkcs_private_key_alloc(const char *name,
617 const unsigned char *prv,
620 SilcPrivateKey private_key;
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);
631 /* Free's private key */
633 void silc_pkcs_private_key_free(SilcPrivateKey private_key)
636 silc_free(private_key->name);
637 silc_free(private_key->prv);
638 silc_free(private_key);
642 /* Encodes SILC style public key from SilcPublicKey. Returns the encoded
646 silc_pkcs_public_key_encode(SilcPublicKey public_key, SilcUInt32 *len)
651 buf = silc_buffer_alloc(public_key->len);
652 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
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,
664 *len = public_key->len;
666 ret = silc_calloc(buf->len, sizeof(*ret));
667 memcpy(ret, buf->data, buf->len);
668 silc_buffer_free(buf);
673 /* Encodes SILC style public key. Returns the encoded data. */
676 silc_pkcs_public_key_data_encode(unsigned char *pk, SilcUInt32 pk_len,
677 char *pkcs, char *identifier,
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));
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),
699 ret = silc_calloc(buf->len, sizeof(*ret));
700 memcpy(ret, buf->data, buf->len);
701 silc_buffer_free(buf);
706 /* Decodes SILC style public key. Returns TRUE if the decoding was
707 successful. Allocates new public key as well. */
709 int silc_pkcs_public_key_decode(unsigned char *data, SilcUInt32 data_len,
710 SilcPublicKey *public_key)
714 SilcUInt16 pkcs_len, identifier_len;
715 SilcUInt32 totlen, key_len;
716 unsigned char *pkcs_name = NULL, *ident = NULL, *key_data = NULL;
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);
724 ret = silc_buffer_unformat(buf,
725 SILC_STR_UI_INT(&totlen),
728 silc_buffer_free(buf);
732 if (totlen != data_len) {
733 silc_buffer_free(buf);
737 /* Get algorithm name and identifier */
738 silc_buffer_pull(buf, 4);
740 silc_buffer_unformat(buf,
741 SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
742 SILC_STR_UI16_NSTRING_ALLOC(&ident, &identifier_len),
747 if (pkcs_len < 1 || identifier_len < 3 ||
748 pkcs_len + identifier_len > totlen)
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));
757 /* Protocol says that at least UN and HN must be provided as identifier,
759 if (!strstr(ident, "UN=") && !strstr(ident, "HN=")) {
760 SILC_LOG_DEBUG(("The public does not have the required UN= and HN= "
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);
768 ret = silc_buffer_unformat(buf,
769 SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
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))
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;
793 silc_buffer_free(buf);
798 silc_free(pkcs_name);
803 silc_buffer_free(buf);
807 /* Compares two public keys and returns TRUE if they are same key, and
808 FALSE if they are not same. */
810 bool silc_pkcs_public_key_compare(SilcPublicKey key1, SilcPublicKey key2)
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)
826 /* Copies the public key indicated by `public_key' and returns new allocated
827 public key which is indentical to the `public_key'. */
829 SilcPublicKey silc_pkcs_public_key_copy(SilcPublicKey public_key)
831 SilcPublicKey key = silc_calloc(1, sizeof(*key));
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;
845 /* Encodes SILC private key from SilcPrivateKey. Returns the encoded data. */
848 silc_pkcs_private_key_encode(SilcPrivateKey private_key, SilcUInt32 *len)
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));
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),
867 ret = silc_calloc(buf->len, sizeof(*ret));
868 memcpy(ret, buf->data, buf->len);
869 silc_buffer_free(buf);
874 /* Encodes SILC private key. Returns the encoded data. */
877 silc_pkcs_private_key_data_encode(unsigned char *prv, SilcUInt32 prv_len,
878 char *pkcs, SilcUInt32 *len)
884 totlen = 2 + strlen(pkcs) + prv_len;
885 buf = silc_buffer_alloc(totlen);
886 silc_buffer_pull_tail(buf, totlen);
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),
896 ret = silc_calloc(buf->len, sizeof(*ret));
897 memcpy(ret, buf->data, buf->len);
898 silc_buffer_free(buf);
903 /* Decodes SILC style public key. Returns TRUE if the decoding was
904 successful. Allocates new private key as well. */
906 int silc_pkcs_private_key_decode(unsigned char *data, SilcUInt32 data_len,
907 SilcPrivateKey *private_key)
913 unsigned char *pkcs_name = NULL, *key_data = NULL;
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);
920 /* Get algorithm name and identifier */
922 silc_buffer_unformat(buf,
923 SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
928 if (pkcs_len < 1 || pkcs_len > buf->truelen)
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));
937 /* Get key data. We assume that rest of the buffer is key data. */
938 silc_buffer_pull(buf, 2 + pkcs_len);
940 ret = silc_buffer_unformat(buf,
941 SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
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))
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;
963 silc_buffer_free(buf);
968 silc_free(pkcs_name);
971 silc_buffer_free(buf);
975 /* Internal routine to save public key */
977 static int silc_pkcs_save_public_key_internal(char *filename,
986 case SILC_PKCS_FILE_BIN:
988 case SILC_PKCS_FILE_PEM:
989 data = silc_pem_encode_file(data, data_len);
990 data_len = strlen(data);
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));
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),
1005 /* Save into file */
1006 if (silc_file_writefile(filename, buf->data, buf->len)) {
1007 silc_buffer_free(buf);
1011 silc_buffer_free(buf);
1015 /* Saves public key into file */
1017 int silc_pkcs_save_public_key(char *filename, SilcPublicKey public_key,
1018 SilcUInt32 encoding)
1020 unsigned char *data;
1021 SilcUInt32 data_len;
1023 data = silc_pkcs_public_key_encode(public_key, &data_len);
1024 return silc_pkcs_save_public_key_internal(filename, data, data_len,
1028 /* Saves public key into file */
1030 int silc_pkcs_save_public_key_data(char *filename, unsigned char *data,
1031 SilcUInt32 data_len,
1032 SilcUInt32 encoding)
1034 return silc_pkcs_save_public_key_internal(filename, data, data_len,
1038 /* Internal routine to save private key. */
1040 static int silc_pkcs_save_private_key_internal(char *filename,
1041 unsigned char *data,
1042 SilcUInt32 data_len,
1043 SilcUInt32 encoding)
1049 case SILC_PKCS_FILE_BIN:
1051 case SILC_PKCS_FILE_PEM:
1052 data = silc_pem_encode_file(data, data_len);
1053 data_len = strlen(data);
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));
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),
1068 /* Save into a file */
1069 if (silc_file_writefile_mode(filename, buf->data, buf->len, 0600)) {
1070 silc_buffer_free(buf);
1074 silc_buffer_free(buf);
1078 /* Saves private key into file. */
1079 /* XXX The buffer should be encrypted if passphrase is provided. */
1081 int silc_pkcs_save_private_key(char *filename, SilcPrivateKey private_key,
1082 unsigned char *passphrase,
1083 SilcUInt32 encoding)
1085 unsigned char *data;
1086 SilcUInt32 data_len;
1088 data = silc_pkcs_private_key_encode(private_key, &data_len);
1089 return silc_pkcs_save_private_key_internal(filename, data, data_len,
1093 /* Saves private key into file. */
1094 /* XXX The buffer should be encrypted if passphrase is provided. */
1096 int silc_pkcs_save_private_key_data(char *filename, unsigned char *data,
1097 SilcUInt32 data_len,
1098 unsigned char *passphrase,
1099 SilcUInt32 encoding)
1101 return silc_pkcs_save_private_key_internal(filename, data, data_len,
1105 /* Loads public key from file and allocates new public key. Returns TRUE
1106 is loading was successful. */
1108 int silc_pkcs_load_public_key(char *filename, SilcPublicKey *public_key,
1109 SilcUInt32 encoding)
1111 unsigned char *cp, *old, *data, byte;
1112 SilcUInt32 i, data_len, len;
1114 old = data = silc_file_readfile(filename, &data_len);
1118 /* Check start of file and remove header from the data. */
1119 len = strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN);
1121 for (i = 0; i < len; i++) {
1124 if (byte != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i]) {
1125 memset(old, 0, data_len);
1132 /* Decode public key */
1134 len = data_len - (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
1135 strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
1138 case SILC_PKCS_FILE_BIN:
1140 case SILC_PKCS_FILE_PEM:
1141 data = silc_pem_decode(data, len, &len);
1142 memset(old, 0, data_len);
1149 if (!data || !silc_pkcs_public_key_decode(data, len, public_key)) {
1150 memset(old, 0, data_len);
1156 memset(old, 0, data_len);
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 */
1165 int silc_pkcs_load_private_key(char *filename, SilcPrivateKey *private_key,
1166 SilcUInt32 encoding)
1168 unsigned char *cp, *old, *data, byte;
1169 SilcUInt32 i, data_len, len;
1171 old = data = silc_file_readfile(filename, &data_len);
1175 /* Check start of file and remove header from the data. */
1176 len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
1178 for (i = 0; i < len; i++) {
1181 if (byte != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i]) {
1182 memset(old, 0, data_len);
1189 /* Decode private key */
1191 len = data_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
1192 strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
1195 case SILC_PKCS_FILE_BIN:
1197 case SILC_PKCS_FILE_PEM:
1198 data = silc_pem_decode(data, len, &len);
1202 if (!data || !silc_pkcs_private_key_decode(data, len, private_key)) {
1203 memset(old, 0, data_len);
1209 memset(old, 0, data_len);