1 /* Copyright (C) 2007 The Written Word, Inc.
2 * Copyright (C) 2008, Simon Josefsson
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms,
6 * with or without modification, are permitted provided
7 * that the following conditions are met:
8 *
9 * Redistributions of source code must retain the above
10 * copyright notice, this list of conditions and the
11 * following disclaimer.
12 *
13 * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials
16 * provided with the distribution.
17 *
18 * Neither the name of the copyright holder nor the names
19 * of any other contributors may be used to endorse or
20 * promote products derived from this software without
21 * specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
24 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
25 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
28 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
33 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
35 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
36 * OF SUCH DAMAGE.
37 */
38
39 #include "libssh2_priv.h"
40
41 static int
readline(char * line,int line_size,FILE * fp)42 readline(char *line, int line_size, FILE * fp)
43 {
44 size_t len;
45
46 if(!line) {
47 return -1;
48 }
49 if(!fgets(line, line_size, fp)) {
50 return -1;
51 }
52
53 if(*line) {
54 len = strlen(line);
55 if(len > 0 && line[len - 1] == '\n') {
56 line[len - 1] = '\0';
57 }
58 }
59
60 if(*line) {
61 len = strlen(line);
62 if(len > 0 && line[len - 1] == '\r') {
63 line[len - 1] = '\0';
64 }
65 }
66
67 return 0;
68 }
69
70 static int
readline_memory(char * line,size_t line_size,const char * filedata,size_t filedata_len,size_t * filedata_offset)71 readline_memory(char *line, size_t line_size,
72 const char *filedata, size_t filedata_len,
73 size_t *filedata_offset)
74 {
75 size_t off, len;
76
77 off = *filedata_offset;
78
79 for(len = 0; off + len < filedata_len && len < line_size - 1; len++) {
80 if(filedata[off + len] == '\n' ||
81 filedata[off + len] == '\r') {
82 break;
83 }
84 }
85
86 if(len) {
87 memcpy(line, filedata + off, len);
88 *filedata_offset += len;
89 }
90
91 line[len] = '\0';
92 *filedata_offset += 1;
93
94 return 0;
95 }
96
97 #define LINE_SIZE 128
98
99 static const char *crypt_annotation = "Proc-Type: 4,ENCRYPTED";
100
hex_decode(char digit)101 static unsigned char hex_decode(char digit)
102 {
103 return (digit >= 'A') ? 0xA + (digit - 'A') : (digit - '0');
104 }
105
106 int
_libssh2_pem_parse(LIBSSH2_SESSION * session,const char * headerbegin,const char * headerend,const unsigned char * passphrase,FILE * fp,unsigned char ** data,unsigned int * datalen)107 _libssh2_pem_parse(LIBSSH2_SESSION * session,
108 const char *headerbegin,
109 const char *headerend,
110 const unsigned char *passphrase,
111 FILE * fp, unsigned char **data, unsigned int *datalen)
112 {
113 char line[LINE_SIZE];
114 unsigned char iv[LINE_SIZE];
115 char *b64data = NULL;
116 unsigned int b64datalen = 0;
117 int ret;
118 const LIBSSH2_CRYPT_METHOD *method = NULL;
119
120 do {
121 *line = '\0';
122
123 if(readline(line, LINE_SIZE, fp)) {
124 return -1;
125 }
126 }
127 while(strcmp(line, headerbegin) != 0);
128
129 if(readline(line, LINE_SIZE, fp)) {
130 return -1;
131 }
132
133 if(passphrase &&
134 memcmp(line, crypt_annotation, strlen(crypt_annotation)) == 0) {
135 const LIBSSH2_CRYPT_METHOD **all_methods, *cur_method;
136 int i;
137
138 if(readline(line, LINE_SIZE, fp)) {
139 ret = -1;
140 goto out;
141 }
142
143 all_methods = libssh2_crypt_methods();
144 while((cur_method = *all_methods++)) {
145 if(*cur_method->pem_annotation &&
146 memcmp(line, cur_method->pem_annotation,
147 strlen(cur_method->pem_annotation)) == 0) {
148 method = cur_method;
149 memcpy(iv, line + strlen(method->pem_annotation) + 1,
150 2*method->iv_len);
151 }
152 }
153
154 /* None of the available crypt methods were able to decrypt the key */
155 if(method == NULL)
156 return -1;
157
158 /* Decode IV from hex */
159 for(i = 0; i < method->iv_len; ++i) {
160 iv[i] = hex_decode(iv[2*i]) << 4;
161 iv[i] |= hex_decode(iv[2*i + 1]);
162 }
163
164 /* skip to the next line */
165 if(readline(line, LINE_SIZE, fp)) {
166 ret = -1;
167 goto out;
168 }
169 }
170
171 do {
172 if(*line) {
173 char *tmp;
174 size_t linelen;
175
176 linelen = strlen(line);
177 tmp = LIBSSH2_REALLOC(session, b64data, b64datalen + linelen);
178 if(!tmp) {
179 ret = -1;
180 goto out;
181 }
182 memcpy(tmp + b64datalen, line, linelen);
183 b64data = tmp;
184 b64datalen += linelen;
185 }
186
187 *line = '\0';
188
189 if(readline(line, LINE_SIZE, fp)) {
190 ret = -1;
191 goto out;
192 }
193 } while(strcmp(line, headerend) != 0);
194
195 if(!b64data) {
196 return -1;
197 }
198
199 if(libssh2_base64_decode(session, (char **) data, datalen,
200 b64data, b64datalen)) {
201 ret = -1;
202 goto out;
203 }
204
205 if(method) {
206 /* Set up decryption */
207 int free_iv = 0, free_secret = 0, len_decrypted = 0, padding = 0;
208 int blocksize = method->blocksize;
209 void *abstract;
210 unsigned char secret[2*MD5_DIGEST_LENGTH];
211 libssh2_md5_ctx fingerprint_ctx;
212
213 /* Perform key derivation (PBKDF1/MD5) */
214 if(!libssh2_md5_init(&fingerprint_ctx)) {
215 ret = -1;
216 goto out;
217 }
218 libssh2_md5_update(fingerprint_ctx, passphrase,
219 strlen((char *)passphrase));
220 libssh2_md5_update(fingerprint_ctx, iv, 8);
221 libssh2_md5_final(fingerprint_ctx, secret);
222 if(method->secret_len > MD5_DIGEST_LENGTH) {
223 if(!libssh2_md5_init(&fingerprint_ctx)) {
224 ret = -1;
225 goto out;
226 }
227 libssh2_md5_update(fingerprint_ctx, secret, MD5_DIGEST_LENGTH);
228 libssh2_md5_update(fingerprint_ctx, passphrase,
229 strlen((char *)passphrase));
230 libssh2_md5_update(fingerprint_ctx, iv, 8);
231 libssh2_md5_final(fingerprint_ctx, secret + MD5_DIGEST_LENGTH);
232 }
233
234 /* Initialize the decryption */
235 if(method->init(session, method, iv, &free_iv, secret,
236 &free_secret, 0, &abstract)) {
237 _libssh2_explicit_zero((char *)secret, sizeof(secret));
238 LIBSSH2_FREE(session, data);
239 ret = -1;
240 goto out;
241 }
242
243 if(free_secret) {
244 _libssh2_explicit_zero((char *)secret, sizeof(secret));
245 }
246
247 /* Do the actual decryption */
248 if((*datalen % blocksize) != 0) {
249 _libssh2_explicit_zero((char *)secret, sizeof(secret));
250 method->dtor(session, &abstract);
251 _libssh2_explicit_zero(*data, *datalen);
252 LIBSSH2_FREE(session, *data);
253 ret = -1;
254 goto out;
255 }
256
257 while(len_decrypted <= (int)*datalen - blocksize) {
258 if(method->crypt(session, *data + len_decrypted, blocksize,
259 &abstract)) {
260 ret = LIBSSH2_ERROR_DECRYPT;
261 _libssh2_explicit_zero((char *)secret, sizeof(secret));
262 method->dtor(session, &abstract);
263 _libssh2_explicit_zero(*data, *datalen);
264 LIBSSH2_FREE(session, *data);
265 goto out;
266 }
267
268 len_decrypted += blocksize;
269 }
270
271 /* Account for padding */
272 padding = (*data)[*datalen - 1];
273 memset(&(*data)[*datalen-padding], 0, padding);
274 *datalen -= padding;
275
276 /* Clean up */
277 _libssh2_explicit_zero((char *)secret, sizeof(secret));
278 method->dtor(session, &abstract);
279 }
280
281 ret = 0;
282 out:
283 if(b64data) {
284 _libssh2_explicit_zero(b64data, b64datalen);
285 LIBSSH2_FREE(session, b64data);
286 }
287 return ret;
288 }
289
290 int
_libssh2_pem_parse_memory(LIBSSH2_SESSION * session,const char * headerbegin,const char * headerend,const char * filedata,size_t filedata_len,unsigned char ** data,unsigned int * datalen)291 _libssh2_pem_parse_memory(LIBSSH2_SESSION * session,
292 const char *headerbegin,
293 const char *headerend,
294 const char *filedata, size_t filedata_len,
295 unsigned char **data, unsigned int *datalen)
296 {
297 char line[LINE_SIZE];
298 char *b64data = NULL;
299 unsigned int b64datalen = 0;
300 size_t off = 0;
301 int ret;
302
303 do {
304 *line = '\0';
305
306 if(readline_memory(line, LINE_SIZE, filedata, filedata_len, &off)) {
307 return -1;
308 }
309 }
310 while(strcmp(line, headerbegin) != 0);
311
312 *line = '\0';
313
314 do {
315 if(*line) {
316 char *tmp;
317 size_t linelen;
318
319 linelen = strlen(line);
320 tmp = LIBSSH2_REALLOC(session, b64data, b64datalen + linelen);
321 if(!tmp) {
322 ret = -1;
323 goto out;
324 }
325 memcpy(tmp + b64datalen, line, linelen);
326 b64data = tmp;
327 b64datalen += linelen;
328 }
329
330 *line = '\0';
331
332 if(readline_memory(line, LINE_SIZE, filedata, filedata_len, &off)) {
333 ret = -1;
334 goto out;
335 }
336 } while(strcmp(line, headerend) != 0);
337
338 if(!b64data) {
339 return -1;
340 }
341
342 if(libssh2_base64_decode(session, (char **) data, datalen,
343 b64data, b64datalen)) {
344 ret = -1;
345 goto out;
346 }
347
348 ret = 0;
349 out:
350 if(b64data) {
351 _libssh2_explicit_zero(b64data, b64datalen);
352 LIBSSH2_FREE(session, b64data);
353 }
354 return ret;
355 }
356
357 /* OpenSSH formatted keys */
358 #define AUTH_MAGIC "openssh-key-v1"
359 #define OPENSSH_HEADER_BEGIN "-----BEGIN OPENSSH PRIVATE KEY-----"
360 #define OPENSSH_HEADER_END "-----END OPENSSH PRIVATE KEY-----"
361
362 static int
_libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session,const unsigned char * passphrase,const char * b64data,size_t b64datalen,struct string_buf ** decrypted_buf)363 _libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session,
364 const unsigned char *passphrase,
365 const char *b64data, size_t b64datalen,
366 struct string_buf **decrypted_buf)
367 {
368 const LIBSSH2_CRYPT_METHOD *method = NULL;
369 struct string_buf decoded, decrypted, kdf_buf;
370 unsigned char *ciphername = NULL;
371 unsigned char *kdfname = NULL;
372 unsigned char *kdf = NULL;
373 unsigned char *buf = NULL;
374 unsigned char *salt = NULL;
375 uint32_t nkeys, check1, check2;
376 uint32_t rounds = 0;
377 unsigned char *key = NULL;
378 unsigned char *key_part = NULL;
379 unsigned char *iv_part = NULL;
380 unsigned char *f = NULL;
381 unsigned int f_len = 0;
382 int ret = 0, keylen = 0, ivlen = 0, total_len = 0;
383 size_t kdf_len = 0, tmp_len = 0, salt_len = 0;
384
385 if(decrypted_buf)
386 *decrypted_buf = NULL;
387
388 /* decode file */
389 if(libssh2_base64_decode(session, (char **)&f, &f_len,
390 b64data, b64datalen)) {
391 ret = -1;
392 goto out;
393 }
394
395 /* Parse the file */
396 decoded.data = (unsigned char *)f;
397 decoded.dataptr = (unsigned char *)f;
398 decoded.len = f_len;
399
400 if(decoded.len < strlen(AUTH_MAGIC)) {
401 ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, "key too short");
402 goto out;
403 }
404
405 if(strncmp((char *) decoded.dataptr, AUTH_MAGIC,
406 strlen(AUTH_MAGIC)) != 0) {
407 ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
408 "key auth magic mismatch");
409 goto out;
410 }
411
412 decoded.dataptr += strlen(AUTH_MAGIC) + 1;
413
414 if(_libssh2_get_string(&decoded, &ciphername, &tmp_len) ||
415 tmp_len == 0) {
416 ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
417 "ciphername is missing");
418 goto out;
419 }
420
421 if(_libssh2_get_string(&decoded, &kdfname, &tmp_len) ||
422 tmp_len == 0) {
423 ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
424 "kdfname is missing");
425 goto out;
426 }
427
428 if(_libssh2_get_string(&decoded, &kdf, &kdf_len)) {
429 ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
430 "kdf is missing");
431 goto out;
432 }
433 else {
434 kdf_buf.data = kdf;
435 kdf_buf.dataptr = kdf;
436 kdf_buf.len = kdf_len;
437 }
438
439 if((passphrase == NULL || strlen((const char *)passphrase) == 0) &&
440 strcmp((const char *)ciphername, "none") != 0) {
441 /* passphrase required */
442 ret = LIBSSH2_ERROR_KEYFILE_AUTH_FAILED;
443 goto out;
444 }
445
446 if(strcmp((const char *)kdfname, "none") != 0 &&
447 strcmp((const char *)kdfname, "bcrypt") != 0) {
448 ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
449 "unknown cipher");
450 goto out;
451 }
452
453 if(!strcmp((const char *)kdfname, "none") &&
454 strcmp((const char *)ciphername, "none") != 0) {
455 ret =_libssh2_error(session, LIBSSH2_ERROR_PROTO,
456 "invalid format");
457 goto out;
458 }
459
460 if(_libssh2_get_u32(&decoded, &nkeys) != 0 || nkeys != 1) {
461 ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
462 "Multiple keys are unsupported");
463 goto out;
464 }
465
466 /* unencrypted public key */
467
468 if(_libssh2_get_string(&decoded, &buf, &tmp_len) || tmp_len == 0) {
469 ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
470 "Invalid private key; "
471 "expect embedded public key");
472 goto out;
473 }
474
475 if(_libssh2_get_string(&decoded, &buf, &tmp_len) || tmp_len == 0) {
476 ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
477 "Private key data not found");
478 goto out;
479 }
480
481 /* decode encrypted private key */
482 decrypted.data = decrypted.dataptr = buf;
483 decrypted.len = tmp_len;
484
485 if(ciphername && strcmp((const char *)ciphername, "none") != 0) {
486 const LIBSSH2_CRYPT_METHOD **all_methods, *cur_method;
487
488 all_methods = libssh2_crypt_methods();
489 while((cur_method = *all_methods++)) {
490 if(*cur_method->name &&
491 memcmp(ciphername, cur_method->name,
492 strlen(cur_method->name)) == 0) {
493 method = cur_method;
494 }
495 }
496
497 /* None of the available crypt methods were able to decrypt the key */
498
499 if(method == NULL) {
500 ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
501 "No supported cipher found");
502 goto out;
503 }
504 }
505
506 if(method) {
507 int free_iv = 0, free_secret = 0, len_decrypted = 0;
508 int blocksize;
509 void *abstract = NULL;
510
511 keylen = method->secret_len;
512 ivlen = method->iv_len;
513 total_len = keylen + ivlen;
514
515 key = LIBSSH2_CALLOC(session, total_len);
516 if(key == NULL) {
517 ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
518 "Could not alloc key");
519 goto out;
520 }
521
522 if(strcmp((const char *)kdfname, "bcrypt") == 0 &&
523 passphrase != NULL) {
524 if((_libssh2_get_string(&kdf_buf, &salt, &salt_len)) ||
525 (_libssh2_get_u32(&kdf_buf, &rounds) != 0) ) {
526 ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
527 "kdf contains unexpected values");
528 LIBSSH2_FREE(session, key);
529 goto out;
530 }
531
532 if(_libssh2_bcrypt_pbkdf((const char *)passphrase,
533 strlen((const char *)passphrase),
534 salt, salt_len, key,
535 keylen + ivlen, rounds) < 0) {
536 ret = _libssh2_error(session, LIBSSH2_ERROR_DECRYPT,
537 "invalid format");
538 LIBSSH2_FREE(session, key);
539 goto out;
540 }
541 }
542 else {
543 ret = _libssh2_error(session, LIBSSH2_ERROR_KEYFILE_AUTH_FAILED,
544 "bcrypted without passphrase");
545 LIBSSH2_FREE(session, key);
546 goto out;
547 }
548
549 /* Set up decryption */
550 blocksize = method->blocksize;
551
552 key_part = LIBSSH2_CALLOC(session, keylen);
553 if(key_part == NULL) {
554 ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
555 "Could not alloc key part");
556 goto out;
557 }
558
559 iv_part = LIBSSH2_CALLOC(session, ivlen);
560 if(iv_part == NULL) {
561 ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
562 "Could not alloc iv part");
563 goto out;
564 }
565
566 memcpy(key_part, key, keylen);
567 memcpy(iv_part, key + keylen, ivlen);
568
569 /* Initialize the decryption */
570 if(method->init(session, method, iv_part, &free_iv, key_part,
571 &free_secret, 0, &abstract)) {
572 ret = LIBSSH2_ERROR_DECRYPT;
573 goto out;
574 }
575
576 /* Do the actual decryption */
577 if((decrypted.len % blocksize) != 0) {
578 method->dtor(session, &abstract);
579 ret = LIBSSH2_ERROR_DECRYPT;
580 goto out;
581 }
582
583 while((size_t)len_decrypted <= decrypted.len - blocksize) {
584 if(method->crypt(session, decrypted.data + len_decrypted,
585 blocksize,
586 &abstract)) {
587 ret = LIBSSH2_ERROR_DECRYPT;
588 method->dtor(session, &abstract);
589 goto out;
590 }
591
592 len_decrypted += blocksize;
593 }
594
595 /* No padding */
596
597 method->dtor(session, &abstract);
598 }
599
600 /* Check random bytes match */
601
602 if(_libssh2_get_u32(&decrypted, &check1) != 0 ||
603 _libssh2_get_u32(&decrypted, &check2) != 0 ||
604 check1 != check2) {
605 _libssh2_error(session, LIBSSH2_ERROR_PROTO,
606 "Private key unpack failed (correct password?)");
607 ret = LIBSSH2_ERROR_KEYFILE_AUTH_FAILED;
608 goto out;
609 }
610
611 if(decrypted_buf != NULL) {
612 /* copy data to out-going buffer */
613 struct string_buf *out_buf = _libssh2_string_buf_new(session);
614 if(!out_buf) {
615 ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
616 "Unable to allocate memory for "
617 "decrypted struct");
618 goto out;
619 }
620
621 out_buf->data = LIBSSH2_CALLOC(session, decrypted.len);
622 if(out_buf->data == NULL) {
623 ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
624 "Unable to allocate memory for "
625 "decrypted struct");
626 _libssh2_string_buf_free(session, out_buf);
627 goto out;
628 }
629 memcpy(out_buf->data, decrypted.data, decrypted.len);
630 out_buf->dataptr = out_buf->data +
631 (decrypted.dataptr - decrypted.data);
632 out_buf->len = decrypted.len;
633
634 *decrypted_buf = out_buf;
635 }
636
637 out:
638
639 /* Clean up */
640 if(key) {
641 _libssh2_explicit_zero(key, total_len);
642 LIBSSH2_FREE(session, key);
643 }
644 if(key_part) {
645 _libssh2_explicit_zero(key_part, keylen);
646 LIBSSH2_FREE(session, key_part);
647 }
648 if(iv_part) {
649 _libssh2_explicit_zero(iv_part, ivlen);
650 LIBSSH2_FREE(session, iv_part);
651 }
652 if(f) {
653 _libssh2_explicit_zero(f, f_len);
654 LIBSSH2_FREE(session, f);
655 }
656
657 return ret;
658 }
659
660 int
_libssh2_openssh_pem_parse(LIBSSH2_SESSION * session,const unsigned char * passphrase,FILE * fp,struct string_buf ** decrypted_buf)661 _libssh2_openssh_pem_parse(LIBSSH2_SESSION * session,
662 const unsigned char *passphrase,
663 FILE * fp, struct string_buf **decrypted_buf)
664 {
665 char line[LINE_SIZE];
666 char *b64data = NULL;
667 unsigned int b64datalen = 0;
668 int ret = 0;
669
670 /* read file */
671
672 do {
673 *line = '\0';
674
675 if(readline(line, LINE_SIZE, fp)) {
676 return -1;
677 }
678 }
679 while(strcmp(line, OPENSSH_HEADER_BEGIN) != 0);
680
681 if(readline(line, LINE_SIZE, fp)) {
682 return -1;
683 }
684
685 do {
686 if(*line) {
687 char *tmp;
688 size_t linelen;
689
690 linelen = strlen(line);
691 tmp = LIBSSH2_REALLOC(session, b64data, b64datalen + linelen);
692 if(!tmp) {
693 ret = -1;
694 goto out;
695 }
696 memcpy(tmp + b64datalen, line, linelen);
697 b64data = tmp;
698 b64datalen += linelen;
699 }
700
701 *line = '\0';
702
703 if(readline(line, LINE_SIZE, fp)) {
704 ret = -1;
705 goto out;
706 }
707 } while(strcmp(line, OPENSSH_HEADER_END) != 0);
708
709 if(!b64data) {
710 return -1;
711 }
712
713 ret = _libssh2_openssh_pem_parse_data(session,
714 passphrase,
715 (const char *)b64data,
716 (size_t)b64datalen,
717 decrypted_buf);
718
719 if(b64data) {
720 _libssh2_explicit_zero(b64data, b64datalen);
721 LIBSSH2_FREE(session, b64data);
722 }
723
724 out:
725
726 return ret;
727 }
728
729 int
_libssh2_openssh_pem_parse_memory(LIBSSH2_SESSION * session,const unsigned char * passphrase,const char * filedata,size_t filedata_len,struct string_buf ** decrypted_buf)730 _libssh2_openssh_pem_parse_memory(LIBSSH2_SESSION * session,
731 const unsigned char *passphrase,
732 const char *filedata, size_t filedata_len,
733 struct string_buf **decrypted_buf)
734 {
735 char line[LINE_SIZE];
736 char *b64data = NULL;
737 unsigned int b64datalen = 0;
738 size_t off = 0;
739 int ret;
740
741 if(filedata == NULL || filedata_len <= 0) {
742 return -1;
743 }
744
745 do {
746
747 *line = '\0';
748
749 if(off >= filedata_len) {
750 return -1;
751 }
752
753 if(readline_memory(line, LINE_SIZE, filedata, filedata_len, &off)) {
754 return -1;
755 }
756 }
757 while(strcmp(line, OPENSSH_HEADER_BEGIN) != 0);
758
759 *line = '\0';
760
761 do {
762 if (*line) {
763 char *tmp;
764 size_t linelen;
765
766 linelen = strlen(line);
767 tmp = LIBSSH2_REALLOC(session, b64data, b64datalen + linelen);
768 if(!tmp) {
769 ret = -1;
770 goto out;
771 }
772 memcpy(tmp + b64datalen, line, linelen);
773 b64data = tmp;
774 b64datalen += linelen;
775 }
776
777 *line = '\0';
778
779 if(off >= filedata_len) {
780 ret = -1;
781 goto out;
782 }
783
784 if(readline_memory(line, LINE_SIZE, filedata, filedata_len, &off)) {
785 ret = -1;
786 goto out;
787 }
788 } while(strcmp(line, OPENSSH_HEADER_END) != 0);
789
790 if(!b64data) {
791 return -1;
792 }
793
794 ret = _libssh2_openssh_pem_parse_data(session, passphrase, b64data,
795 b64datalen, decrypted_buf);
796
797 out:
798 if(b64data) {
799 _libssh2_explicit_zero(b64data, b64datalen);
800 LIBSSH2_FREE(session, b64data);
801 }
802 return ret;
803
804 }
805
806 static int
read_asn1_length(const unsigned char * data,unsigned int datalen,unsigned int * len)807 read_asn1_length(const unsigned char *data,
808 unsigned int datalen, unsigned int *len)
809 {
810 unsigned int lenlen;
811 int nextpos;
812
813 if(datalen < 1) {
814 return -1;
815 }
816 *len = data[0];
817
818 if(*len >= 0x80) {
819 lenlen = *len & 0x7F;
820 *len = data[1];
821 if(1 + lenlen > datalen) {
822 return -1;
823 }
824 if(lenlen > 1) {
825 *len <<= 8;
826 *len |= data[2];
827 }
828 }
829 else {
830 lenlen = 0;
831 }
832
833 nextpos = 1 + lenlen;
834 if(lenlen > 2 || 1 + lenlen + *len > datalen) {
835 return -1;
836 }
837
838 return nextpos;
839 }
840
841 int
_libssh2_pem_decode_sequence(unsigned char ** data,unsigned int * datalen)842 _libssh2_pem_decode_sequence(unsigned char **data, unsigned int *datalen)
843 {
844 unsigned int len;
845 int lenlen;
846
847 if(*datalen < 1) {
848 return -1;
849 }
850
851 if((*data)[0] != '\x30') {
852 return -1;
853 }
854
855 (*data)++;
856 (*datalen)--;
857
858 lenlen = read_asn1_length(*data, *datalen, &len);
859 if(lenlen < 0 || lenlen + len != *datalen) {
860 return -1;
861 }
862
863 *data += lenlen;
864 *datalen -= lenlen;
865
866 return 0;
867 }
868
869 int
_libssh2_pem_decode_integer(unsigned char ** data,unsigned int * datalen,unsigned char ** i,unsigned int * ilen)870 _libssh2_pem_decode_integer(unsigned char **data, unsigned int *datalen,
871 unsigned char **i, unsigned int *ilen)
872 {
873 unsigned int len;
874 int lenlen;
875
876 if(*datalen < 1) {
877 return -1;
878 }
879
880 if((*data)[0] != '\x02') {
881 return -1;
882 }
883
884 (*data)++;
885 (*datalen)--;
886
887 lenlen = read_asn1_length(*data, *datalen, &len);
888 if(lenlen < 0 || lenlen + len > *datalen) {
889 return -1;
890 }
891
892 *data += lenlen;
893 *datalen -= lenlen;
894
895 *i = *data;
896 *ilen = len;
897
898 *data += len;
899 *datalen -= len;
900
901 return 0;
902 }
903