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 = hash->hash->hash_len;
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 = hash->hash->hash_len;
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->len = 4 + 2 + strlen(name) + 2 + strlen(identifier) + pk_len;
572 public_key->name = strdup(name);
573 public_key->pk_len = pk_len;
574 public_key->pk = silc_calloc(pk_len, sizeof(*public_key->pk));
575 memcpy(public_key->pk, pk, pk_len);
577 if (!silc_utf8_valid(identifier, strlen(identifier))) {
578 int len = silc_utf8_encoded_len(identifier, strlen(identifier), 0);
579 tmp = silc_calloc(len + 1, sizeof(*tmp));
580 silc_utf8_encode(identifier, strlen(identifier), 0, tmp, len);
584 public_key->identifier = strdup(identifier);
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 /* Encodes SILC private key from SilcPrivateKey. Returns the encoded data. */
817 silc_pkcs_private_key_encode(SilcPrivateKey private_key, SilcUInt32 *len)
823 totlen = 2 + strlen(private_key->name) + private_key->prv_len;
824 buf = silc_buffer_alloc(totlen);
825 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
827 silc_buffer_format(buf,
828 SILC_STR_UI_SHORT(strlen(private_key->name)),
829 SILC_STR_UI32_STRING(private_key->name),
830 SILC_STR_UI_XNSTRING(private_key->prv,
831 private_key->prv_len),
836 ret = silc_calloc(buf->len, sizeof(*ret));
837 memcpy(ret, buf->data, buf->len);
838 silc_buffer_free(buf);
843 /* Encodes SILC private key. Returns the encoded data. */
846 silc_pkcs_private_key_data_encode(unsigned char *prv, SilcUInt32 prv_len,
847 char *pkcs, SilcUInt32 *len)
853 totlen = 2 + strlen(pkcs) + prv_len;
854 buf = silc_buffer_alloc(totlen);
855 silc_buffer_pull_tail(buf, totlen);
857 silc_buffer_format(buf,
858 SILC_STR_UI_SHORT(strlen(pkcs)),
859 SILC_STR_UI32_STRING(pkcs),
860 SILC_STR_UI_XNSTRING(prv, prv_len),
865 ret = silc_calloc(buf->len, sizeof(*ret));
866 memcpy(ret, buf->data, buf->len);
867 silc_buffer_free(buf);
872 /* Decodes SILC style public key. Returns TRUE if the decoding was
873 successful. Allocates new private key as well. */
875 int silc_pkcs_private_key_decode(unsigned char *data, SilcUInt32 data_len,
876 SilcPrivateKey *private_key)
882 unsigned char *pkcs_name = NULL, *key_data = NULL;
885 buf = silc_buffer_alloc(data_len);
886 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
887 silc_buffer_put(buf, data, data_len);
889 /* Get algorithm name and identifier */
891 silc_buffer_unformat(buf,
892 SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
897 if (pkcs_len < 1 || pkcs_len > buf->truelen)
900 /* See if we support this algorithm (check only if PKCS are registered). */
901 if (SILC_PKCS_LIST && !silc_pkcs_is_supported(pkcs_name)) {
902 SILC_LOG_DEBUG(("Unknown PKCS `%s'", pkcs_name));
906 /* Get key data. We assume that rest of the buffer is key data. */
907 silc_buffer_pull(buf, 2 + pkcs_len);
909 ret = silc_buffer_unformat(buf,
910 SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
915 /* Try to set the key. If this fails the key must be malformed. This
916 code assumes that the PKCS routine checks the format of the key.
917 (check only if PKCS are registered) */
918 if (SILC_PKCS_LIST) {
919 silc_pkcs_alloc(pkcs_name, &alg);
920 if (!alg->pkcs->set_private_key(alg->context, key_data, key_len))
926 *private_key = silc_calloc(1, sizeof(**private_key));
927 (*private_key)->name = pkcs_name;
928 (*private_key)->prv = key_data;
929 (*private_key)->prv_len = key_len;
932 silc_buffer_free(buf);
937 silc_free(pkcs_name);
940 silc_buffer_free(buf);
944 /* Internal routine to save public key */
946 static int silc_pkcs_save_public_key_internal(char *filename,
955 case SILC_PKCS_FILE_BIN:
957 case SILC_PKCS_FILE_PEM:
958 data = silc_pem_encode_file(data, data_len);
959 data_len = strlen(data);
963 len = data_len + (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
964 strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
965 buf = silc_buffer_alloc(len);
966 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
968 silc_buffer_format(buf,
969 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
970 SILC_STR_UI_XNSTRING(data, data_len),
971 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END),
975 if (silc_file_writefile(filename, buf->data, buf->len)) {
976 silc_buffer_free(buf);
980 silc_buffer_free(buf);
984 /* Saves public key into file */
986 int silc_pkcs_save_public_key(char *filename, SilcPublicKey public_key,
992 data = silc_pkcs_public_key_encode(public_key, &data_len);
993 return silc_pkcs_save_public_key_internal(filename, data, data_len,
997 /* Saves public key into file */
999 int silc_pkcs_save_public_key_data(char *filename, unsigned char *data,
1000 SilcUInt32 data_len,
1001 SilcUInt32 encoding)
1003 return silc_pkcs_save_public_key_internal(filename, data, data_len,
1007 /* Internal routine to save private key. */
1009 static int silc_pkcs_save_private_key_internal(char *filename,
1010 unsigned char *data,
1011 SilcUInt32 data_len,
1012 SilcUInt32 encoding)
1018 case SILC_PKCS_FILE_BIN:
1020 case SILC_PKCS_FILE_PEM:
1021 data = silc_pem_encode_file(data, data_len);
1022 data_len = strlen(data);
1026 len = data_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
1027 strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
1028 buf = silc_buffer_alloc(len);
1029 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1031 silc_buffer_format(buf,
1032 SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
1033 SILC_STR_UI_XNSTRING(data, data_len),
1034 SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
1037 /* Save into a file */
1038 if (silc_file_writefile_mode(filename, buf->data, buf->len, 0600)) {
1039 silc_buffer_free(buf);
1043 silc_buffer_free(buf);
1047 /* Saves private key into file. */
1048 /* XXX The buffer should be encrypted if passphrase is provided. */
1050 int silc_pkcs_save_private_key(char *filename, SilcPrivateKey private_key,
1051 unsigned char *passphrase,
1052 SilcUInt32 encoding)
1054 unsigned char *data;
1055 SilcUInt32 data_len;
1057 data = silc_pkcs_private_key_encode(private_key, &data_len);
1058 return silc_pkcs_save_private_key_internal(filename, data, data_len,
1062 /* Saves private key into file. */
1063 /* XXX The buffer should be encrypted if passphrase is provided. */
1065 int silc_pkcs_save_private_key_data(char *filename, unsigned char *data,
1066 SilcUInt32 data_len,
1067 unsigned char *passphrase,
1068 SilcUInt32 encoding)
1070 return silc_pkcs_save_private_key_internal(filename, data, data_len,
1074 /* Loads public key from file and allocates new public key. Returns TRUE
1075 is loading was successful. */
1077 int silc_pkcs_load_public_key(char *filename, SilcPublicKey *public_key,
1078 SilcUInt32 encoding)
1080 unsigned char *cp, *old, *data, byte;
1081 SilcUInt32 i, data_len, len;
1083 old = data = silc_file_readfile(filename, &data_len);
1087 /* Check start of file and remove header from the data. */
1088 len = strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN);
1090 for (i = 0; i < len; i++) {
1093 if (byte != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i]) {
1094 memset(old, 0, data_len);
1101 /* Decode public key */
1103 len = data_len - (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
1104 strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
1107 case SILC_PKCS_FILE_BIN:
1109 case SILC_PKCS_FILE_PEM:
1110 data = silc_pem_decode(data, len, &len);
1111 memset(old, 0, data_len);
1118 if (!data || !silc_pkcs_public_key_decode(data, len, public_key)) {
1119 memset(old, 0, data_len);
1125 memset(old, 0, data_len);
1130 /* Load private key from file and allocates new private key. Returns TRUE
1131 if loading was successful. */
1132 /* XXX Should support encrypted private key files */
1134 int silc_pkcs_load_private_key(char *filename, SilcPrivateKey *private_key,
1135 SilcUInt32 encoding)
1137 unsigned char *cp, *old, *data, byte;
1138 SilcUInt32 i, data_len, len;
1140 old = data = silc_file_readfile(filename, &data_len);
1144 /* Check start of file and remove header from the data. */
1145 len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
1147 for (i = 0; i < len; i++) {
1150 if (byte != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i]) {
1151 memset(old, 0, data_len);
1158 /* Decode private key */
1160 len = data_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
1161 strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
1164 case SILC_PKCS_FILE_BIN:
1166 case SILC_PKCS_FILE_PEM:
1167 data = silc_pem_decode(data, len, &len);
1171 if (!data || !silc_pkcs_private_key_decode(data, len, private_key)) {
1172 memset(old, 0, data_len);
1178 memset(old, 0, data_len);