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))
328 for (i = 0; i < len; i++) {
329 if (*filedata != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i])
333 filedata_len -= (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
334 strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
337 case SILC_PKCS_FILE_BIN:
340 case SILC_PKCS_FILE_BASE64:
341 data = silc_base64_decode(filedata, filedata_len, &filedata_len);
348 ret = silc_pkcs_silc_import_public_key(filedata, filedata_len,
352 return ret ? TRUE : FALSE;
355 /* Imports SILC protocol style public key */
357 int silc_pkcs_silc_import_public_key(unsigned char *key,
359 void **ret_public_key)
361 const SilcPKCSAlgorithm *pkcs;
362 SilcBufferStruct buf, alg_key;
363 SilcSILCPublicKey silc_pubkey = NULL;
364 SilcAsn1 asn1 = NULL;
365 SilcUInt32 totlen, keydata_len;
366 SilcUInt16 pkcs_len, identifier_len;
367 unsigned char *pkcs_name = NULL, *ident = NULL, *key_data = NULL;
370 SILC_LOG_DEBUG(("Parsing SILC public key"));
375 silc_buffer_set(&buf, key, key_len);
378 ret = silc_buffer_unformat(&buf,
380 SILC_STR_UI_INT(&totlen),
385 /* Backwards compatibility */
386 if (totlen == key_len)
389 if (totlen + 4 != key_len)
392 /* Get algorithm name and identifier */
394 silc_buffer_unformat(&buf,
396 SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
397 SILC_STR_UI16_NSTRING_ALLOC(&ident, &identifier_len),
402 if (pkcs_len < 1 || identifier_len < 3 ||
403 pkcs_len + identifier_len > totlen)
407 keydata_len = silc_buffer_len(&buf);
408 ret = silc_buffer_unformat(&buf,
409 SILC_STR_DATA(&key_data, keydata_len),
414 /* Allocate SILC public key context */
415 silc_pubkey = silc_calloc(1, sizeof(*silc_pubkey));
419 /* Decode SILC identifier */
420 if (!silc_pkcs_silc_decode_identifier(ident, &silc_pubkey->identifier))
423 asn1 = silc_asn1_alloc();
427 SILC_LOG_DEBUG(("Public key version %s",
428 (!silc_pubkey->identifier.version ? "1" :
429 silc_pubkey->identifier.version)));
431 if (!strcmp(pkcs_name, "rsa")) {
432 /* Parse the SILC RSA public key */
433 SilcUInt32 e_len, n_len;
436 /* Get PKCS object. Different PKCS #1 scheme is used with different
438 if (!silc_pubkey->identifier.version ||
439 atoi(silc_pubkey->identifier.version) <= 1) {
441 pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1-no-oid");
443 /* Version 2 and newer */
444 pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1");
447 SILC_LOG_DEBUG(("Unsupported PKCS algorithm: rsa"));
450 silc_pubkey->pkcs = pkcs;
454 SILC_GET32_MSB(e_len, key_data);
455 if (!e_len || e_len + 4 > keydata_len)
458 silc_mp_bin2mp(key_data + 4, e_len, &e);
459 if (keydata_len < 4 + e_len + 4) {
463 SILC_GET32_MSB(n_len, key_data + 4 + e_len);
464 if (!n_len || e_len + 4 + n_len + 4 > keydata_len) {
469 silc_mp_bin2mp(key_data + 4 + e_len + 4, n_len, &n);
471 /* Encode to PKCS #1 format */
472 memset(&alg_key, 0, sizeof(alg_key));
473 if (!silc_asn1_encode(asn1, &alg_key,
477 SILC_ASN1_END, SILC_ASN1_END)) {
486 } else if (!strcmp(pkcs_name, "dsa")) {
487 SILC_NOT_IMPLEMENTED("DSA SILC Public Key");
491 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
495 /* Import PKCS algorithm public key */
496 if (!pkcs->import_public_key(alg_key.data, silc_buffer_len(&alg_key),
497 &silc_pubkey->public_key))
500 silc_free(pkcs_name);
502 silc_asn1_free(asn1);
504 *ret_public_key = silc_pubkey;
509 silc_free(pkcs_name);
511 silc_free(silc_pubkey);
513 silc_asn1_free(asn1);
517 /* Exports public key as SILC protocol style public key file */
520 silc_pkcs_silc_export_public_key_file(void *public_key,
521 SilcPKCSFileEncoding encoding,
525 unsigned char *key, *data;
528 SILC_LOG_DEBUG(("Encoding SILC public key file"));
531 key = silc_pkcs_silc_export_public_key(public_key, &key_len);
536 case SILC_PKCS_FILE_BIN:
539 case SILC_PKCS_FILE_BASE64:
540 data = silc_base64_encode_file(key, key_len);
545 key_len = strlen(data);
549 /* Encode SILC public key file */
550 buf = silc_buffer_alloc_size(key_len +
551 (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
552 strlen(SILC_PKCS_PUBLIC_KEYFILE_END)));
558 if (silc_buffer_format(buf,
559 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
560 SILC_STR_UI_XNSTRING(key, key_len),
561 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END),
563 silc_buffer_free(buf);
569 key = silc_buffer_steal(buf, ret_len);
570 silc_buffer_free(buf);
575 /* Exports public key as SILC protocol style public key */
577 unsigned char *silc_pkcs_silc_export_public_key(void *public_key,
580 SilcSILCPublicKey silc_pubkey = public_key;
581 const SilcPKCSAlgorithm *pkcs = silc_pubkey->pkcs;
582 SilcBufferStruct alg_key;
583 SilcBuffer buf = NULL;
584 SilcAsn1 asn1 = NULL;
585 unsigned char *pk = NULL, *key = NULL, *ret;
586 SilcUInt32 pk_len, key_len, totlen;
589 SILC_LOG_DEBUG(("Encoding SILC public key"));
591 /* Export PKCS algorithm public key */
592 if (pkcs->export_public_key)
593 pk = pkcs->export_public_key(silc_pubkey->public_key, &pk_len);
596 silc_buffer_set(&alg_key, pk, pk_len);
598 /* Encode identifier */
600 silc_pkcs_silc_encode_identifier(silc_pubkey->identifier.username,
601 silc_pubkey->identifier.host,
602 silc_pubkey->identifier.realname,
603 silc_pubkey->identifier.email,
604 silc_pubkey->identifier.org,
605 silc_pubkey->identifier.country,
606 silc_pubkey->identifier.version);
610 asn1 = silc_asn1_alloc();
614 if (!strcmp(pkcs->name, "rsa")) {
615 /* Parse the PKCS #1 public key */
617 SilcUInt32 n_len, e_len;
618 unsigned char *nb, *eb;
620 memset(&n, 0, sizeof(n));
621 memset(&e, 0, sizeof(e));
622 if (!silc_asn1_decode(asn1, &alg_key,
626 SILC_ASN1_END, SILC_ASN1_END))
629 /* Encode to SILC RSA public key */
630 eb = silc_mp_mp2bin(&e, 0, &e_len);
633 nb = silc_mp_mp2bin(&n, 0, &n_len);
636 key_len = e_len + 4 + n_len + 4;
637 key = silc_calloc(key_len, sizeof(*key));
641 /* Put e length and e */
642 SILC_PUT32_MSB(e_len, key);
643 memcpy(key + 4, eb, e_len);
645 /* Put n length and n. */
646 SILC_PUT32_MSB(n_len, key + 4 + e_len);
647 memcpy(key + 4 + e_len + 4, nb, n_len);
652 } else if (!strcmp(pkcs->name, "dsa")) {
653 SILC_NOT_IMPLEMENTED("SILC DSA Public Key");
657 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
661 /* Encode SILC Public Key */
662 totlen = 2 + strlen(pkcs->name) + 2 + strlen(identifier) + key_len;
663 buf = silc_buffer_alloc_size(totlen + 4);
666 if (silc_buffer_format(buf,
667 SILC_STR_UI_INT(totlen),
668 SILC_STR_UI_SHORT(strlen(pkcs->name)),
669 SILC_STR_UI32_STRING(pkcs->name),
670 SILC_STR_UI_SHORT(strlen(identifier)),
671 SILC_STR_UI32_STRING(identifier),
672 SILC_STR_UI_XNSTRING(key, key_len),
676 ret = silc_buffer_steal(buf, ret_len);
677 silc_buffer_free(buf);
679 silc_free(identifier);
680 silc_buffer_purge(&alg_key);
681 silc_asn1_free(asn1);
686 silc_free(identifier);
690 silc_buffer_free(buf);
692 silc_asn1_free(asn1);
696 /* Return key length */
698 SilcUInt32 silc_pkcs_silc_public_key_bitlen(void *public_key)
700 SilcSILCPublicKey silc_pubkey = public_key;
701 return silc_pubkey->pkcs->public_key_bitlen(silc_pubkey->public_key);
704 /* Copy public key */
706 void *silc_pkcs_silc_public_key_copy(void *public_key)
708 SilcSILCPublicKey silc_pubkey = public_key, new_pubkey;
709 SilcPublicKeyIdentifier ident = &silc_pubkey->identifier;
711 new_pubkey = silc_calloc(1, sizeof(*new_pubkey));
714 new_pubkey->pkcs = silc_pubkey->pkcs;
716 new_pubkey->public_key =
717 silc_pubkey->pkcs->public_key_copy(silc_pubkey->public_key);
718 if (!new_pubkey->public_key) {
719 silc_free(new_pubkey);
724 new_pubkey->identifier.username =
725 silc_memdup(ident->username, strlen(ident->username));
727 new_pubkey->identifier.host =
728 silc_memdup(ident->host, strlen(ident->host));
730 new_pubkey->identifier.realname =
731 silc_memdup(ident->realname, strlen(ident->realname));
733 new_pubkey->identifier.email =
734 silc_memdup(ident->email, strlen(ident->email));
736 new_pubkey->identifier.org =
737 silc_memdup(ident->org, strlen(ident->org));
739 new_pubkey->identifier.country =
740 silc_memdup(ident->country, strlen(ident->country));
742 new_pubkey->identifier.version =
743 silc_memdup(ident->version, strlen(ident->version));
748 /* Compares public keys */
750 SilcBool silc_pkcs_silc_public_key_compare(void *key1, void *key2)
752 SilcSILCPublicKey k1 = key1, k2 = key2;
754 if (strcmp(k1->pkcs->name, k2->pkcs->name))
757 if ((k1->identifier.username && !k2->identifier.username) ||
758 (!k1->identifier.username && k2->identifier.username) ||
759 (k1->identifier.username && k2->identifier.username &&
760 strcmp(k1->identifier.username, k2->identifier.username)))
763 if ((k1->identifier.host && !k2->identifier.host) ||
764 (!k1->identifier.host && k2->identifier.host) ||
765 (k1->identifier.host && k2->identifier.host &&
766 strcmp(k1->identifier.host, k2->identifier.host)))
769 if ((k1->identifier.realname && !k2->identifier.realname) ||
770 (!k1->identifier.realname && k2->identifier.realname) ||
771 (k1->identifier.realname && k2->identifier.realname &&
772 strcmp(k1->identifier.realname, k2->identifier.realname)))
775 if ((k1->identifier.email && !k2->identifier.email) ||
776 (!k1->identifier.email && k2->identifier.email) ||
777 (k1->identifier.email && k2->identifier.email &&
778 strcmp(k1->identifier.email, k2->identifier.email)))
781 if ((k1->identifier.org && !k2->identifier.org) ||
782 (!k1->identifier.org && k2->identifier.org) ||
783 (k1->identifier.org && k2->identifier.org &&
784 strcmp(k1->identifier.org, k2->identifier.org)))
787 if ((k1->identifier.country && !k2->identifier.country) ||
788 (!k1->identifier.country && k2->identifier.country) ||
789 (k1->identifier.country && k2->identifier.country &&
790 strcmp(k1->identifier.country, k2->identifier.country)))
793 if ((k1->identifier.version && !k2->identifier.version) ||
794 (!k1->identifier.version && k2->identifier.version) ||
795 (k1->identifier.version && k2->identifier.version &&
796 strcmp(k1->identifier.version, k2->identifier.version)))
799 return k1->pkcs->public_key_compare(k1->public_key, k2->public_key);
802 /* Frees public key */
804 void silc_pkcs_silc_public_key_free(void *public_key)
806 SilcSILCPublicKey silc_pubkey = public_key;
808 silc_pubkey->pkcs->public_key_free(silc_pubkey->public_key);
810 silc_free(silc_pubkey->identifier.username);
811 silc_free(silc_pubkey->identifier.host);
812 silc_free(silc_pubkey->identifier.realname);
813 silc_free(silc_pubkey->identifier.email);
814 silc_free(silc_pubkey->identifier.org);
815 silc_free(silc_pubkey->identifier.country);
816 silc_free(silc_pubkey->identifier.version);
817 silc_free(silc_pubkey);
821 /*************************** Private key routines ****************************/
823 /* Private key file magic */
824 #define SILC_PKCS_PRIVATE_KEY_MAGIC 0x738df531
826 /* Imports SILC implementation style private key file */
828 SilcBool silc_pkcs_silc_import_private_key_file(unsigned char *filedata,
829 SilcUInt32 filedata_len,
830 const char *passphrase,
831 SilcUInt32 passphrase_len,
832 SilcPKCSFileEncoding encoding,
833 void **ret_private_key)
839 unsigned char tmp[32], keymat[64], *data = NULL;
840 SilcUInt32 i, len, magic, mac_len;
843 SILC_LOG_DEBUG(("Parsing SILC private key file"));
845 /* Check start of file and remove header from the data. */
846 len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
847 if (filedata_len < len + strlen(SILC_PKCS_PRIVATE_KEYFILE_END))
849 for (i = 0; i < len; i++) {
850 if (*filedata != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i])
855 len = filedata_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
856 strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
859 case SILC_PKCS_FILE_BIN:
862 case SILC_PKCS_FILE_BASE64:
863 data = silc_base64_decode(filedata, filedata_len, &len);
870 memset(tmp, 0, sizeof(tmp));
871 memset(keymat, 0, sizeof(keymat));
873 /* Check file magic */
874 SILC_GET32_MSB(magic, filedata);
875 if (magic != SILC_PKCS_PRIVATE_KEY_MAGIC) {
876 SILC_LOG_DEBUG(("Private key does not have correct magic"));
880 /* Allocate the AES cipher */
881 if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
882 SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
885 blocklen = silc_cipher_get_block_len(aes);
886 if (blocklen * 2 > sizeof(tmp)) {
887 silc_cipher_free(aes);
891 /* Allocate SHA1 hash */
892 if (!silc_hash_alloc("sha1", &sha1)) {
893 SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered"));
894 silc_cipher_free(aes);
899 if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
900 SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
901 silc_hash_free(sha1);
902 silc_cipher_free(aes);
906 /* Derive the decryption key from the provided key material. The key
907 is 256 bits length, and derived by taking hash of the data, then
908 re-hashing the data and the previous digest, and using the first and
909 second digest as the key. */
910 silc_hash_init(sha1);
911 silc_hash_update(sha1, passphrase, passphrase_len);
912 silc_hash_final(sha1, keymat);
913 silc_hash_init(sha1);
914 silc_hash_update(sha1, passphrase, passphrase_len);
915 silc_hash_update(sha1, keymat, 16);
916 silc_hash_final(sha1, keymat + 16);
918 /* Set the key to the cipher */
919 silc_cipher_set_key(aes, keymat, 256, FALSE);
921 /* First, verify the MAC of the private key data */
922 mac_len = silc_hmac_len(sha1hmac);
923 silc_hmac_init_with_key(sha1hmac, keymat, 16);
924 silc_hmac_update(sha1hmac, filedata, len - mac_len);
925 silc_hmac_final(sha1hmac, tmp, NULL);
926 if (memcmp(tmp, filedata + (len - mac_len), mac_len)) {
927 SILC_LOG_DEBUG(("Integrity check for private key failed"));
928 memset(keymat, 0, sizeof(keymat));
929 memset(tmp, 0, sizeof(tmp));
930 silc_hmac_free(sha1hmac);
931 silc_hash_free(sha1);
932 silc_cipher_free(aes);
938 /* Decrypt the private key buffer */
939 silc_cipher_decrypt(aes, filedata, filedata, len - mac_len, NULL);
940 SILC_GET32_MSB(i, filedata);
942 SILC_LOG_DEBUG(("Bad private key length in buffer!"));
943 memset(keymat, 0, sizeof(keymat));
944 memset(tmp, 0, sizeof(tmp));
945 silc_hmac_free(sha1hmac);
946 silc_hash_free(sha1);
947 silc_cipher_free(aes);
954 memset(keymat, 0, sizeof(keymat));
955 memset(tmp, 0, sizeof(tmp));
956 silc_hmac_free(sha1hmac);
957 silc_hash_free(sha1);
958 silc_cipher_free(aes);
960 /* Import the private key */
961 ret = silc_pkcs_silc_import_private_key(filedata, len, ret_private_key);
965 return ret ? TRUE : FALSE;
968 /* Private key version */
969 #define SILC_PRIVATE_KEY_VERSION_1 0x82171273
970 #define SILC_PRIVATE_KEY_VERSION_2 0xf911a3d1
972 /* Imports SILC implementation style private key */
974 int silc_pkcs_silc_import_private_key(unsigned char *key,
976 void **ret_private_key)
978 SilcBufferStruct buf;
979 const SilcPKCSAlgorithm *pkcs;
980 SilcBufferStruct alg_key;
981 SilcSILCPrivateKey silc_privkey = NULL;
982 SilcAsn1 asn1 = NULL;
984 SilcUInt32 keydata_len;
985 unsigned char *pkcs_name = NULL, *key_data;
988 SILC_LOG_DEBUG(("Parsing SILC private key"));
990 if (!ret_private_key)
993 silc_buffer_set(&buf, key, key_len);
995 /* Get algorithm name and identifier */
997 silc_buffer_unformat(&buf,
998 SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
1001 SILC_LOG_DEBUG(("Cannot decode private key buffer"));
1005 if (pkcs_len < 1 || pkcs_len > silc_buffer_truelen(&buf)) {
1006 SILC_LOG_DEBUG(("Malformed private key buffer"));
1010 /* Get key data. We assume that rest of the buffer is key data. */
1011 silc_buffer_pull(&buf, 2 + pkcs_len);
1012 keydata_len = silc_buffer_len(&buf);
1013 ret = silc_buffer_unformat(&buf,
1014 SILC_STR_UI_XNSTRING(&key_data, keydata_len),
1019 /* Allocate SILC private key context */
1020 silc_privkey = silc_calloc(1, sizeof(*silc_privkey));
1024 asn1 = silc_asn1_alloc();
1028 if (!strcmp(pkcs_name, "rsa")) {
1029 /* Parse the RSA SILC private key */
1031 SilcMPInt n, e, d, dp, dq, qp, p, q;
1033 SilcUInt32 len, ver;
1035 if (keydata_len < 4)
1037 silc_buffer_set(&k, key_data, keydata_len);
1039 /* Get version. Key without the version is old style private key
1040 and we need to do some computation to get it to correct format. */
1041 if (silc_buffer_unformat(&k,
1042 SILC_STR_UI_INT(&ver),
1045 silc_buffer_pull(&k, 4);
1047 if (ver != SILC_PRIVATE_KEY_VERSION_1 &&
1048 ver != SILC_PRIVATE_KEY_VERSION_2) {
1052 if (silc_buffer_unformat(&k,
1053 SILC_STR_UI_INT(&len),
1056 silc_buffer_pull(&k, 4);
1059 /* Get PKCS object. Different PKCS #1 scheme is used with different
1061 if (ver == 0 || ver == SILC_PRIVATE_KEY_VERSION_1) {
1062 /* Version 0 and 1 */
1063 pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1-no-oid");
1065 /* Version 2 and newer */
1066 pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1");
1069 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
1072 silc_privkey->pkcs = pkcs;
1074 SILC_LOG_DEBUG(("Private key version %s",
1075 (ver == SILC_PRIVATE_KEY_VERSION_1 ? "1" :
1076 ver == SILC_PRIVATE_KEY_VERSION_2 ? "2" : "0")));
1079 if (silc_buffer_unformat(&k,
1080 SILC_STR_DATA(&tmp, len),
1084 silc_mp_bin2mp(tmp, len, &e);
1085 silc_buffer_pull(&k, len);
1088 if (silc_buffer_unformat(&k,
1089 SILC_STR_UI_INT(&len),
1092 silc_buffer_pull(&k, 4);
1093 if (silc_buffer_unformat(&k,
1094 SILC_STR_DATA(&tmp, len),
1098 silc_mp_bin2mp(tmp, len, &n);
1099 silc_buffer_pull(&k, len);
1102 if (silc_buffer_unformat(&k,
1103 SILC_STR_UI_INT(&len),
1106 silc_buffer_pull(&k, 4);
1107 if (silc_buffer_unformat(&k,
1108 SILC_STR_DATA(&tmp, len),
1112 silc_mp_bin2mp(tmp, len, &d);
1113 silc_buffer_pull(&k, len);
1116 if (silc_buffer_unformat(&k,
1117 SILC_STR_UI_INT(&len),
1120 silc_buffer_pull(&k, 4);
1121 if (silc_buffer_unformat(&k,
1122 SILC_STR_DATA(&tmp, len),
1126 silc_mp_bin2mp(tmp, len, &dp);
1127 silc_buffer_pull(&k, len);
1130 if (silc_buffer_unformat(&k,
1131 SILC_STR_UI_INT(&len),
1134 silc_buffer_pull(&k, 4);
1135 if (silc_buffer_unformat(&k,
1136 SILC_STR_DATA(&tmp, len),
1140 silc_mp_bin2mp(tmp, len, &dq);
1141 silc_buffer_pull(&k, len);
1147 if (silc_buffer_unformat(&k,
1148 SILC_STR_UI_INT(&len),
1151 silc_buffer_pull(&k, 4);
1152 if (silc_buffer_len(&k) < len)
1154 silc_buffer_pull(&k, len);
1157 if (silc_buffer_unformat(&k,
1158 SILC_STR_UI_INT(&len),
1161 silc_buffer_pull(&k, 4);
1162 if (silc_buffer_len(&k) < len)
1164 silc_buffer_pull(&k, len);
1169 if (silc_buffer_unformat(&k,
1170 SILC_STR_UI_INT(&len),
1173 silc_buffer_pull(&k, 4);
1174 if (silc_buffer_unformat(&k,
1175 SILC_STR_DATA(&tmp, len),
1179 silc_mp_bin2mp(tmp, len, &qp);
1180 silc_buffer_pull(&k, len);
1184 if (silc_buffer_unformat(&k,
1185 SILC_STR_UI_INT(&len),
1188 silc_buffer_pull(&k, 4);
1189 if (silc_buffer_unformat(&k,
1190 SILC_STR_DATA(&tmp, len),
1194 silc_mp_bin2mp(tmp, len, &p);
1195 silc_buffer_pull(&k, len);
1198 if (silc_buffer_unformat(&k,
1199 SILC_STR_UI_INT(&len),
1202 silc_buffer_pull(&k, 4);
1203 if (silc_buffer_unformat(&k,
1204 SILC_STR_DATA(&tmp, len),
1208 silc_mp_bin2mp(tmp, len, &q);
1209 silc_buffer_pull(&k, len);
1212 /* Old version. Compute to new version */
1213 SILC_LOG_DEBUG(("Old version private key"));
1215 silc_mp_modinv(&qp, &q, &p);
1218 /* Encode to PKCS #1 format */
1219 memset(&alg_key, 0, sizeof(alg_key));
1220 if (!silc_asn1_encode(asn1, &alg_key,
1222 SILC_ASN1_SHORT_INT(0),
1231 SILC_ASN1_END, SILC_ASN1_END))
1240 silc_mp_uninit(&dp);
1241 silc_mp_uninit(&dq);
1242 silc_mp_uninit(&qp);
1244 } else if (!strcmp(pkcs_name, "dsa")) {
1245 SILC_NOT_IMPLEMENTED("DSA SILC Private Key");
1249 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
1253 /* Import PKCS algorithm private key */
1254 if (!pkcs->import_private_key(alg_key.data, silc_buffer_len(&alg_key),
1255 &silc_privkey->private_key))
1258 silc_free(pkcs_name);
1259 silc_asn1_free(asn1);
1261 *ret_private_key = silc_privkey;
1266 silc_free(pkcs_name);
1267 silc_free(silc_privkey);
1269 silc_asn1_free(asn1);
1273 /* Exports private key as SILC implementation style private key file */
1276 silc_pkcs_silc_export_private_key_file(void *private_key,
1277 const char *passphrase,
1278 SilcUInt32 passphrase_len,
1279 SilcPKCSFileEncoding encoding,
1281 SilcUInt32 *ret_len)
1286 SilcBuffer buf, enc;
1287 SilcUInt32 len, blocklen, padlen, key_len;
1288 unsigned char *key, *data;
1289 unsigned char tmp[32], keymat[64];
1292 SILC_LOG_DEBUG(("Encoding SILC private key file"));
1294 /* Export the private key */
1295 key = silc_pkcs_silc_export_private_key(private_key, &key_len);
1299 memset(tmp, 0, sizeof(tmp));
1300 memset(keymat, 0, sizeof(keymat));
1302 /* Allocate the AES cipher */
1303 if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
1304 SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
1308 blocklen = silc_cipher_get_block_len(aes);
1309 if (blocklen * 2 > sizeof(tmp)) {
1310 silc_cipher_free(aes);
1315 /* Allocate SHA1 hash */
1316 if (!silc_hash_alloc("sha1", &sha1)) {
1317 SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered"));
1318 silc_cipher_free(aes);
1323 if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
1324 SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
1325 silc_hash_free(sha1);
1326 silc_cipher_free(aes);
1330 /* Derive the encryption key from the provided key material. The key
1331 is 256 bits length, and derived by taking hash of the data, then
1332 re-hashing the data and the previous digest, and using the first and
1333 second digest as the key. */
1334 silc_hash_init(sha1);
1335 silc_hash_update(sha1, passphrase, passphrase_len);
1336 silc_hash_final(sha1, keymat);
1337 silc_hash_init(sha1);
1338 silc_hash_update(sha1, passphrase, passphrase_len);
1339 silc_hash_update(sha1, keymat, 16);
1340 silc_hash_final(sha1, keymat + 16);
1342 /* Set the key to the cipher */
1343 silc_cipher_set_key(aes, keymat, 256, TRUE);
1345 /* Encode the buffer to be encrypted. Add padding to it too, at least
1346 block size of the cipher. */
1348 /* Allocate buffer for encryption */
1349 len = silc_hmac_len(sha1hmac);
1350 padlen = 16 + (16 - ((key_len + 4) % blocklen));
1351 enc = silc_buffer_alloc_size(4 + 4 + key_len + padlen + len);
1353 silc_hmac_free(sha1hmac);
1354 silc_hash_free(sha1);
1355 silc_cipher_free(aes);
1359 /* Generate padding */
1360 for (i = 0; i < padlen; i++)
1361 tmp[i] = silc_rng_get_byte_fast(rng);
1363 /* Put magic number */
1364 SILC_PUT32_MSB(SILC_PKCS_PRIVATE_KEY_MAGIC, enc->data);
1365 silc_buffer_pull(enc, 4);
1367 /* Encode the buffer */
1368 silc_buffer_format(enc,
1369 SILC_STR_UI_INT(key_len),
1370 SILC_STR_UI_XNSTRING(key, key_len),
1371 SILC_STR_UI_XNSTRING(tmp, padlen),
1376 silc_cipher_encrypt(aes, enc->data, enc->data, silc_buffer_len(enc) - len,
1377 silc_cipher_get_iv(aes));
1379 silc_buffer_push(enc, 4);
1381 /* Compute HMAC over the encrypted data and append the MAC to data.
1382 The key is the first digest of the original key material. */
1383 key_len = silc_buffer_len(enc) - len;
1384 silc_hmac_init_with_key(sha1hmac, keymat, 16);
1385 silc_hmac_update(sha1hmac, enc->data, key_len);
1386 silc_buffer_pull(enc, key_len);
1387 silc_hmac_final(sha1hmac, enc->data, NULL);
1388 silc_buffer_push(enc, key_len);
1391 memset(keymat, 0, sizeof(keymat));
1392 memset(tmp, 0, sizeof(tmp));
1393 silc_hmac_free(sha1hmac);
1394 silc_hash_free(sha1);
1395 silc_cipher_free(aes);
1398 case SILC_PKCS_FILE_BIN:
1401 case SILC_PKCS_FILE_BASE64:
1402 data = silc_base64_encode_file(enc->data, silc_buffer_len(enc));
1404 silc_buffer_clear(enc);
1405 silc_buffer_free(enc);
1408 silc_free(silc_buffer_steal(enc, NULL));
1409 silc_buffer_set(enc, data, strlen(data));
1414 key_len = silc_buffer_len(enc);
1416 /* Encode the data and save to file */
1417 len = key_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
1418 strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
1419 buf = silc_buffer_alloc_size(len);
1421 silc_buffer_free(enc);
1424 silc_buffer_format(buf,
1425 SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
1426 SILC_STR_UI_XNSTRING(key, key_len),
1427 SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
1430 silc_buffer_free(enc);
1431 data = silc_buffer_steal(buf, ret_len);
1432 silc_buffer_free(buf);
1437 /* Exports private key as SILC implementation style private key */
1439 unsigned char *silc_pkcs_silc_export_private_key(void *private_key,
1440 SilcUInt32 *ret_len)
1442 SilcSILCPrivateKey silc_privkey = private_key;
1443 const SilcPKCSAlgorithm *pkcs = silc_privkey->pkcs;
1444 SilcBufferStruct alg_key;
1445 SilcBuffer buf = NULL;
1446 SilcAsn1 asn1 = NULL;
1447 unsigned char *prv = NULL, *key = NULL, *ret;
1448 SilcUInt32 prv_len, key_len, totlen;
1450 SILC_LOG_DEBUG(("Encoding SILC private key"));
1452 /* Export PKCS algorithm private key */
1453 if (pkcs->export_private_key)
1454 prv = pkcs->export_private_key(silc_privkey->private_key, &prv_len);
1457 silc_buffer_set(&alg_key, prv, prv_len);
1459 asn1 = silc_asn1_alloc();
1463 if (!strcmp(pkcs->name, "rsa")) {
1464 /* Parse the PKCS #1 private key */
1465 SilcMPInt n, e, d, dp, dq, qp, p, q;
1466 SilcUInt32 e_len, n_len, d_len, dp_len, dq_len,
1467 qp_len, p_len, q_len, len = 0;
1468 unsigned char *nb, *eb, *db, *dpb, *dqb, *qpb, *pb, *qb;
1470 if (!silc_asn1_decode(asn1, &alg_key,
1472 SILC_ASN1_INT(NULL),
1481 SILC_ASN1_END, SILC_ASN1_END))
1484 /* Encode to SILC RSA private key */
1485 eb = silc_mp_mp2bin(&e, 0, &e_len);
1486 nb = silc_mp_mp2bin(&n, 0, &n_len);
1487 db = silc_mp_mp2bin(&d, 0, &d_len);
1488 dpb = silc_mp_mp2bin(&dp, 0, &dp_len);
1489 dqb = silc_mp_mp2bin(&dq, 0, &dq_len);
1490 qpb = silc_mp_mp2bin(&qp, 0, &qp_len);
1491 pb = silc_mp_mp2bin(&p, 0, &p_len);
1492 qb = silc_mp_mp2bin(&q, 0, &q_len);
1493 len = 4 + e_len + 4 + n_len + 4 + d_len + 4+ dp_len + 4 +
1494 dq_len + 4 + qp_len + 4 + p_len + 4 + q_len + 4;
1496 buf = silc_buffer_alloc_size(len);
1499 if (silc_buffer_format(buf,
1500 SILC_STR_UI_INT(SILC_PRIVATE_KEY_VERSION_1),
1501 SILC_STR_UI_INT(e_len),
1502 SILC_STR_UI_XNSTRING(eb, e_len),
1503 SILC_STR_UI_INT(n_len),
1504 SILC_STR_UI_XNSTRING(nb, n_len),
1505 SILC_STR_UI_INT(d_len),
1506 SILC_STR_UI_XNSTRING(db, d_len),
1507 SILC_STR_UI_INT(dp_len),
1508 SILC_STR_UI_XNSTRING(dpb, dp_len),
1509 SILC_STR_UI_INT(dq_len),
1510 SILC_STR_UI_XNSTRING(dqb, dq_len),
1511 SILC_STR_UI_INT(qp_len),
1512 SILC_STR_UI_XNSTRING(qpb, qp_len),
1513 SILC_STR_UI_INT(p_len),
1514 SILC_STR_UI_XNSTRING(pb, p_len),
1515 SILC_STR_UI_INT(q_len),
1516 SILC_STR_UI_XNSTRING(qb, q_len),
1520 key = silc_buffer_steal(buf, &key_len);
1521 silc_buffer_free(buf);
1531 } else if (!strcmp(pkcs->name, "dsa")) {
1532 SILC_NOT_IMPLEMENTED("SILC DSA Private Key");
1536 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
1540 /* Encode SILC private key */
1541 totlen = 2 + strlen(pkcs->name) + key_len;
1542 buf = silc_buffer_alloc_size(totlen);
1545 if (silc_buffer_format(buf,
1546 SILC_STR_UI_SHORT(strlen(pkcs->name)),
1547 SILC_STR_UI32_STRING(pkcs->name),
1548 SILC_STR_UI_XNSTRING(key, key_len),
1552 ret = silc_buffer_steal(buf, ret_len);
1553 silc_buffer_free(buf);
1556 silc_asn1_free(asn1);
1564 silc_buffer_free(buf);
1568 /* Return key length */
1570 SilcUInt32 silc_pkcs_silc_private_key_bitlen(void *private_key)
1572 SilcSILCPrivateKey silc_privkey = private_key;
1573 return silc_privkey->pkcs->private_key_bitlen(silc_privkey->private_key);
1576 /* Frees private key */
1578 void silc_pkcs_silc_private_key_free(void *private_key)
1580 SilcSILCPrivateKey silc_privkey = private_key;
1582 silc_privkey->pkcs->private_key_free(silc_privkey->private_key);
1584 silc_free(silc_privkey);
1588 /***************************** PKCS operations ******************************/
1590 /* Encrypts as specified in SILC protocol specification */
1592 SilcBool silc_pkcs_silc_encrypt(void *public_key,
1596 SilcUInt32 dst_size,
1597 SilcUInt32 *ret_dst_len,
1600 SilcSILCPublicKey silc_pubkey = public_key;
1602 if (!silc_pubkey->pkcs->encrypt)
1605 return silc_pubkey->pkcs->encrypt(silc_pubkey->public_key,
1607 dst, dst_size, ret_dst_len, rng);
1610 /* Decrypts as specified in SILC protocol specification */
1612 SilcBool silc_pkcs_silc_decrypt(void *private_key,
1616 SilcUInt32 dst_size,
1617 SilcUInt32 *ret_dst_len)
1619 SilcSILCPrivateKey silc_privkey = private_key;
1621 if (!silc_privkey->pkcs->decrypt)
1624 return silc_privkey->pkcs->decrypt(silc_privkey->private_key,
1626 dst, dst_size, ret_dst_len);
1629 /* Signs as specified in SILC protocol specification */
1631 SilcBool silc_pkcs_silc_sign(void *private_key,
1634 unsigned char *signature,
1635 SilcUInt32 signature_size,
1636 SilcUInt32 *ret_signature_len,
1637 SilcBool compute_hash,
1640 SilcSILCPrivateKey silc_privkey = private_key;
1642 if (!silc_privkey->pkcs->sign)
1645 return silc_privkey->pkcs->sign(silc_privkey->private_key,
1647 signature, signature_size,
1648 ret_signature_len, compute_hash, hash);
1651 /* Verifies as specified in SILC protocol specification */
1653 SilcBool silc_pkcs_silc_verify(void *public_key,
1654 unsigned char *signature,
1655 SilcUInt32 signature_len,
1656 unsigned char *data,
1657 SilcUInt32 data_len,
1660 SilcSILCPublicKey silc_pubkey = public_key;
1662 if (!silc_pubkey->pkcs->verify)
1665 return silc_pubkey->pkcs->verify(silc_pubkey->public_key,
1666 signature, signature_len,
1667 data, data_len, hash);