5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2006 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,
29 SilcUInt32 bits_key_len,
30 const char *identifier,
32 SilcPublicKey *ret_public_key,
33 SilcPrivateKey *ret_private_key)
35 SilcSILCPublicKey pubkey;
36 SilcSILCPrivateKey privkey;
37 const SilcPKCSAlgorithm *alg;
38 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 alg = silc_pkcs_find_algorithm(algorithm, scheme);
54 /* Allocate SILC public key */
55 pubkey = silc_calloc(1, sizeof(*pubkey));
60 /* Decode identifier */
61 if (!silc_pkcs_silc_decode_identifier(identifier, &pubkey->identifier)) {
66 /* Allocate SILC private key */
67 privkey = silc_calloc(1, sizeof(*privkey));
74 /* Allocate public key */
75 *ret_public_key = silc_calloc(1, sizeof(**ret_public_key));
76 if (!(*ret_public_key)) {
81 (*ret_public_key)->pkcs = pkcs;
82 (*ret_public_key)->public_key = pubkey;
84 /* Allocate private key */
85 *ret_private_key = silc_calloc(1, sizeof(**ret_private_key));
86 if (!(*ret_private_key)) {
89 silc_free(*ret_public_key);
92 (*ret_private_key)->pkcs = pkcs;
93 (*ret_private_key)->private_key = privkey;
95 /* Generate the algorithm key pair */
96 if (!alg->generate_key(bits_key_len, rng, &pubkey->public_key,
97 &privkey->private_key)) {
100 silc_free(*ret_public_key);
101 silc_free(*ret_private_key);
109 /**************************** Utility functions ******************************/
111 /* Decodes the provided `identifier' */
113 SilcBool silc_pkcs_silc_decode_identifier(const char *identifier,
114 SilcPublicKeyIdentifier ident)
119 /* Protocol says that at least UN and HN must be provided as identifier */
120 if (!strstr(identifier, "UN=") && !strstr(identifier, "HN=")) {
121 SILC_LOG_DEBUG(("The public does not have the required UN= and HN= "
126 cp = (char *)identifier;
128 len = strcspn(cp, ",");
133 if (len - 1 >= 0 && cp[len - 1] == '\\') {
135 if (len + 1 > strlen(cp)) {
140 len = strcspn(cp, ",") + len;
145 if (len - 1 >= 0 && cp[len - 1] != '\\')
153 item = silc_calloc(len + 1, sizeof(char));
156 if (len > strlen(cp))
158 memcpy(item, cp, len);
160 if (strstr(item, "UN="))
161 ident->username = strdup(item + strcspn(cp, "=") + 1);
162 else if (strstr(item, "HN="))
163 ident->host = strdup(item + strcspn(cp, "=") + 1);
164 else if (strstr(item, "RN="))
165 ident->realname = strdup(item + strcspn(cp, "=") + 1);
166 else if (strstr(item, "E="))
167 ident->email = strdup(item + strcspn(cp, "=") + 1);
168 else if (strstr(item, "O="))
169 ident->org = strdup(item + strcspn(cp, "=") + 1);
170 else if (strstr(item, "C="))
171 ident->country = strdup(item + strcspn(cp, "=") + 1);
186 /* Encodes and returns SILC public key identifier. If some of the
187 arguments is NULL those are not encoded into the identifier string.
188 Protocol says that at least username and host must be provided. */
190 char *silc_pkcs_silc_encode_identifier(char *username, char *host,
191 char *realname, char *email,
192 char *org, char *country)
196 SilcUInt32 len, tlen = 0;
198 if (!username || !host)
201 len = (username ? strlen(username) : 0) +
202 (host ? strlen(host) : 0) +
203 (realname ? strlen(realname) : 0) +
204 (email ? strlen(email) : 0) +
205 (org ? strlen(org) : 0) +
206 (country ? strlen(country) : 0);
211 len += 3 + 5 + 5 + 4 + 4 + 4;
212 buf = silc_buffer_alloc(len);
215 silc_buffer_pull_tail(buf, len);
218 silc_buffer_format(buf,
219 SILC_STR_UI32_STRING("UN="),
220 SILC_STR_UI32_STRING(username),
222 silc_buffer_pull(buf, 3 + strlen(username));
223 tlen = 3 + strlen(username);
227 silc_buffer_format(buf,
228 SILC_STR_UI32_STRING(", "),
229 SILC_STR_UI32_STRING("HN="),
230 SILC_STR_UI32_STRING(host),
232 silc_buffer_pull(buf, 5 + strlen(host));
233 tlen += 5 + strlen(host);
237 silc_buffer_format(buf,
238 SILC_STR_UI32_STRING(", "),
239 SILC_STR_UI32_STRING("RN="),
240 SILC_STR_UI32_STRING(realname),
242 silc_buffer_pull(buf, 5 + strlen(realname));
243 tlen += 5 + strlen(realname);
247 silc_buffer_format(buf,
248 SILC_STR_UI32_STRING(", "),
249 SILC_STR_UI32_STRING("E="),
250 SILC_STR_UI32_STRING(email),
252 silc_buffer_pull(buf, 4 + strlen(email));
253 tlen += 4 + strlen(email);
257 silc_buffer_format(buf,
258 SILC_STR_UI32_STRING(", "),
259 SILC_STR_UI32_STRING("O="),
260 SILC_STR_UI32_STRING(org),
262 silc_buffer_pull(buf, 4 + strlen(org));
263 tlen += 4 + strlen(org);
267 silc_buffer_format(buf,
268 SILC_STR_UI32_STRING(", "),
269 SILC_STR_UI32_STRING("C="),
270 SILC_STR_UI32_STRING(country),
272 silc_buffer_pull(buf, 4 + strlen(country));
273 tlen += 4 + strlen(country);
276 silc_buffer_push(buf, buf->data - buf->head);
277 identifier = silc_calloc(tlen + 1, sizeof(*identifier));
280 memcpy(identifier, buf->data, tlen);
281 silc_buffer_free(buf);
287 /*************************** Public key routines *****************************/
289 /* Returns PKCS algorithm context */
291 const SilcPKCSAlgorithm *silc_pkcs_silc_get_algorithm(void *public_key)
293 SilcSILCPublicKey silc_pubkey = public_key;
294 return silc_pubkey->pkcs;
297 /* Imports SILC protocol style public key from SILC public key file */
299 SilcBool silc_pkcs_silc_import_public_key_file(unsigned char *filedata,
300 SilcUInt32 filedata_len,
301 SilcPKCSFileEncoding encoding,
302 void **ret_public_key)
305 unsigned char *data = NULL;
308 SILC_LOG_DEBUG(("Parsing SILC public key file"));
313 /* Check start of file and remove header from the data. */
314 len = strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN);
315 if (filedata_len < len + strlen(SILC_PKCS_PUBLIC_KEYFILE_END))
317 for (i = 0; i < len; i++) {
318 if (*filedata != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i])
322 filedata_len -= (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
323 strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
326 case SILC_PKCS_FILE_BIN:
329 case SILC_PKCS_FILE_BASE64:
330 data = silc_pem_decode(filedata, filedata_len, &filedata_len);
337 ret = silc_pkcs_silc_import_public_key(filedata, filedata_len,
344 /* Imports SILC protocol style public key */
346 SilcBool silc_pkcs_silc_import_public_key(unsigned char *key,
348 void **ret_public_key)
350 const SilcPKCSAlgorithm *pkcs;
351 SilcBufferStruct buf, alg_key;
352 SilcSILCPublicKey silc_pubkey = NULL;
353 SilcAsn1 asn1 = NULL;
354 SilcUInt32 totlen, keydata_len;
355 SilcUInt16 pkcs_len, identifier_len;
356 unsigned char *pkcs_name = NULL, *ident = NULL, *key_data = NULL;
359 SILC_LOG_DEBUG(("Parsing SILC public key"));
364 silc_buffer_set(&buf, key, key_len);
367 ret = silc_buffer_unformat(&buf,
368 SILC_STR_UI_INT(&totlen),
373 /* Backwards compatibility */
374 if (totlen == key_len)
377 if (totlen + 4 != key_len)
380 /* Get algorithm name and identifier */
382 silc_buffer_unformat(&buf,
384 SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
385 SILC_STR_UI16_NSTRING_ALLOC(&ident, &identifier_len),
390 if (pkcs_len < 1 || identifier_len < 3 ||
391 pkcs_len + identifier_len > totlen)
395 silc_buffer_pull(&buf, 4 + 2 + pkcs_len + 2 + identifier_len);
396 keydata_len = silc_buffer_len(&buf);
397 ret = silc_buffer_unformat(&buf,
398 SILC_STR_UI_XNSTRING(&key_data,
404 /* Allocate SILC public key context */
405 silc_pubkey = silc_calloc(1, sizeof(*silc_pubkey));
409 /* Decode SILC identifier */
410 if (!silc_pkcs_silc_decode_identifier(ident, &silc_pubkey->identifier))
413 asn1 = silc_asn1_alloc();
417 if (!strcmp(pkcs_name, "rsa")) {
418 /* Parse the SILC RSA public key */
419 SilcUInt32 e_len, n_len;
422 /* Get PKCS object */
423 pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1-no-oid");
425 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
428 silc_pubkey->pkcs = pkcs;
432 SILC_GET32_MSB(e_len, key_data);
433 if (!e_len || e_len + 4 > keydata_len)
436 silc_mp_bin2mp(key_data + 4, e_len, &e);
437 if (keydata_len < 4 + e_len + 4) {
441 SILC_GET32_MSB(n_len, key_data + 4 + e_len);
442 if (!n_len || e_len + 4 + n_len + 4 > keydata_len) {
447 silc_mp_bin2mp(key_data + 4 + e_len + 4, n_len, &n);
449 /* Encode to PKCS #1 format */
450 memset(&alg_key, 0, sizeof(alg_key));
451 if (!silc_asn1_encode(asn1, &alg_key,
455 SILC_ASN1_END, SILC_ASN1_END)) {
464 } else if (!strcmp(pkcs_name, "dsa")) {
465 SILC_NOT_IMPLEMENTED("DSA SILC Public Key");
469 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
473 /* Import PKCS algorithm public key */
474 if (pkcs->import_public_key)
475 if (!pkcs->import_public_key(alg_key.data, silc_buffer_len(&alg_key),
476 &silc_pubkey->public_key))
479 silc_free(pkcs_name);
481 silc_asn1_free(asn1);
483 *ret_public_key = silc_pubkey;
488 silc_free(pkcs_name);
490 silc_free(silc_pubkey);
492 silc_asn1_free(asn1);
496 /* Exports public key as SILC protocol style public key file */
499 silc_pkcs_silc_export_public_key_file(void *public_key,
500 SilcPKCSFileEncoding encoding,
504 unsigned char *key, *data;
507 SILC_LOG_DEBUG(("Encoding SILC public key file"));
510 key = silc_pkcs_silc_export_public_key(public_key, &key_len);
515 case SILC_PKCS_FILE_BIN:
518 case SILC_PKCS_FILE_BASE64:
519 data = silc_pem_encode_file(key, key_len);
524 key_len = strlen(data);
528 /* Encode SILC public key file */
529 buf = silc_buffer_alloc_size(key_len +
530 (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
531 strlen(SILC_PKCS_PUBLIC_KEYFILE_END)));
537 if (silc_buffer_format(buf,
538 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
539 SILC_STR_UI_XNSTRING(key, key_len),
540 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END),
542 silc_buffer_free(buf);
548 key = silc_buffer_steal(buf, ret_len);
549 silc_buffer_free(buf);
554 /* Exports public key as SILC protocol style public key */
556 unsigned char *silc_pkcs_silc_export_public_key(void *public_key,
559 SilcSILCPublicKey silc_pubkey = public_key;
560 const SilcPKCSAlgorithm *pkcs = silc_pubkey->pkcs;
561 SilcBufferStruct alg_key;
562 SilcBuffer buf = NULL;
563 SilcAsn1 asn1 = NULL;
564 unsigned char *pk = NULL, *key = NULL, *ret;
565 SilcUInt32 pk_len, key_len, totlen;
568 SILC_LOG_DEBUG(("Encoding SILC public key"));
570 /* Export PKCS algorithm public key */
571 if (pkcs->export_public_key)
572 pk = pkcs->export_public_key(silc_pubkey->public_key, &pk_len);
575 silc_buffer_set(&alg_key, pk, pk_len);
577 /* Encode identifier */
579 silc_pkcs_silc_encode_identifier(silc_pubkey->identifier.username,
580 silc_pubkey->identifier.host,
581 silc_pubkey->identifier.realname,
582 silc_pubkey->identifier.email,
583 silc_pubkey->identifier.org,
584 silc_pubkey->identifier.country);
588 asn1 = silc_asn1_alloc();
592 if (!strcmp(pkcs->name, "rsa")) {
593 /* Parse the PKCS #1 public key */
595 SilcUInt32 n_len, e_len;
596 unsigned char *nb, *eb;
598 memset(&n, 0, sizeof(n));
599 memset(&e, 0, sizeof(e));
600 if (!silc_asn1_decode(asn1, &alg_key,
604 SILC_ASN1_END, SILC_ASN1_END))
607 /* Encode to SILC RSA public key */
608 eb = silc_mp_mp2bin(&e, 0, &e_len);
611 nb = silc_mp_mp2bin(&n, 0, &n_len);
614 key_len = e_len + 4 + n_len + 4;
615 key = silc_calloc(key_len, sizeof(*key));
619 /* Put e length and e */
620 SILC_PUT32_MSB(e_len, key);
621 memcpy(key + 4, eb, e_len);
623 /* Put n length and n. */
624 SILC_PUT32_MSB(n_len, key + 4 + e_len);
625 memcpy(key + 4 + e_len + 4, nb, n_len);
630 } else if (!strcmp(pkcs->name, "dsa")) {
631 SILC_NOT_IMPLEMENTED("SILC DSA Public Key");
635 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
639 /* Encode SILC Public Key */
640 totlen = 2 + strlen(pkcs->name) + 2 + strlen(identifier) + key_len;
641 buf = silc_buffer_alloc_size(totlen + 4);
644 if (silc_buffer_format(buf,
645 SILC_STR_UI_INT(totlen),
646 SILC_STR_UI_SHORT(strlen(pkcs->name)),
647 SILC_STR_UI32_STRING(pkcs->name),
648 SILC_STR_UI_SHORT(strlen(identifier)),
649 SILC_STR_UI32_STRING(identifier),
650 SILC_STR_UI_XNSTRING(key, key_len),
654 ret = silc_buffer_steal(buf, ret_len);
655 silc_buffer_free(buf);
657 silc_free(identifier);
658 silc_asn1_free(asn1);
663 silc_free(identifier);
667 silc_buffer_free(buf);
669 silc_asn1_free(asn1);
673 /* Return key length */
675 SilcUInt32 silc_pkcs_silc_public_key_bitlen(void *public_key)
677 SilcSILCPublicKey silc_pubkey = public_key;
678 return silc_pubkey->pkcs->public_key_bitlen(silc_pubkey->public_key);
681 /* Copy public key */
683 void *silc_pkcs_silc_public_key_copy(void *public_key)
685 SilcSILCPublicKey silc_pubkey = public_key, new_pubkey;
687 new_pubkey = silc_calloc(1, sizeof(*new_pubkey));
690 new_pubkey->pkcs = silc_pubkey->pkcs;
692 new_pubkey->public_key =
693 silc_pubkey->pkcs->public_key_copy(silc_pubkey->public_key);
694 if (!new_pubkey->public_key) {
695 silc_free(new_pubkey);
702 /* Compares public keys */
704 SilcBool silc_pkcs_silc_public_key_compare(void *key1, void *key2)
706 SilcSILCPublicKey k1 = key1, k2 = key2;
708 if (strcmp(k1->pkcs->name, k2->pkcs->name))
711 if ((k1->identifier.username && !k2->identifier.username) ||
712 (!k1->identifier.username && k2->identifier.username) ||
713 (k1->identifier.username && k2->identifier.username &&
714 strcmp(k1->identifier.username, k2->identifier.username)))
717 if ((k1->identifier.host && !k2->identifier.host) ||
718 (!k1->identifier.host && k2->identifier.host) ||
719 (k1->identifier.host && k2->identifier.host &&
720 strcmp(k1->identifier.host, k2->identifier.host)))
723 if ((k1->identifier.realname && !k2->identifier.realname) ||
724 (!k1->identifier.realname && k2->identifier.realname) ||
725 (k1->identifier.realname && k2->identifier.realname &&
726 strcmp(k1->identifier.realname, k2->identifier.realname)))
729 if ((k1->identifier.email && !k2->identifier.email) ||
730 (!k1->identifier.email && k2->identifier.email) ||
731 (k1->identifier.email && k2->identifier.email &&
732 strcmp(k1->identifier.email, k2->identifier.email)))
735 if ((k1->identifier.org && !k2->identifier.org) ||
736 (!k1->identifier.org && k2->identifier.org) ||
737 (k1->identifier.org && k2->identifier.org &&
738 strcmp(k1->identifier.org, k2->identifier.org)))
741 if ((k1->identifier.country && !k2->identifier.country) ||
742 (!k1->identifier.country && k2->identifier.country) ||
743 (k1->identifier.country && k2->identifier.country &&
744 strcmp(k1->identifier.country, k2->identifier.country)))
747 return k1->pkcs->public_key_compare(k1->public_key, k2->public_key);
750 /* Frees public key */
752 void silc_pkcs_silc_public_key_free(void *public_key)
754 SilcSILCPublicKey silc_pubkey = public_key;
756 silc_pubkey->pkcs->public_key_free(silc_pubkey->public_key);
758 silc_free(silc_pubkey->identifier.username);
759 silc_free(silc_pubkey->identifier.host);
760 silc_free(silc_pubkey->identifier.realname);
761 silc_free(silc_pubkey->identifier.email);
762 silc_free(silc_pubkey->identifier.org);
763 silc_free(silc_pubkey->identifier.country);
764 silc_free(silc_pubkey);
768 /*************************** Private key routines ****************************/
770 /* Private key file magic */
771 #define SILC_PKCS_PRIVATE_KEY_MAGIC 0x738df531
773 /* Imports SILC implementation style private key file */
775 SilcBool silc_pkcs_silc_import_private_key_file(unsigned char *filedata,
776 SilcUInt32 filedata_len,
777 const char *passphrase,
778 SilcUInt32 passphrase_len,
779 SilcPKCSFileEncoding encoding,
780 void **ret_private_key)
786 unsigned char tmp[32], keymat[64], *data = NULL;
787 SilcUInt32 i, len, magic, mac_len;
790 SILC_LOG_DEBUG(("Parsing SILC private key file"));
792 /* Check start of file and remove header from the data. */
793 len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
794 if (filedata_len < len + strlen(SILC_PKCS_PRIVATE_KEYFILE_END))
796 for (i = 0; i < len; i++) {
797 if (*filedata != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i])
802 len = filedata_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
803 strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
806 case SILC_PKCS_FILE_BIN:
809 case SILC_PKCS_FILE_BASE64:
810 data = silc_pem_decode(filedata, filedata_len, &len);
817 memset(tmp, 0, sizeof(tmp));
818 memset(keymat, 0, sizeof(keymat));
820 /* Check file magic */
821 SILC_GET32_MSB(magic, filedata);
822 if (magic != SILC_PKCS_PRIVATE_KEY_MAGIC) {
823 SILC_LOG_DEBUG(("Private key does not have correct magic"));
827 /* Allocate the AES cipher */
828 if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
829 SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
832 blocklen = silc_cipher_get_block_len(aes);
833 if (blocklen * 2 > sizeof(tmp)) {
834 silc_cipher_free(aes);
838 /* Allocate SHA1 hash */
839 if (!silc_hash_alloc("sha1", &sha1)) {
840 SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered"));
841 silc_cipher_free(aes);
846 if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
847 SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
848 silc_hash_free(sha1);
849 silc_cipher_free(aes);
853 /* Derive the decryption key from the provided key material. The key
854 is 256 bits length, and derived by taking hash of the data, then
855 re-hashing the data and the previous digest, and using the first and
856 second digest as the key. */
857 silc_hash_init(sha1);
858 silc_hash_update(sha1, passphrase, passphrase_len);
859 silc_hash_final(sha1, keymat);
860 silc_hash_init(sha1);
861 silc_hash_update(sha1, passphrase, passphrase_len);
862 silc_hash_update(sha1, keymat, 16);
863 silc_hash_final(sha1, keymat + 16);
865 /* Set the key to the cipher */
866 silc_cipher_set_key(aes, keymat, 256);
868 /* First, verify the MAC of the private key data */
869 mac_len = silc_hmac_len(sha1hmac);
870 silc_hmac_init_with_key(sha1hmac, keymat, 16);
871 silc_hmac_update(sha1hmac, filedata, len - mac_len);
872 silc_hmac_final(sha1hmac, tmp, NULL);
873 if (memcmp(tmp, filedata + (len - mac_len), mac_len)) {
874 SILC_LOG_DEBUG(("Integrity check for private key failed"));
875 memset(keymat, 0, sizeof(keymat));
876 memset(tmp, 0, sizeof(tmp));
877 silc_hmac_free(sha1hmac);
878 silc_hash_free(sha1);
879 silc_cipher_free(aes);
885 /* Decrypt the private key buffer */
886 silc_cipher_decrypt(aes, filedata, filedata, len - mac_len, NULL);
887 SILC_GET32_MSB(i, filedata);
889 SILC_LOG_DEBUG(("Bad private key length in buffer!"));
890 memset(keymat, 0, sizeof(keymat));
891 memset(tmp, 0, sizeof(tmp));
892 silc_hmac_free(sha1hmac);
893 silc_hash_free(sha1);
894 silc_cipher_free(aes);
901 memset(keymat, 0, sizeof(keymat));
902 memset(tmp, 0, sizeof(tmp));
903 silc_hmac_free(sha1hmac);
904 silc_hash_free(sha1);
905 silc_cipher_free(aes);
907 /* Import the private key */
908 ret = silc_pkcs_silc_import_private_key(filedata, len, ret_private_key);
915 /* Private key version */
916 #define SILC_PRIVATE_KEY_VERSION_1 0x82171273
918 /* Imports SILC implementation style private key */
920 SilcBool silc_pkcs_silc_import_private_key(unsigned char *key,
922 void **ret_private_key)
924 SilcBufferStruct buf;
925 const SilcPKCSAlgorithm *pkcs;
926 SilcBufferStruct alg_key;
927 SilcSILCPrivateKey silc_privkey = NULL;
928 SilcAsn1 asn1 = NULL;
930 SilcUInt32 keydata_len;
931 unsigned char *pkcs_name = NULL, *key_data;
934 SILC_LOG_DEBUG(("Parsing SILC private key"));
936 if (!ret_private_key)
939 silc_buffer_set(&buf, key, key_len);
941 /* Get algorithm name and identifier */
943 silc_buffer_unformat(&buf,
944 SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
947 SILC_LOG_DEBUG(("Cannot decode private key buffer"));
951 if (pkcs_len < 1 || pkcs_len > silc_buffer_truelen(&buf)) {
952 SILC_LOG_DEBUG(("Malformed private key buffer"));
956 /* Get key data. We assume that rest of the buffer is key data. */
957 silc_buffer_pull(&buf, 2 + pkcs_len);
958 keydata_len = silc_buffer_len(&buf);
959 ret = silc_buffer_unformat(&buf,
960 SILC_STR_UI_XNSTRING(&key_data, keydata_len),
965 /* Allocate SILC private key context */
966 silc_privkey = silc_calloc(1, sizeof(*silc_privkey));
970 asn1 = silc_asn1_alloc();
974 if (!strcmp(pkcs_name, "rsa")) {
975 /* Parse the RSA SILC private key */
977 SilcMPInt n, e, d, dp, dq, qp, p, q;
981 /* Get PKCS object */
982 pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1-no-oid");
984 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
987 silc_privkey->pkcs = pkcs;
992 silc_buffer_set(&k, key_data, keydata_len);
994 /* Get version. Key without the version is old style private key
995 and we need to do some computation to get it to correct format. */
996 if (silc_buffer_unformat(&k,
997 SILC_STR_UI_INT(&ver),
1000 silc_buffer_pull(&k, 4);
1002 if (ver != SILC_PRIVATE_KEY_VERSION_1) {
1005 if (silc_buffer_unformat(&k,
1006 SILC_STR_UI_INT(&len),
1009 silc_buffer_pull(&k, 4);
1013 if (silc_buffer_unformat(&k,
1014 SILC_STR_UI_XNSTRING(&tmp, len),
1018 silc_mp_bin2mp(tmp, len, &e);
1019 silc_buffer_pull(&k, len);
1022 if (silc_buffer_unformat(&k,
1023 SILC_STR_UI_INT(&len),
1026 silc_buffer_pull(&k, 4);
1027 if (silc_buffer_unformat(&k,
1028 SILC_STR_UI_XNSTRING(&tmp, len),
1032 silc_mp_bin2mp(tmp, len, &n);
1033 silc_buffer_pull(&k, len);
1036 if (silc_buffer_unformat(&k,
1037 SILC_STR_UI_INT(&len),
1040 silc_buffer_pull(&k, 4);
1041 if (silc_buffer_unformat(&k,
1042 SILC_STR_UI_XNSTRING(&tmp, len),
1046 silc_mp_bin2mp(tmp, len, &d);
1047 silc_buffer_pull(&k, len);
1050 if (silc_buffer_unformat(&k,
1051 SILC_STR_UI_INT(&len),
1054 silc_buffer_pull(&k, 4);
1055 if (silc_buffer_unformat(&k,
1056 SILC_STR_UI_XNSTRING(&tmp, len),
1060 silc_mp_bin2mp(tmp, len, &dp);
1061 silc_buffer_pull(&k, len);
1064 if (silc_buffer_unformat(&k,
1065 SILC_STR_UI_INT(&len),
1068 silc_buffer_pull(&k, 4);
1069 if (silc_buffer_unformat(&k,
1070 SILC_STR_UI_XNSTRING(&tmp, len),
1074 silc_mp_bin2mp(tmp, len, &dq);
1075 silc_buffer_pull(&k, len);
1077 if (ver != SILC_PRIVATE_KEY_VERSION_1) {
1081 if (silc_buffer_unformat(&k,
1082 SILC_STR_UI_INT(&len),
1085 silc_buffer_pull(&k, 4);
1086 if (silc_buffer_len(&k) < len)
1088 silc_buffer_pull(&k, len);
1091 if (silc_buffer_unformat(&k,
1092 SILC_STR_UI_INT(&len),
1095 silc_buffer_pull(&k, 4);
1096 if (silc_buffer_len(&k) < len)
1098 silc_buffer_pull(&k, len);
1103 if (silc_buffer_unformat(&k,
1104 SILC_STR_UI_INT(&len),
1107 silc_buffer_pull(&k, 4);
1108 if (silc_buffer_unformat(&k,
1109 SILC_STR_UI_XNSTRING(&tmp, len),
1113 silc_mp_bin2mp(tmp, len, &qp);
1114 silc_buffer_pull(&k, len);
1118 if (silc_buffer_unformat(&k,
1119 SILC_STR_UI_INT(&len),
1122 silc_buffer_pull(&k, 4);
1123 if (silc_buffer_unformat(&k,
1124 SILC_STR_UI_XNSTRING(&tmp, len),
1128 silc_mp_bin2mp(tmp, len, &p);
1129 silc_buffer_pull(&k, len);
1132 if (silc_buffer_unformat(&k,
1133 SILC_STR_UI_INT(&len),
1136 silc_buffer_pull(&k, 4);
1137 if (silc_buffer_unformat(&k,
1138 SILC_STR_UI_XNSTRING(&tmp, len),
1142 silc_mp_bin2mp(tmp, len, &q);
1143 silc_buffer_pull(&k, len);
1145 if (ver != SILC_PRIVATE_KEY_VERSION_1) {
1146 /* Old version. Compute to new version */
1147 SILC_LOG_DEBUG(("Old version private key"));
1149 silc_mp_modinv(&qp, &q, &p);
1152 /* Encode to PKCS #1 format */
1153 memset(&alg_key, 0, sizeof(alg_key));
1154 if (!silc_asn1_encode(asn1, &alg_key,
1156 SILC_ASN1_SHORT_INT(0),
1165 SILC_ASN1_END, SILC_ASN1_END))
1174 silc_mp_uninit(&dp);
1175 silc_mp_uninit(&dq);
1176 silc_mp_uninit(&qp);
1178 } else if (!strcmp(pkcs_name, "dsa")) {
1179 SILC_NOT_IMPLEMENTED("DSA SILC Private Key");
1183 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
1187 /* Import PKCS algorithm private key */
1188 if (pkcs->import_private_key)
1189 if (!pkcs->import_private_key(alg_key.data, silc_buffer_len(&alg_key),
1190 &silc_privkey->private_key))
1193 silc_free(pkcs_name);
1194 silc_asn1_free(asn1);
1196 *ret_private_key = silc_privkey;
1201 silc_free(pkcs_name);
1202 silc_free(silc_privkey);
1204 silc_asn1_free(asn1);
1208 /* Exports private key as SILC implementation style private key file */
1211 silc_pkcs_silc_export_private_key_file(void *private_key,
1212 const char *passphrase,
1213 SilcUInt32 passphrase_len,
1214 SilcPKCSFileEncoding encoding,
1216 SilcUInt32 *ret_len)
1221 SilcBuffer buf, enc;
1222 SilcUInt32 len, blocklen, padlen, key_len;
1223 unsigned char *key, *data;
1224 unsigned char tmp[32], keymat[64];
1227 SILC_LOG_DEBUG(("Encoding SILC private key file"));
1229 /* Export the private key */
1230 key = silc_pkcs_silc_export_private_key(private_key, &key_len);
1234 memset(tmp, 0, sizeof(tmp));
1235 memset(keymat, 0, sizeof(keymat));
1237 /* Allocate the AES cipher */
1238 if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
1239 SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
1243 blocklen = silc_cipher_get_block_len(aes);
1244 if (blocklen * 2 > sizeof(tmp)) {
1245 silc_cipher_free(aes);
1250 /* Allocate SHA1 hash */
1251 if (!silc_hash_alloc("sha1", &sha1)) {
1252 SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered"));
1253 silc_cipher_free(aes);
1258 if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
1259 SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
1260 silc_hash_free(sha1);
1261 silc_cipher_free(aes);
1265 /* Derive the encryption key from the provided key material. The key
1266 is 256 bits length, and derived by taking hash of the data, then
1267 re-hashing the data and the previous digest, and using the first and
1268 second digest as the key. */
1269 silc_hash_init(sha1);
1270 silc_hash_update(sha1, passphrase, passphrase_len);
1271 silc_hash_final(sha1, keymat);
1272 silc_hash_init(sha1);
1273 silc_hash_update(sha1, passphrase, passphrase_len);
1274 silc_hash_update(sha1, keymat, 16);
1275 silc_hash_final(sha1, keymat + 16);
1277 /* Set the key to the cipher */
1278 silc_cipher_set_key(aes, keymat, 256);
1280 /* Encode the buffer to be encrypted. Add padding to it too, at least
1281 block size of the cipher. */
1283 /* Allocate buffer for encryption */
1284 len = silc_hmac_len(sha1hmac);
1285 padlen = 16 + (16 - ((key_len + 4) % blocklen));
1286 enc = silc_buffer_alloc_size(4 + 4 + key_len + padlen + len);
1288 silc_hmac_free(sha1hmac);
1289 silc_hash_free(sha1);
1290 silc_cipher_free(aes);
1294 /* Generate padding */
1295 for (i = 0; i < padlen; i++)
1296 tmp[i] = silc_rng_get_byte_fast(rng);
1298 /* Put magic number */
1299 SILC_PUT32_MSB(SILC_PKCS_PRIVATE_KEY_MAGIC, enc->data);
1300 silc_buffer_pull(enc, 4);
1302 /* Encode the buffer */
1303 silc_buffer_format(enc,
1304 SILC_STR_UI_INT(key_len),
1305 SILC_STR_UI_XNSTRING(key, key_len),
1306 SILC_STR_UI_XNSTRING(tmp, padlen),
1311 silc_cipher_encrypt(aes, enc->data, enc->data, silc_buffer_len(enc) - len,
1312 silc_cipher_get_iv(aes));
1314 silc_buffer_push(enc, 4);
1316 /* Compute HMAC over the encrypted data and append the MAC to data.
1317 The key is the first digest of the original key material. */
1318 key_len = silc_buffer_len(enc) - len;
1319 silc_hmac_init_with_key(sha1hmac, keymat, 16);
1320 silc_hmac_update(sha1hmac, enc->data, key_len);
1321 silc_buffer_pull(enc, key_len);
1322 silc_hmac_final(sha1hmac, enc->data, NULL);
1323 silc_buffer_push(enc, key_len);
1326 memset(keymat, 0, sizeof(keymat));
1327 memset(tmp, 0, sizeof(tmp));
1328 silc_hmac_free(sha1hmac);
1329 silc_hash_free(sha1);
1330 silc_cipher_free(aes);
1333 case SILC_PKCS_FILE_BIN:
1336 case SILC_PKCS_FILE_BASE64:
1337 data = silc_pem_encode_file(enc->data, silc_buffer_len(enc));
1339 silc_buffer_clear(enc);
1340 silc_buffer_free(enc);
1343 silc_free(silc_buffer_steal(enc, NULL));
1344 silc_buffer_set(enc, data, strlen(data));
1349 key_len = silc_buffer_len(enc);
1351 /* Encode the data and save to file */
1352 len = key_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
1353 strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
1354 buf = silc_buffer_alloc_size(len);
1356 silc_buffer_free(enc);
1359 silc_buffer_format(buf,
1360 SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
1361 SILC_STR_UI_XNSTRING(key, key_len),
1362 SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
1365 silc_buffer_free(enc);
1366 data = silc_buffer_steal(buf, ret_len);
1367 silc_buffer_free(buf);
1372 /* Exports private key as SILC implementation style private key */
1374 unsigned char *silc_pkcs_silc_export_private_key(void *private_key,
1375 SilcUInt32 *ret_len)
1377 SilcSILCPrivateKey silc_privkey = private_key;
1378 const SilcPKCSAlgorithm *pkcs = silc_privkey->pkcs;
1379 SilcBufferStruct alg_key;
1380 SilcBuffer buf = NULL;
1381 SilcAsn1 asn1 = NULL;
1382 unsigned char *prv = NULL, *key = NULL, *ret;
1383 SilcUInt32 prv_len, key_len, totlen;
1385 SILC_LOG_DEBUG(("Encoding SILC private key"));
1387 /* Export PKCS algorithm private key */
1388 if (pkcs->export_private_key)
1389 prv = pkcs->export_private_key(silc_privkey->private_key, &prv_len);
1392 silc_buffer_set(&alg_key, prv, prv_len);
1394 asn1 = silc_asn1_alloc();
1398 if (!strcmp(pkcs->name, "rsa")) {
1399 /* Parse the PKCS #1 private key */
1400 SilcMPInt n, e, d, dp, dq, qp, p, q;
1401 SilcUInt32 e_len, n_len, d_len, dp_len, dq_len,
1402 qp_len, p_len, q_len, len = 0;
1403 unsigned char *nb, *eb, *db, *dpb, *dqb, *qpb, *pb, *qb;
1405 if (!silc_asn1_decode(asn1, &alg_key,
1407 SILC_ASN1_INT(NULL),
1416 SILC_ASN1_END, SILC_ASN1_END))
1419 /* Encode to SILC RSA private key */
1420 eb = silc_mp_mp2bin(&e, 0, &e_len);
1421 nb = silc_mp_mp2bin(&n, 0, &n_len);
1422 db = silc_mp_mp2bin(&d, 0, &d_len);
1423 dpb = silc_mp_mp2bin(&dp, 0, &dp_len);
1424 dqb = silc_mp_mp2bin(&dq, 0, &dq_len);
1425 qpb = silc_mp_mp2bin(&qp, 0, &qp_len);
1426 pb = silc_mp_mp2bin(&p, 0, &p_len);
1427 qb = silc_mp_mp2bin(&q, 0, &q_len);
1428 len = 4 + e_len + 4 + n_len + 4 + d_len + 4+ dp_len + 4 +
1429 dq_len + 4 + qp_len + 4 + p_len + 4 + q_len + 4;
1431 buf = silc_buffer_alloc_size(len);
1434 if (silc_buffer_format(buf,
1435 SILC_STR_UI_INT(SILC_PRIVATE_KEY_VERSION_1),
1436 SILC_STR_UI_INT(e_len),
1437 SILC_STR_UI_XNSTRING(eb, e_len),
1438 SILC_STR_UI_INT(n_len),
1439 SILC_STR_UI_XNSTRING(nb, n_len),
1440 SILC_STR_UI_INT(d_len),
1441 SILC_STR_UI_XNSTRING(db, d_len),
1442 SILC_STR_UI_INT(dp_len),
1443 SILC_STR_UI_XNSTRING(dpb, dp_len),
1444 SILC_STR_UI_INT(dq_len),
1445 SILC_STR_UI_XNSTRING(dqb, dq_len),
1446 SILC_STR_UI_INT(qp_len),
1447 SILC_STR_UI_XNSTRING(qpb, qp_len),
1448 SILC_STR_UI_INT(p_len),
1449 SILC_STR_UI_XNSTRING(pb, p_len),
1450 SILC_STR_UI_INT(q_len),
1451 SILC_STR_UI_XNSTRING(qb, q_len),
1455 key = silc_buffer_steal(buf, &key_len);
1456 silc_buffer_free(buf);
1466 } else if (!strcmp(pkcs->name, "dsa")) {
1467 SILC_NOT_IMPLEMENTED("SILC DSA Private Key");
1471 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
1475 /* Encode SILC private key */
1476 totlen = 2 + strlen(pkcs->name) + key_len;
1477 buf = silc_buffer_alloc_size(totlen);
1480 if (silc_buffer_format(buf,
1481 SILC_STR_UI_SHORT(strlen(pkcs->name)),
1482 SILC_STR_UI32_STRING(pkcs->name),
1483 SILC_STR_UI_XNSTRING(key, key_len),
1487 ret = silc_buffer_steal(buf, ret_len);
1488 silc_buffer_free(buf);
1491 silc_asn1_free(asn1);
1499 silc_buffer_free(buf);
1503 /* Return key length */
1505 SilcUInt32 silc_pkcs_silc_private_key_bitlen(void *private_key)
1507 SilcSILCPrivateKey silc_privkey = private_key;
1508 return silc_privkey->pkcs->private_key_bitlen(silc_privkey->private_key);
1511 /* Frees private key */
1513 void silc_pkcs_silc_private_key_free(void *private_key)
1515 SilcSILCPrivateKey silc_privkey = private_key;
1517 silc_privkey->pkcs->private_key_free(silc_privkey->private_key);
1519 silc_free(silc_privkey);
1523 /***************************** PKCS operations ******************************/
1525 /* Encrypts as specified in SILC protocol specification */
1527 SilcBool silc_pkcs_silc_encrypt(void *public_key,
1531 SilcUInt32 dst_size,
1532 SilcUInt32 *ret_dst_len)
1534 SilcSILCPublicKey silc_pubkey = public_key;
1536 if (!silc_pubkey->pkcs->encrypt)
1539 return silc_pubkey->pkcs->encrypt(silc_pubkey->public_key,
1541 dst, dst_size, ret_dst_len);
1544 /* Decrypts as specified in SILC protocol specification */
1546 SilcBool silc_pkcs_silc_decrypt(void *private_key,
1550 SilcUInt32 dst_size,
1551 SilcUInt32 *ret_dst_len)
1553 SilcSILCPrivateKey silc_privkey = private_key;
1555 if (!silc_privkey->pkcs->decrypt)
1558 return silc_privkey->pkcs->decrypt(silc_privkey->private_key,
1560 dst, dst_size, ret_dst_len);
1563 /* Signs as specified in SILC protocol specification */
1565 SilcBool silc_pkcs_silc_sign(void *private_key,
1568 unsigned char *signature,
1569 SilcUInt32 signature_size,
1570 SilcUInt32 *ret_signature_len,
1573 SilcSILCPrivateKey silc_privkey = private_key;
1575 if (!silc_privkey->pkcs->sign)
1578 return silc_privkey->pkcs->sign(silc_privkey->private_key,
1580 signature, signature_size,
1581 ret_signature_len, hash);
1584 /* Verifies as specified in SILC protocol specification */
1586 SilcBool silc_pkcs_silc_verify(void *public_key,
1587 unsigned char *signature,
1588 SilcUInt32 signature_len,
1589 unsigned char *data,
1590 SilcUInt32 data_len,
1593 SilcSILCPublicKey silc_pubkey = public_key;
1595 if (!silc_pubkey->pkcs->verify)
1598 return silc_pubkey->pkcs->verify(silc_pubkey->public_key,
1599 signature, signature_len,
1600 data, data_len, hash);