5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2003 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 {
28 void *context; /* Algorithm internal context */
29 SilcPKCSObject *pkcs; /* Algorithm implementation */
30 SilcUInt32 key_len; /* Key length in bits */
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 /* Check if exists already */
76 SilcPKCSObject *entry;
77 silc_dlist_start(silc_pkcs_list);
78 while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
79 if (!strcmp(entry->name, pkcs->name))
84 new = silc_calloc(1, sizeof(*new));
85 new->name = strdup(pkcs->name);
86 new->init = pkcs->init;
87 new->clear_keys = pkcs->clear_keys;
88 new->get_public_key = pkcs->get_public_key;
89 new->get_private_key = pkcs->get_private_key;
90 new->set_public_key = pkcs->set_public_key;
91 new->set_private_key = pkcs->set_private_key;
92 new->context_len = pkcs->context_len;
93 new->encrypt = pkcs->encrypt;
94 new->decrypt = pkcs->decrypt;
95 new->sign = pkcs->sign;
96 new->verify = pkcs->verify;
99 if (silc_pkcs_list == NULL)
100 silc_pkcs_list = silc_dlist_init();
101 silc_dlist_add(silc_pkcs_list, new);
103 #endif /* SILC_EPOC */
107 /* Unregister a PKCS from the SILC. */
109 bool silc_pkcs_unregister(SilcPKCSObject *pkcs)
112 SilcPKCSObject *entry;
114 SILC_LOG_DEBUG(("Unregistering PKCS"));
119 silc_dlist_start(silc_pkcs_list);
120 while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
121 if (pkcs == SILC_ALL_PKCS || entry == pkcs) {
122 silc_dlist_del(silc_pkcs_list, entry);
123 silc_free(entry->name);
126 if (silc_dlist_count(silc_pkcs_list) == 0) {
127 silc_dlist_uninit(silc_pkcs_list);
128 silc_pkcs_list = NULL;
135 #endif /* SILC_EPOC */
139 /* Function that registers all the default PKCS (all builtin PKCS).
140 The application may use this to register the default PKCS if specific
141 PKCS in any specific order is not wanted. */
143 bool silc_pkcs_register_default(void)
148 for (i = 0; silc_default_pkcs[i].name; i++)
149 silc_pkcs_register(&(silc_default_pkcs[i]));
151 #endif /* SILC_EPOC */
155 bool silc_pkcs_unregister_all(void)
158 SilcPKCSObject *entry;
163 silc_dlist_start(silc_pkcs_list);
164 while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
165 silc_pkcs_unregister(entry);
169 #endif /* SILC_EPOC */
173 /* Allocates a new SilcPKCS object. The new allocated object is returned
174 to the 'new_pkcs' argument. */
176 bool silc_pkcs_alloc(const unsigned char *name, SilcPKCS *new_pkcs)
178 SilcPKCSObject *entry = NULL;
180 SILC_LOG_DEBUG(("Allocating new PKCS object"));
183 if (silc_pkcs_list) {
184 silc_dlist_start(silc_pkcs_list);
185 while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
186 if (!strcmp(entry->name, name))
192 /* On EPOC which don't have globals we check our constant hash list. */
194 for (i = 0; silc_default_pkcs[i].name; i++) {
195 if (!strcmp(silc_default_pkcs[i].name, name)) {
196 entry = (SilcPKCSObject *)&(silc_default_pkcs[i]);
201 #endif /* SILC_EPOC */
204 *new_pkcs = silc_calloc(1, sizeof(**new_pkcs));
205 (*new_pkcs)->pkcs = entry;
206 (*new_pkcs)->context = silc_calloc(1, entry->context_len());
213 /* Free's the PKCS object */
215 void silc_pkcs_free(SilcPKCS pkcs)
218 pkcs->pkcs->clear_keys(pkcs->context);
219 silc_free(pkcs->context);
224 /* Return TRUE if PKCS algorithm `name' is supported. */
226 bool silc_pkcs_is_supported(const unsigned char *name)
229 SilcPKCSObject *entry;
231 if (silc_pkcs_list) {
232 silc_dlist_start(silc_pkcs_list);
233 while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
234 if (!strcmp(entry->name, name))
241 for (i = 0; silc_default_pkcs[i].name; i++)
242 if (!strcmp(silc_default_pkcs[i].name, name))
245 #endif /* SILC_EPOC */
249 /* Returns comma separated list of supported PKCS algorithms */
251 char *silc_pkcs_get_supported(void)
253 SilcPKCSObject *entry;
258 if (silc_pkcs_list) {
259 silc_dlist_start(silc_pkcs_list);
260 while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
261 len += strlen(entry->name);
262 list = silc_realloc(list, len + 1);
264 memcpy(list + (len - strlen(entry->name)),
265 entry->name, strlen(entry->name));
266 memcpy(list + len, ",", 1);
273 for (i = 0; silc_default_pkcs[i].name; i++) {
274 entry = (SilcPKCSObject *)&(silc_default_pkcs[i]);
275 len += strlen(entry->name);
276 list = silc_realloc(list, len + 1);
278 memcpy(list + (len - strlen(entry->name)),
279 entry->name, strlen(entry->name));
280 memcpy(list + len, ",", 1);
284 #endif /* SILC_EPOC */
291 /* Generate new key pair into the `pkcs' context. */
293 bool silc_pkcs_generate_key(SilcPKCS pkcs, SilcUInt32 bits_key_len,
296 return pkcs->pkcs->init(pkcs->context, bits_key_len, rng);
299 /* Returns the length of the key */
301 SilcUInt32 silc_pkcs_get_key_len(SilcPKCS pkcs)
303 return pkcs->key_len;
306 const char *silc_pkcs_get_name(SilcPKCS pkcs)
308 return pkcs->pkcs->name;
311 /* Returns SILC style public key */
313 unsigned char *silc_pkcs_get_public_key(SilcPKCS pkcs, SilcUInt32 *len)
315 return pkcs->pkcs->get_public_key(pkcs->context, len);
318 /* Returns SILC style private key */
320 unsigned char *silc_pkcs_get_private_key(SilcPKCS pkcs, SilcUInt32 *len)
322 return pkcs->pkcs->get_private_key(pkcs->context, len);
325 /* Sets public key from SilcPublicKey. */
327 SilcUInt32 silc_pkcs_public_key_set(SilcPKCS pkcs, SilcPublicKey public_key)
329 pkcs->key_len = pkcs->pkcs->set_public_key(pkcs->context, public_key->pk,
331 return pkcs->key_len;
334 /* Sets public key from data. */
336 SilcUInt32 silc_pkcs_public_key_data_set(SilcPKCS pkcs, unsigned char *pk,
339 pkcs->key_len = pkcs->pkcs->set_public_key(pkcs->context, pk, pk_len);
340 return pkcs->key_len;
343 /* Sets private key from SilcPrivateKey. */
345 SilcUInt32 silc_pkcs_private_key_set(SilcPKCS pkcs, SilcPrivateKey private_key)
348 key_len = pkcs->pkcs->set_private_key(pkcs->context, private_key->prv,
349 private_key->prv_len);
351 pkcs->key_len = key_len;
352 return pkcs->key_len;
355 /* Sets private key from data. */
357 SilcUInt32 silc_pkcs_private_key_data_set(SilcPKCS pkcs, unsigned char *prv,
361 key_len = pkcs->pkcs->set_private_key(pkcs->context, prv, prv_len);
363 pkcs->key_len = key_len;
364 return pkcs->key_len;
369 bool silc_pkcs_encrypt(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len,
370 unsigned char *dst, SilcUInt32 *dst_len)
372 return pkcs->pkcs->encrypt(pkcs->context, src, src_len, dst, dst_len);
377 bool silc_pkcs_decrypt(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len,
378 unsigned char *dst, SilcUInt32 *dst_len)
380 return pkcs->pkcs->decrypt(pkcs->context, src, src_len, dst, dst_len);
383 /* Generates signature */
385 bool silc_pkcs_sign(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len,
386 unsigned char *dst, SilcUInt32 *dst_len)
388 return pkcs->pkcs->sign(pkcs->context, src, src_len, dst, dst_len);
391 /* Verifies signature */
393 bool silc_pkcs_verify(SilcPKCS pkcs, unsigned char *signature,
394 SilcUInt32 signature_len, unsigned char *data,
397 return pkcs->pkcs->verify(pkcs->context, signature, signature_len,
401 /* Generates signature with hash. The hash is signed. */
403 bool silc_pkcs_sign_with_hash(SilcPKCS pkcs, SilcHash hash,
404 unsigned char *src, SilcUInt32 src_len,
405 unsigned char *dst, SilcUInt32 *dst_len)
407 unsigned char hashr[32];
411 silc_hash_make(hash, src, src_len, hashr);
412 hash_len = silc_hash_len(hash);
414 SILC_LOG_HEXDUMP(("Hash"), hashr, hash_len);
416 ret = pkcs->pkcs->sign(pkcs->context, hashr, hash_len, dst, dst_len);
417 memset(hashr, 0, sizeof(hashr));
422 /* Verifies signature with hash. The `data' is hashed and verified against
425 bool silc_pkcs_verify_with_hash(SilcPKCS pkcs, SilcHash hash,
426 unsigned char *signature,
427 SilcUInt32 signature_len,
431 unsigned char hashr[32];
435 silc_hash_make(hash, data, data_len, hashr);
436 hash_len = silc_hash_len(hash);
438 SILC_LOG_HEXDUMP(("Hash"), hashr, hash_len);
440 ret = pkcs->pkcs->verify(pkcs->context, signature, signature_len,
442 memset(hashr, 0, sizeof(hashr));
447 /* Encodes and returns SILC public key identifier. If some of the
448 arguments is NULL those are not encoded into the identifier string.
449 Protocol says that at least username and host must be provided. */
451 char *silc_pkcs_encode_identifier(char *username, char *host, char *realname,
452 char *email, char *org, char *country)
456 SilcUInt32 len, tlen = 0;
458 if (!username || !host)
461 len = (username ? strlen(username) : 0) +
462 (host ? strlen(host) : 0) +
463 (realname ? strlen(realname) : 0) +
464 (email ? strlen(email) : 0) +
465 (org ? strlen(org) : 0) +
466 (country ? strlen(country) : 0);
471 len += 3 + 5 + 5 + 4 + 4 + 4;
472 buf = silc_buffer_alloc(len);
473 silc_buffer_pull_tail(buf, len);
476 silc_buffer_format(buf,
477 SILC_STR_UI32_STRING("UN="),
478 SILC_STR_UI32_STRING(username),
480 silc_buffer_pull(buf, 3 + strlen(username));
481 tlen = 3 + strlen(username);
485 silc_buffer_format(buf,
486 SILC_STR_UI32_STRING(", "),
487 SILC_STR_UI32_STRING("HN="),
488 SILC_STR_UI32_STRING(host),
490 silc_buffer_pull(buf, 5 + strlen(host));
491 tlen += 5 + strlen(host);
495 silc_buffer_format(buf,
496 SILC_STR_UI32_STRING(", "),
497 SILC_STR_UI32_STRING("RN="),
498 SILC_STR_UI32_STRING(realname),
500 silc_buffer_pull(buf, 5 + strlen(realname));
501 tlen += 5 + strlen(realname);
505 silc_buffer_format(buf,
506 SILC_STR_UI32_STRING(", "),
507 SILC_STR_UI32_STRING("E="),
508 SILC_STR_UI32_STRING(email),
510 silc_buffer_pull(buf, 4 + strlen(email));
511 tlen += 4 + strlen(email);
515 silc_buffer_format(buf,
516 SILC_STR_UI32_STRING(", "),
517 SILC_STR_UI32_STRING("O="),
518 SILC_STR_UI32_STRING(org),
520 silc_buffer_pull(buf, 4 + strlen(org));
521 tlen += 4 + strlen(org);
525 silc_buffer_format(buf,
526 SILC_STR_UI32_STRING(", "),
527 SILC_STR_UI32_STRING("C="),
528 SILC_STR_UI32_STRING(country),
530 silc_buffer_pull(buf, 4 + strlen(country));
531 tlen += 4 + strlen(country);
534 silc_buffer_push(buf, buf->data - buf->head);
535 identifier = silc_calloc(tlen + 1, sizeof(*identifier));
536 memcpy(identifier, buf->data, tlen);
537 silc_buffer_free(buf);
542 /* Decodes the provided `identifier' and returns allocated context for
545 SilcPublicKeyIdentifier silc_pkcs_decode_identifier(char *identifier)
547 SilcPublicKeyIdentifier ident;
551 ident = silc_calloc(1, sizeof(*ident));
555 len = strcspn(cp, ",");
560 if (len - 1 >= 0 && cp[len - 1] == '\\') {
562 if (len + 1 > strlen(cp)) {
567 len = strcspn(cp, ",") + len;
572 if (len - 1 >= 0 && cp[len - 1] != '\\')
580 item = silc_calloc(len + 1, sizeof(char));
581 if (len > strlen(cp))
583 memcpy(item, cp, len);
585 if (strstr(item, "UN="))
586 ident->username = strdup(item + strcspn(cp, "=") + 1);
587 else if (strstr(item, "HN="))
588 ident->host = strdup(item + strcspn(cp, "=") + 1);
589 else if (strstr(item, "RN="))
590 ident->realname = strdup(item + strcspn(cp, "=") + 1);
591 else if (strstr(item, "E="))
592 ident->email = strdup(item + strcspn(cp, "=") + 1);
593 else if (strstr(item, "O="))
594 ident->org = strdup(item + strcspn(cp, "=") + 1);
595 else if (strstr(item, "C="))
596 ident->country = strdup(item + strcspn(cp, "=") + 1);
611 /* Free's decoded public key identifier context. Call this to free the
612 context returned by the silc_pkcs_decode_identifier. */
614 void silc_pkcs_free_identifier(SilcPublicKeyIdentifier identifier)
616 silc_free(identifier->username);
617 silc_free(identifier->host);
618 silc_free(identifier->realname);
619 silc_free(identifier->email);
620 silc_free(identifier->org);
621 silc_free(identifier->country);
622 silc_free(identifier);
625 /* Allocates SILC style public key formed from sent arguments. All data
628 SilcPublicKey silc_pkcs_public_key_alloc(const char *name,
629 const char *identifier,
630 const unsigned char *pk,
633 SilcPublicKey public_key;
636 public_key = silc_calloc(1, sizeof(*public_key));
637 public_key->name = strdup(name);
638 public_key->pk_len = pk_len;
639 public_key->pk = silc_calloc(pk_len, sizeof(*public_key->pk));
640 public_key->pk_type = SILC_SKE_PK_TYPE_SILC;
641 memcpy(public_key->pk, pk, pk_len);
643 if (!silc_utf8_valid(identifier, strlen(identifier))) {
644 int len = silc_utf8_encoded_len(identifier, strlen(identifier), 0);
645 tmp = silc_calloc(len + 1, sizeof(*tmp));
646 silc_utf8_encode(identifier, strlen(identifier), 0, tmp, len);
650 public_key->identifier = strdup(identifier);
651 public_key->len = 2 + strlen(name) + 2 + strlen(identifier) + pk_len;
657 /* Free's public key */
659 void silc_pkcs_public_key_free(SilcPublicKey public_key)
662 silc_free(public_key->name);
663 silc_free(public_key->identifier);
664 silc_free(public_key->pk);
665 silc_free(public_key);
669 /* Allocates SILC private key formed from sent arguments. All data is
672 SilcPrivateKey silc_pkcs_private_key_alloc(const char *name,
673 const unsigned char *prv,
676 SilcPrivateKey private_key;
678 private_key = silc_calloc(1, sizeof(*private_key));
679 private_key->name = strdup(name);
680 private_key->prv_len = prv_len;
681 private_key->prv = silc_calloc(prv_len, sizeof(*private_key->prv));
682 memcpy(private_key->prv, prv, prv_len);
687 /* Free's private key */
689 void silc_pkcs_private_key_free(SilcPrivateKey private_key)
692 silc_free(private_key->name);
693 silc_free(private_key->prv);
694 silc_free(private_key);
698 /* Encodes SILC style public key from SilcPublicKey. Returns the encoded
702 silc_pkcs_public_key_encode(SilcPublicKey public_key, SilcUInt32 *len)
707 buf = silc_buffer_alloc_size(public_key->len + 4);
711 silc_buffer_format(buf,
712 SILC_STR_UI_INT(public_key->len),
713 SILC_STR_UI_SHORT(strlen(public_key->name)),
714 SILC_STR_UI32_STRING(public_key->name),
715 SILC_STR_UI_SHORT(strlen(public_key->identifier)),
716 SILC_STR_UI32_STRING(public_key->identifier),
717 SILC_STR_UI_XNSTRING(public_key->pk,
721 ret = silc_buffer_steal(buf, len);
722 silc_buffer_free(buf);
726 /* Encodes SILC style public key. Returns the encoded data. */
729 silc_pkcs_public_key_data_encode(unsigned char *pk, SilcUInt32 pk_len,
730 char *pkcs, char *identifier,
737 totlen = 2 + strlen(pkcs) + 2 + strlen(identifier) + pk_len;
738 buf = silc_buffer_alloc_size(totlen + 4);
742 silc_buffer_format(buf,
743 SILC_STR_UI_INT(totlen),
744 SILC_STR_UI_SHORT(strlen(pkcs)),
745 SILC_STR_UI32_STRING(pkcs),
746 SILC_STR_UI_SHORT(strlen(identifier)),
747 SILC_STR_UI32_STRING(identifier),
748 SILC_STR_UI_XNSTRING(pk, pk_len),
751 ret = silc_buffer_steal(buf, len);
752 silc_buffer_free(buf);
756 /* Decodes SILC style public key. Returns TRUE if the decoding was
757 successful. Allocates new public key as well. */
759 bool silc_pkcs_public_key_decode(unsigned char *data, SilcUInt32 data_len,
760 SilcPublicKey *public_key)
762 SilcBufferStruct buf;
764 SilcUInt16 pkcs_len, identifier_len;
765 SilcUInt32 totlen, key_len;
766 unsigned char *pkcs_name = NULL, *ident = NULL, *key_data = NULL;
769 silc_buffer_set(&buf, data, data_len);
772 ret = silc_buffer_unformat(&buf,
773 SILC_STR_UI_INT(&totlen),
778 #if 1 /* Backwards support, remove! */
779 if (totlen == data_len)
783 if (totlen + 4 != data_len)
786 /* Get algorithm name and identifier */
787 silc_buffer_pull(&buf, 4);
789 silc_buffer_unformat(&buf,
790 SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
791 SILC_STR_UI16_NSTRING_ALLOC(&ident, &identifier_len),
796 if (pkcs_len < 1 || identifier_len < 3 ||
797 pkcs_len + identifier_len > totlen)
800 /* See if we support this algorithm (check only if PKCS are registered) */
801 if (SILC_PKCS_LIST && !silc_pkcs_is_supported(pkcs_name)) {
802 SILC_LOG_DEBUG(("Unknown PKCS %s", pkcs_name));
806 /* Protocol says that at least UN and HN must be provided as identifier,
808 if (!strstr(ident, "UN=") && !strstr(ident, "HN=")) {
809 SILC_LOG_DEBUG(("The public does not have the required UN= and HN= "
814 /* Get key data. We assume that rest of the buffer is key data. */
815 silc_buffer_pull(&buf, 2 + pkcs_len + 2 + identifier_len);
817 ret = silc_buffer_unformat(&buf,
818 SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
823 /* Try to set the key. If this fails the key must be malformed. This
824 code assumes that the PKCS routine checks the format of the key.
825 (check only if PKCS are registered) */
826 if (SILC_PKCS_LIST) {
827 silc_pkcs_alloc(pkcs_name, &alg);
828 if (!alg->pkcs->set_public_key(alg->context, key_data, key_len))
834 *public_key = silc_calloc(1, sizeof(**public_key));
835 (*public_key)->len = totlen;
836 (*public_key)->name = pkcs_name;
837 (*public_key)->identifier = ident;
838 (*public_key)->pk = key_data;
839 (*public_key)->pk_len = key_len;
840 (*public_key)->pk_type = SILC_SKE_PK_TYPE_SILC;
846 silc_free(pkcs_name);
852 /* Encodes Public Key Payload for transmitting public keys and certificates. */
854 SilcBuffer silc_pkcs_public_key_payload_encode(SilcPublicKey public_key)
863 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
867 buffer = silc_buffer_alloc_size(4 + pk_len);
873 silc_buffer_format(buffer,
874 SILC_STR_UI_SHORT(pk_len),
875 SILC_STR_UI_SHORT(public_key->pk_type),
876 SILC_STR_UI_XNSTRING(pk, pk_len),
883 /* Decode Public Key Payload and decodes the public key inside it to
886 bool silc_pkcs_public_key_payload_decode(unsigned char *data,
888 SilcPublicKey *public_key)
890 SilcBufferStruct buf;
891 SilcUInt16 pk_len, pk_type;
898 silc_buffer_set(&buf, data, data_len);
899 ret = silc_buffer_unformat(&buf,
900 SILC_STR_UI_SHORT(&pk_len),
901 SILC_STR_UI_SHORT(&pk_type),
903 if (ret < 0 || pk_len > data_len - 4)
906 /* For now we support only SILC public keys */
907 if (pk_type != SILC_SKE_PK_TYPE_SILC)
910 silc_buffer_pull(&buf, 4);
911 ret = silc_buffer_unformat(&buf,
912 SILC_STR_UI_XNSTRING(&pk, pk_len),
914 silc_buffer_push(&buf, 4);
918 if (!silc_pkcs_public_key_decode(pk, pk_len, public_key))
920 (*public_key)->pk_type = SILC_SKE_PK_TYPE_SILC;
925 /* Compares two public keys and returns TRUE if they are same key, and
926 FALSE if they are not same. */
928 bool silc_pkcs_public_key_compare(SilcPublicKey key1, SilcPublicKey key2)
933 if (key1->len == key2->len &&
934 key1->name && key2->name && key1->identifier && key2->identifier &&
935 !strcmp(key1->name, key2->name) &&
936 !strcmp(key1->identifier, key2->identifier) &&
937 !memcmp(key1->pk, key2->pk, key1->pk_len) &&
938 key1->pk_len == key2->pk_len)
944 /* Copies the public key indicated by `public_key' and returns new allocated
945 public key which is indentical to the `public_key'. */
947 SilcPublicKey silc_pkcs_public_key_copy(SilcPublicKey public_key)
949 SilcPublicKey key = silc_calloc(1, sizeof(*key));
953 key->len = public_key->len;
954 key->name = silc_memdup(public_key->name, strlen(public_key->name));
955 key->identifier = silc_memdup(public_key->identifier,
956 strlen(public_key->identifier));
957 key->pk = silc_memdup(public_key->pk, public_key->pk_len);
958 key->pk_len = public_key->pk_len;
959 key->pk_type = public_key->pk_type;
964 /* Encodes SILC private key from SilcPrivateKey. Returns the encoded data. */
967 silc_pkcs_private_key_encode(SilcPrivateKey private_key, SilcUInt32 *len)
973 totlen = 2 + strlen(private_key->name) + private_key->prv_len;
974 buf = silc_buffer_alloc_size(totlen);
978 silc_buffer_format(buf,
979 SILC_STR_UI_SHORT(strlen(private_key->name)),
980 SILC_STR_UI32_STRING(private_key->name),
981 SILC_STR_UI_XNSTRING(private_key->prv,
982 private_key->prv_len),
985 ret = silc_buffer_steal(buf, len);
986 silc_buffer_free(buf);
990 /* Encodes SILC private key. Returns the encoded data. */
993 silc_pkcs_private_key_data_encode(unsigned char *prv, SilcUInt32 prv_len,
994 char *pkcs, SilcUInt32 *len)
1000 totlen = 2 + strlen(pkcs) + prv_len;
1001 buf = silc_buffer_alloc_size(totlen);
1005 silc_buffer_format(buf,
1006 SILC_STR_UI_SHORT(strlen(pkcs)),
1007 SILC_STR_UI32_STRING(pkcs),
1008 SILC_STR_UI_XNSTRING(prv, prv_len),
1011 ret = silc_buffer_steal(buf, len);
1012 silc_buffer_free(buf);
1016 /* Decodes SILC style private key. Returns TRUE if the decoding was
1017 successful. Allocates new private key as well. */
1019 bool silc_pkcs_private_key_decode(unsigned char *data, SilcUInt32 data_len,
1020 SilcPrivateKey *private_key)
1022 SilcBufferStruct buf;
1024 SilcUInt16 pkcs_len;
1026 unsigned char *pkcs_name = NULL, *key_data = NULL;
1029 silc_buffer_set(&buf, data, data_len);
1031 /* Get algorithm name and identifier */
1033 silc_buffer_unformat(&buf,
1034 SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
1037 SILC_LOG_DEBUG(("Cannot decode private key buffer"));
1041 if (pkcs_len < 1 || pkcs_len > buf.truelen) {
1042 SILC_LOG_DEBUG(("Malformed private key buffer"));
1046 /* See if we support this algorithm (check only if PKCS are registered). */
1047 if (SILC_PKCS_LIST && !silc_pkcs_is_supported(pkcs_name)) {
1048 SILC_LOG_DEBUG(("Unknown PKCS `%s'", pkcs_name));
1052 /* Get key data. We assume that rest of the buffer is key data. */
1053 silc_buffer_pull(&buf, 2 + pkcs_len);
1055 ret = silc_buffer_unformat(&buf,
1056 SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
1061 /* Try to set the key. If this fails the key must be malformed. This
1062 code assumes that the PKCS routine checks the format of the key.
1063 (check only if PKCS are registered) */
1064 if (SILC_PKCS_LIST) {
1065 silc_pkcs_alloc(pkcs_name, &alg);
1066 if (!alg->pkcs->set_private_key(alg->context, key_data, key_len)) {
1067 SILC_LOG_DEBUG(("Could not set private key data"));
1070 silc_pkcs_free(alg);
1074 *private_key = silc_calloc(1, sizeof(**private_key));
1075 (*private_key)->name = pkcs_name;
1076 (*private_key)->prv = key_data;
1077 (*private_key)->prv_len = key_len;
1083 silc_free(pkcs_name);
1084 silc_free(key_data);
1088 /* Internal routine to save public key */
1090 static bool silc_pkcs_save_public_key_internal(const char *filename,
1091 unsigned char *data,
1092 SilcUInt32 data_len,
1093 SilcUInt32 encoding)
1097 unsigned char *tmp = NULL;
1100 case SILC_PKCS_FILE_BIN:
1102 case SILC_PKCS_FILE_PEM:
1103 tmp = data = silc_pem_encode_file(data, data_len);
1104 data_len = strlen(data);
1108 len = data_len + (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
1109 strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
1110 buf = silc_buffer_alloc_size(len);
1116 silc_buffer_format(buf,
1117 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
1118 SILC_STR_UI_XNSTRING(data, data_len),
1119 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END),
1122 /* Save into file */
1123 if (silc_file_writefile(filename, buf->data, buf->len)) {
1125 silc_buffer_free(buf);
1130 silc_buffer_free(buf);
1134 /* Saves public key into file */
1136 bool silc_pkcs_save_public_key(const char *filename, SilcPublicKey public_key,
1137 SilcUInt32 encoding)
1139 unsigned char *data;
1140 SilcUInt32 data_len;
1143 data = silc_pkcs_public_key_encode(public_key, &data_len);
1144 ret = silc_pkcs_save_public_key_internal(filename, data, data_len,
1150 /* Saves public key into file */
1152 bool silc_pkcs_save_public_key_data(const char *filename, unsigned char *data,
1153 SilcUInt32 data_len, SilcUInt32 encoding)
1155 return silc_pkcs_save_public_key_internal(filename, data, data_len,
1159 #define SILC_PKCS_PRIVATE_KEY_MAGIC 0x738df531
1161 /* Internal routine to save private key. */
1163 static bool silc_pkcs_save_private_key_internal(const char *filename,
1164 unsigned char *data,
1165 SilcUInt32 data_len,
1168 SilcUInt32 encoding)
1173 SilcBuffer buf, enc;
1174 SilcUInt32 len, blocklen, padlen;
1175 unsigned char tmp[32], keymat[64];
1178 memset(tmp, 0, sizeof(tmp));
1179 memset(keymat, 0, sizeof(keymat));
1181 /* Allocate the AES cipher */
1182 if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
1183 SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
1186 blocklen = silc_cipher_get_block_len(aes);
1187 if (blocklen * 2 > sizeof(tmp))
1190 /* Allocate SHA1 hash */
1191 if (!silc_hash_alloc("sha1", &sha1)) {
1192 SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered"));
1193 silc_cipher_free(aes);
1198 if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
1199 SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
1200 silc_hash_free(sha1);
1201 silc_cipher_free(aes);
1205 /* Derive the encryption key from the provided key material. The key
1206 is 256 bits length, and derived by taking hash of the data, then
1207 re-hashing the data and the previous digest, and using the first and
1208 second digest as the key. */
1209 silc_hash_init(sha1);
1210 silc_hash_update(sha1, key, key_len);
1211 silc_hash_final(sha1, keymat);
1212 silc_hash_init(sha1);
1213 silc_hash_update(sha1, key, key_len);
1214 silc_hash_update(sha1, keymat, 16);
1215 silc_hash_final(sha1, keymat + 16);
1217 /* Set the key to the cipher */
1218 silc_cipher_set_key(aes, keymat, 256);
1220 /* Encode the buffer to be encrypted. Add padding to it too, at least
1221 block size of the cipher. */
1223 /* Allocate buffer for encryption */
1224 len = silc_hmac_len(sha1hmac);
1225 padlen = 16 + (16 - ((data_len + 4) % blocklen));
1226 enc = silc_buffer_alloc_size(4 + 4 + data_len + padlen + len);
1228 silc_hmac_free(sha1hmac);
1229 silc_hash_free(sha1);
1230 silc_cipher_free(aes);
1234 /* Generate padding */
1235 for (i = 0; i < padlen; i++)
1236 tmp[i] = silc_rng_global_get_byte_fast();
1238 /* Put magic number */
1239 SILC_PUT32_MSB(SILC_PKCS_PRIVATE_KEY_MAGIC, enc->data);
1240 silc_buffer_pull(enc, 4);
1242 /* Encode the buffer */
1243 silc_buffer_format(enc,
1244 SILC_STR_UI_INT(data_len),
1245 SILC_STR_UI_XNSTRING(data, data_len),
1246 SILC_STR_UI_XNSTRING(tmp, padlen),
1250 silc_cipher_encrypt(aes, enc->data, enc->data, enc->len - len,
1251 silc_cipher_get_iv(aes));
1253 silc_buffer_push(enc, 4);
1255 /* Compute HMAC over the encrypted data and append the MAC to data.
1256 The key is the first digest of the original key material. */
1257 data_len = enc->len - len;
1258 silc_hmac_init_with_key(sha1hmac, keymat, 16);
1259 silc_hmac_update(sha1hmac, enc->data, data_len);
1260 silc_buffer_pull(enc, data_len);
1261 silc_hmac_final(sha1hmac, enc->data, NULL);
1262 silc_buffer_push(enc, data_len);
1265 memset(keymat, 0, sizeof(keymat));
1266 memset(tmp, 0, sizeof(tmp));
1267 silc_hmac_free(sha1hmac);
1268 silc_hash_free(sha1);
1269 silc_cipher_free(aes);
1272 data_len = enc->len;
1275 case SILC_PKCS_FILE_BIN:
1277 case SILC_PKCS_FILE_PEM:
1278 data = silc_pem_encode_file(data, data_len);
1279 data_len = strlen(data);
1283 /* Encode the data and save to file */
1284 len = data_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
1285 strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
1286 buf = silc_buffer_alloc_size(len);
1287 silc_buffer_format(buf,
1288 SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
1289 SILC_STR_UI_XNSTRING(data, data_len),
1290 SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
1293 /* Save into a file */
1294 if (silc_file_writefile_mode(filename, buf->data, buf->len, 0600)) {
1295 silc_buffer_clear(buf);
1296 silc_buffer_free(buf);
1297 silc_buffer_clear(enc);
1298 silc_buffer_free(enc);
1302 silc_buffer_clear(buf);
1303 silc_buffer_free(buf);
1304 silc_buffer_clear(enc);
1305 silc_buffer_free(enc);
1309 /* Saves private key into file. */
1311 bool silc_pkcs_save_private_key(const char *filename,
1312 SilcPrivateKey private_key,
1313 unsigned char *passphrase,
1314 SilcUInt32 passphrase_len,
1315 SilcUInt32 encoding)
1317 unsigned char *data;
1318 SilcUInt32 data_len;
1321 data = silc_pkcs_private_key_encode(private_key, &data_len);
1322 ret = silc_pkcs_save_private_key_internal(filename, data, data_len,
1323 passphrase, passphrase_len,
1325 memset(data, 0, data_len);
1330 /* Loads public key from file and allocates new public key. Returns TRUE
1331 if loading was successful. */
1333 bool silc_pkcs_load_public_key(const char *filename, SilcPublicKey *public_key,
1334 SilcUInt32 encoding)
1336 unsigned char *cp, *old, *data, byte;
1337 SilcUInt32 i, data_len, len;
1339 SILC_LOG_DEBUG(("Loading public key `%s' with %s encoding", filename,
1340 encoding == SILC_PKCS_FILE_PEM ? "Base64" :
1341 encoding == SILC_PKCS_FILE_BIN ? "Binary" : "Unkonwn"));
1343 old = data = silc_file_readfile(filename, &data_len);
1347 /* Check start of file and remove header from the data. */
1348 len = strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN);
1350 for (i = 0; i < len; i++) {
1353 if (byte != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i]) {
1354 memset(old, 0, data_len);
1361 /* Decode public key */
1363 len = data_len - (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
1364 strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
1367 case SILC_PKCS_FILE_BIN:
1369 case SILC_PKCS_FILE_PEM:
1370 data = silc_pem_decode(data, len, &len);
1371 memset(old, 0, data_len);
1378 if (!data || !silc_pkcs_public_key_decode(data, len, public_key)) {
1379 memset(old, 0, data_len);
1385 memset(old, 0, data_len);
1390 /* Load private key from file and allocates new private key. Returns TRUE
1391 if loading was successful. */
1393 bool silc_pkcs_load_private_key(const char *filename,
1394 SilcPrivateKey *private_key,
1395 unsigned char *passphrase,
1396 SilcUInt32 passphrase_len,
1397 SilcUInt32 encoding)
1402 SilcUInt32 blocklen;
1403 unsigned char tmp[32], keymat[64];
1404 unsigned char *cp, *old, *data, byte;
1405 SilcUInt32 i, data_len, len, magic, mac_len;
1407 SILC_LOG_DEBUG(("Loading private key `%s' with %s encoding", filename,
1408 encoding == SILC_PKCS_FILE_PEM ? "Base64" :
1409 encoding == SILC_PKCS_FILE_BIN ? "Binary" : "Unkonwn"));
1411 old = data = silc_file_readfile(filename, &data_len);
1415 /* Check start of file and remove header from the data. */
1416 len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
1418 for (i = 0; i < len; i++) {
1421 if (byte != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i]) {
1422 memset(old, 0, data_len);
1429 /* Decode private key */
1430 len = data_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
1431 strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
1434 case SILC_PKCS_FILE_BIN:
1436 case SILC_PKCS_FILE_PEM:
1437 data = silc_pem_decode(data, len, &len);
1439 memset(old, 0, data_len);
1446 memset(tmp, 0, sizeof(tmp));
1447 memset(keymat, 0, sizeof(keymat));
1449 /* Private key files without the specific magic number are assumed
1450 to be the old-style private keys that are not encrypted. */
1451 SILC_GET32_MSB(magic, data);
1452 if (magic != SILC_PKCS_PRIVATE_KEY_MAGIC) {
1453 SILC_LOG_DEBUG(("Private key does not have correct magic!"));
1455 /* Now decode the actual private key */
1456 if (!silc_pkcs_private_key_decode(data, len, private_key)) {
1457 memset(old, 0, data_len);
1462 memset(old, 0, data_len);
1467 /* Allocate the AES cipher */
1468 if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
1469 SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
1470 memset(old, 0, data_len);
1474 blocklen = silc_cipher_get_block_len(aes);
1475 if (blocklen * 2 > sizeof(tmp)) {
1476 memset(old, 0, data_len);
1481 /* Allocate SHA1 hash */
1482 if (!silc_hash_alloc("sha1", &sha1)) {
1483 SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered"));
1484 silc_cipher_free(aes);
1485 memset(old, 0, data_len);
1491 if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
1492 SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
1493 silc_hash_free(sha1);
1494 silc_cipher_free(aes);
1495 memset(old, 0, data_len);
1500 /* Derive the decryption key from the provided key material. The key
1501 is 256 bits length, and derived by taking hash of the data, then
1502 re-hashing the data and the previous digest, and using the first and
1503 second digest as the key. */
1504 silc_hash_init(sha1);
1505 silc_hash_update(sha1, passphrase, passphrase_len);
1506 silc_hash_final(sha1, keymat);
1507 silc_hash_init(sha1);
1508 silc_hash_update(sha1, passphrase, passphrase_len);
1509 silc_hash_update(sha1, keymat, 16);
1510 silc_hash_final(sha1, keymat + 16);
1512 /* Set the key to the cipher */
1513 silc_cipher_set_key(aes, keymat, 256);
1515 /* First, verify the MAC of the private key data */
1516 mac_len = silc_hmac_len(sha1hmac);
1517 silc_hmac_init_with_key(sha1hmac, keymat, 16);
1518 silc_hmac_update(sha1hmac, data, len - mac_len);
1519 silc_hmac_final(sha1hmac, tmp, NULL);
1520 if (memcmp(tmp, data + (len - mac_len), mac_len)) {
1521 SILC_LOG_DEBUG(("Integrity check for private key failed"));
1522 memset(keymat, 0, sizeof(keymat));
1523 memset(tmp, 0, sizeof(tmp));
1524 silc_hmac_free(sha1hmac);
1525 silc_hash_free(sha1);
1526 silc_cipher_free(aes);
1527 memset(old, 0, data_len);
1534 /* Decrypt the private key buffer */
1535 silc_cipher_decrypt(aes, data, data, len - mac_len, NULL);
1536 SILC_GET32_MSB(i, data);
1538 SILC_LOG_DEBUG(("Bad private key length in buffer!"));
1539 memset(keymat, 0, sizeof(keymat));
1540 memset(tmp, 0, sizeof(tmp));
1541 silc_hmac_free(sha1hmac);
1542 silc_hash_free(sha1);
1543 silc_cipher_free(aes);
1544 memset(old, 0, data_len);
1552 memset(keymat, 0, sizeof(keymat));
1553 memset(tmp, 0, sizeof(tmp));
1554 silc_hmac_free(sha1hmac);
1555 silc_hash_free(sha1);
1556 silc_cipher_free(aes);
1558 /* Now decode the actual private key */
1559 if (!silc_pkcs_private_key_decode(data, len, private_key)) {
1560 memset(old, 0, data_len);
1565 memset(old, 0, data_len);