5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 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 #include "silcssh_pkcs.h"
25 /************************** Types and definitions ***************************/
27 /* RFC 4716 public key file markers */
28 #define SILC_SSH_PUBLIC_KEY_BEGIN "---- BEGIN SSH2 PUBLIC KEY ----"
29 #define SILC_SSH_PUBLIC_KEY_END "---- END SSH2 PUBLIC KEY ----"
31 /* OpenSSH private key file markers */
32 #define SILC_SSH_RSA_BEGIN "-----BEGIN RSA PRIVATE KEY-----"
33 #define SILC_SSH_RSA_END "-----END RSA PRIVATE KEY-----"
34 #define SILC_SSH_DSA_BEGIN "-----BEGIN DSA PRIVATE KEY-----"
35 #define SILC_SSH_DSA_END "-----END DSA PRIVATE KEY-----"
37 /****************************** SSH2 PKCS API *******************************/
39 /* Get algorithm context */
41 SILC_PKCS_GET_ALGORITHM(silc_pkcs_ssh_get_algorithm)
43 SilcSshPublicKey pubkey = public_key;
47 /* Import public key file */
49 SILC_PKCS_IMPORT_PUBLIC_KEY_FILE(silc_pkcs_ssh_import_public_key_file)
51 SilcSshPublicKey pubkey;
52 SilcBufferStruct keybuf, line;
58 SILC_LOG_DEBUG(("Parsing SSH2 public key file"));
62 if (encoding == SILC_PKCS_FILE_BIN)
65 silc_buffer_set(&keybuf, filedata, filedata_len);
67 /* Check for RFC 4716 style public key markers */
68 if (!silc_ssh_parse_line(&keybuf, &line, TRUE)) {
69 SILC_LOG_DEBUG(("Malformed SSH2 public key markers"));
72 if ((silc_buffer_len(&keybuf) < (strlen(SILC_SSH_PUBLIC_KEY_BEGIN) +
73 strlen(SILC_SSH_PUBLIC_KEY_END))) ||
74 strncmp(silc_buffer_data(&line), SILC_SSH_PUBLIC_KEY_BEGIN,
75 silc_buffer_len(&line))) {
76 /* We assume the key is OpenSSH style public key. */
77 type = SILC_SSH_KEY_OPENSSH;
78 silc_buffer_set(&keybuf, filedata, filedata_len);
80 /* Get subject name from the end of the file */
81 if (!silc_buffer_strchr(&keybuf, ' ', FALSE)) {
82 SILC_LOG_DEBUG(("Malformed SSH2 public key"));
85 if (!silc_buffer_pull(&keybuf, 1)) {
86 SILC_LOG_DEBUG(("Malformed SSH2 public key"));
89 if (!silc_buffer_len(&keybuf)) {
90 SILC_LOG_DEBUG(("Malformed SSH2 public key"));
94 /* Add subject name to public key headers */
95 fields = silc_ssh_allocate_fields();
98 silc_hash_table_add(fields, strdup("Subject"),
99 silc_memdup(silc_buffer_data(&keybuf),
100 silc_buffer_len(&keybuf)));
102 filedata_len = silc_buffer_headlen(&keybuf) - 1;
103 SILC_LOG_DEBUG(("Add Subject header to public key"));
105 /* Skip algorithm name */
106 silc_buffer_start(&keybuf);
107 if (!silc_buffer_strchr(&keybuf, ' ', TRUE)) {
108 SILC_LOG_DEBUG(("Malformed SSH2 public key"));
109 silc_hash_table_free(fields);
112 if (!silc_buffer_pull(&keybuf, 1)) {
113 SILC_LOG_DEBUG(("Malformed SSH2 public key"));
114 silc_hash_table_free(fields);
117 if (silc_buffer_len(&keybuf) < filedata_len) {
118 SILC_LOG_DEBUG(("Malformed SSH2 public key"));
119 silc_hash_table_free(fields);
123 filedata = silc_buffer_data(&keybuf);
124 SILC_LOG_DEBUG(("Public key is OpenSSH public key"));
127 /* RFC 4716 style public key */
128 type = SILC_SSH_KEY_SSH2;
130 filedata = silc_buffer_data(&keybuf);
131 filedata_len = silc_buffer_len(&keybuf) - strlen(SILC_SSH_PUBLIC_KEY_END);
132 silc_buffer_set(&keybuf, filedata, filedata_len);
134 /* Parse public key headers */
135 fields = silc_ssh_parse_headers(&keybuf);
139 filedata = silc_buffer_data(&keybuf);
140 filedata_len = silc_buffer_len(&keybuf);
142 SILC_LOG_DEBUG(("Public key is standard SSH2 public key"));
146 data = silc_base64_decode(NULL, filedata, filedata_len, &filedata_len);
148 silc_hash_table_free(fields);
153 /* Decode the public key */
154 ret = silc_pkcs_ssh_import_public_key(pkcs, NULL, filedata, filedata_len,
155 (void *)&pubkey, ret_alg);
159 pubkey->fields = fields;
161 *ret_public_key = pubkey;
162 SILC_LOG_DEBUG(("SSH2 public key file imported successfully"));
166 silc_hash_table_free(fields);
170 /* Import public key */
172 SILC_PKCS_IMPORT_PUBLIC_KEY(silc_pkcs_ssh_import_public_key)
174 SilcSshPublicKey pubkey;
177 ret = silc_ssh_public_key_decode(key, key_len, &pubkey);
180 *ret_alg = pubkey->pkcs;
182 *ret_public_key = pubkey;
188 /* Export public key file */
190 SILC_PKCS_EXPORT_PUBLIC_KEY_FILE(silc_pkcs_ssh_export_public_key_file)
192 SilcSshPublicKey pubkey = public_key;
193 SilcHashTableList htl;
194 SilcBufferStruct buf, fields;
195 unsigned char *key, *data;
197 char *field, *value, tmp[1024], tmp2[1024 + 24];
200 SILC_LOG_DEBUG(("Encoding %s public key file",
201 pubkey->type == SILC_SSH_KEY_SSH2 ? "SSH2" : "OpenSSH"));
204 key = silc_pkcs_ssh_export_public_key(pkcs, stack, pubkey, &key_len);
208 /* Base64 encode the key data */
209 if (pubkey->type == SILC_SSH_KEY_SSH2)
210 data = silc_base64_encode_file(stack, key, key_len);
212 data = silc_base64_encode(stack, key, key_len);
215 silc_sfree(stack, key);
217 key_len = strlen(data);
219 memset(&buf, 0, sizeof(buf));
220 memset(&fields, 0, sizeof(fields));
221 memset(tmp, 0, sizeof(tmp));
222 memset(tmp2, 0, sizeof(tmp2));
224 switch (pubkey->type) {
225 case SILC_SSH_KEY_SSH2:
226 /* RFC 4716 style public key file */
228 if (pubkey->fields) {
229 /* Encode public key headers */
230 silc_hash_table_list(pubkey->fields, &htl);
231 while (silc_hash_table_get(&htl, (void *)&field, (void *)&value)) {
232 /* Wrap lines with over 72 characters */
233 silc_snprintf(tmp, sizeof(tmp), "%s: %s", field, value);
234 for (i = 0, j = 0, c = 1; i < strlen(tmp); i++, c++) {
247 if (silc_buffer_sstrformat(stack, &fields, tmp2, SILC_STRFMT_END) < 0) {
248 silc_buffer_spurge(stack, &fields);
249 silc_sfree(stack, key);
253 memset(tmp2, 0, sizeof(tmp2));
255 silc_hash_table_list_reset(&htl);
258 /* Encode the file */
259 if (silc_buffer_sformat(stack, &buf,
260 SILC_STR_UI32_STRING(SILC_SSH_PUBLIC_KEY_BEGIN),
261 SILC_STR_UI32_STRING("\n"),
262 SILC_STR_UI_XNSTRING(silc_buffer_data(&fields),
263 silc_buffer_len(&fields)),
264 SILC_STR_UI_XNSTRING(key, key_len),
265 SILC_STR_UI32_STRING("\n"),
266 SILC_STR_UI32_STRING(SILC_SSH_PUBLIC_KEY_END),
267 SILC_STR_UI32_STRING("\n"),
269 silc_buffer_spurge(stack, &fields);
270 silc_sfree(stack, key);
276 case SILC_SSH_KEY_OPENSSH:
277 /* OpenSSH style public key file */
279 if (!strcmp(pubkey->pkcs->name, "rsa"))
280 silc_snprintf(tmp, sizeof(tmp), "ssh-rsa ");
281 else if (!strcmp(pubkey->pkcs->name, "dsa"))
282 silc_snprintf(tmp, sizeof(tmp), "ssh-dss ");
285 value = (char *)silc_ssh_public_key_get_field(pubkey, "Subject");
287 /* Encode the file */
288 if (silc_buffer_sformat(stack, &buf,
289 SILC_STR_UI32_STRING(tmp),
290 SILC_STR_UI_XNSTRING(key, key_len),
291 SILC_STR_UI32_STRING(" "),
292 SILC_STR_UI32_STRING(value),
293 SILC_STR_UI32_STRING("\n"),
295 silc_buffer_spurge(stack, &buf);
296 silc_sfree(stack, key);
303 silc_sfree(stack, key);
308 silc_sfree(stack, key);
309 key = silc_buffer_steal(&buf, ret_len);
311 silc_buffer_spurge(stack, &fields);
316 /* Export public key */
318 SILC_PKCS_EXPORT_PUBLIC_KEY(silc_pkcs_ssh_export_public_key)
320 return silc_ssh_public_key_encode(stack, public_key, ret_len);
323 /* Return key length in bits */
325 SILC_PKCS_PUBLIC_KEY_BITLEN(silc_pkcs_ssh_public_key_bitlen)
327 SilcSshPublicKey pubkey = public_key;
328 return pubkey->pkcs->public_key_bitlen(pubkey->pkcs, pubkey->public_key);
331 /* Copy public key */
333 SILC_PKCS_PUBLIC_KEY_COPY(silc_pkcs_ssh_public_key_copy)
335 SilcSshPublicKey pubkey = public_key, new_pubkey;
336 SilcHashTableList htl;
339 new_pubkey = silc_calloc(1, sizeof(*new_pubkey));
342 new_pubkey->pkcs = pubkey->pkcs;
343 new_pubkey->type = pubkey->type;
345 new_pubkey->public_key =
346 pubkey->pkcs->public_key_copy(pubkey->pkcs, pubkey->public_key);
347 if (!new_pubkey->public_key) {
348 silc_free(new_pubkey);
352 if (pubkey->fields) {
353 new_pubkey->fields = silc_ssh_allocate_fields();
354 if (!new_pubkey->fields) {
355 pubkey->pkcs->public_key_free(pubkey->pkcs, pubkey->public_key);
356 silc_free(new_pubkey);
360 silc_hash_table_list(pubkey->fields, &htl);
361 while (silc_hash_table_get(&htl, (void *)&field, (void *)&value))
362 silc_hash_table_add(new_pubkey->fields, strdup(field), strdup(value));
363 silc_hash_table_list_reset(&htl);
369 /* Compare two public keys */
371 SILC_PKCS_PUBLIC_KEY_COMPARE(silc_pkcs_ssh_public_key_compare)
373 SilcSshPublicKey k1 = key1, k2 = key2;
374 SilcHashTableList htl;
375 char *field, *value, *value2;
377 if (strcmp(k1->pkcs->name, k2->pkcs->name))
380 if (k1->fields && !k2->fields)
382 if (!k1->fields && k2->fields)
385 if (k1->fields && k2->fields) {
386 if (silc_hash_table_count(k1->fields) != silc_hash_table_count(k2->fields))
389 silc_hash_table_list(k1->fields, &htl);
390 while (silc_hash_table_get(&htl, (void *)&field, (void *)&value)) {
391 value2 = (char *)silc_ssh_public_key_get_field(k2, field);
394 if (strcmp(value, value2))
397 silc_hash_table_list_reset(&htl);
400 return k1->pkcs->public_key_compare(k1->pkcs, k1->public_key,
404 /* Free public key */
406 SILC_PKCS_PUBLIC_KEY_FREE(silc_pkcs_ssh_public_key_free)
408 silc_ssh_public_key_free(public_key);
411 /* Import private key file. Supports only OpenSSH (OpenSSL to be exact)
412 private key files. */
414 SILC_PKCS_IMPORT_PRIVATE_KEY_FILE(silc_pkcs_ssh_import_private_key_file)
416 const SilcPKCSAlgorithm *alg;
417 SilcSshPrivateKey privkey = NULL;
418 SilcHashTable fields;
419 SilcBufferStruct keybuf, line;
420 unsigned char *data, iv[8], key[32];
422 char *proctype, *dekinfo;
427 SILC_LOG_DEBUG(("Parsing SSH2 private key file"));
429 if (!ret_private_key)
431 if (encoding == SILC_PKCS_FILE_BIN)
434 silc_buffer_set(&keybuf, filedata, filedata_len);
436 /* Check for private key markers */
437 if (!silc_ssh_parse_line(&keybuf, &line, TRUE)) {
438 SILC_LOG_DEBUG(("Malformed SSH2 private key markers"));
441 if ((silc_buffer_len(&keybuf) < (strlen(SILC_SSH_RSA_BEGIN) +
442 strlen(SILC_SSH_RSA_END))) ||
443 (strncmp(silc_buffer_data(&line), SILC_SSH_RSA_BEGIN,
444 silc_buffer_len(&line)) &&
445 strncmp(silc_buffer_data(&line), SILC_SSH_DSA_BEGIN,
446 silc_buffer_len(&line)))) {
447 SILC_LOG_DEBUG(("Malformed SSH2 private key markers"));
451 /* Get PKCS algorithm */
452 if (!strncmp(silc_buffer_data(&line), SILC_SSH_RSA_BEGIN,
453 silc_buffer_len(&line))) {
454 alg = silc_pkcs_find_algorithm("rsa", "ssh");
456 SILC_LOG_ERROR(("Unsupported PKCS algorithm rsa/ssh"));
459 } else if (!strncmp(silc_buffer_data(&line), SILC_SSH_DSA_BEGIN,
460 silc_buffer_len(&line))) {
461 alg = silc_pkcs_find_algorithm("dsa", "ssh");
463 SILC_LOG_ERROR(("Unsupported PKCS algorithm dsa/ssh"));
469 type = SILC_SSH_KEY_OPENSSH;
470 filedata = silc_buffer_data(&keybuf);
472 /* Skip end marker */
473 if (!silc_buffer_strchr(&keybuf, '-', FALSE)) {
474 SILC_LOG_DEBUG(("Malformed SSH2 private key markers"));
477 filedata_len = silc_buffer_data(&keybuf) - filedata;
478 silc_buffer_set(&keybuf, filedata, filedata_len);
480 /* Parse private key headers. They define how the private key has been
482 fields = silc_ssh_parse_headers(&keybuf);
486 /* Skip empty line after headers */
487 if (silc_hash_table_count(fields) > 0)
488 silc_ssh_parse_line(&keybuf, NULL, TRUE);
490 filedata = silc_buffer_data(&keybuf);
491 filedata_len = silc_buffer_len(&keybuf);
494 data = silc_base64_decode(NULL, filedata, filedata_len, &filedata_len);
496 SILC_LOG_DEBUG(("Malformed SSH2 private key"));
501 SILC_LOG_DEBUG(("Private key is %s", (silc_hash_table_count(fields) ?
502 "encrypted" : "not encrypted")));
504 if (silc_hash_table_count(fields) > 0 && passphrase) {
507 /* Get encryption info */
508 if (!silc_hash_table_find(fields, "Proc-Type", NULL, (void *)&proctype)) {
509 SILC_LOG_ERROR(("Malformed SSH2 private key"));
512 if (strcmp(proctype, "4,ENCRYPTED")) {
513 SILC_LOG_ERROR(("Malformed SSH2 private key"));
517 /* OpenSSH uses 3DES-EDE only */
518 if (!silc_hash_table_find(fields, "DEK-Info", NULL, (void *)&dekinfo)) {
519 SILC_LOG_ERROR(("Malformed SSH2 private key"));
522 if (strncmp(dekinfo, "DES-EDE3-CBC", strlen("DES-EDE3-CBC"))) {
523 SILC_LOG_ERROR(("Unsupported SSH2 private key cipher '%s'", dekinfo));
527 /* Allocate cipher */
528 if (!silc_cipher_alloc("3des-168-cbc", &des)) {
529 SILC_LOG_ERROR(("Unsupported algorithm 3des-168-cbc"));
534 if (!silc_hash_alloc("md5", &md5)) {
535 SILC_LOG_ERROR(("Unsupported hash algorithm md5"));
539 /* Get IV from private key file */
540 dekinfo = strchr(dekinfo, ',');
541 if (!dekinfo || strlen(dekinfo) < 16) {
542 SILC_LOG_ERROR(("Malformed SSH2 private key"));
546 silc_hex2data(dekinfo, iv, sizeof(iv), NULL);
548 /* Generate key from passphrase and IV as salt. The passphrase is
549 hashed with the IV, then rehashed with the previous hash, passphrase
550 and the IV to produce the final key, which is the concatenation of
553 silc_hash_update(md5, passphrase, passphrase_len);
554 silc_hash_update(md5, iv, 8);
555 silc_hash_final(md5, key);
557 silc_hash_update(md5, key, 16);
558 silc_hash_update(md5, passphrase, passphrase_len);
559 silc_hash_update(md5, iv, 8);
560 silc_hash_final(md5, key + 16);
563 silc_cipher_set_key(des, key, 192, FALSE);
564 if (!silc_cipher_decrypt(des, filedata, filedata, filedata_len, iv)) {
565 SILC_LOG_ERROR(("Malformed SSH2 private key"));
566 silc_cipher_free(des);
571 silc_cipher_free(des);
575 /* Decode the private key */
576 ret = silc_pkcs_ssh_import_private_key(pkcs, alg, filedata, filedata_len,
577 (void *)&privkey, ret_alg);
581 privkey->fields = fields;
582 privkey->type = type;
583 *ret_private_key = privkey;
584 SILC_LOG_DEBUG(("SSH2 private key file imported successfully"));
590 silc_hash_table_free(fields);
594 /* Import private key. The key format for RSA is PKCS#1 compliant and for
595 DSA is equivalent to our DSA implementation, so we just simply call the
596 algorithm specific import function to do the magic. */
598 SILC_PKCS_IMPORT_PRIVATE_KEY(silc_pkcs_ssh_import_private_key)
600 SilcSshPrivateKey privkey;
603 if (!ret_private_key || !alg)
606 /* Allocate SSH private key context */
607 privkey = silc_calloc(1, sizeof(*privkey));
611 /* Import PKCS algorithm private key */
612 ret = alg->import_private_key(alg, key, key_len, &privkey->private_key);
619 privkey->type = SILC_SSH_KEY_OPENSSH;
621 *ret_private_key = privkey;
628 /* Export private key file */
630 SILC_PKCS_EXPORT_PRIVATE_KEY_FILE(silc_pkcs_ssh_export_private_key_file)
632 SilcSshPrivateKey privkey = private_key;
633 const SilcPKCSAlgorithm *alg = privkey->pkcs;
634 SilcBufferStruct buf;
635 unsigned char *key, *keyenc, ivdata[8], iv[16 + 1], enc[32];
636 SilcUInt32 key_len, pad_len;
637 SilcCipher des = NULL;
640 SILC_LOG_DEBUG(("Encode SSH2 private key file"));
642 /* Export the private key */
643 key = silc_pkcs_ssh_export_private_key(pkcs, stack, private_key, &key_len);
647 memset(&buf, 0, sizeof(buf));
648 if (!strcmp(alg->name, "rsa")) {
649 if (silc_buffer_sformat(stack, &buf,
651 SILC_STR_UI32_STRING(SILC_SSH_RSA_BEGIN),
652 SILC_STR_UI32_STRING("\n"),
655 } else if (!strcmp(alg->name, "dsa")) {
656 if (silc_buffer_sformat(stack, &buf,
658 SILC_STR_UI32_STRING(SILC_SSH_DSA_BEGIN),
659 SILC_STR_UI32_STRING("\n"),
665 if (passphrase && strlen(passphrase) > 0) {
666 /* Encrypt the key */
668 /* Allocate cipher */
669 if (!silc_cipher_alloc("3des-168-cbc", &des)) {
670 SILC_LOG_ERROR(("Unsupported algorithm 3des-168-cbc"));
675 if (!silc_hash_alloc("md5", &md5)) {
676 SILC_LOG_ERROR(("Unsupported hash algorithm md5"));
681 silc_rng_get_rn_data(rng, sizeof(ivdata), ivdata, sizeof(ivdata));
682 silc_data2hex(ivdata, sizeof(ivdata), iv, sizeof(iv));
685 if (silc_buffer_sformat(stack, &buf,
687 SILC_STR_UI32_STRING("Proc-Type: 4,ENCRYPTED\n"),
688 SILC_STR_UI32_STRING("DEK-Info: DES-EDE3-CBC,"),
689 SILC_STR_UI32_STRING(iv),
690 SILC_STR_UI32_STRING("\n\n"),
694 /* Generate key from passphrase and IV as salt. The passphrase is
695 hashed with the IV, then rehashed with the previous hash, passphrase
696 and the IV to produce the final key, which is the concatenation of
699 silc_hash_update(md5, passphrase, passphrase_len);
700 silc_hash_update(md5, ivdata, 8);
701 silc_hash_final(md5, enc);
703 silc_hash_update(md5, enc, 16);
704 silc_hash_update(md5, passphrase, passphrase_len);
705 silc_hash_update(md5, ivdata, 8);
706 silc_hash_final(md5, enc + 16);
709 pad_len = 8 - (key_len % 8);
711 keyenc = silc_smalloc(stack, (key_len + pad_len) * sizeof(*keyenc));
714 memset(keyenc + key_len, 'F', pad_len);
715 memcpy(keyenc, key, key_len);
717 keyenc = silc_memdup(key, key_len);
723 silc_cipher_set_key(des, enc, 192, TRUE);
724 silc_cipher_encrypt(des, keyenc, keyenc, key_len + pad_len, ivdata);
726 silc_sfree(stack, key);
730 silc_cipher_free(des);
735 keyenc = silc_base64_encode_file(stack, key, key_len);
739 silc_sfree(stack, key);
741 key_len = strlen(keyenc);
743 /* Encode rest of the public key */
744 if (!strcmp(alg->name, "rsa")) {
745 if (silc_buffer_sformat(stack, &buf,
747 SILC_STR_DATA(key, key_len),
748 SILC_STR_UI32_STRING("\n"),
749 SILC_STR_UI32_STRING(SILC_SSH_RSA_END),
750 SILC_STR_UI32_STRING("\n"),
753 } else if (!strcmp(alg->name, "dsa")) {
754 if (silc_buffer_sformat(stack, &buf,
756 SILC_STR_DATA(key, key_len),
757 SILC_STR_UI32_STRING("\n"),
758 SILC_STR_UI32_STRING(SILC_SSH_DSA_END),
759 SILC_STR_UI32_STRING("\n"),
764 silc_sfree(stack, key);
765 key = silc_buffer_steal(&buf, ret_len);
770 silc_cipher_free(des);
773 silc_sfree(stack, key);
777 /* Export private key */
779 SILC_PKCS_EXPORT_PRIVATE_KEY(silc_pkcs_ssh_export_private_key)
781 SilcSshPrivateKey privkey = private_key;
782 const SilcPKCSAlgorithm *alg = privkey->pkcs;
784 SILC_LOG_DEBUG(("Encode SSH2 private key"));
786 /* Export PKCS algorithm private key */
787 if (alg->export_private_key)
788 return alg->export_private_key(alg, stack,
789 privkey->private_key, ret_len);
793 /* Return key length in bits */
795 SILC_PKCS_PRIVATE_KEY_BITLEN(silc_pkcs_ssh_private_key_bitlen)
797 SilcSshPrivateKey privkey = private_key;
798 return privkey->pkcs->private_key_bitlen(privkey->pkcs,
799 privkey->private_key);
802 /* Free private key */
804 SILC_PKCS_PRIVATE_KEY_FREE(silc_pkcs_ssh_private_key_free)
806 SilcSshPrivateKey privkey = private_key;
808 privkey->pkcs->private_key_free(privkey->pkcs,
809 privkey->private_key);
812 silc_hash_table_free(privkey->fields);
818 SILC_PKCS_ENCRYPT(silc_pkcs_ssh_encrypt)
820 SilcSshPublicKey pubkey = public_key;
822 if (!pubkey->pkcs->encrypt) {
823 encrypt_cb(FALSE, NULL, 0, context);
827 return pubkey->pkcs->encrypt(pubkey->pkcs, pubkey->public_key,
828 src, src_len, rng, encrypt_cb, context);
833 SILC_PKCS_DECRYPT(silc_pkcs_ssh_decrypt)
835 SilcSshPrivateKey privkey = private_key;
837 if (!privkey->pkcs->decrypt) {
838 decrypt_cb(FALSE, NULL, 0, context);
842 return privkey->pkcs->decrypt(privkey->pkcs, privkey->private_key,
843 src, src_len, decrypt_cb, context);
848 SilcSshPrivateKey privkey;
849 SilcPKCSSignCb sign_cb;
853 /* Sign callback. This formats the signature into SSH2 protocool compliant
856 static void silc_pkcs_ssh_sign_cb(SilcBool success,
857 const unsigned char *signature,
858 SilcUInt32 signature_len,
861 SilcSshSign sign = context;
862 SilcBufferStruct sig;
865 if (!strcmp(sign->privkey->pkcs->name, "rsa"))
870 memset(&sig, 0, sizeof(sig));
871 if (silc_buffer_format(&sig,
872 SILC_STR_UI_INT(strlen(name)),
873 SILC_STR_UI32_STRING(name),
874 SILC_STR_UI_INT(signature_len),
875 SILC_STR_DATA(signature, signature_len),
878 sign->sign_cb(FALSE, NULL, 0, sign->context);
882 sign->sign_cb(TRUE, silc_buffer_data(&sig), silc_buffer_len(&sig),
885 silc_buffer_purge(&sig);
891 SILC_PKCS_SIGN(silc_pkcs_ssh_sign)
893 SilcSshPrivateKey privkey = private_key;
896 if (!privkey->pkcs->sign) {
897 sign_cb(FALSE, NULL, 0, context);
901 sign = silc_calloc(1, sizeof(*sign));
903 sign_cb(FALSE, NULL, 0, context);
907 sign->privkey = privkey;
908 sign->sign_cb = sign_cb;
909 sign->context = context;
911 /* Sign. The callback will format it to SSH2 compliant format. */
912 return privkey->pkcs->sign(privkey->pkcs, privkey->private_key,
914 compute_hash, hash, rng,
915 silc_pkcs_ssh_sign_cb, sign);
920 SILC_PKCS_VERIFY(silc_pkcs_ssh_verify)
922 SilcSshPublicKey pubkey = public_key;
923 SilcBufferStruct sig;
925 if (!pubkey->pkcs->verify) {
926 verify_cb(FALSE, context);
930 /* Decode the SSH2 protocol style signature encoding. Ignore the
931 algorithm name. We know the algorithm. */
932 silc_buffer_set(&sig, signature, signature_len);
933 if (silc_buffer_unformat(&sig,
934 SILC_STR_UI32_NSTRING(NULL, NULL),
935 SILC_STR_UI32_NSTRING(&signature, &signature_len),
937 verify_cb(FALSE, context);
942 return pubkey->pkcs->verify(pubkey->pkcs, pubkey->public_key,
943 signature, signature_len,
944 data, data_len, hash, rng,
948 /************************** SSH2 PKCS RSA Alg API ***************************/
950 /* The SSH2 RSA PKCS Algorithm API. We implement here only the necessary
951 parts of the API and the common code is used from PKCS#1 Algorithm API
952 in silccrypt/silcpkcs1.c. Basically everything else is PKCS#1 except
953 the format of the public key. */
955 /* Import RSA public key. Both RFC 4716 and OpenSSH have same format. */
957 SILC_PKCS_ALG_IMPORT_PUBLIC_KEY(silc_ssh_rsa_import_public_key)
959 SilcBufferStruct alg_key;
960 RsaPublicKey *pubkey;
961 unsigned char *n, *e;
962 SilcUInt32 n_len, e_len;
965 SILC_LOG_DEBUG(("Import public key"));
970 /* Allocate RSA public key */
971 *ret_public_key = pubkey = silc_calloc(1, sizeof(*pubkey));
975 /* Parse SSH2 RSA public key */
976 silc_buffer_set(&alg_key, key, key_len);
977 ret = silc_buffer_unformat(&alg_key,
978 SILC_STR_UI32_NSTRING(&e, &e_len),
979 SILC_STR_UI32_NSTRING(&n, &n_len),
983 if (!n_len || !e_len)
986 /* Get MP integers */
987 silc_mp_init(&pubkey->n);
988 silc_mp_init(&pubkey->e);
989 silc_mp_bin2mp(n, n_len, &pubkey->n);
990 silc_mp_bin2mp(e, e_len, &pubkey->e);
993 pubkey->bits = ((silc_mp_sizeinbase(&pubkey->n, 2) + 7) / 8) * 8;
1002 /* Export RSA public key. Both RFC 4716 and OpenSSH have same format. */
1004 SILC_PKCS_ALG_EXPORT_PUBLIC_KEY(silc_ssh_rsa_export_public_key)
1006 RsaPublicKey *pubkey = public_key;
1007 SilcBufferStruct alg_key;
1008 unsigned char *n = NULL, *e = NULL, *ret;
1009 SilcUInt32 n_len, e_len;
1011 SILC_LOG_DEBUG(("Export public key"));
1013 /* Encode MP integers */
1014 n = silc_mp_mp2bin(&pubkey->n, 0, &n_len);
1017 e = silc_mp_mp2bin(&pubkey->e, 0, &e_len);
1021 /* Encode SSH2 RSA public key */
1022 memset(&alg_key, 0, sizeof(alg_key));
1023 if (silc_buffer_sformat(stack, &alg_key,
1024 SILC_STR_UI_INT(e_len),
1025 SILC_STR_DATA(e, e_len),
1026 SILC_STR_UI_INT(n_len),
1027 SILC_STR_DATA(n, n_len),
1034 ret = silc_buffer_steal(&alg_key, ret_len);
1043 /************************** SSH2 PKCS DSA Alg API ***************************/
1045 /* The SSH2 DSA PKCS Algorithm API. We implement here only the necessary
1046 parts of the API and the common code is used from DSS Algorithm API
1047 in silccrypt/dsa.c. */
1049 /* Import DSA public key. Both RFC 4716 and OpenSSH have same format. */
1051 SILC_PKCS_ALG_IMPORT_PUBLIC_KEY(silc_ssh_dsa_import_public_key)
1053 SilcBufferStruct alg_key;
1054 DsaPublicKey *pubkey;
1055 unsigned char *p, *q, *g, *y;
1056 SilcUInt32 p_len, q_len, g_len, y_len;
1059 SILC_LOG_DEBUG(("Import public key"));
1061 if (!ret_public_key)
1064 /* Allocate DSA public key */
1065 *ret_public_key = pubkey = silc_calloc(1, sizeof(*pubkey));
1069 /* Parse SSH2 DSA public key */
1070 silc_buffer_set(&alg_key, key, key_len);
1071 ret = silc_buffer_unformat(&alg_key,
1072 SILC_STR_UI32_NSTRING(&p, &p_len),
1073 SILC_STR_UI32_NSTRING(&q, &q_len),
1074 SILC_STR_UI32_NSTRING(&g, &g_len),
1075 SILC_STR_UI32_NSTRING(&y, &y_len),
1079 if (!p_len || !q_len || !g_len || !y_len)
1082 /* Get MP integers */
1083 silc_mp_init(&pubkey->p);
1084 silc_mp_init(&pubkey->q);
1085 silc_mp_init(&pubkey->g);
1086 silc_mp_init(&pubkey->y);
1087 silc_mp_bin2mp(p, p_len, &pubkey->p);
1088 silc_mp_bin2mp(q, q_len, &pubkey->q);
1089 silc_mp_bin2mp(g, g_len, &pubkey->g);
1090 silc_mp_bin2mp(y, y_len, &pubkey->y);
1092 /* Set key length */
1093 pubkey->bits = ((silc_mp_sizeinbase(&pubkey->p, 2) + 7) / 8) * 8;
1102 /* Export DSA public key. Both RFC 4716 and OpenSSH have same format. */
1104 SILC_PKCS_ALG_EXPORT_PUBLIC_KEY(silc_ssh_dsa_export_public_key)
1106 DsaPublicKey *pubkey = public_key;
1107 SilcBufferStruct alg_key;
1108 unsigned char *p = NULL, *q = NULL, *g = NULL, *y = NULL, *ret;
1109 SilcUInt32 p_len, q_len, g_len, y_len;
1111 SILC_LOG_DEBUG(("Export public key"));
1113 /* Encode MP integers */
1114 p = silc_mp_mp2bin(&pubkey->p, 0, &p_len);
1117 q = silc_mp_mp2bin(&pubkey->q, 0, &q_len);
1120 g = silc_mp_mp2bin(&pubkey->g, 0, &g_len);
1123 y = silc_mp_mp2bin(&pubkey->y, 0, &y_len);
1127 /* Encode SSH2 DSA public key */
1128 memset(&alg_key, 0, sizeof(alg_key));
1129 if (silc_buffer_sformat(stack, &alg_key,
1130 SILC_STR_UI_INT(p_len),
1131 SILC_STR_DATA(p, p_len),
1132 SILC_STR_UI_INT(q_len),
1133 SILC_STR_DATA(q, q_len),
1134 SILC_STR_UI_INT(g_len),
1135 SILC_STR_DATA(g, g_len),
1136 SILC_STR_UI_INT(y_len),
1137 SILC_STR_DATA(y, y_len),
1146 ret = silc_buffer_steal(&alg_key, ret_len);