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 if (totlen + 4 != key_len)
376 /* Get algorithm name and identifier */
378 silc_buffer_unformat(&buf,
380 SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
381 SILC_STR_UI16_NSTRING_ALLOC(&ident, &identifier_len),
386 if (pkcs_len < 1 || identifier_len < 3 ||
387 pkcs_len + identifier_len > totlen)
391 silc_buffer_pull(&buf, 4 + 2 + pkcs_len + 2 + identifier_len);
392 keydata_len = silc_buffer_len(&buf);
393 ret = silc_buffer_unformat(&buf,
394 SILC_STR_UI_XNSTRING(&key_data,
400 /* Allocate SILC public key context */
401 silc_pubkey = silc_calloc(1, sizeof(*silc_pubkey));
405 /* Decode SILC identifier */
406 if (!silc_pkcs_silc_decode_identifier(ident, &silc_pubkey->identifier))
409 asn1 = silc_asn1_alloc();
413 if (!strcmp(pkcs_name, "rsa")) {
414 /* Parse the SILC RSA public key */
415 SilcUInt32 e_len, n_len;
418 /* Get PKCS object */
419 pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1-no-oid");
421 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
424 silc_pubkey->pkcs = pkcs;
428 SILC_GET32_MSB(e_len, key_data);
429 if (!e_len || e_len + 4 > keydata_len)
432 silc_mp_bin2mp(key_data + 4, e_len, &e);
433 if (keydata_len < 4 + e_len + 4) {
437 SILC_GET32_MSB(n_len, key_data + 4 + e_len);
438 if (!n_len || e_len + 4 + n_len + 4 > keydata_len) {
443 silc_mp_bin2mp(key_data + 4 + e_len + 4, n_len, &n);
445 /* Encode to PKCS #1 format */
446 memset(&alg_key, 0, sizeof(alg_key));
447 if (!silc_asn1_encode(asn1, &alg_key,
451 SILC_ASN1_END, SILC_ASN1_END)) {
460 } else if (!strcmp(pkcs_name, "dsa")) {
461 SILC_NOT_IMPLEMENTED("DSA SILC Public Key");
465 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
469 /* Import PKCS algorithm public key */
470 if (pkcs->import_public_key)
471 if (!pkcs->import_public_key(alg_key.data, silc_buffer_len(&alg_key),
472 &silc_pubkey->public_key))
475 silc_free(pkcs_name);
477 silc_asn1_free(asn1);
479 *ret_public_key = silc_pubkey;
484 silc_free(pkcs_name);
486 silc_free(silc_pubkey);
488 silc_asn1_free(asn1);
492 /* Exports public key as SILC protocol style public key file */
495 silc_pkcs_silc_export_public_key_file(void *public_key,
496 SilcPKCSFileEncoding encoding,
500 unsigned char *key, *data;
503 SILC_LOG_DEBUG(("Encoding SILC public key file"));
506 key = silc_pkcs_silc_export_public_key(public_key, &key_len);
511 case SILC_PKCS_FILE_BIN:
514 case SILC_PKCS_FILE_BASE64:
515 data = silc_pem_encode_file(key, key_len);
520 key_len = strlen(data);
524 /* Encode SILC public key file */
525 buf = silc_buffer_alloc_size(key_len +
526 (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
527 strlen(SILC_PKCS_PUBLIC_KEYFILE_END)));
533 if (silc_buffer_format(buf,
534 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
535 SILC_STR_UI_XNSTRING(key, key_len),
536 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END),
538 silc_buffer_free(buf);
544 key = silc_buffer_steal(buf, ret_len);
545 silc_buffer_free(buf);
550 /* Exports public key as SILC protocol style public key */
552 unsigned char *silc_pkcs_silc_export_public_key(void *public_key,
555 SilcSILCPublicKey silc_pubkey = public_key;
556 const SilcPKCSAlgorithm *pkcs = silc_pubkey->pkcs;
557 SilcBufferStruct alg_key;
558 SilcBuffer buf = NULL;
559 SilcAsn1 asn1 = NULL;
560 unsigned char *pk = NULL, *key = NULL, *ret;
561 SilcUInt32 pk_len, key_len, totlen;
564 SILC_LOG_DEBUG(("Encoding SILC public key"));
566 /* Export PKCS algorithm public key */
567 if (pkcs->export_public_key)
568 pk = pkcs->export_public_key(silc_pubkey->public_key, &pk_len);
571 silc_buffer_set(&alg_key, pk, pk_len);
573 /* Encode identifier */
575 silc_pkcs_silc_encode_identifier(silc_pubkey->identifier.username,
576 silc_pubkey->identifier.host,
577 silc_pubkey->identifier.realname,
578 silc_pubkey->identifier.email,
579 silc_pubkey->identifier.org,
580 silc_pubkey->identifier.country);
584 asn1 = silc_asn1_alloc();
588 if (!strcmp(pkcs->name, "rsa")) {
589 /* Parse the PKCS #1 public key */
591 SilcUInt32 n_len, e_len;
592 unsigned char *nb, *eb;
594 memset(&n, 0, sizeof(n));
595 memset(&e, 0, sizeof(e));
596 if (!silc_asn1_decode(asn1, &alg_key,
600 SILC_ASN1_END, SILC_ASN1_END))
603 /* Encode to SILC RSA public key */
604 eb = silc_mp_mp2bin(&e, 0, &e_len);
607 nb = silc_mp_mp2bin(&n, 0, &n_len);
610 key_len = e_len + 4 + n_len + 4;
611 key = silc_calloc(key_len, sizeof(*key));
615 /* Put e length and e */
616 SILC_PUT32_MSB(e_len, key);
617 memcpy(key + 4, eb, e_len);
619 /* Put n length and n. */
620 SILC_PUT32_MSB(n_len, key + 4 + e_len);
621 memcpy(key + 4 + e_len + 4, nb, n_len);
626 } else if (!strcmp(pkcs->name, "dsa")) {
627 SILC_NOT_IMPLEMENTED("SILC DSA Public Key");
631 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
635 /* Encode SILC Public Key */
636 totlen = 2 + strlen(pkcs->name) + 2 + strlen(identifier) + key_len;
637 buf = silc_buffer_alloc_size(totlen + 4);
640 if (silc_buffer_format(buf,
641 SILC_STR_UI_INT(totlen),
642 SILC_STR_UI_SHORT(strlen(pkcs->name)),
643 SILC_STR_UI32_STRING(pkcs->name),
644 SILC_STR_UI_SHORT(strlen(identifier)),
645 SILC_STR_UI32_STRING(identifier),
646 SILC_STR_UI_XNSTRING(key, key_len),
650 ret = silc_buffer_steal(buf, ret_len);
651 silc_buffer_free(buf);
653 silc_free(identifier);
654 silc_asn1_free(asn1);
659 silc_free(identifier);
663 silc_buffer_free(buf);
665 silc_asn1_free(asn1);
669 /* Return key length */
671 SilcUInt32 silc_pkcs_silc_public_key_bitlen(void *public_key)
673 SilcSILCPublicKey silc_pubkey = public_key;
674 return silc_pubkey->pkcs->public_key_bitlen(silc_pubkey->public_key);
677 /* Copy public key */
679 void *silc_pkcs_silc_public_key_copy(void *public_key)
681 SilcSILCPublicKey silc_pubkey = public_key, new_pubkey;
683 new_pubkey = silc_calloc(1, sizeof(*new_pubkey));
686 new_pubkey->pkcs = silc_pubkey->pkcs;
688 new_pubkey->public_key =
689 silc_pubkey->pkcs->public_key_copy(silc_pubkey->public_key);
690 if (!new_pubkey->public_key) {
691 silc_free(new_pubkey);
698 /* Compares public keys */
700 SilcBool silc_pkcs_silc_public_key_compare(void *key1, void *key2)
702 SilcSILCPublicKey k1 = key1, k2 = key2;
704 if (strcmp(k1->pkcs->name, k2->pkcs->name))
707 if ((k1->identifier.username && !k2->identifier.username) ||
708 (!k1->identifier.username && k2->identifier.username) ||
709 (k1->identifier.username && k2->identifier.username &&
710 strcmp(k1->identifier.username, k2->identifier.username)))
713 if ((k1->identifier.host && !k2->identifier.host) ||
714 (!k1->identifier.host && k2->identifier.host) ||
715 (k1->identifier.host && k2->identifier.host &&
716 strcmp(k1->identifier.host, k2->identifier.host)))
719 if ((k1->identifier.realname && !k2->identifier.realname) ||
720 (!k1->identifier.realname && k2->identifier.realname) ||
721 (k1->identifier.realname && k2->identifier.realname &&
722 strcmp(k1->identifier.realname, k2->identifier.realname)))
725 if ((k1->identifier.email && !k2->identifier.email) ||
726 (!k1->identifier.email && k2->identifier.email) ||
727 (k1->identifier.email && k2->identifier.email &&
728 strcmp(k1->identifier.email, k2->identifier.email)))
731 if ((k1->identifier.org && !k2->identifier.org) ||
732 (!k1->identifier.org && k2->identifier.org) ||
733 (k1->identifier.org && k2->identifier.org &&
734 strcmp(k1->identifier.org, k2->identifier.org)))
737 if ((k1->identifier.country && !k2->identifier.country) ||
738 (!k1->identifier.country && k2->identifier.country) ||
739 (k1->identifier.country && k2->identifier.country &&
740 strcmp(k1->identifier.country, k2->identifier.country)))
743 return k1->pkcs->public_key_compare(k1->public_key, k2->public_key);
746 /* Frees public key */
748 void silc_pkcs_silc_public_key_free(void *public_key)
750 SilcSILCPublicKey silc_pubkey = public_key;
752 silc_pubkey->pkcs->public_key_free(silc_pubkey->public_key);
754 silc_free(silc_pubkey->identifier.username);
755 silc_free(silc_pubkey->identifier.host);
756 silc_free(silc_pubkey->identifier.realname);
757 silc_free(silc_pubkey->identifier.email);
758 silc_free(silc_pubkey->identifier.org);
759 silc_free(silc_pubkey->identifier.country);
760 silc_free(silc_pubkey);
764 /*************************** Private key routines ****************************/
766 /* Private key file magic */
767 #define SILC_PKCS_PRIVATE_KEY_MAGIC 0x738df531
769 /* Imports SILC implementation style private key file */
771 SilcBool silc_pkcs_silc_import_private_key_file(unsigned char *filedata,
772 SilcUInt32 filedata_len,
773 const char *passphrase,
774 SilcUInt32 passphrase_len,
775 SilcPKCSFileEncoding encoding,
776 void **ret_private_key)
782 unsigned char tmp[32], keymat[64], *data = NULL;
783 SilcUInt32 i, len, magic, mac_len;
786 SILC_LOG_DEBUG(("Parsing SILC private key file"));
788 /* Check start of file and remove header from the data. */
789 len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
790 if (filedata_len < len + strlen(SILC_PKCS_PRIVATE_KEYFILE_END))
792 for (i = 0; i < len; i++) {
793 if (*filedata != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i])
798 len = filedata_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
799 strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
802 case SILC_PKCS_FILE_BIN:
805 case SILC_PKCS_FILE_BASE64:
806 data = silc_pem_decode(filedata, filedata_len, &len);
813 memset(tmp, 0, sizeof(tmp));
814 memset(keymat, 0, sizeof(keymat));
816 /* Check file magic */
817 SILC_GET32_MSB(magic, filedata);
818 if (magic != SILC_PKCS_PRIVATE_KEY_MAGIC) {
819 SILC_LOG_ERROR(("Private key does not have correct magic"));
823 /* Allocate the AES cipher */
824 if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
825 SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
828 blocklen = silc_cipher_get_block_len(aes);
829 if (blocklen * 2 > sizeof(tmp)) {
830 silc_cipher_free(aes);
834 /* Allocate SHA1 hash */
835 if (!silc_hash_alloc("sha1", &sha1)) {
836 SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered"));
837 silc_cipher_free(aes);
842 if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
843 SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
844 silc_hash_free(sha1);
845 silc_cipher_free(aes);
849 /* Derive the decryption key from the provided key material. The key
850 is 256 bits length, and derived by taking hash of the data, then
851 re-hashing the data and the previous digest, and using the first and
852 second digest as the key. */
853 silc_hash_init(sha1);
854 silc_hash_update(sha1, passphrase, passphrase_len);
855 silc_hash_final(sha1, keymat);
856 silc_hash_init(sha1);
857 silc_hash_update(sha1, passphrase, passphrase_len);
858 silc_hash_update(sha1, keymat, 16);
859 silc_hash_final(sha1, keymat + 16);
861 /* Set the key to the cipher */
862 silc_cipher_set_key(aes, keymat, 256);
864 /* First, verify the MAC of the private key data */
865 mac_len = silc_hmac_len(sha1hmac);
866 silc_hmac_init_with_key(sha1hmac, keymat, 16);
867 silc_hmac_update(sha1hmac, filedata, len - mac_len);
868 silc_hmac_final(sha1hmac, tmp, NULL);
869 if (memcmp(tmp, filedata + (len - mac_len), mac_len)) {
870 SILC_LOG_DEBUG(("Integrity check for private key failed"));
871 memset(keymat, 0, sizeof(keymat));
872 memset(tmp, 0, sizeof(tmp));
873 silc_hmac_free(sha1hmac);
874 silc_hash_free(sha1);
875 silc_cipher_free(aes);
881 /* Decrypt the private key buffer */
882 silc_cipher_decrypt(aes, filedata, filedata, len - mac_len, NULL);
883 SILC_GET32_MSB(i, filedata);
885 SILC_LOG_DEBUG(("Bad private key length in buffer!"));
886 memset(keymat, 0, sizeof(keymat));
887 memset(tmp, 0, sizeof(tmp));
888 silc_hmac_free(sha1hmac);
889 silc_hash_free(sha1);
890 silc_cipher_free(aes);
897 memset(keymat, 0, sizeof(keymat));
898 memset(tmp, 0, sizeof(tmp));
899 silc_hmac_free(sha1hmac);
900 silc_hash_free(sha1);
901 silc_cipher_free(aes);
903 /* Import the private key */
904 ret = silc_pkcs_silc_import_private_key(filedata, len, ret_private_key);
911 /* Private key version */
912 #define SILC_PRIVATE_KEY_VERSION_1 0x82171273
914 /* Imports SILC implementation style private key */
916 SilcBool silc_pkcs_silc_import_private_key(unsigned char *key,
918 void **ret_private_key)
920 SilcBufferStruct buf;
921 const SilcPKCSAlgorithm *pkcs;
922 SilcBufferStruct alg_key;
923 SilcSILCPrivateKey silc_privkey = NULL;
924 SilcAsn1 asn1 = NULL;
926 SilcUInt32 keydata_len;
927 unsigned char *pkcs_name = NULL, *key_data;
930 SILC_LOG_DEBUG(("Parsing SILC private key"));
932 if (!ret_private_key)
935 silc_buffer_set(&buf, key, key_len);
937 /* Get algorithm name and identifier */
939 silc_buffer_unformat(&buf,
940 SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
943 SILC_LOG_DEBUG(("Cannot decode private key buffer"));
947 if (pkcs_len < 1 || pkcs_len > silc_buffer_truelen(&buf)) {
948 SILC_LOG_DEBUG(("Malformed private key buffer"));
952 /* Get key data. We assume that rest of the buffer is key data. */
953 silc_buffer_pull(&buf, 2 + pkcs_len);
954 keydata_len = silc_buffer_len(&buf);
955 ret = silc_buffer_unformat(&buf,
956 SILC_STR_UI_XNSTRING(&key_data, keydata_len),
961 /* Allocate SILC private key context */
962 silc_privkey = silc_calloc(1, sizeof(*silc_privkey));
966 asn1 = silc_asn1_alloc();
970 if (!strcmp(pkcs_name, "rsa")) {
971 /* Parse the RSA SILC private key */
973 SilcMPInt n, e, d, dp, dq, qp, p, q;
978 /* Get PKCS object */
979 pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1-no-oid");
981 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
984 silc_privkey->pkcs = pkcs;
989 silc_buffer_set(&k, key_data, keydata_len);
991 /* Get version. Key without the version is old style private key
992 and we need to do some computation to get it to correct format. */
993 if (silc_buffer_unformat(&k,
994 SILC_STR_UI_INT(&ver),
997 silc_buffer_pull(&k, 4);
999 if (ver != SILC_PRIVATE_KEY_VERSION_1) {
1002 if (silc_buffer_unformat(&k,
1003 SILC_STR_UI_INT(&len),
1006 silc_buffer_pull(&k, 4);
1010 if (silc_buffer_unformat(&k,
1011 SILC_STR_UI_XNSTRING(&tmp, len),
1015 silc_mp_bin2mp(tmp, len, &e);
1016 silc_buffer_pull(&k, len);
1019 if (silc_buffer_unformat(&k,
1020 SILC_STR_UI_INT(&len),
1023 silc_buffer_pull(&k, 4);
1024 if (silc_buffer_unformat(&k,
1025 SILC_STR_UI_XNSTRING(&tmp, len),
1029 silc_mp_bin2mp(tmp, len, &n);
1030 silc_buffer_pull(&k, len);
1033 if (silc_buffer_unformat(&k,
1034 SILC_STR_UI_INT(&len),
1037 silc_buffer_pull(&k, 4);
1038 if (silc_buffer_unformat(&k,
1039 SILC_STR_UI_XNSTRING(&tmp, len),
1043 silc_mp_bin2mp(tmp, len, &d);
1044 silc_buffer_pull(&k, len);
1047 if (silc_buffer_unformat(&k,
1048 SILC_STR_UI_INT(&len),
1051 silc_buffer_pull(&k, 4);
1052 if (silc_buffer_unformat(&k,
1053 SILC_STR_UI_XNSTRING(&tmp, len),
1057 silc_mp_bin2mp(tmp, len, &dp);
1058 silc_buffer_pull(&k, len);
1061 if (silc_buffer_unformat(&k,
1062 SILC_STR_UI_INT(&len),
1065 silc_buffer_pull(&k, 4);
1066 if (silc_buffer_unformat(&k,
1067 SILC_STR_UI_XNSTRING(&tmp, len),
1071 silc_mp_bin2mp(tmp, len, &dq);
1072 silc_buffer_pull(&k, len);
1074 if (ver != SILC_PRIVATE_KEY_VERSION_1) {
1078 if (silc_buffer_unformat(&k,
1079 SILC_STR_UI_INT(&len),
1082 silc_buffer_pull(&k, 4);
1083 if (silc_buffer_len(&k) < len)
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_len(&k) < len)
1095 silc_buffer_pull(&k, len);
1100 if (silc_buffer_unformat(&k,
1101 SILC_STR_UI_INT(&len),
1104 silc_buffer_pull(&k, 4);
1105 if (silc_buffer_unformat(&k,
1106 SILC_STR_UI_XNSTRING(&tmp, len),
1110 silc_mp_bin2mp(tmp, len, &qp);
1111 silc_buffer_pull(&k, len);
1115 if (silc_buffer_unformat(&k,
1116 SILC_STR_UI_INT(&len),
1119 silc_buffer_pull(&k, 4);
1120 if (silc_buffer_unformat(&k,
1121 SILC_STR_UI_XNSTRING(&tmp, len),
1125 silc_mp_bin2mp(tmp, len, &p);
1126 silc_buffer_pull(&k, len);
1129 if (silc_buffer_unformat(&k,
1130 SILC_STR_UI_INT(&len),
1133 silc_buffer_pull(&k, 4);
1134 if (silc_buffer_unformat(&k,
1135 SILC_STR_UI_XNSTRING(&tmp, len),
1139 silc_mp_bin2mp(tmp, len, &q);
1140 silc_buffer_pull(&k, len);
1142 if (ver != SILC_PRIVATE_KEY_VERSION_1) {
1143 /* Old version. Compute to new version */
1144 SILC_LOG_DEBUG(("Old version private key"));
1146 silc_mp_modinv(&qp, &q, &p);
1149 /* Encode to PKCS #1 format */
1150 silc_mp_init(&version);
1151 silc_mp_set_ui(&version, 0);
1152 memset(&alg_key, 0, sizeof(alg_key));
1153 if (!silc_asn1_encode(asn1, &alg_key,
1155 SILC_ASN1_INT(&version),
1164 SILC_ASN1_END, SILC_ASN1_END))
1167 silc_mp_uninit(&version);
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);