2
* keyfiles.c - private and public key handling for authentication.
4
* This file is part of the SSH Library
6
* Copyright (c) 2003-2009 by Aris Adamantiadis
7
* Copyright (c) 2009 by Andreas Schneider <mail@cynapses.org>
9
* The SSH Library is free software; you can redistribute it and/or modify
10
* it under the terms of the GNU Lesser General Public License as published by
11
* the Free Software Foundation; either version 2.1 of the License, or (at your
12
* option) any later version.
14
* The SSH Library is distributed in the hope that it will be useful, but
15
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
17
* License for more details.
19
* You should have received a copy of the GNU Lesser General Public License
20
* along with the SSH Library; see the file COPYING. If not, write to
21
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
30
#include <sys/types.h>
45
# define unlink _unlink
46
# endif /* _MSC_VER */
48
# include <arpa/inet.h>
51
#include "libssh/priv.h"
52
#include "libssh/buffer.h"
53
#include "libssh/keyfiles.h"
54
#include "libssh/session.h"
55
#include "libssh/wrapper.h"
56
#include "libssh/misc.h"
57
#include "libssh/keys.h"
59
/*todo: remove this include */
60
#include "libssh/string.h"
65
#elif defined HAVE_LIBCRYPTO
66
#include <openssl/pem.h>
67
#include <openssl/dsa.h>
68
#include <openssl/err.h>
69
#include <openssl/rsa.h>
70
#endif /* HAVE_LIBCRYPTO */
72
#define MAXLINESIZE 80
73
#define RSA_HEADER_BEGIN "-----BEGIN RSA PRIVATE KEY-----"
74
#define RSA_HEADER_END "-----END RSA PRIVATE KEY-----"
75
#define DSA_HEADER_BEGIN "-----BEGIN DSA PRIVATE KEY-----"
76
#define DSA_HEADER_END "-----END DSA PRIVATE KEY-----"
80
#define MAX_KEY_SIZE 32
81
#define MAX_PASSPHRASE_SIZE 1024
82
#define ASN1_INTEGER 2
83
#define ASN1_SEQUENCE 48
84
#define PKCS5_SALT_LEN 8
86
static int load_iv(char *header, unsigned char *iv, int iv_len) {
91
memset(iv, 0, iv_len);
92
for (i = 0; i < iv_len; i++) {
93
if ((header[2*i] >= '0') && (header[2*i] <= '9'))
94
j = header[2*i] - '0';
95
else if ((header[2*i] >= 'A') && (header[2*i] <= 'F'))
96
j = header[2*i] - 'A' + 10;
97
else if ((header[2*i] >= 'a') && (header[2*i] <= 'f'))
98
j = header[2*i] - 'a' + 10;
101
if ((header[2*i+1] >= '0') && (header[2*i+1] <= '9'))
102
k = header[2*i+1] - '0';
103
else if ((header[2*i+1] >= 'A') && (header[2*i+1] <= 'F'))
104
k = header[2*i+1] - 'A' + 10;
105
else if ((header[2*i+1] >= 'a') && (header[2*i+1] <= 'f'))
106
k = header[2*i+1] - 'a' + 10;
109
iv[i] = (j << 4) + k;
114
static uint32_t char_to_u32(unsigned char *data, uint32_t size) {
118
for (i = 0, ret = 0; i < size; ret = ret << 8, ret += data[i++])
123
static uint32_t asn1_get_len(ssh_buffer buffer) {
125
unsigned char tmp[4];
127
if (buffer_get_data(buffer,tmp,1) == 0) {
134
return 0; /* Length doesn't fit in u32. Can this really happen? */
136
if (buffer_get_data(buffer,tmp,len) == 0) {
139
len = char_to_u32(tmp, len);
141
len = char_to_u32(tmp, 1);
147
static ssh_string asn1_get_int(ssh_buffer buffer) {
152
if (buffer_get_data(buffer, &type, 1) == 0 || type != ASN1_INTEGER) {
155
size = asn1_get_len(buffer);
160
str = ssh_string_new(size);
165
if (buffer_get_data(buffer, str->string, size) == 0) {
166
ssh_string_free(str);
173
static int asn1_check_sequence(ssh_buffer buffer) {
174
unsigned char *j = NULL;
180
if (buffer_get_data(buffer, &tmp, 1) == 0 || tmp != ASN1_SEQUENCE) {
184
size = asn1_get_len(buffer);
185
if ((padding = ssh_buffer_get_len(buffer) - buffer->pos - size) > 0) {
186
for (i = ssh_buffer_get_len(buffer) - buffer->pos - size,
187
j = (unsigned char*)ssh_buffer_get_begin(buffer) + size + buffer->pos;
191
if (*j != padding) { /* padding is allowed */
192
return 0; /* but nothing else */
200
static int read_line(char *data, unsigned int len, FILE *fp) {
204
for (i = 0; fread(&tmp, 1, 1, fp) && tmp != '\n' && i < len; data[i++] = tmp)
217
static int passphrase_to_key(char *data, unsigned int datalen,
218
unsigned char *salt, unsigned char *key, unsigned int keylen) {
220
unsigned char digest[MD5_DIGEST_LEN] = {0};
223
unsigned int md_not_empty;
225
for (j = 0, md_not_empty = 0; j < keylen; ) {
232
md5_update(md, digest, MD5_DIGEST_LEN);
237
md5_update(md, data, datalen);
239
md5_update(md, salt, PKCS5_SALT_LEN);
241
md5_final(digest, md);
243
for (i = 0; j < keylen && i < MD5_DIGEST_LEN; j++, i++) {
253
static int privatekey_decrypt(int algo, int mode, unsigned int key_len,
254
unsigned char *iv, unsigned int iv_len,
255
ssh_buffer data, ssh_auth_callback cb,
259
char passphrase[MAX_PASSPHRASE_SIZE] = {0};
260
unsigned char key[MAX_KEY_SIZE] = {0};
261
unsigned char *tmp = NULL;
262
gcry_cipher_hd_t cipher;
270
rc = (*cb)(desc, passphrase, MAX_PASSPHRASE_SIZE, 0, 0, userdata);
274
} else if (cb == NULL && userdata != NULL) {
275
snprintf(passphrase, MAX_PASSPHRASE_SIZE, "%s", (char *) userdata);
278
if (passphrase_to_key(passphrase, strlen(passphrase), iv, key, key_len) < 0) {
282
if (gcry_cipher_open(&cipher, algo, mode, 0)
283
|| gcry_cipher_setkey(cipher, key, key_len)
284
|| gcry_cipher_setiv(cipher, iv, iv_len)
285
|| (tmp = malloc(ssh_buffer_get_len(data) * sizeof (char))) == NULL
286
|| gcry_cipher_decrypt(cipher, tmp, ssh_buffer_get_len(data),
287
ssh_buffer_get_begin(data), ssh_buffer_get_len(data))) {
288
gcry_cipher_close(cipher);
292
memcpy(ssh_buffer_get_begin(data), tmp, ssh_buffer_get_len(data));
295
gcry_cipher_close(cipher);
300
static int privatekey_dek_header(char *header, unsigned int header_len,
301
int *algo, int *mode, unsigned int *key_len, unsigned char **iv,
302
unsigned int *iv_len) {
305
if (header_len > 13 && !strncmp("DES-EDE3-CBC", header, 12))
307
*algo = GCRY_CIPHER_3DES;
309
*mode = GCRY_CIPHER_MODE_CBC;
313
else if (header_len > 8 && !strncmp("DES-CBC", header, 7))
315
*algo = GCRY_CIPHER_DES;
317
*mode = GCRY_CIPHER_MODE_CBC;
321
else if (header_len > 12 && !strncmp("AES-128-CBC", header, 11))
323
*algo = GCRY_CIPHER_AES128;
325
*mode = GCRY_CIPHER_MODE_CBC;
329
else if (header_len > 12 && !strncmp("AES-192-CBC", header, 11))
331
*algo = GCRY_CIPHER_AES192;
333
*mode = GCRY_CIPHER_MODE_CBC;
337
else if (header_len > 12 && !strncmp("AES-256-CBC", header, 11))
339
*algo = GCRY_CIPHER_AES256;
341
*mode = GCRY_CIPHER_MODE_CBC;
348
*iv = malloc(*iv_len);
353
return load_iv(header + iv_pos, *iv, *iv_len);
356
static ssh_buffer privatekey_file_to_buffer(FILE *fp, int type,
357
ssh_auth_callback cb, void *userdata, const char *desc) {
358
ssh_buffer buffer = NULL;
359
ssh_buffer out = NULL;
360
char buf[MAXLINESIZE] = {0};
361
unsigned char *iv = NULL;
362
const char *header_begin;
363
const char *header_end;
364
unsigned int header_begin_size;
365
unsigned int header_end_size;
366
unsigned int key_len = 0;
367
unsigned int iv_len = 0;
372
buffer = ssh_buffer_new();
373
if (buffer == NULL) {
378
case SSH_KEYTYPE_DSS:
379
header_begin = DSA_HEADER_BEGIN;
380
header_end = DSA_HEADER_END;
382
case SSH_KEYTYPE_RSA:
383
header_begin = RSA_HEADER_BEGIN;
384
header_end = RSA_HEADER_END;
387
ssh_buffer_free(buffer);
391
header_begin_size = strlen(header_begin);
392
header_end_size = strlen(header_end);
394
while (read_line(buf, MAXLINESIZE, fp) &&
395
strncmp(buf, header_begin, header_begin_size))
398
len = read_line(buf, MAXLINESIZE, fp);
399
if (len > 11 && strncmp("Proc-Type: 4,ENCRYPTED", buf, 11) == 0) {
400
len = read_line(buf, MAXLINESIZE, fp);
401
if (len > 10 && strncmp("DEK-Info: ", buf, 10) == 0) {
402
if ((privatekey_dek_header(buf + 10, len - 10, &algo, &mode, &key_len,
404
|| read_line(buf, MAXLINESIZE, fp)) {
405
ssh_buffer_free(buffer);
410
ssh_buffer_free(buffer);
415
if (buffer_add_data(buffer, buf, len) < 0) {
416
ssh_buffer_free(buffer);
422
while ((len = read_line(buf,MAXLINESIZE,fp)) &&
423
strncmp(buf, header_end, header_end_size) != 0) {
425
ssh_buffer_free(buffer);
429
if (buffer_add_data(buffer, buf, len) < 0) {
430
ssh_buffer_free(buffer);
436
if (strncmp(buf,header_end,header_end_size) != 0) {
437
ssh_buffer_free(buffer);
442
if (buffer_add_data(buffer, "\0", 1) < 0) {
443
ssh_buffer_free(buffer);
448
out = base64_to_bin(ssh_buffer_get_begin(buffer));
449
ssh_buffer_free(buffer);
456
if (privatekey_decrypt(algo, mode, key_len, iv, iv_len, out,
457
cb, userdata, desc) < 0) {
458
ssh_buffer_free(out);
468
static int read_rsa_privatekey(FILE *fp, gcry_sexp_t *r,
469
ssh_auth_callback cb, void *userdata, const char *desc) {
475
ssh_string unused1 = NULL;
476
ssh_string unused2 = NULL;
479
ssh_buffer buffer = NULL;
482
buffer = privatekey_file_to_buffer(fp, SSH_KEYTYPE_RSA, cb, userdata, desc);
483
if (buffer == NULL) {
487
if (!asn1_check_sequence(buffer)) {
488
ssh_buffer_free(buffer);
492
v = asn1_get_int(buffer);
493
if (ntohl(v->size) != 1 || v->string[0] != 0) {
494
ssh_buffer_free(buffer);
498
n = asn1_get_int(buffer);
499
e = asn1_get_int(buffer);
500
d = asn1_get_int(buffer);
501
q = asn1_get_int(buffer);
502
p = asn1_get_int(buffer);
503
unused1 = asn1_get_int(buffer);
504
unused2 = asn1_get_int(buffer);
505
u = asn1_get_int(buffer);
507
ssh_buffer_free(buffer);
509
if (n == NULL || e == NULL || d == NULL || p == NULL || q == NULL ||
510
unused1 == NULL || unused2 == NULL|| u == NULL) {
515
if (gcry_sexp_build(r, NULL,
516
"(private-key(rsa(n %b)(e %b)(d %b)(p %b)(q %b)(u %b)))",
517
ntohl(n->size), n->string,
518
ntohl(e->size), e->string,
519
ntohl(d->size), d->string,
520
ntohl(p->size), p->string,
521
ntohl(q->size), q->string,
522
ntohl(u->size), u->string)) {
532
ssh_string_free(unused1);
533
ssh_string_free(unused2);
540
static int read_dsa_privatekey(FILE *fp, gcry_sexp_t *r, ssh_auth_callback cb,
541
void *userdata, const char *desc) {
542
ssh_buffer buffer = NULL;
551
buffer = privatekey_file_to_buffer(fp, SSH_KEYTYPE_DSS, cb, userdata, desc);
552
if (buffer == NULL) {
556
if (!asn1_check_sequence(buffer)) {
557
ssh_buffer_free(buffer);
561
v = asn1_get_int(buffer);
562
if (ntohl(v->size) != 1 || v->string[0] != 0) {
563
ssh_buffer_free(buffer);
567
p = asn1_get_int(buffer);
568
q = asn1_get_int(buffer);
569
g = asn1_get_int(buffer);
570
y = asn1_get_int(buffer);
571
x = asn1_get_int(buffer);
572
ssh_buffer_free(buffer);
574
if (p == NULL || q == NULL || g == NULL || y == NULL || x == NULL) {
579
if (gcry_sexp_build(r, NULL,
580
"(private-key(dsa(p %b)(q %b)(g %b)(y %b)(x %b)))",
581
ntohl(p->size), p->string,
582
ntohl(q->size), q->string,
583
ntohl(g->size), g->string,
584
ntohl(y->size), y->string,
585
ntohl(x->size), x->string)) {
599
#endif /* HAVE_LIBGCRYPT */
601
#ifdef HAVE_LIBCRYPTO
602
static int pem_get_password(char *buf, int size, int rwflag, void *userdata) {
603
ssh_session session = userdata;
609
memset(buf,'\0',size);
610
ssh_log(session, SSH_LOG_RARE,
611
"Trying to call external authentication function");
613
if (session && session->callbacks && session->callbacks->auth_function) {
614
if (session->callbacks->auth_function("Passphrase for private key:", buf, size, 0, 0,
615
session->callbacks->userdata) < 0) {
624
#endif /* HAVE_LIBCRYPTO */
626
static int privatekey_type_from_file(FILE *fp) {
627
char buffer[MAXLINESIZE] = {0};
629
if (!fgets(buffer, MAXLINESIZE, fp)) {
632
fseek(fp, 0, SEEK_SET);
633
if (strncmp(buffer, DSA_HEADER_BEGIN, strlen(DSA_HEADER_BEGIN)) == 0) {
634
return SSH_KEYTYPE_DSS;
636
if (strncmp(buffer, RSA_HEADER_BEGIN, strlen(RSA_HEADER_BEGIN)) == 0) {
637
return SSH_KEYTYPE_RSA;
643
* @addtogroup libssh_auth
649
* @brief Reads a SSH private key from a file.
651
* @param[in] session The SSH Session to use.
653
* @param[in] filename The filename of the the private key.
655
* @param[in] type The type of the private key. This could be SSH_KEYTYPE_DSS or
656
* SSH_KEYTYPE_RSA. Pass 0 to automatically detect the type.
658
* @param[in] passphrase The passphrase to decrypt the private key. Set to null
659
* if none is needed or it is unknown.
661
* @return A private_key object containing the private key, or
663
* @see privatekey_free()
664
* @see publickey_from_privatekey()
666
ssh_private_key privatekey_from_file(ssh_session session, const char *filename,
667
int type, const char *passphrase) {
668
ssh_private_key privkey = NULL;
670
#ifdef HAVE_LIBGCRYPT
671
ssh_auth_callback auth_cb = NULL;
672
void *auth_ud = NULL;
674
gcry_sexp_t dsa = NULL;
675
gcry_sexp_t rsa = NULL;
677
#elif defined HAVE_LIBCRYPTO
682
/* TODO Implement to read both DSA and RSA at once. */
684
/* needed for openssl initialization */
685
if (ssh_init() < 0) {
689
ssh_log(session, SSH_LOG_RARE, "Trying to open %s", filename);
690
file = fopen(filename,"r");
692
ssh_set_error(session, SSH_REQUEST_DENIED,
693
"Error opening %s: %s", filename, strerror(errno));
697
#ifdef HAVE_LIBCRYPTO
698
bio = BIO_new_file(filename,"r");
701
ssh_set_error(session, SSH_FATAL, "Could not create BIO.");
706
ssh_log(session, SSH_LOG_RARE, "Trying to read %s, passphase=%s, authcb=%s",
707
filename, passphrase ? "true" : "false",
708
session->callbacks && session->callbacks->auth_function ? "true" : "false");
711
type = privatekey_type_from_file(file);
714
ssh_set_error(session, SSH_FATAL, "Invalid private key file.");
719
case SSH_KEYTYPE_DSS:
720
if (passphrase == NULL) {
721
#ifdef HAVE_LIBGCRYPT
722
if (session->callbacks && session->callbacks->auth_function) {
723
auth_cb = session->callbacks->auth_function;
724
auth_ud = session->callbacks->userdata;
726
valid = read_dsa_privatekey(file, &dsa, auth_cb, auth_ud,
727
"Passphrase for private key:");
728
} else { /* authcb */
729
valid = read_dsa_privatekey(file, &dsa, NULL, NULL, NULL);
731
} else { /* passphrase */
732
valid = read_dsa_privatekey(file, &dsa, NULL,
733
(void *) passphrase, NULL);
739
ssh_set_error(session, SSH_FATAL, "Parsing private key %s", filename);
740
#elif defined HAVE_LIBCRYPTO
741
if (session->callbacks && session->callbacks->auth_function) {
742
dsa = PEM_read_bio_DSAPrivateKey(bio, NULL, pem_get_password, session);
743
} else { /* authcb */
744
/* openssl uses its own callback to get the passphrase here */
745
dsa = PEM_read_bio_DSAPrivateKey(bio, NULL, NULL, NULL);
747
} else { /* passphrase */
748
dsa = PEM_read_bio_DSAPrivateKey(bio, NULL, NULL, (void *) passphrase);
754
ssh_set_error(session, SSH_FATAL,
755
"Parsing private key %s: %s",
756
filename, ERR_error_string(ERR_get_error(), NULL));
761
case SSH_KEYTYPE_RSA:
762
if (passphrase == NULL) {
763
#ifdef HAVE_LIBGCRYPT
764
if (session->callbacks && session->callbacks->auth_function) {
765
auth_cb = session->callbacks->auth_function;
766
auth_ud = session->callbacks->userdata;
767
valid = read_rsa_privatekey(file, &rsa, auth_cb, auth_ud,
768
"Passphrase for private key:");
769
} else { /* authcb */
770
valid = read_rsa_privatekey(file, &rsa, NULL, NULL, NULL);
772
} else { /* passphrase */
773
valid = read_rsa_privatekey(file, &rsa, NULL,
774
(void *) passphrase, NULL);
780
ssh_set_error(session,SSH_FATAL, "Parsing private key %s", filename);
781
#elif defined HAVE_LIBCRYPTO
782
if (session->callbacks && session->callbacks->auth_function) {
783
rsa = PEM_read_bio_RSAPrivateKey(bio, NULL, pem_get_password, session);
784
} else { /* authcb */
785
/* openssl uses its own callback to get the passphrase here */
786
rsa = PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, NULL);
788
} else { /* passphrase */
789
rsa = PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, (void *) passphrase);
796
ssh_set_error(session, SSH_FATAL,
797
"Parsing private key %s: %s",
798
filename, ERR_error_string(ERR_get_error(),NULL));
804
#ifdef HAVE_LIBCRYPTO
808
ssh_set_error(session, SSH_FATAL, "Invalid private key type %d", type);
812
privkey = malloc(sizeof(struct ssh_private_key_struct));
813
if (privkey == NULL) {
814
#ifdef HAVE_LIBGCRYPT
815
gcry_sexp_release(dsa);
816
gcry_sexp_release(rsa);
817
#elif defined HAVE_LIBCRYPTO
823
ZERO_STRUCTP(privkey);
824
privkey->type = type;
825
privkey->dsa_priv = dsa;
826
privkey->rsa_priv = rsa;
832
* @brief returns the type of a private key
833
* @param[in] privatekey the private key handle
834
* @returns one of SSH_KEYTYPE_RSA,SSH_KEYTYPE_DSS,SSH_KEYTYPE_RSA1
835
* @returns SSH_KEYTYPE_UNKNOWN if the type is unknown
836
* @see privatekey_from_file
837
* @see ssh_userauth_offer_pubkey
839
enum ssh_keytypes_e ssh_privatekey_type(ssh_private_key privatekey){
840
if (privatekey==NULL)
841
return SSH_KEYTYPE_UNKNOWN;
842
return privatekey->type;
845
/* same that privatekey_from_file() but without any passphrase things. */
846
ssh_private_key _privatekey_from_file(void *session, const char *filename,
848
ssh_private_key privkey = NULL;
849
#ifdef HAVE_LIBGCRYPT
851
gcry_sexp_t dsa = NULL;
852
gcry_sexp_t rsa = NULL;
854
#elif defined HAVE_LIBCRYPTO
860
#ifdef HAVE_LIBGCRYPT
861
file = fopen(filename,"r");
863
ssh_set_error(session, SSH_REQUEST_DENIED,
864
"Error opening %s: %s", filename, strerror(errno));
867
#elif defined HAVE_LIBCRYPTO
868
bio = BIO_new_file(filename,"r");
870
ssh_set_error(session, SSH_FATAL, "Could not create BIO.");
876
case SSH_KEYTYPE_DSS:
877
#ifdef HAVE_LIBGCRYPT
878
valid = read_dsa_privatekey(file, &dsa, NULL, NULL, NULL);
883
ssh_set_error(session, SSH_FATAL, "Parsing private key %s", filename);
884
#elif defined HAVE_LIBCRYPTO
885
dsa = PEM_read_bio_DSAPrivateKey(bio, NULL, NULL, NULL);
890
ssh_set_error(session, SSH_FATAL,
891
"Parsing private key %s: %s",
892
filename, ERR_error_string(ERR_get_error(), NULL));
899
case SSH_KEYTYPE_RSA:
900
#ifdef HAVE_LIBGCRYPT
901
valid = read_rsa_privatekey(file, &rsa, NULL, NULL, NULL);
906
ssh_set_error(session, SSH_FATAL, "Parsing private key %s", filename);
907
#elif defined HAVE_LIBCRYPTO
908
rsa = PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, NULL);
913
ssh_set_error(session, SSH_FATAL,
914
"Parsing private key %s: %s",
915
filename, ERR_error_string(ERR_get_error(), NULL));
923
#ifdef HAVE_LIBGCRYPT
925
#elif defined HAVE_LIBCRYPTO
928
ssh_set_error(session, SSH_FATAL, "Invalid private key type %d", type);
932
privkey = malloc(sizeof(struct ssh_private_key_struct));
933
if (privkey == NULL) {
934
#ifdef HAVE_LIBGCRYPT
935
gcry_sexp_release(dsa);
936
gcry_sexp_release(rsa);
937
#elif defined HAVE_LIBCRYPTO
944
privkey->type = type;
945
privkey->dsa_priv = dsa;
946
privkey->rsa_priv = rsa;
952
* @brief Deallocate a private key object.
954
* @param[in] prv The private_key object to free.
956
void privatekey_free(ssh_private_key prv) {
961
#ifdef HAVE_LIBGCRYPT
962
gcry_sexp_release(prv->dsa_priv);
963
gcry_sexp_release(prv->rsa_priv);
964
#elif defined HAVE_LIBCRYPTO
965
DSA_free(prv->dsa_priv);
966
RSA_free(prv->rsa_priv);
968
memset(prv, 0, sizeof(struct ssh_private_key_struct));
973
* @brief Write a public key to a file.
975
* @param[in] session The ssh session to use.
977
* @param[in] file The filename to write the key into.
979
* @param[in] pubkey The public key to write.
981
* @param[in] type The type of the public key.
983
* @return 0 on success, -1 on error.
985
int ssh_publickey_to_file(ssh_session session, const char *file,
986
ssh_string pubkey, int type) {
991
unsigned char *pubkey_64;
996
if(file==NULL || pubkey==NULL){
997
ssh_set_error(session, SSH_FATAL, "Invalid parameters");
1000
pubkey_64 = bin_to_base64(pubkey->string, ssh_string_len(pubkey));
1001
if (pubkey_64 == NULL) {
1005
user = ssh_get_local_username(session);
1007
SAFE_FREE(pubkey_64);
1011
rc = gethostname(host, sizeof(host));
1014
SAFE_FREE(pubkey_64);
1018
snprintf(buffer, sizeof(buffer), "%s %s %s@%s\n",
1019
ssh_type_to_char(type),
1024
SAFE_FREE(pubkey_64);
1027
ssh_log(session, SSH_LOG_RARE, "Trying to write public key file: %s", file);
1028
ssh_log(session, SSH_LOG_PACKET, "public key file content: %s", buffer);
1030
fp = fopen(file, "w+");
1032
ssh_set_error(session, SSH_REQUEST_DENIED,
1033
"Error opening %s: %s", file, strerror(errno));
1037
len = strlen(buffer);
1038
if (fwrite(buffer, len, 1, fp) != 1 || ferror(fp)) {
1039
ssh_set_error(session, SSH_REQUEST_DENIED,
1040
"Unable to write to %s", file);
1051
* @brief Retrieve a public key from a file.
1053
* @param[in] session The SSH session to use.
1055
* @param[in] filename The filename of the public key.
1057
* @param[out] type The Pointer to a integer. If it is not NULL, it will
1058
* contain the type of the key after execution.
1060
* @return A SSH String containing the public key, or NULL if it
1063
* @see string_free()
1064
* @see publickey_from_privatekey()
1066
ssh_string publickey_from_file(ssh_session session, const char *filename,
1068
ssh_buffer buffer = NULL;
1069
char buf[4096] = {0};
1070
ssh_string str = NULL;
1076
fd = open(filename, O_RDONLY);
1078
ssh_set_error(session, SSH_REQUEST_DENIED, "Public key file doesn't exist");
1082
if (read(fd, buf, 8) != 8) {
1084
ssh_set_error(session, SSH_REQUEST_DENIED, "Invalid public key file");
1090
key_type = ssh_type_from_name(buf);
1091
if (key_type == -1) {
1093
ssh_set_error(session, SSH_REQUEST_DENIED, "Invalid public key file");
1097
r = read(fd, buf, sizeof(buf) - 1);
1100
ssh_set_error(session, SSH_REQUEST_DENIED, "Invalid public key file");
1105
ptr = strchr(buf, ' ');
1107
/* eliminate the garbage at end of file */
1112
buffer = base64_to_bin(buf);
1113
if (buffer == NULL) {
1114
ssh_set_error(session, SSH_REQUEST_DENIED, "Invalid public key file");
1118
str = ssh_string_new(buffer_get_rest_len(buffer));
1120
ssh_set_error(session, SSH_FATAL, "Not enough space");
1121
ssh_buffer_free(buffer);
1125
ssh_string_fill(str, buffer_get_rest(buffer), buffer_get_rest_len(buffer));
1126
ssh_buffer_free(buffer);
1136
* @brief Try to read the public key from a given file.
1138
* @param[in] session The ssh session to use.
1140
* @param[in] keyfile The name of the private keyfile.
1142
* @param[out] publickey A ssh_string to store the public key.
1144
* @param[out] type A pointer to an integer to store the type.
1146
* @return 0 on success, -1 on error or the private key doesn't
1147
* exist, 1 if the public key doesn't exist.
1149
int ssh_try_publickey_from_file(ssh_session session, const char *keyfile,
1150
ssh_string *publickey, int *type) {
1153
ssh_string pubkey_string;
1156
if (session == NULL || keyfile == NULL || publickey == NULL || type == NULL) {
1160
if (session->sshdir == NULL) {
1161
if (ssh_options_apply(session) < 0) {
1166
ssh_log(session, SSH_LOG_PACKET, "Trying to open privatekey %s", keyfile);
1167
if (!ssh_file_readaccess_ok(keyfile)) {
1168
ssh_log(session, SSH_LOG_PACKET, "Failed to open privatekey %s", keyfile);
1172
len = strlen(keyfile) + 5;
1173
pubkey_file = malloc(len);
1174
if (pubkey_file == NULL) {
1177
snprintf(pubkey_file, len, "%s.pub", keyfile);
1179
ssh_log(session, SSH_LOG_PACKET, "Trying to open publickey %s",
1181
if (!ssh_file_readaccess_ok(pubkey_file)) {
1182
ssh_log(session, SSH_LOG_PACKET, "Failed to open publickey %s",
1184
SAFE_FREE(pubkey_file);
1188
ssh_log(session, SSH_LOG_PACKET, "Success opening public and private key");
1191
* We are sure both the private and public key file is readable. We return
1192
* the public as a string, and the private filename as an argument
1194
pubkey_string = publickey_from_file(session, pubkey_file, &pubkey_type);
1195
if (pubkey_string == NULL) {
1196
ssh_log(session, SSH_LOG_PACKET,
1197
"Wasn't able to open public key file %s: %s",
1199
ssh_get_error(session));
1200
SAFE_FREE(pubkey_file);
1204
SAFE_FREE(pubkey_file);
1206
*publickey = pubkey_string;
1207
*type = pubkey_type;
1212
ssh_string try_publickey_from_file(ssh_session session, struct ssh_keys_struct keytab,
1213
char **privkeyfile, int *type) {
1217
ssh_string pubkey=NULL;
1219
pub = keytab.publickey;
1223
priv = keytab.privatekey;
1228
if (session->sshdir == NULL) {
1229
if (ssh_options_apply(session) < 0) {
1234
ssh_log(session, SSH_LOG_PACKET, "Trying to open publickey %s", pub);
1235
if (!ssh_file_readaccess_ok(pub)) {
1236
ssh_log(session, SSH_LOG_PACKET, "Failed to open publickey %s", pub);
1240
ssh_log(session, SSH_LOG_PACKET, "Trying to open privatekey %s", priv);
1241
if (!ssh_file_readaccess_ok(priv)) {
1242
ssh_log(session, SSH_LOG_PACKET, "Failed to open privatekey %s", priv);
1246
ssh_log(session, SSH_LOG_PACKET, "Success opening public and private key");
1249
* We are sure both the private and public key file is readable. We return
1250
* the public as a string, and the private filename as an argument
1252
pubkey = publickey_from_file(session, pub, type);
1253
if (pubkey == NULL) {
1254
ssh_log(session, SSH_LOG_PACKET,
1255
"Wasn't able to open public key file %s: %s",
1257
ssh_get_error(session));
1261
new = realloc(*privkeyfile, strlen(priv) + 1);
1263
ssh_string_free(pubkey);
1275
/* vim: set ts=4 sw=4 et cindent: */