5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2007 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.
23 /****************************** Key generation *******************************/
25 /* Generate new SILC key pair. */
27 SilcBool silc_pkcs_silc_generate_key(const char *algorithm,
28 SilcUInt32 bits_key_len,
29 const char *identifier,
31 SilcPublicKey *ret_public_key,
32 SilcPrivateKey *ret_private_key)
34 SilcSILCPublicKey pubkey;
35 SilcSILCPrivateKey privkey;
36 const SilcPKCSAlgorithm *alg;
37 const SilcPKCSObject *pkcs;
40 SILC_LOG_DEBUG(("Generating SILC %s key pair with key length %d bits",
41 algorithm, bits_key_len));
46 pkcs = silc_pkcs_find_pkcs(SILC_PKCS_SILC);
50 /* Allocate SILC public key */
51 pubkey = silc_calloc(1, sizeof(*pubkey));
55 /* Decode identifier */
56 if (!silc_pkcs_silc_decode_identifier(identifier, &pubkey->identifier))
59 if (pubkey->identifier.version && atoi(pubkey->identifier.version) >= 2)
64 /* Allocate algorithm */
65 alg = silc_pkcs_find_algorithm(algorithm, (version == 1 ? "pkcs1-no-oid" :
73 /* Allocate SILC private key */
74 privkey = silc_calloc(1, sizeof(*privkey));
81 /* Allocate public key */
82 *ret_public_key = silc_calloc(1, sizeof(**ret_public_key));
83 if (!(*ret_public_key)) {
88 (*ret_public_key)->pkcs = pkcs;
89 (*ret_public_key)->public_key = pubkey;
91 /* Allocate private key */
92 *ret_private_key = silc_calloc(1, sizeof(**ret_private_key));
93 if (!(*ret_private_key)) {
96 silc_free(*ret_public_key);
99 (*ret_private_key)->pkcs = pkcs;
100 (*ret_private_key)->private_key = privkey;
102 /* Generate the algorithm key pair */
103 if (!alg->generate_key(bits_key_len, rng, &pubkey->public_key,
104 &privkey->private_key)) {
107 silc_free(*ret_public_key);
108 silc_free(*ret_private_key);
116 /**************************** Utility functions ******************************/
118 /* Decodes the provided `identifier' */
120 SilcBool silc_pkcs_silc_decode_identifier(const char *identifier,
121 SilcPublicKeyIdentifier ident)
126 /* Protocol says that at least UN and HN must be provided as identifier */
127 if (!strstr(identifier, "UN=") && !strstr(identifier, "HN=")) {
128 SILC_LOG_DEBUG(("The public does not have the required UN= and HN= "
133 cp = (char *)identifier;
135 len = strcspn(cp, ",");
140 if (len - 1 >= 0 && cp[len - 1] == '\\') {
142 if (len + 1 > strlen(cp)) {
147 len = strcspn(cp, ",") + len;
152 if (len - 1 >= 0 && cp[len - 1] != '\\')
160 item = silc_calloc(len + 1, sizeof(char));
163 if (len > strlen(cp))
165 memcpy(item, cp, len);
167 if (strstr(item, "UN="))
168 ident->username = strdup(item + strcspn(cp, "=") + 1);
169 else if (strstr(item, "HN="))
170 ident->host = strdup(item + strcspn(cp, "=") + 1);
171 else if (strstr(item, "RN="))
172 ident->realname = strdup(item + strcspn(cp, "=") + 1);
173 else if (strstr(item, "E="))
174 ident->email = strdup(item + strcspn(cp, "=") + 1);
175 else if (strstr(item, "O="))
176 ident->org = strdup(item + strcspn(cp, "=") + 1);
177 else if (strstr(item, "C="))
178 ident->country = strdup(item + strcspn(cp, "=") + 1);
179 else if (strstr(item, "V="))
180 ident->version = strdup(item + strcspn(cp, "=") + 1);
195 /* Encodes and returns SILC public key identifier. If some of the
196 arguments is NULL those are not encoded into the identifier string.
197 Protocol says that at least username and host must be provided. */
199 char *silc_pkcs_silc_encode_identifier(char *username, char *host,
200 char *realname, char *email,
201 char *org, char *country,
204 SilcBufferStruct buf;
207 if (!username || !host)
209 if (strlen(username) < 3 || strlen(host) < 3)
212 memset(&buf, 0, sizeof(buf));
215 silc_buffer_format(&buf,
217 SILC_STR_UI32_STRING("UN="),
218 SILC_STR_UI32_STRING(username),
222 silc_buffer_format(&buf,
224 SILC_STR_UI32_STRING(", "),
225 SILC_STR_UI32_STRING("HN="),
226 SILC_STR_UI32_STRING(host),
230 silc_buffer_format(&buf,
232 SILC_STR_UI32_STRING(", "),
233 SILC_STR_UI32_STRING("RN="),
234 SILC_STR_UI32_STRING(realname),
238 silc_buffer_format(&buf,
240 SILC_STR_UI32_STRING(", "),
241 SILC_STR_UI32_STRING("E="),
242 SILC_STR_UI32_STRING(email),
246 silc_buffer_format(&buf,
248 SILC_STR_UI32_STRING(", "),
249 SILC_STR_UI32_STRING("O="),
250 SILC_STR_UI32_STRING(org),
254 silc_buffer_format(&buf,
256 SILC_STR_UI32_STRING(", "),
257 SILC_STR_UI32_STRING("C="),
258 SILC_STR_UI32_STRING(country),
262 if (strlen(version) > 1 || !isdigit(version[0])) {
263 silc_buffer_purge(&buf);
266 silc_buffer_format(&buf,
268 SILC_STR_UI32_STRING(", "),
269 SILC_STR_UI32_STRING("V="),
270 SILC_STR_UI32_STRING(version),
274 silc_buffer_format(&buf, SILC_STR_UI_CHAR(0), SILC_STR_END);
276 identifier = silc_buffer_steal(&buf, NULL);
280 /* Return SILC public key version */
282 int silc_pkcs_silc_public_key_version(SilcPublicKey public_key)
284 SilcSILCPublicKey silc_pubkey;
286 if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC)
289 silc_pubkey = public_key->public_key;
291 /* If version identifire is not present it is version 1. */
292 if (!silc_pubkey->identifier.version)
295 return atoi(silc_pubkey->identifier.version);
298 /*************************** Public key routines *****************************/
300 /* Returns PKCS algorithm context */
302 const SilcPKCSAlgorithm *silc_pkcs_silc_get_algorithm(void *public_key)
304 SilcSILCPublicKey silc_pubkey = public_key;
305 return silc_pubkey->pkcs;
308 /* Imports SILC protocol style public key from SILC public key file */
310 SilcBool silc_pkcs_silc_import_public_key_file(unsigned char *filedata,
311 SilcUInt32 filedata_len,
312 SilcPKCSFileEncoding encoding,
313 void **ret_public_key)
316 unsigned char *data = NULL;
319 SILC_LOG_DEBUG(("Parsing SILC public key file"));
324 /* Check start of file and remove header from the data. */
325 len = strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN);
326 if (filedata_len < len + strlen(SILC_PKCS_PUBLIC_KEYFILE_END)) {
327 SILC_LOG_ERROR(("Malformed SILC public key header"));
330 for (i = 0; i < len; i++) {
331 if (*filedata != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i]) {
332 SILC_LOG_ERROR(("Malformed SILC public key header"));
337 filedata_len -= (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
338 strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
341 case SILC_PKCS_FILE_BIN:
344 case SILC_PKCS_FILE_BASE64:
345 data = silc_base64_decode(filedata, filedata_len, &filedata_len);
352 ret = silc_pkcs_silc_import_public_key(filedata, filedata_len,
356 return ret ? TRUE : FALSE;
359 /* Imports SILC protocol style public key */
361 int silc_pkcs_silc_import_public_key(unsigned char *key,
363 void **ret_public_key)
365 const SilcPKCSAlgorithm *pkcs;
366 SilcBufferStruct buf, alg_key;
367 SilcSILCPublicKey silc_pubkey = NULL;
368 SilcAsn1 asn1 = NULL;
369 SilcUInt32 totlen, keydata_len;
370 SilcUInt16 pkcs_len, identifier_len;
371 unsigned char *pkcs_name = NULL, *ident = NULL, *key_data = NULL;
374 SILC_LOG_DEBUG(("Parsing SILC public key"));
379 silc_buffer_set(&buf, key, key_len);
382 ret = silc_buffer_unformat(&buf,
384 SILC_STR_UI_INT(&totlen),
389 /* Backwards compatibility */
390 if (totlen == key_len)
393 if (totlen + 4 != key_len)
396 /* Get algorithm name and identifier */
398 silc_buffer_unformat(&buf,
400 SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
401 SILC_STR_UI16_NSTRING_ALLOC(&ident, &identifier_len),
406 if (pkcs_len < 1 || identifier_len < 3 ||
407 pkcs_len + identifier_len > totlen)
411 keydata_len = silc_buffer_len(&buf);
412 ret = silc_buffer_unformat(&buf,
413 SILC_STR_DATA(&key_data, keydata_len),
418 /* Allocate SILC public key context */
419 silc_pubkey = silc_calloc(1, sizeof(*silc_pubkey));
423 /* Decode SILC identifier */
424 if (!silc_pkcs_silc_decode_identifier(ident, &silc_pubkey->identifier))
427 asn1 = silc_asn1_alloc();
431 SILC_LOG_DEBUG(("Public key version %s",
432 (!silc_pubkey->identifier.version ? "1" :
433 silc_pubkey->identifier.version)));
435 if (!strcmp(pkcs_name, "rsa")) {
436 /* Parse the SILC RSA public key */
437 SilcUInt32 e_len, n_len;
440 /* Get PKCS object. Different PKCS #1 scheme is used with different
442 if (!silc_pubkey->identifier.version ||
443 atoi(silc_pubkey->identifier.version) <= 1) {
445 pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1-no-oid");
447 /* Version 2 and newer */
448 pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1");
451 SILC_LOG_DEBUG(("Unsupported PKCS algorithm: rsa"));
454 silc_pubkey->pkcs = pkcs;
458 SILC_GET32_MSB(e_len, key_data);
459 if (!e_len || e_len + 4 > keydata_len)
462 silc_mp_bin2mp(key_data + 4, e_len, &e);
463 if (keydata_len < 4 + e_len + 4) {
467 SILC_GET32_MSB(n_len, key_data + 4 + e_len);
468 if (!n_len || e_len + 4 + n_len + 4 > keydata_len) {
473 silc_mp_bin2mp(key_data + 4 + e_len + 4, n_len, &n);
475 /* Encode to PKCS #1 format */
476 memset(&alg_key, 0, sizeof(alg_key));
477 if (!silc_asn1_encode(asn1, &alg_key,
481 SILC_ASN1_END, SILC_ASN1_END)) {
490 } else if (!strcmp(pkcs_name, "dsa")) {
491 SILC_NOT_IMPLEMENTED("DSA SILC Public Key");
495 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
499 /* Import PKCS algorithm public key */
500 if (!pkcs->import_public_key(alg_key.data, silc_buffer_len(&alg_key),
501 &silc_pubkey->public_key))
504 silc_free(pkcs_name);
506 silc_asn1_free(asn1);
508 *ret_public_key = silc_pubkey;
513 silc_free(pkcs_name);
515 silc_free(silc_pubkey);
517 silc_asn1_free(asn1);
521 /* Exports public key as SILC protocol style public key file */
524 silc_pkcs_silc_export_public_key_file(void *public_key,
525 SilcPKCSFileEncoding encoding,
529 unsigned char *key, *data;
532 SILC_LOG_DEBUG(("Encoding SILC public key file"));
535 key = silc_pkcs_silc_export_public_key(public_key, &key_len);
540 case SILC_PKCS_FILE_BIN:
543 case SILC_PKCS_FILE_BASE64:
544 data = silc_base64_encode_file(key, key_len);
549 key_len = strlen(data);
553 /* Encode SILC public key file */
554 buf = silc_buffer_alloc_size(key_len +
555 (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
556 strlen(SILC_PKCS_PUBLIC_KEYFILE_END)));
562 if (silc_buffer_format(buf,
563 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
564 SILC_STR_UI_XNSTRING(key, key_len),
565 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END),
567 silc_buffer_free(buf);
573 key = silc_buffer_steal(buf, ret_len);
574 silc_buffer_free(buf);
579 /* Exports public key as SILC protocol style public key */
581 unsigned char *silc_pkcs_silc_export_public_key(void *public_key,
584 SilcSILCPublicKey silc_pubkey = public_key;
585 const SilcPKCSAlgorithm *pkcs = silc_pubkey->pkcs;
586 SilcBufferStruct alg_key;
587 SilcBuffer buf = NULL;
588 SilcAsn1 asn1 = NULL;
589 unsigned char *pk = NULL, *key = NULL, *ret;
590 SilcUInt32 pk_len, key_len, totlen;
593 SILC_LOG_DEBUG(("Encoding SILC public key"));
595 /* Export PKCS algorithm public key */
596 if (pkcs->export_public_key)
597 pk = pkcs->export_public_key(silc_pubkey->public_key, &pk_len);
600 silc_buffer_set(&alg_key, pk, pk_len);
602 /* Encode identifier */
604 silc_pkcs_silc_encode_identifier(silc_pubkey->identifier.username,
605 silc_pubkey->identifier.host,
606 silc_pubkey->identifier.realname,
607 silc_pubkey->identifier.email,
608 silc_pubkey->identifier.org,
609 silc_pubkey->identifier.country,
610 silc_pubkey->identifier.version);
614 asn1 = silc_asn1_alloc();
618 if (!strcmp(pkcs->name, "rsa")) {
619 /* Parse the PKCS #1 public key */
621 SilcUInt32 n_len, e_len;
622 unsigned char *nb, *eb;
624 memset(&n, 0, sizeof(n));
625 memset(&e, 0, sizeof(e));
626 if (!silc_asn1_decode(asn1, &alg_key,
630 SILC_ASN1_END, SILC_ASN1_END))
633 /* Encode to SILC RSA public key */
634 eb = silc_mp_mp2bin(&e, 0, &e_len);
637 nb = silc_mp_mp2bin(&n, 0, &n_len);
640 key_len = e_len + 4 + n_len + 4;
641 key = silc_calloc(key_len, sizeof(*key));
645 /* Put e length and e */
646 SILC_PUT32_MSB(e_len, key);
647 memcpy(key + 4, eb, e_len);
649 /* Put n length and n. */
650 SILC_PUT32_MSB(n_len, key + 4 + e_len);
651 memcpy(key + 4 + e_len + 4, nb, n_len);
656 } else if (!strcmp(pkcs->name, "dsa")) {
657 SILC_NOT_IMPLEMENTED("SILC DSA Public Key");
661 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
665 /* Encode SILC Public Key */
666 totlen = 2 + strlen(pkcs->name) + 2 + strlen(identifier) + key_len;
667 buf = silc_buffer_alloc_size(totlen + 4);
670 if (silc_buffer_format(buf,
671 SILC_STR_UI_INT(totlen),
672 SILC_STR_UI_SHORT(strlen(pkcs->name)),
673 SILC_STR_UI32_STRING(pkcs->name),
674 SILC_STR_UI_SHORT(strlen(identifier)),
675 SILC_STR_UI32_STRING(identifier),
676 SILC_STR_UI_XNSTRING(key, key_len),
680 ret = silc_buffer_steal(buf, ret_len);
681 silc_buffer_free(buf);
683 silc_free(identifier);
684 silc_buffer_purge(&alg_key);
685 silc_asn1_free(asn1);
690 silc_free(identifier);
694 silc_buffer_free(buf);
696 silc_asn1_free(asn1);
700 /* Return key length */
702 SilcUInt32 silc_pkcs_silc_public_key_bitlen(void *public_key)
704 SilcSILCPublicKey silc_pubkey = public_key;
705 return silc_pubkey->pkcs->public_key_bitlen(silc_pubkey->public_key);
708 /* Copy public key */
710 void *silc_pkcs_silc_public_key_copy(void *public_key)
712 SilcSILCPublicKey silc_pubkey = public_key, new_pubkey;
713 SilcPublicKeyIdentifier ident = &silc_pubkey->identifier;
715 new_pubkey = silc_calloc(1, sizeof(*new_pubkey));
718 new_pubkey->pkcs = silc_pubkey->pkcs;
720 new_pubkey->public_key =
721 silc_pubkey->pkcs->public_key_copy(silc_pubkey->public_key);
722 if (!new_pubkey->public_key) {
723 silc_free(new_pubkey);
728 new_pubkey->identifier.username =
729 silc_memdup(ident->username, strlen(ident->username));
731 new_pubkey->identifier.host =
732 silc_memdup(ident->host, strlen(ident->host));
734 new_pubkey->identifier.realname =
735 silc_memdup(ident->realname, strlen(ident->realname));
737 new_pubkey->identifier.email =
738 silc_memdup(ident->email, strlen(ident->email));
740 new_pubkey->identifier.org =
741 silc_memdup(ident->org, strlen(ident->org));
743 new_pubkey->identifier.country =
744 silc_memdup(ident->country, strlen(ident->country));
746 new_pubkey->identifier.version =
747 silc_memdup(ident->version, strlen(ident->version));
752 /* Compares public keys */
754 SilcBool silc_pkcs_silc_public_key_compare(void *key1, void *key2)
756 SilcSILCPublicKey k1 = key1, k2 = key2;
758 if (strcmp(k1->pkcs->name, k2->pkcs->name))
761 if ((k1->identifier.username && !k2->identifier.username) ||
762 (!k1->identifier.username && k2->identifier.username) ||
763 (k1->identifier.username && k2->identifier.username &&
764 strcmp(k1->identifier.username, k2->identifier.username)))
767 if ((k1->identifier.host && !k2->identifier.host) ||
768 (!k1->identifier.host && k2->identifier.host) ||
769 (k1->identifier.host && k2->identifier.host &&
770 strcmp(k1->identifier.host, k2->identifier.host)))
773 if ((k1->identifier.realname && !k2->identifier.realname) ||
774 (!k1->identifier.realname && k2->identifier.realname) ||
775 (k1->identifier.realname && k2->identifier.realname &&
776 strcmp(k1->identifier.realname, k2->identifier.realname)))
779 if ((k1->identifier.email && !k2->identifier.email) ||
780 (!k1->identifier.email && k2->identifier.email) ||
781 (k1->identifier.email && k2->identifier.email &&
782 strcmp(k1->identifier.email, k2->identifier.email)))
785 if ((k1->identifier.org && !k2->identifier.org) ||
786 (!k1->identifier.org && k2->identifier.org) ||
787 (k1->identifier.org && k2->identifier.org &&
788 strcmp(k1->identifier.org, k2->identifier.org)))
791 if ((k1->identifier.country && !k2->identifier.country) ||
792 (!k1->identifier.country && k2->identifier.country) ||
793 (k1->identifier.country && k2->identifier.country &&
794 strcmp(k1->identifier.country, k2->identifier.country)))
797 if ((k1->identifier.version && !k2->identifier.version) ||
798 (!k1->identifier.version && k2->identifier.version) ||
799 (k1->identifier.version && k2->identifier.version &&
800 strcmp(k1->identifier.version, k2->identifier.version)))
803 return k1->pkcs->public_key_compare(k1->public_key, k2->public_key);
806 /* Frees public key */
808 void silc_pkcs_silc_public_key_free(void *public_key)
810 SilcSILCPublicKey silc_pubkey = public_key;
812 silc_pubkey->pkcs->public_key_free(silc_pubkey->public_key);
814 silc_free(silc_pubkey->identifier.username);
815 silc_free(silc_pubkey->identifier.host);
816 silc_free(silc_pubkey->identifier.realname);
817 silc_free(silc_pubkey->identifier.email);
818 silc_free(silc_pubkey->identifier.org);
819 silc_free(silc_pubkey->identifier.country);
820 silc_free(silc_pubkey->identifier.version);
821 silc_free(silc_pubkey);
825 /*************************** Private key routines ****************************/
827 /* Private key file magic */
828 #define SILC_PKCS_PRIVATE_KEY_MAGIC 0x738df531
830 /* Imports SILC implementation style private key file */
832 SilcBool silc_pkcs_silc_import_private_key_file(unsigned char *filedata,
833 SilcUInt32 filedata_len,
834 const char *passphrase,
835 SilcUInt32 passphrase_len,
836 SilcPKCSFileEncoding encoding,
837 void **ret_private_key)
843 unsigned char tmp[32], keymat[64], *data = NULL;
844 SilcUInt32 i, len, magic, mac_len;
847 SILC_LOG_DEBUG(("Parsing SILC private key file"));
849 /* Check start of file and remove header from the data. */
850 len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
851 if (filedata_len < len + strlen(SILC_PKCS_PRIVATE_KEYFILE_END)) {
852 SILC_LOG_ERROR(("Malformed SILC private key header"));
855 for (i = 0; i < len; i++) {
856 if (*filedata != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i]) {
857 SILC_LOG_ERROR(("Malformed SILC private key header"));
863 len = filedata_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
864 strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
867 case SILC_PKCS_FILE_BIN:
870 case SILC_PKCS_FILE_BASE64:
871 data = silc_base64_decode(filedata, filedata_len, &len);
878 memset(tmp, 0, sizeof(tmp));
879 memset(keymat, 0, sizeof(keymat));
881 /* Check file magic */
882 SILC_GET32_MSB(magic, filedata);
883 if (magic != SILC_PKCS_PRIVATE_KEY_MAGIC) {
884 SILC_LOG_DEBUG(("Private key does not have correct magic"));
888 /* Allocate the AES cipher */
889 if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
890 SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
893 blocklen = silc_cipher_get_block_len(aes);
894 if (blocklen * 2 > sizeof(tmp)) {
895 silc_cipher_free(aes);
899 /* Allocate SHA1 hash */
900 if (!silc_hash_alloc("sha1", &sha1)) {
901 SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered"));
902 silc_cipher_free(aes);
907 if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
908 SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
909 silc_hash_free(sha1);
910 silc_cipher_free(aes);
914 /* Derive the decryption key from the provided key material. The key
915 is 256 bits length, and derived by taking hash of the data, then
916 re-hashing the data and the previous digest, and using the first and
917 second digest as the key. */
918 silc_hash_init(sha1);
919 silc_hash_update(sha1, passphrase, passphrase_len);
920 silc_hash_final(sha1, keymat);
921 silc_hash_init(sha1);
922 silc_hash_update(sha1, passphrase, passphrase_len);
923 silc_hash_update(sha1, keymat, 16);
924 silc_hash_final(sha1, keymat + 16);
926 /* Set the key to the cipher */
927 silc_cipher_set_key(aes, keymat, 256, FALSE);
929 /* First, verify the MAC of the private key data */
930 mac_len = silc_hmac_len(sha1hmac);
931 silc_hmac_init_with_key(sha1hmac, keymat, 16);
932 silc_hmac_update(sha1hmac, filedata, len - mac_len);
933 silc_hmac_final(sha1hmac, tmp, NULL);
934 if (memcmp(tmp, filedata + (len - mac_len), mac_len)) {
935 SILC_LOG_DEBUG(("Integrity check for private key failed"));
936 memset(keymat, 0, sizeof(keymat));
937 memset(tmp, 0, sizeof(tmp));
938 silc_hmac_free(sha1hmac);
939 silc_hash_free(sha1);
940 silc_cipher_free(aes);
946 /* Decrypt the private key buffer */
947 silc_cipher_decrypt(aes, filedata, filedata, len - mac_len, NULL);
948 SILC_GET32_MSB(i, filedata);
950 SILC_LOG_DEBUG(("Bad private key length in buffer!"));
951 memset(keymat, 0, sizeof(keymat));
952 memset(tmp, 0, sizeof(tmp));
953 silc_hmac_free(sha1hmac);
954 silc_hash_free(sha1);
955 silc_cipher_free(aes);
962 memset(keymat, 0, sizeof(keymat));
963 memset(tmp, 0, sizeof(tmp));
964 silc_hmac_free(sha1hmac);
965 silc_hash_free(sha1);
966 silc_cipher_free(aes);
968 /* Import the private key */
969 ret = silc_pkcs_silc_import_private_key(filedata, len, ret_private_key);
973 return ret ? TRUE : FALSE;
976 /* Private key version */
977 #define SILC_PRIVATE_KEY_VERSION_1 0x82171273
978 #define SILC_PRIVATE_KEY_VERSION_2 0xf911a3d1
980 /* Imports SILC implementation style private key */
982 int silc_pkcs_silc_import_private_key(unsigned char *key,
984 void **ret_private_key)
986 SilcBufferStruct buf;
987 const SilcPKCSAlgorithm *pkcs;
988 SilcBufferStruct alg_key;
989 SilcSILCPrivateKey silc_privkey = NULL;
990 SilcAsn1 asn1 = NULL;
992 SilcUInt32 keydata_len;
993 unsigned char *pkcs_name = NULL, *key_data;
996 SILC_LOG_DEBUG(("Parsing SILC private key"));
998 if (!ret_private_key)
1001 silc_buffer_set(&buf, key, key_len);
1003 /* Get algorithm name and identifier */
1005 silc_buffer_unformat(&buf,
1006 SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
1009 SILC_LOG_DEBUG(("Cannot decode private key buffer"));
1013 if (pkcs_len < 1 || pkcs_len > silc_buffer_truelen(&buf)) {
1014 SILC_LOG_DEBUG(("Malformed private key buffer"));
1018 /* Get key data. We assume that rest of the buffer is key data. */
1019 silc_buffer_pull(&buf, 2 + pkcs_len);
1020 keydata_len = silc_buffer_len(&buf);
1021 ret = silc_buffer_unformat(&buf,
1022 SILC_STR_UI_XNSTRING(&key_data, keydata_len),
1027 /* Allocate SILC private key context */
1028 silc_privkey = silc_calloc(1, sizeof(*silc_privkey));
1032 asn1 = silc_asn1_alloc();
1036 if (!strcmp(pkcs_name, "rsa")) {
1037 /* Parse the RSA SILC private key */
1039 SilcMPInt n, e, d, dp, dq, qp, p, q;
1041 SilcUInt32 len, ver;
1043 if (keydata_len < 4)
1045 silc_buffer_set(&k, key_data, keydata_len);
1047 /* Get version. Key without the version is old style private key
1048 and we need to do some computation to get it to correct format. */
1049 if (silc_buffer_unformat(&k,
1050 SILC_STR_UI_INT(&ver),
1053 silc_buffer_pull(&k, 4);
1055 if (ver != SILC_PRIVATE_KEY_VERSION_1 &&
1056 ver != SILC_PRIVATE_KEY_VERSION_2) {
1060 if (silc_buffer_unformat(&k,
1061 SILC_STR_UI_INT(&len),
1064 silc_buffer_pull(&k, 4);
1067 /* Get PKCS object. Different PKCS #1 scheme is used with different
1069 if (ver == 0 || ver == SILC_PRIVATE_KEY_VERSION_1) {
1070 /* Version 0 and 1 */
1071 pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1-no-oid");
1073 /* Version 2 and newer */
1074 pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1");
1077 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
1080 silc_privkey->pkcs = pkcs;
1082 SILC_LOG_DEBUG(("Private key version %s",
1083 (ver == SILC_PRIVATE_KEY_VERSION_1 ? "1" :
1084 ver == SILC_PRIVATE_KEY_VERSION_2 ? "2" : "0")));
1087 if (silc_buffer_unformat(&k,
1088 SILC_STR_DATA(&tmp, len),
1092 silc_mp_bin2mp(tmp, len, &e);
1093 silc_buffer_pull(&k, len);
1096 if (silc_buffer_unformat(&k,
1097 SILC_STR_UI_INT(&len),
1100 silc_buffer_pull(&k, 4);
1101 if (silc_buffer_unformat(&k,
1102 SILC_STR_DATA(&tmp, len),
1106 silc_mp_bin2mp(tmp, len, &n);
1107 silc_buffer_pull(&k, len);
1110 if (silc_buffer_unformat(&k,
1111 SILC_STR_UI_INT(&len),
1114 silc_buffer_pull(&k, 4);
1115 if (silc_buffer_unformat(&k,
1116 SILC_STR_DATA(&tmp, len),
1120 silc_mp_bin2mp(tmp, len, &d);
1121 silc_buffer_pull(&k, len);
1124 if (silc_buffer_unformat(&k,
1125 SILC_STR_UI_INT(&len),
1128 silc_buffer_pull(&k, 4);
1129 if (silc_buffer_unformat(&k,
1130 SILC_STR_DATA(&tmp, len),
1134 silc_mp_bin2mp(tmp, len, &dp);
1135 silc_buffer_pull(&k, len);
1138 if (silc_buffer_unformat(&k,
1139 SILC_STR_UI_INT(&len),
1142 silc_buffer_pull(&k, 4);
1143 if (silc_buffer_unformat(&k,
1144 SILC_STR_DATA(&tmp, len),
1148 silc_mp_bin2mp(tmp, len, &dq);
1149 silc_buffer_pull(&k, len);
1155 if (silc_buffer_unformat(&k,
1156 SILC_STR_UI_INT(&len),
1159 silc_buffer_pull(&k, 4);
1160 if (silc_buffer_len(&k) < len)
1162 silc_buffer_pull(&k, len);
1165 if (silc_buffer_unformat(&k,
1166 SILC_STR_UI_INT(&len),
1169 silc_buffer_pull(&k, 4);
1170 if (silc_buffer_len(&k) < len)
1172 silc_buffer_pull(&k, len);
1177 if (silc_buffer_unformat(&k,
1178 SILC_STR_UI_INT(&len),
1181 silc_buffer_pull(&k, 4);
1182 if (silc_buffer_unformat(&k,
1183 SILC_STR_DATA(&tmp, len),
1187 silc_mp_bin2mp(tmp, len, &qp);
1188 silc_buffer_pull(&k, len);
1192 if (silc_buffer_unformat(&k,
1193 SILC_STR_UI_INT(&len),
1196 silc_buffer_pull(&k, 4);
1197 if (silc_buffer_unformat(&k,
1198 SILC_STR_DATA(&tmp, len),
1202 silc_mp_bin2mp(tmp, len, &p);
1203 silc_buffer_pull(&k, len);
1206 if (silc_buffer_unformat(&k,
1207 SILC_STR_UI_INT(&len),
1210 silc_buffer_pull(&k, 4);
1211 if (silc_buffer_unformat(&k,
1212 SILC_STR_DATA(&tmp, len),
1216 silc_mp_bin2mp(tmp, len, &q);
1217 silc_buffer_pull(&k, len);
1220 /* Old version. Compute to new version */
1221 SILC_LOG_DEBUG(("Old version private key"));
1223 silc_mp_modinv(&qp, &q, &p);
1226 /* Encode to PKCS #1 format */
1227 memset(&alg_key, 0, sizeof(alg_key));
1228 if (!silc_asn1_encode(asn1, &alg_key,
1230 SILC_ASN1_SHORT_INT(0),
1239 SILC_ASN1_END, SILC_ASN1_END))
1248 silc_mp_uninit(&dp);
1249 silc_mp_uninit(&dq);
1250 silc_mp_uninit(&qp);
1252 } else if (!strcmp(pkcs_name, "dsa")) {
1253 SILC_NOT_IMPLEMENTED("DSA SILC Private Key");
1257 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
1261 /* Import PKCS algorithm private key */
1262 if (!pkcs->import_private_key(alg_key.data, silc_buffer_len(&alg_key),
1263 &silc_privkey->private_key))
1266 silc_free(pkcs_name);
1267 silc_asn1_free(asn1);
1269 *ret_private_key = silc_privkey;
1274 silc_free(pkcs_name);
1275 silc_free(silc_privkey);
1277 silc_asn1_free(asn1);
1278 SILC_LOG_ERROR(("Malformed SILC private key "));
1282 /* Exports private key as SILC implementation style private key file */
1285 silc_pkcs_silc_export_private_key_file(void *private_key,
1286 const char *passphrase,
1287 SilcUInt32 passphrase_len,
1288 SilcPKCSFileEncoding encoding,
1290 SilcUInt32 *ret_len)
1295 SilcBuffer buf, enc;
1296 SilcUInt32 len, blocklen, padlen, key_len;
1297 unsigned char *key, *data;
1298 unsigned char tmp[32], keymat[64];
1301 SILC_LOG_DEBUG(("Encoding SILC private key file"));
1303 /* Export the private key */
1304 key = silc_pkcs_silc_export_private_key(private_key, &key_len);
1308 memset(tmp, 0, sizeof(tmp));
1309 memset(keymat, 0, sizeof(keymat));
1311 /* Allocate the AES cipher */
1312 if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
1313 SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
1317 blocklen = silc_cipher_get_block_len(aes);
1318 if (blocklen * 2 > sizeof(tmp)) {
1319 silc_cipher_free(aes);
1324 /* Allocate SHA1 hash */
1325 if (!silc_hash_alloc("sha1", &sha1)) {
1326 SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered"));
1327 silc_cipher_free(aes);
1332 if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
1333 SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
1334 silc_hash_free(sha1);
1335 silc_cipher_free(aes);
1339 /* Derive the encryption key from the provided key material. The key
1340 is 256 bits length, and derived by taking hash of the data, then
1341 re-hashing the data and the previous digest, and using the first and
1342 second digest as the key. */
1343 silc_hash_init(sha1);
1344 silc_hash_update(sha1, passphrase, passphrase_len);
1345 silc_hash_final(sha1, keymat);
1346 silc_hash_init(sha1);
1347 silc_hash_update(sha1, passphrase, passphrase_len);
1348 silc_hash_update(sha1, keymat, 16);
1349 silc_hash_final(sha1, keymat + 16);
1351 /* Set the key to the cipher */
1352 silc_cipher_set_key(aes, keymat, 256, TRUE);
1354 /* Encode the buffer to be encrypted. Add padding to it too, at least
1355 block size of the cipher. */
1357 /* Allocate buffer for encryption */
1358 len = silc_hmac_len(sha1hmac);
1359 padlen = 16 + (16 - ((key_len + 4) % blocklen));
1360 enc = silc_buffer_alloc_size(4 + 4 + key_len + padlen + len);
1362 silc_hmac_free(sha1hmac);
1363 silc_hash_free(sha1);
1364 silc_cipher_free(aes);
1368 /* Generate padding */
1369 for (i = 0; i < padlen; i++)
1370 tmp[i] = silc_rng_get_byte_fast(rng);
1372 /* Put magic number */
1373 SILC_PUT32_MSB(SILC_PKCS_PRIVATE_KEY_MAGIC, enc->data);
1374 silc_buffer_pull(enc, 4);
1376 /* Encode the buffer */
1377 silc_buffer_format(enc,
1378 SILC_STR_UI_INT(key_len),
1379 SILC_STR_UI_XNSTRING(key, key_len),
1380 SILC_STR_UI_XNSTRING(tmp, padlen),
1385 silc_cipher_encrypt(aes, enc->data, enc->data, silc_buffer_len(enc) - len,
1386 silc_cipher_get_iv(aes));
1388 silc_buffer_push(enc, 4);
1390 /* Compute HMAC over the encrypted data and append the MAC to data.
1391 The key is the first digest of the original key material. */
1392 key_len = silc_buffer_len(enc) - len;
1393 silc_hmac_init_with_key(sha1hmac, keymat, 16);
1394 silc_hmac_update(sha1hmac, enc->data, key_len);
1395 silc_buffer_pull(enc, key_len);
1396 silc_hmac_final(sha1hmac, enc->data, NULL);
1397 silc_buffer_push(enc, key_len);
1400 memset(keymat, 0, sizeof(keymat));
1401 memset(tmp, 0, sizeof(tmp));
1402 silc_hmac_free(sha1hmac);
1403 silc_hash_free(sha1);
1404 silc_cipher_free(aes);
1407 case SILC_PKCS_FILE_BIN:
1410 case SILC_PKCS_FILE_BASE64:
1411 data = silc_base64_encode_file(enc->data, silc_buffer_len(enc));
1413 silc_buffer_clear(enc);
1414 silc_buffer_free(enc);
1417 silc_free(silc_buffer_steal(enc, NULL));
1418 silc_buffer_set(enc, data, strlen(data));
1423 key_len = silc_buffer_len(enc);
1425 /* Encode the data and save to file */
1426 len = key_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
1427 strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
1428 buf = silc_buffer_alloc_size(len);
1430 silc_buffer_free(enc);
1433 silc_buffer_format(buf,
1434 SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
1435 SILC_STR_UI_XNSTRING(key, key_len),
1436 SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
1439 silc_buffer_free(enc);
1440 data = silc_buffer_steal(buf, ret_len);
1441 silc_buffer_free(buf);
1446 /* Exports private key as SILC implementation style private key */
1448 unsigned char *silc_pkcs_silc_export_private_key(void *private_key,
1449 SilcUInt32 *ret_len)
1451 SilcSILCPrivateKey silc_privkey = private_key;
1452 const SilcPKCSAlgorithm *pkcs = silc_privkey->pkcs;
1453 SilcBufferStruct alg_key;
1454 SilcBuffer buf = NULL;
1455 SilcAsn1 asn1 = NULL;
1456 unsigned char *prv = NULL, *key = NULL, *ret;
1457 SilcUInt32 prv_len, key_len, totlen;
1459 SILC_LOG_DEBUG(("Encoding SILC private key"));
1461 /* Export PKCS algorithm private key */
1462 if (pkcs->export_private_key)
1463 prv = pkcs->export_private_key(silc_privkey->private_key, &prv_len);
1466 silc_buffer_set(&alg_key, prv, prv_len);
1468 asn1 = silc_asn1_alloc();
1472 if (!strcmp(pkcs->name, "rsa")) {
1473 /* Parse the PKCS #1 private key */
1474 SilcMPInt n, e, d, dp, dq, qp, p, q;
1475 SilcUInt32 e_len, n_len, d_len, dp_len, dq_len,
1476 qp_len, p_len, q_len, len = 0;
1477 unsigned char *nb, *eb, *db, *dpb, *dqb, *qpb, *pb, *qb;
1479 if (!silc_asn1_decode(asn1, &alg_key,
1481 SILC_ASN1_INT(NULL),
1490 SILC_ASN1_END, SILC_ASN1_END))
1493 /* Encode to SILC RSA private key */
1494 eb = silc_mp_mp2bin(&e, 0, &e_len);
1495 nb = silc_mp_mp2bin(&n, 0, &n_len);
1496 db = silc_mp_mp2bin(&d, 0, &d_len);
1497 dpb = silc_mp_mp2bin(&dp, 0, &dp_len);
1498 dqb = silc_mp_mp2bin(&dq, 0, &dq_len);
1499 qpb = silc_mp_mp2bin(&qp, 0, &qp_len);
1500 pb = silc_mp_mp2bin(&p, 0, &p_len);
1501 qb = silc_mp_mp2bin(&q, 0, &q_len);
1502 len = 4 + e_len + 4 + n_len + 4 + d_len + 4+ dp_len + 4 +
1503 dq_len + 4 + qp_len + 4 + p_len + 4 + q_len + 4;
1505 buf = silc_buffer_alloc_size(len);
1508 if (silc_buffer_format(buf,
1509 SILC_STR_UI_INT(SILC_PRIVATE_KEY_VERSION_1),
1510 SILC_STR_UI_INT(e_len),
1511 SILC_STR_UI_XNSTRING(eb, e_len),
1512 SILC_STR_UI_INT(n_len),
1513 SILC_STR_UI_XNSTRING(nb, n_len),
1514 SILC_STR_UI_INT(d_len),
1515 SILC_STR_UI_XNSTRING(db, d_len),
1516 SILC_STR_UI_INT(dp_len),
1517 SILC_STR_UI_XNSTRING(dpb, dp_len),
1518 SILC_STR_UI_INT(dq_len),
1519 SILC_STR_UI_XNSTRING(dqb, dq_len),
1520 SILC_STR_UI_INT(qp_len),
1521 SILC_STR_UI_XNSTRING(qpb, qp_len),
1522 SILC_STR_UI_INT(p_len),
1523 SILC_STR_UI_XNSTRING(pb, p_len),
1524 SILC_STR_UI_INT(q_len),
1525 SILC_STR_UI_XNSTRING(qb, q_len),
1529 key = silc_buffer_steal(buf, &key_len);
1530 silc_buffer_free(buf);
1540 } else if (!strcmp(pkcs->name, "dsa")) {
1541 SILC_NOT_IMPLEMENTED("SILC DSA Private Key");
1545 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
1549 /* Encode SILC private key */
1550 totlen = 2 + strlen(pkcs->name) + key_len;
1551 buf = silc_buffer_alloc_size(totlen);
1554 if (silc_buffer_format(buf,
1555 SILC_STR_UI_SHORT(strlen(pkcs->name)),
1556 SILC_STR_UI32_STRING(pkcs->name),
1557 SILC_STR_UI_XNSTRING(key, key_len),
1561 ret = silc_buffer_steal(buf, ret_len);
1562 silc_buffer_free(buf);
1565 silc_asn1_free(asn1);
1573 silc_buffer_free(buf);
1577 /* Return key length */
1579 SilcUInt32 silc_pkcs_silc_private_key_bitlen(void *private_key)
1581 SilcSILCPrivateKey silc_privkey = private_key;
1582 return silc_privkey->pkcs->private_key_bitlen(silc_privkey->private_key);
1585 /* Frees private key */
1587 void silc_pkcs_silc_private_key_free(void *private_key)
1589 SilcSILCPrivateKey silc_privkey = private_key;
1591 silc_privkey->pkcs->private_key_free(silc_privkey->private_key);
1593 silc_free(silc_privkey);
1597 /***************************** PKCS operations ******************************/
1599 /* Encrypts as specified in SILC protocol specification */
1601 SilcBool silc_pkcs_silc_encrypt(void *public_key,
1605 SilcUInt32 dst_size,
1606 SilcUInt32 *ret_dst_len,
1609 SilcSILCPublicKey silc_pubkey = public_key;
1611 if (!silc_pubkey->pkcs->encrypt)
1614 return silc_pubkey->pkcs->encrypt(silc_pubkey->public_key,
1616 dst, dst_size, ret_dst_len, rng);
1619 /* Decrypts as specified in SILC protocol specification */
1621 SilcBool silc_pkcs_silc_decrypt(void *private_key,
1625 SilcUInt32 dst_size,
1626 SilcUInt32 *ret_dst_len)
1628 SilcSILCPrivateKey silc_privkey = private_key;
1630 if (!silc_privkey->pkcs->decrypt)
1633 return silc_privkey->pkcs->decrypt(silc_privkey->private_key,
1635 dst, dst_size, ret_dst_len);
1638 /* Signs as specified in SILC protocol specification */
1640 SilcBool silc_pkcs_silc_sign(void *private_key,
1643 unsigned char *signature,
1644 SilcUInt32 signature_size,
1645 SilcUInt32 *ret_signature_len,
1646 SilcBool compute_hash,
1649 SilcSILCPrivateKey silc_privkey = private_key;
1651 if (!silc_privkey->pkcs->sign)
1654 return silc_privkey->pkcs->sign(silc_privkey->private_key,
1656 signature, signature_size,
1657 ret_signature_len, compute_hash, hash);
1660 /* Verifies as specified in SILC protocol specification */
1662 SilcBool silc_pkcs_silc_verify(void *public_key,
1663 unsigned char *signature,
1664 SilcUInt32 signature_len,
1665 unsigned char *data,
1666 SilcUInt32 data_len,
1669 SilcSILCPublicKey silc_pubkey = public_key;
1671 if (!silc_pubkey->pkcs->verify)
1674 return silc_pubkey->pkcs->verify(silc_pubkey->public_key,
1675 signature, signature_len,
1676 data, data_len, hash);