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,
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,
341 return ret ? TRUE : FALSE;
344 /* Imports SILC protocol style public key */
346 int 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(alg_key.data, silc_buffer_len(&alg_key),
475 &silc_pubkey->public_key))
478 silc_free(pkcs_name);
480 silc_asn1_free(asn1);
482 *ret_public_key = silc_pubkey;
487 silc_free(pkcs_name);
489 silc_free(silc_pubkey);
491 silc_asn1_free(asn1);
495 /* Exports public key as SILC protocol style public key file */
498 silc_pkcs_silc_export_public_key_file(void *public_key,
499 SilcPKCSFileEncoding encoding,
503 unsigned char *key, *data;
506 SILC_LOG_DEBUG(("Encoding SILC public key file"));
509 key = silc_pkcs_silc_export_public_key(public_key, &key_len);
514 case SILC_PKCS_FILE_BIN:
517 case SILC_PKCS_FILE_BASE64:
518 data = silc_pem_encode_file(key, key_len);
523 key_len = strlen(data);
527 /* Encode SILC public key file */
528 buf = silc_buffer_alloc_size(key_len +
529 (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
530 strlen(SILC_PKCS_PUBLIC_KEYFILE_END)));
536 if (silc_buffer_format(buf,
537 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
538 SILC_STR_UI_XNSTRING(key, key_len),
539 SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END),
541 silc_buffer_free(buf);
547 key = silc_buffer_steal(buf, ret_len);
548 silc_buffer_free(buf);
553 /* Exports public key as SILC protocol style public key */
555 unsigned char *silc_pkcs_silc_export_public_key(void *public_key,
558 SilcSILCPublicKey silc_pubkey = public_key;
559 const SilcPKCSAlgorithm *pkcs = silc_pubkey->pkcs;
560 SilcBufferStruct alg_key;
561 SilcBuffer buf = NULL;
562 SilcAsn1 asn1 = NULL;
563 unsigned char *pk = NULL, *key = NULL, *ret;
564 SilcUInt32 pk_len, key_len, totlen;
567 SILC_LOG_DEBUG(("Encoding SILC public key"));
569 /* Export PKCS algorithm public key */
570 if (pkcs->export_public_key)
571 pk = pkcs->export_public_key(silc_pubkey->public_key, &pk_len);
574 silc_buffer_set(&alg_key, pk, pk_len);
576 /* Encode identifier */
578 silc_pkcs_silc_encode_identifier(silc_pubkey->identifier.username,
579 silc_pubkey->identifier.host,
580 silc_pubkey->identifier.realname,
581 silc_pubkey->identifier.email,
582 silc_pubkey->identifier.org,
583 silc_pubkey->identifier.country);
587 asn1 = silc_asn1_alloc();
591 if (!strcmp(pkcs->name, "rsa")) {
592 /* Parse the PKCS #1 public key */
594 SilcUInt32 n_len, e_len;
595 unsigned char *nb, *eb;
597 memset(&n, 0, sizeof(n));
598 memset(&e, 0, sizeof(e));
599 if (!silc_asn1_decode(asn1, &alg_key,
603 SILC_ASN1_END, SILC_ASN1_END))
606 /* Encode to SILC RSA public key */
607 eb = silc_mp_mp2bin(&e, 0, &e_len);
610 nb = silc_mp_mp2bin(&n, 0, &n_len);
613 key_len = e_len + 4 + n_len + 4;
614 key = silc_calloc(key_len, sizeof(*key));
618 /* Put e length and e */
619 SILC_PUT32_MSB(e_len, key);
620 memcpy(key + 4, eb, e_len);
622 /* Put n length and n. */
623 SILC_PUT32_MSB(n_len, key + 4 + e_len);
624 memcpy(key + 4 + e_len + 4, nb, n_len);
629 } else if (!strcmp(pkcs->name, "dsa")) {
630 SILC_NOT_IMPLEMENTED("SILC DSA Public Key");
634 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
638 /* Encode SILC Public Key */
639 totlen = 2 + strlen(pkcs->name) + 2 + strlen(identifier) + key_len;
640 buf = silc_buffer_alloc_size(totlen + 4);
643 if (silc_buffer_format(buf,
644 SILC_STR_UI_INT(totlen),
645 SILC_STR_UI_SHORT(strlen(pkcs->name)),
646 SILC_STR_UI32_STRING(pkcs->name),
647 SILC_STR_UI_SHORT(strlen(identifier)),
648 SILC_STR_UI32_STRING(identifier),
649 SILC_STR_UI_XNSTRING(key, key_len),
653 ret = silc_buffer_steal(buf, ret_len);
654 silc_buffer_free(buf);
656 silc_free(identifier);
657 silc_asn1_free(asn1);
662 silc_free(identifier);
666 silc_buffer_free(buf);
668 silc_asn1_free(asn1);
672 /* Return key length */
674 SilcUInt32 silc_pkcs_silc_public_key_bitlen(void *public_key)
676 SilcSILCPublicKey silc_pubkey = public_key;
677 return silc_pubkey->pkcs->public_key_bitlen(silc_pubkey->public_key);
680 /* Copy public key */
682 void *silc_pkcs_silc_public_key_copy(void *public_key)
684 SilcSILCPublicKey silc_pubkey = public_key, new_pubkey;
686 new_pubkey = silc_calloc(1, sizeof(*new_pubkey));
689 new_pubkey->pkcs = silc_pubkey->pkcs;
691 new_pubkey->public_key =
692 silc_pubkey->pkcs->public_key_copy(silc_pubkey->public_key);
693 if (!new_pubkey->public_key) {
694 silc_free(new_pubkey);
701 /* Compares public keys */
703 SilcBool silc_pkcs_silc_public_key_compare(void *key1, void *key2)
705 SilcSILCPublicKey k1 = key1, k2 = key2;
707 if (strcmp(k1->pkcs->name, k2->pkcs->name))
710 if ((k1->identifier.username && !k2->identifier.username) ||
711 (!k1->identifier.username && k2->identifier.username) ||
712 (k1->identifier.username && k2->identifier.username &&
713 strcmp(k1->identifier.username, k2->identifier.username)))
716 if ((k1->identifier.host && !k2->identifier.host) ||
717 (!k1->identifier.host && k2->identifier.host) ||
718 (k1->identifier.host && k2->identifier.host &&
719 strcmp(k1->identifier.host, k2->identifier.host)))
722 if ((k1->identifier.realname && !k2->identifier.realname) ||
723 (!k1->identifier.realname && k2->identifier.realname) ||
724 (k1->identifier.realname && k2->identifier.realname &&
725 strcmp(k1->identifier.realname, k2->identifier.realname)))
728 if ((k1->identifier.email && !k2->identifier.email) ||
729 (!k1->identifier.email && k2->identifier.email) ||
730 (k1->identifier.email && k2->identifier.email &&
731 strcmp(k1->identifier.email, k2->identifier.email)))
734 if ((k1->identifier.org && !k2->identifier.org) ||
735 (!k1->identifier.org && k2->identifier.org) ||
736 (k1->identifier.org && k2->identifier.org &&
737 strcmp(k1->identifier.org, k2->identifier.org)))
740 if ((k1->identifier.country && !k2->identifier.country) ||
741 (!k1->identifier.country && k2->identifier.country) ||
742 (k1->identifier.country && k2->identifier.country &&
743 strcmp(k1->identifier.country, k2->identifier.country)))
746 return k1->pkcs->public_key_compare(k1->public_key, k2->public_key);
749 /* Frees public key */
751 void silc_pkcs_silc_public_key_free(void *public_key)
753 SilcSILCPublicKey silc_pubkey = public_key;
755 silc_pubkey->pkcs->public_key_free(silc_pubkey->public_key);
757 silc_free(silc_pubkey->identifier.username);
758 silc_free(silc_pubkey->identifier.host);
759 silc_free(silc_pubkey->identifier.realname);
760 silc_free(silc_pubkey->identifier.email);
761 silc_free(silc_pubkey->identifier.org);
762 silc_free(silc_pubkey->identifier.country);
763 silc_free(silc_pubkey);
767 /*************************** Private key routines ****************************/
769 /* Private key file magic */
770 #define SILC_PKCS_PRIVATE_KEY_MAGIC 0x738df531
772 /* Imports SILC implementation style private key file */
774 SilcBool silc_pkcs_silc_import_private_key_file(unsigned char *filedata,
775 SilcUInt32 filedata_len,
776 const char *passphrase,
777 SilcUInt32 passphrase_len,
778 SilcPKCSFileEncoding encoding,
779 void **ret_private_key)
785 unsigned char tmp[32], keymat[64], *data = NULL;
786 SilcUInt32 i, len, magic, mac_len;
789 SILC_LOG_DEBUG(("Parsing SILC private key file"));
791 /* Check start of file and remove header from the data. */
792 len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
793 if (filedata_len < len + strlen(SILC_PKCS_PRIVATE_KEYFILE_END))
795 for (i = 0; i < len; i++) {
796 if (*filedata != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i])
801 len = filedata_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
802 strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
805 case SILC_PKCS_FILE_BIN:
808 case SILC_PKCS_FILE_BASE64:
809 data = silc_pem_decode(filedata, filedata_len, &len);
816 memset(tmp, 0, sizeof(tmp));
817 memset(keymat, 0, sizeof(keymat));
819 /* Check file magic */
820 SILC_GET32_MSB(magic, filedata);
821 if (magic != SILC_PKCS_PRIVATE_KEY_MAGIC) {
822 SILC_LOG_DEBUG(("Private key does not have correct magic"));
826 /* Allocate the AES cipher */
827 if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
828 SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
831 blocklen = silc_cipher_get_block_len(aes);
832 if (blocklen * 2 > sizeof(tmp)) {
833 silc_cipher_free(aes);
837 /* Allocate SHA1 hash */
838 if (!silc_hash_alloc("sha1", &sha1)) {
839 SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered"));
840 silc_cipher_free(aes);
845 if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
846 SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
847 silc_hash_free(sha1);
848 silc_cipher_free(aes);
852 /* Derive the decryption key from the provided key material. The key
853 is 256 bits length, and derived by taking hash of the data, then
854 re-hashing the data and the previous digest, and using the first and
855 second digest as the key. */
856 silc_hash_init(sha1);
857 silc_hash_update(sha1, passphrase, passphrase_len);
858 silc_hash_final(sha1, keymat);
859 silc_hash_init(sha1);
860 silc_hash_update(sha1, passphrase, passphrase_len);
861 silc_hash_update(sha1, keymat, 16);
862 silc_hash_final(sha1, keymat + 16);
864 /* Set the key to the cipher */
865 silc_cipher_set_key(aes, keymat, 256, FALSE);
867 /* First, verify the MAC of the private key data */
868 mac_len = silc_hmac_len(sha1hmac);
869 silc_hmac_init_with_key(sha1hmac, keymat, 16);
870 silc_hmac_update(sha1hmac, filedata, len - mac_len);
871 silc_hmac_final(sha1hmac, tmp, NULL);
872 if (memcmp(tmp, filedata + (len - mac_len), mac_len)) {
873 SILC_LOG_DEBUG(("Integrity check for private key failed"));
874 memset(keymat, 0, sizeof(keymat));
875 memset(tmp, 0, sizeof(tmp));
876 silc_hmac_free(sha1hmac);
877 silc_hash_free(sha1);
878 silc_cipher_free(aes);
884 /* Decrypt the private key buffer */
885 silc_cipher_decrypt(aes, filedata, filedata, len - mac_len, NULL);
886 SILC_GET32_MSB(i, filedata);
888 SILC_LOG_DEBUG(("Bad private key length in buffer!"));
889 memset(keymat, 0, sizeof(keymat));
890 memset(tmp, 0, sizeof(tmp));
891 silc_hmac_free(sha1hmac);
892 silc_hash_free(sha1);
893 silc_cipher_free(aes);
900 memset(keymat, 0, sizeof(keymat));
901 memset(tmp, 0, sizeof(tmp));
902 silc_hmac_free(sha1hmac);
903 silc_hash_free(sha1);
904 silc_cipher_free(aes);
906 /* Import the private key */
907 ret = silc_pkcs_silc_import_private_key(filedata, len, ret_private_key);
911 return ret ? TRUE : FALSE;
914 /* Private key version */
915 #define SILC_PRIVATE_KEY_VERSION_1 0x82171273
917 /* Imports SILC implementation style private key */
919 int silc_pkcs_silc_import_private_key(unsigned char *key,
921 void **ret_private_key)
923 SilcBufferStruct buf;
924 const SilcPKCSAlgorithm *pkcs;
925 SilcBufferStruct alg_key;
926 SilcSILCPrivateKey silc_privkey = NULL;
927 SilcAsn1 asn1 = NULL;
929 SilcUInt32 keydata_len;
930 unsigned char *pkcs_name = NULL, *key_data;
933 SILC_LOG_DEBUG(("Parsing SILC private key"));
935 if (!ret_private_key)
938 silc_buffer_set(&buf, key, key_len);
940 /* Get algorithm name and identifier */
942 silc_buffer_unformat(&buf,
943 SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
946 SILC_LOG_DEBUG(("Cannot decode private key buffer"));
950 if (pkcs_len < 1 || pkcs_len > silc_buffer_truelen(&buf)) {
951 SILC_LOG_DEBUG(("Malformed private key buffer"));
955 /* Get key data. We assume that rest of the buffer is key data. */
956 silc_buffer_pull(&buf, 2 + pkcs_len);
957 keydata_len = silc_buffer_len(&buf);
958 ret = silc_buffer_unformat(&buf,
959 SILC_STR_UI_XNSTRING(&key_data, keydata_len),
964 /* Allocate SILC private key context */
965 silc_privkey = silc_calloc(1, sizeof(*silc_privkey));
969 asn1 = silc_asn1_alloc();
973 if (!strcmp(pkcs_name, "rsa")) {
974 /* Parse the RSA SILC private key */
976 SilcMPInt n, e, d, dp, dq, qp, p, q;
980 /* Get PKCS object */
981 pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1-no-oid");
983 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
986 silc_privkey->pkcs = pkcs;
991 silc_buffer_set(&k, key_data, keydata_len);
993 /* Get version. Key without the version is old style private key
994 and we need to do some computation to get it to correct format. */
995 if (silc_buffer_unformat(&k,
996 SILC_STR_UI_INT(&ver),
999 silc_buffer_pull(&k, 4);
1001 if (ver != SILC_PRIVATE_KEY_VERSION_1) {
1004 if (silc_buffer_unformat(&k,
1005 SILC_STR_UI_INT(&len),
1008 silc_buffer_pull(&k, 4);
1012 if (silc_buffer_unformat(&k,
1013 SILC_STR_UI_XNSTRING(&tmp, len),
1017 silc_mp_bin2mp(tmp, len, &e);
1018 silc_buffer_pull(&k, len);
1021 if (silc_buffer_unformat(&k,
1022 SILC_STR_UI_INT(&len),
1025 silc_buffer_pull(&k, 4);
1026 if (silc_buffer_unformat(&k,
1027 SILC_STR_UI_XNSTRING(&tmp, len),
1031 silc_mp_bin2mp(tmp, len, &n);
1032 silc_buffer_pull(&k, len);
1035 if (silc_buffer_unformat(&k,
1036 SILC_STR_UI_INT(&len),
1039 silc_buffer_pull(&k, 4);
1040 if (silc_buffer_unformat(&k,
1041 SILC_STR_UI_XNSTRING(&tmp, len),
1045 silc_mp_bin2mp(tmp, len, &d);
1046 silc_buffer_pull(&k, len);
1049 if (silc_buffer_unformat(&k,
1050 SILC_STR_UI_INT(&len),
1053 silc_buffer_pull(&k, 4);
1054 if (silc_buffer_unformat(&k,
1055 SILC_STR_UI_XNSTRING(&tmp, len),
1059 silc_mp_bin2mp(tmp, len, &dp);
1060 silc_buffer_pull(&k, len);
1063 if (silc_buffer_unformat(&k,
1064 SILC_STR_UI_INT(&len),
1067 silc_buffer_pull(&k, 4);
1068 if (silc_buffer_unformat(&k,
1069 SILC_STR_UI_XNSTRING(&tmp, len),
1073 silc_mp_bin2mp(tmp, len, &dq);
1074 silc_buffer_pull(&k, len);
1076 if (ver != SILC_PRIVATE_KEY_VERSION_1) {
1080 if (silc_buffer_unformat(&k,
1081 SILC_STR_UI_INT(&len),
1084 silc_buffer_pull(&k, 4);
1085 if (silc_buffer_len(&k) < len)
1087 silc_buffer_pull(&k, len);
1090 if (silc_buffer_unformat(&k,
1091 SILC_STR_UI_INT(&len),
1094 silc_buffer_pull(&k, 4);
1095 if (silc_buffer_len(&k) < len)
1097 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_UI_XNSTRING(&tmp, len),
1112 silc_mp_bin2mp(tmp, len, &qp);
1113 silc_buffer_pull(&k, len);
1117 if (silc_buffer_unformat(&k,
1118 SILC_STR_UI_INT(&len),
1121 silc_buffer_pull(&k, 4);
1122 if (silc_buffer_unformat(&k,
1123 SILC_STR_UI_XNSTRING(&tmp, len),
1127 silc_mp_bin2mp(tmp, len, &p);
1128 silc_buffer_pull(&k, len);
1131 if (silc_buffer_unformat(&k,
1132 SILC_STR_UI_INT(&len),
1135 silc_buffer_pull(&k, 4);
1136 if (silc_buffer_unformat(&k,
1137 SILC_STR_UI_XNSTRING(&tmp, len),
1141 silc_mp_bin2mp(tmp, len, &q);
1142 silc_buffer_pull(&k, len);
1144 if (ver != SILC_PRIVATE_KEY_VERSION_1) {
1145 /* Old version. Compute to new version */
1146 SILC_LOG_DEBUG(("Old version private key"));
1148 silc_mp_modinv(&qp, &q, &p);
1151 /* Encode to PKCS #1 format */
1152 memset(&alg_key, 0, sizeof(alg_key));
1153 if (!silc_asn1_encode(asn1, &alg_key,
1155 SILC_ASN1_SHORT_INT(0),
1164 SILC_ASN1_END, SILC_ASN1_END))
1173 silc_mp_uninit(&dp);
1174 silc_mp_uninit(&dq);
1175 silc_mp_uninit(&qp);
1177 } else if (!strcmp(pkcs_name, "dsa")) {
1178 SILC_NOT_IMPLEMENTED("DSA SILC Private Key");
1182 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
1186 /* Import PKCS algorithm private key */
1187 if (!pkcs->import_private_key(alg_key.data, silc_buffer_len(&alg_key),
1188 &silc_privkey->private_key))
1191 silc_free(pkcs_name);
1192 silc_asn1_free(asn1);
1194 *ret_private_key = silc_privkey;
1199 silc_free(pkcs_name);
1200 silc_free(silc_privkey);
1202 silc_asn1_free(asn1);
1206 /* Exports private key as SILC implementation style private key file */
1209 silc_pkcs_silc_export_private_key_file(void *private_key,
1210 const char *passphrase,
1211 SilcUInt32 passphrase_len,
1212 SilcPKCSFileEncoding encoding,
1214 SilcUInt32 *ret_len)
1219 SilcBuffer buf, enc;
1220 SilcUInt32 len, blocklen, padlen, key_len;
1221 unsigned char *key, *data;
1222 unsigned char tmp[32], keymat[64];
1225 SILC_LOG_DEBUG(("Encoding SILC private key file"));
1227 /* Export the private key */
1228 key = silc_pkcs_silc_export_private_key(private_key, &key_len);
1232 memset(tmp, 0, sizeof(tmp));
1233 memset(keymat, 0, sizeof(keymat));
1235 /* Allocate the AES cipher */
1236 if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
1237 SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
1241 blocklen = silc_cipher_get_block_len(aes);
1242 if (blocklen * 2 > sizeof(tmp)) {
1243 silc_cipher_free(aes);
1248 /* Allocate SHA1 hash */
1249 if (!silc_hash_alloc("sha1", &sha1)) {
1250 SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered"));
1251 silc_cipher_free(aes);
1256 if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
1257 SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
1258 silc_hash_free(sha1);
1259 silc_cipher_free(aes);
1263 /* Derive the encryption key from the provided key material. The key
1264 is 256 bits length, and derived by taking hash of the data, then
1265 re-hashing the data and the previous digest, and using the first and
1266 second digest as the key. */
1267 silc_hash_init(sha1);
1268 silc_hash_update(sha1, passphrase, passphrase_len);
1269 silc_hash_final(sha1, keymat);
1270 silc_hash_init(sha1);
1271 silc_hash_update(sha1, passphrase, passphrase_len);
1272 silc_hash_update(sha1, keymat, 16);
1273 silc_hash_final(sha1, keymat + 16);
1275 /* Set the key to the cipher */
1276 silc_cipher_set_key(aes, keymat, 256, TRUE);
1278 /* Encode the buffer to be encrypted. Add padding to it too, at least
1279 block size of the cipher. */
1281 /* Allocate buffer for encryption */
1282 len = silc_hmac_len(sha1hmac);
1283 padlen = 16 + (16 - ((key_len + 4) % blocklen));
1284 enc = silc_buffer_alloc_size(4 + 4 + key_len + padlen + len);
1286 silc_hmac_free(sha1hmac);
1287 silc_hash_free(sha1);
1288 silc_cipher_free(aes);
1292 /* Generate padding */
1293 for (i = 0; i < padlen; i++)
1294 tmp[i] = silc_rng_get_byte_fast(rng);
1296 /* Put magic number */
1297 SILC_PUT32_MSB(SILC_PKCS_PRIVATE_KEY_MAGIC, enc->data);
1298 silc_buffer_pull(enc, 4);
1300 /* Encode the buffer */
1301 silc_buffer_format(enc,
1302 SILC_STR_UI_INT(key_len),
1303 SILC_STR_UI_XNSTRING(key, key_len),
1304 SILC_STR_UI_XNSTRING(tmp, padlen),
1309 silc_cipher_encrypt(aes, enc->data, enc->data, silc_buffer_len(enc) - len,
1310 silc_cipher_get_iv(aes));
1312 silc_buffer_push(enc, 4);
1314 /* Compute HMAC over the encrypted data and append the MAC to data.
1315 The key is the first digest of the original key material. */
1316 key_len = silc_buffer_len(enc) - len;
1317 silc_hmac_init_with_key(sha1hmac, keymat, 16);
1318 silc_hmac_update(sha1hmac, enc->data, key_len);
1319 silc_buffer_pull(enc, key_len);
1320 silc_hmac_final(sha1hmac, enc->data, NULL);
1321 silc_buffer_push(enc, key_len);
1324 memset(keymat, 0, sizeof(keymat));
1325 memset(tmp, 0, sizeof(tmp));
1326 silc_hmac_free(sha1hmac);
1327 silc_hash_free(sha1);
1328 silc_cipher_free(aes);
1331 case SILC_PKCS_FILE_BIN:
1334 case SILC_PKCS_FILE_BASE64:
1335 data = silc_pem_encode_file(enc->data, silc_buffer_len(enc));
1337 silc_buffer_clear(enc);
1338 silc_buffer_free(enc);
1341 silc_free(silc_buffer_steal(enc, NULL));
1342 silc_buffer_set(enc, data, strlen(data));
1347 key_len = silc_buffer_len(enc);
1349 /* Encode the data and save to file */
1350 len = key_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
1351 strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
1352 buf = silc_buffer_alloc_size(len);
1354 silc_buffer_free(enc);
1357 silc_buffer_format(buf,
1358 SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
1359 SILC_STR_UI_XNSTRING(key, key_len),
1360 SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
1363 silc_buffer_free(enc);
1364 data = silc_buffer_steal(buf, ret_len);
1365 silc_buffer_free(buf);
1370 /* Exports private key as SILC implementation style private key */
1372 unsigned char *silc_pkcs_silc_export_private_key(void *private_key,
1373 SilcUInt32 *ret_len)
1375 SilcSILCPrivateKey silc_privkey = private_key;
1376 const SilcPKCSAlgorithm *pkcs = silc_privkey->pkcs;
1377 SilcBufferStruct alg_key;
1378 SilcBuffer buf = NULL;
1379 SilcAsn1 asn1 = NULL;
1380 unsigned char *prv = NULL, *key = NULL, *ret;
1381 SilcUInt32 prv_len, key_len, totlen;
1383 SILC_LOG_DEBUG(("Encoding SILC private key"));
1385 /* Export PKCS algorithm private key */
1386 if (pkcs->export_private_key)
1387 prv = pkcs->export_private_key(silc_privkey->private_key, &prv_len);
1390 silc_buffer_set(&alg_key, prv, prv_len);
1392 asn1 = silc_asn1_alloc();
1396 if (!strcmp(pkcs->name, "rsa")) {
1397 /* Parse the PKCS #1 private key */
1398 SilcMPInt n, e, d, dp, dq, qp, p, q;
1399 SilcUInt32 e_len, n_len, d_len, dp_len, dq_len,
1400 qp_len, p_len, q_len, len = 0;
1401 unsigned char *nb, *eb, *db, *dpb, *dqb, *qpb, *pb, *qb;
1403 if (!silc_asn1_decode(asn1, &alg_key,
1405 SILC_ASN1_INT(NULL),
1414 SILC_ASN1_END, SILC_ASN1_END))
1417 /* Encode to SILC RSA private key */
1418 eb = silc_mp_mp2bin(&e, 0, &e_len);
1419 nb = silc_mp_mp2bin(&n, 0, &n_len);
1420 db = silc_mp_mp2bin(&d, 0, &d_len);
1421 dpb = silc_mp_mp2bin(&dp, 0, &dp_len);
1422 dqb = silc_mp_mp2bin(&dq, 0, &dq_len);
1423 qpb = silc_mp_mp2bin(&qp, 0, &qp_len);
1424 pb = silc_mp_mp2bin(&p, 0, &p_len);
1425 qb = silc_mp_mp2bin(&q, 0, &q_len);
1426 len = 4 + e_len + 4 + n_len + 4 + d_len + 4+ dp_len + 4 +
1427 dq_len + 4 + qp_len + 4 + p_len + 4 + q_len + 4;
1429 buf = silc_buffer_alloc_size(len);
1432 if (silc_buffer_format(buf,
1433 SILC_STR_UI_INT(SILC_PRIVATE_KEY_VERSION_1),
1434 SILC_STR_UI_INT(e_len),
1435 SILC_STR_UI_XNSTRING(eb, e_len),
1436 SILC_STR_UI_INT(n_len),
1437 SILC_STR_UI_XNSTRING(nb, n_len),
1438 SILC_STR_UI_INT(d_len),
1439 SILC_STR_UI_XNSTRING(db, d_len),
1440 SILC_STR_UI_INT(dp_len),
1441 SILC_STR_UI_XNSTRING(dpb, dp_len),
1442 SILC_STR_UI_INT(dq_len),
1443 SILC_STR_UI_XNSTRING(dqb, dq_len),
1444 SILC_STR_UI_INT(qp_len),
1445 SILC_STR_UI_XNSTRING(qpb, qp_len),
1446 SILC_STR_UI_INT(p_len),
1447 SILC_STR_UI_XNSTRING(pb, p_len),
1448 SILC_STR_UI_INT(q_len),
1449 SILC_STR_UI_XNSTRING(qb, q_len),
1453 key = silc_buffer_steal(buf, &key_len);
1454 silc_buffer_free(buf);
1464 } else if (!strcmp(pkcs->name, "dsa")) {
1465 SILC_NOT_IMPLEMENTED("SILC DSA Private Key");
1469 SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
1473 /* Encode SILC private key */
1474 totlen = 2 + strlen(pkcs->name) + key_len;
1475 buf = silc_buffer_alloc_size(totlen);
1478 if (silc_buffer_format(buf,
1479 SILC_STR_UI_SHORT(strlen(pkcs->name)),
1480 SILC_STR_UI32_STRING(pkcs->name),
1481 SILC_STR_UI_XNSTRING(key, key_len),
1485 ret = silc_buffer_steal(buf, ret_len);
1486 silc_buffer_free(buf);
1489 silc_asn1_free(asn1);
1497 silc_buffer_free(buf);
1501 /* Return key length */
1503 SilcUInt32 silc_pkcs_silc_private_key_bitlen(void *private_key)
1505 SilcSILCPrivateKey silc_privkey = private_key;
1506 return silc_privkey->pkcs->private_key_bitlen(silc_privkey->private_key);
1509 /* Frees private key */
1511 void silc_pkcs_silc_private_key_free(void *private_key)
1513 SilcSILCPrivateKey silc_privkey = private_key;
1515 silc_privkey->pkcs->private_key_free(silc_privkey->private_key);
1517 silc_free(silc_privkey);
1521 /***************************** PKCS operations ******************************/
1523 /* Encrypts as specified in SILC protocol specification */
1525 SilcBool silc_pkcs_silc_encrypt(void *public_key,
1529 SilcUInt32 dst_size,
1530 SilcUInt32 *ret_dst_len,
1533 SilcSILCPublicKey silc_pubkey = public_key;
1535 if (!silc_pubkey->pkcs->encrypt)
1538 return silc_pubkey->pkcs->encrypt(silc_pubkey->public_key,
1540 dst, dst_size, ret_dst_len, rng);
1543 /* Decrypts as specified in SILC protocol specification */
1545 SilcBool silc_pkcs_silc_decrypt(void *private_key,
1549 SilcUInt32 dst_size,
1550 SilcUInt32 *ret_dst_len)
1552 SilcSILCPrivateKey silc_privkey = private_key;
1554 if (!silc_privkey->pkcs->decrypt)
1557 return silc_privkey->pkcs->decrypt(silc_privkey->private_key,
1559 dst, dst_size, ret_dst_len);
1562 /* Signs as specified in SILC protocol specification */
1564 SilcBool silc_pkcs_silc_sign(void *private_key,
1567 unsigned char *signature,
1568 SilcUInt32 signature_size,
1569 SilcUInt32 *ret_signature_len,
1572 SilcSILCPrivateKey silc_privkey = private_key;
1574 if (!silc_privkey->pkcs->sign)
1577 return silc_privkey->pkcs->sign(silc_privkey->private_key,
1579 signature, signature_size,
1580 ret_signature_len, hash);
1583 /* Verifies as specified in SILC protocol specification */
1585 SilcBool silc_pkcs_silc_verify(void *public_key,
1586 unsigned char *signature,
1587 SilcUInt32 signature_len,
1588 unsigned char *data,
1589 SilcUInt32 data_len,
1592 SilcSILCPublicKey silc_pubkey = public_key;
1594 if (!silc_pubkey->pkcs->verify)
1597 return silc_pubkey->pkcs->verify(silc_pubkey->public_key,
1598 signature, signature_len,
1599 data, data_len, hash);