41
#include "libssh2_priv.h"
44
readline(char *line, int line_size, FILE * fp)
51
if(!fgets(line, line_size, fp)) {
57
if(len > 0 && line[len - 1] == '\n') {
64
if(len > 0 && line[len - 1] == '\r') {
73
readline_memory(char *line, size_t line_size,
74
const char *filedata, size_t filedata_len,
75
size_t *filedata_offset)
79
off = *filedata_offset;
81
for(len = 0; off + len < filedata_len && len < line_size - 1; len++) {
82
if(filedata[off + len] == '\n' ||
83
filedata[off + len] == '\r') {
89
memcpy(line, filedata + off, len);
90
*filedata_offset += len;
94
*filedata_offset += 1;
101
static const char *crypt_annotation = "Proc-Type: 4,ENCRYPTED";
103
static unsigned char hex_decode(char digit)
105
return (unsigned char)
106
((digit >= 'A') ? (0xA + (digit - 'A')) : (digit - '0'));
110
_libssh2_pem_parse(LIBSSH2_SESSION * session,
111
const char *headerbegin,
112
const char *headerend,
113
const unsigned char *passphrase,
114
FILE * fp, unsigned char **data, size_t *datalen)
116
char line[LINE_SIZE];
117
unsigned char iv[LINE_SIZE];
118
char *b64data = NULL;
119
size_t b64datalen = 0;
121
const LIBSSH2_CRYPT_METHOD *method = NULL;
126
if(readline(line, LINE_SIZE, fp)) {
130
while(strcmp(line, headerbegin) != 0);
132
if(readline(line, LINE_SIZE, fp)) {
137
memcmp(line, crypt_annotation, strlen(crypt_annotation)) == 0) {
138
const LIBSSH2_CRYPT_METHOD **all_methods, *cur_method;
141
if(readline(line, LINE_SIZE, fp)) {
146
all_methods = libssh2_crypt_methods();
148
while((cur_method = *all_methods++) != NULL) {
149
if(*cur_method->pem_annotation &&
150
memcmp(line, cur_method->pem_annotation,
151
strlen(cur_method->pem_annotation)) == 0) {
153
memcpy(iv, line + strlen(method->pem_annotation) + 1,
163
for(i = 0; i < method->iv_len; ++i) {
164
iv[i] = (unsigned char)(hex_decode(iv[2*i]) << 4);
165
iv[i] |= hex_decode(iv[2*i + 1]);
169
if(readline(line, LINE_SIZE, fp)) {
180
linelen = strlen(line);
181
tmp = LIBSSH2_REALLOC(session, b64data, b64datalen + linelen);
183
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
184
"Unable to allocate memory for PEM parsing");
188
memcpy(tmp + b64datalen, line, linelen);
190
b64datalen += linelen;
195
if(readline(line, LINE_SIZE, fp)) {
199
} while(strcmp(line, headerend) != 0);
205
if(_libssh2_base64_decode(session, (char **) data, datalen,
206
b64data, b64datalen)) {
214
int free_iv = 0, free_secret = 0, len_decrypted = 0, padding = 0;
215
int blocksize = method->blocksize;
217
unsigned char secret[2*MD5_DIGEST_LENGTH];
218
libssh2_md5_ctx fingerprint_ctx;
221
if(!libssh2_md5_init(&fingerprint_ctx) ||
222
!libssh2_md5_update(fingerprint_ctx, passphrase,
223
strlen((char *)passphrase)) ||
224
!libssh2_md5_update(fingerprint_ctx, iv, 8) ||
225
!libssh2_md5_final(fingerprint_ctx, secret)) {
229
if(method->secret_len > MD5_DIGEST_LENGTH) {
230
if(!libssh2_md5_init(&fingerprint_ctx) ||
231
!libssh2_md5_update(fingerprint_ctx,
232
secret, MD5_DIGEST_LENGTH) ||
233
!libssh2_md5_update(fingerprint_ctx,
234
passphrase, strlen((char *)passphrase)) ||
235
!libssh2_md5_update(fingerprint_ctx, iv, 8) ||
236
!libssh2_md5_final(fingerprint_ctx,
237
secret + MD5_DIGEST_LENGTH)) {
244
if(method->init(session, method, iv, &free_iv, secret,
245
&free_secret, 0, &abstract)) {
246
_libssh2_explicit_zero((char *)secret, sizeof(secret));
247
LIBSSH2_FREE(session, data);
253
_libssh2_explicit_zero((char *)secret, sizeof(secret));
257
if((*datalen % blocksize) != 0) {
258
_libssh2_explicit_zero((char *)secret, sizeof(secret));
259
method->dtor(session, &abstract);
260
_libssh2_explicit_zero(*data, *datalen);
261
LIBSSH2_FREE(session, *data);
266
while(len_decrypted <= (int)*datalen - blocksize) {
267
if(method->crypt(session, *data + len_decrypted, blocksize,
269
len_decrypted == 0 ? FIRST_BLOCK :
270
((len_decrypted == (int)*datalen - blocksize) ?
271
LAST_BLOCK : MIDDLE_BLOCK)
273
ret = LIBSSH2_ERROR_DECRYPT;
274
_libssh2_explicit_zero((char *)secret, sizeof(secret));
275
method->dtor(session, &abstract);
276
_libssh2_explicit_zero(*data, *datalen);
277
LIBSSH2_FREE(session, *data);
281
len_decrypted += blocksize;
285
padding = (*data)[*datalen - 1];
286
memset(&(*data)[*datalen-padding], 0, padding);
290
_libssh2_explicit_zero((char *)secret, sizeof(secret));
291
method->dtor(session, &abstract);
301
_libssh2_explicit_zero(b64data, b64datalen);
302
LIBSSH2_FREE(session, b64data);
308
_libssh2_pem_parse_memory(LIBSSH2_SESSION * session,
309
const char *headerbegin,
310
const char *headerend,
311
const char *filedata, size_t filedata_len,
312
unsigned char **data, size_t *datalen)
314
char line[LINE_SIZE];
315
char *b64data = NULL;
316
size_t b64datalen = 0;
323
if(readline_memory(line, LINE_SIZE, filedata, filedata_len, &off)) {
327
while(strcmp(line, headerbegin) != 0);
336
linelen = strlen(line);
337
tmp = LIBSSH2_REALLOC(session, b64data, b64datalen + linelen);
339
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
340
"Unable to allocate memory for PEM parsing");
344
memcpy(tmp + b64datalen, line, linelen);
346
b64datalen += linelen;
351
if(readline_memory(line, LINE_SIZE, filedata, filedata_len, &off)) {
355
} while(strcmp(line, headerend) != 0);
361
if(_libssh2_base64_decode(session, (char **) data, datalen,
362
b64data, b64datalen)) {
370
_libssh2_explicit_zero(b64data, b64datalen);
371
LIBSSH2_FREE(session, b64data);
377
#define AUTH_MAGIC "openssh-key-v1"
378
#define OPENSSH_HEADER_BEGIN "-----BEGIN OPENSSH PRIVATE KEY-----"
379
#define OPENSSH_HEADER_END "-----END OPENSSH PRIVATE KEY-----"
382
_libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session,
383
const unsigned char *passphrase,
384
const char *b64data, size_t b64datalen,
385
struct string_buf **decrypted_buf)
387
const LIBSSH2_CRYPT_METHOD *method = NULL;
388
struct string_buf decoded, decrypted, kdf_buf;
389
unsigned char *ciphername = NULL;
390
unsigned char *kdfname = NULL;
391
unsigned char *kdf = NULL;
392
unsigned char *buf = NULL;
393
unsigned char *salt = NULL;
394
uint32_t nkeys, check1, check2;
396
unsigned char *key = NULL;
397
unsigned char *key_part = NULL;
398
unsigned char *iv_part = NULL;
399
unsigned char *f = NULL;
401
int ret = 0, keylen = 0, ivlen = 0, total_len = 0;
402
size_t kdf_len = 0, tmp_len = 0, salt_len = 0;
405
*decrypted_buf = NULL;
408
if(_libssh2_base64_decode(session, (char **)&f, &f_len,
409
b64data, b64datalen)) {
415
decoded.data = (unsigned char *)f;
416
decoded.dataptr = (unsigned char *)f;
419
if(decoded.len < strlen(AUTH_MAGIC)) {
420
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, "key too short");
424
if(strncmp((char *) decoded.dataptr, AUTH_MAGIC,
425
strlen(AUTH_MAGIC)) != 0) {
426
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
427
"key auth magic mismatch");
431
decoded.dataptr += strlen(AUTH_MAGIC) + 1;
433
if(_libssh2_get_string(&decoded, &ciphername, &tmp_len) ||
435
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
436
"ciphername is missing");
440
if(_libssh2_get_string(&decoded, &kdfname, &tmp_len) ||
442
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
443
"kdfname is missing");
447
if(_libssh2_get_string(&decoded, &kdf, &kdf_len)) {
448
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
454
kdf_buf.dataptr = kdf;
455
kdf_buf.len = kdf_len;
458
if((!passphrase || strlen((const char *)passphrase) == 0) &&
459
strcmp((const char *)ciphername, "none") != 0) {
461
ret = LIBSSH2_ERROR_KEYFILE_AUTH_FAILED;
465
if(strcmp((const char *)kdfname, "none") != 0 &&
466
strcmp((const char *)kdfname, "bcrypt") != 0) {
467
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
472
if(!strcmp((const char *)kdfname, "none") &&
473
strcmp((const char *)ciphername, "none") != 0) {
474
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
479
if(_libssh2_get_u32(&decoded, &nkeys) != 0 || nkeys != 1) {
480
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
481
"Multiple keys are unsupported");
487
if(_libssh2_get_string(&decoded, &buf, &tmp_len) || tmp_len == 0) {
488
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
489
"Invalid private key; "
490
"expect embedded public key");
494
if(_libssh2_get_string(&decoded, &buf, &tmp_len) || tmp_len == 0) {
495
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
496
"Private key data not found");
501
decrypted.data = decrypted.dataptr = buf;
502
decrypted.len = tmp_len;
504
if(ciphername && strcmp((const char *)ciphername, "none") != 0) {
505
const LIBSSH2_CRYPT_METHOD **all_methods, *cur_method;
507
all_methods = libssh2_crypt_methods();
509
while((cur_method = *all_methods++) != NULL) {
510
if(*cur_method->name &&
511
memcmp(ciphername, cur_method->name,
512
strlen(cur_method->name)) == 0) {
520
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
521
"No supported cipher found");
527
int free_iv = 0, free_secret = 0, len_decrypted = 0;
529
void *abstract = NULL;
531
keylen = method->secret_len;
532
ivlen = method->iv_len;
533
total_len = keylen + ivlen;
535
key = LIBSSH2_CALLOC(session, total_len);
537
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
538
"Could not alloc key");
542
if(strcmp((const char *)kdfname, "bcrypt") == 0 && passphrase) {
543
if((_libssh2_get_string(&kdf_buf, &salt, &salt_len)) ||
544
(_libssh2_get_u32(&kdf_buf, &rounds) != 0)) {
545
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
546
"kdf contains unexpected values");
547
LIBSSH2_FREE(session, key);
551
if(_libssh2_bcrypt_pbkdf((const char *)passphrase,
552
strlen((const char *)passphrase),
554
keylen + ivlen, rounds) < 0) {
555
ret = _libssh2_error(session, LIBSSH2_ERROR_DECRYPT,
557
LIBSSH2_FREE(session, key);
562
ret = _libssh2_error(session, LIBSSH2_ERROR_KEYFILE_AUTH_FAILED,
563
"bcrypted without passphrase");
564
LIBSSH2_FREE(session, key);
569
blocksize = method->blocksize;
571
key_part = LIBSSH2_CALLOC(session, keylen);
573
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
574
"Could not alloc key part");
578
iv_part = LIBSSH2_CALLOC(session, ivlen);
580
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
581
"Could not alloc iv part");
585
memcpy(key_part, key, keylen);
586
memcpy(iv_part, key + keylen, ivlen);
589
if(method->init(session, method, iv_part, &free_iv, key_part,
590
&free_secret, 0, &abstract)) {
591
ret = LIBSSH2_ERROR_DECRYPT;
596
if((decrypted.len % blocksize) != 0) {
597
method->dtor(session, &abstract);
598
ret = LIBSSH2_ERROR_DECRYPT;
602
while((size_t)len_decrypted <= decrypted.len - blocksize) {
610
if(method->crypt(session, decrypted.data + len_decrypted,
614
ret = LIBSSH2_ERROR_DECRYPT;
615
method->dtor(session, &abstract);
619
len_decrypted += blocksize;
626
if(strcmp(method->name, "aes256-gcm@openssh.com") == 0 ||
627
strcmp(method->name, "aes128-gcm@openssh.com") == 0) {
628
if(!_libssh2_check_length(&decoded, 16)) {
629
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
630
"GCM auth tag missing");
631
method->dtor(session, &abstract);
634
if(method->crypt(session, decoded.dataptr, 16, &abstract,
636
ret = _libssh2_error(session, LIBSSH2_ERROR_DECRYPT,
637
"GCM auth tag invalid");
638
method->dtor(session, &abstract);
641
decoded.dataptr += 16;
644
method->dtor(session, &abstract);
649
if(_libssh2_get_u32(&decrypted, &check1) != 0 ||
650
_libssh2_get_u32(&decrypted, &check2) != 0 ||
652
_libssh2_error(session, LIBSSH2_ERROR_PROTO,
653
"Private key unpack failed (correct password?)");
654
ret = LIBSSH2_ERROR_KEYFILE_AUTH_FAILED;
660
struct string_buf *out_buf = _libssh2_string_buf_new(session);
662
ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
663
"Unable to allocate memory for "
668
out_buf->data = LIBSSH2_CALLOC(session, decrypted.len);
670
ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
671
"Unable to allocate memory for "
673
_libssh2_string_buf_free(session, out_buf);
676
memcpy(out_buf->data, decrypted.data, decrypted.len);
677
out_buf->dataptr = out_buf->data +
678
(decrypted.dataptr - decrypted.data);
679
out_buf->len = decrypted.len;
681
*decrypted_buf = out_buf;
688
_libssh2_explicit_zero(key, total_len);
689
LIBSSH2_FREE(session, key);
692
_libssh2_explicit_zero(key_part, keylen);
693
LIBSSH2_FREE(session, key_part);
696
_libssh2_explicit_zero(iv_part, ivlen);
697
LIBSSH2_FREE(session, iv_part);
700
_libssh2_explicit_zero(f, f_len);
701
LIBSSH2_FREE(session, f);
708
_libssh2_openssh_pem_parse(LIBSSH2_SESSION * session,
709
const unsigned char *passphrase,
710
FILE * fp, struct string_buf **decrypted_buf)
712
char line[LINE_SIZE];
713
char *b64data = NULL;
714
size_t b64datalen = 0;
722
if(readline(line, LINE_SIZE, fp)) {
726
while(strcmp(line, OPENSSH_HEADER_BEGIN) != 0);
728
if(readline(line, LINE_SIZE, fp)) {
737
linelen = strlen(line);
738
tmp = LIBSSH2_REALLOC(session, b64data, b64datalen + linelen);
740
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
741
"Unable to allocate memory for PEM parsing");
745
memcpy(tmp + b64datalen, line, linelen);
747
b64datalen += linelen;
752
if(readline(line, LINE_SIZE, fp)) {
756
} while(strcmp(line, OPENSSH_HEADER_END) != 0);
762
ret = _libssh2_openssh_pem_parse_data(session,
764
(const char *)b64data,
769
_libssh2_explicit_zero(b64data, b64datalen);
770
LIBSSH2_FREE(session, b64data);
779
_libssh2_openssh_pem_parse_memory(LIBSSH2_SESSION * session,
780
const unsigned char *passphrase,
781
const char *filedata, size_t filedata_len,
782
struct string_buf **decrypted_buf)
784
char line[LINE_SIZE];
785
char *b64data = NULL;
786
size_t b64datalen = 0;
790
if(!filedata || filedata_len <= 0)
791
return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
792
"Error parsing PEM: filedata missing");
798
if(off >= filedata_len)
799
return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
800
"Error parsing PEM: "
801
"OpenSSH header not found");
803
if(readline_memory(line, LINE_SIZE, filedata, filedata_len, &off)) {
807
while(strcmp(line, OPENSSH_HEADER_BEGIN) != 0);
816
linelen = strlen(line);
817
tmp = LIBSSH2_REALLOC(session, b64data, b64datalen + linelen);
819
ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
820
"Unable to allocate memory for "
824
memcpy(tmp + b64datalen, line, linelen);
826
b64datalen += linelen;
831
if(off >= filedata_len) {
832
ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
833
"Error parsing PEM: offset out of bounds");
837
if(readline_memory(line, LINE_SIZE, filedata, filedata_len, &off)) {
841
} while(strcmp(line, OPENSSH_HEADER_END) != 0);
844
return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
845
"Error parsing PEM: base 64 data missing");
847
ret = _libssh2_openssh_pem_parse_data(session, passphrase, b64data,
848
b64datalen, decrypted_buf);
852
_libssh2_explicit_zero(b64data, b64datalen);
853
LIBSSH2_FREE(session, b64data);
860
read_asn1_length(const unsigned char *data,
861
size_t datalen, size_t *len)
872
lenlen = *len & 0x7F;
874
if(1 + lenlen > datalen) {
886
nextpos = 1 + lenlen;
887
if(lenlen > 2 || 1 + lenlen + *len > datalen) {
895
_libssh2_pem_decode_sequence(unsigned char **data, size_t *datalen)
904
if((*data)[0] != '\x30') {
911
lenlen = read_asn1_length(*data, *datalen, &len);
912
if(lenlen < 0 || lenlen + len != *datalen) {
923
_libssh2_pem_decode_integer(unsigned char **data, size_t *datalen,
924
unsigned char **i, unsigned int *ilen)
933
if((*data)[0] != '\x02') {
940
lenlen = read_asn1_length(*data, *datalen, &len);
941
if(lenlen < 0 || lenlen + len > *datalen) {
949
*ilen = (unsigned int)len;