pem.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902
  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. #include "libssh2_priv.h"
  39. static int
  40. readline(char *line, int line_size, FILE * fp)
  41. {
  42. size_t len;
  43. if(!line) {
  44. return -1;
  45. }
  46. if(!fgets(line, line_size, fp)) {
  47. return -1;
  48. }
  49. if(*line) {
  50. len = strlen(line);
  51. if(len > 0 && line[len - 1] == '\n') {
  52. line[len - 1] = '\0';
  53. }
  54. }
  55. if(*line) {
  56. len = strlen(line);
  57. if(len > 0 && line[len - 1] == '\r') {
  58. line[len - 1] = '\0';
  59. }
  60. }
  61. return 0;
  62. }
  63. static int
  64. readline_memory(char *line, size_t line_size,
  65. const char *filedata, size_t filedata_len,
  66. size_t *filedata_offset)
  67. {
  68. size_t off, len;
  69. off = *filedata_offset;
  70. for(len = 0; off + len < filedata_len && len < line_size - 1; len++) {
  71. if(filedata[off + len] == '\n' ||
  72. filedata[off + len] == '\r') {
  73. break;
  74. }
  75. }
  76. if(len) {
  77. memcpy(line, filedata + off, len);
  78. *filedata_offset += len;
  79. }
  80. line[len] = '\0';
  81. *filedata_offset += 1;
  82. return 0;
  83. }
  84. #define LINE_SIZE 128
  85. static const char *crypt_annotation = "Proc-Type: 4,ENCRYPTED";
  86. static unsigned char hex_decode(char digit)
  87. {
  88. return (digit >= 'A') ? 0xA + (digit - 'A') : (digit - '0');
  89. }
  90. int
  91. _libssh2_pem_parse(LIBSSH2_SESSION * session,
  92. const char *headerbegin,
  93. const char *headerend,
  94. const unsigned char *passphrase,
  95. FILE * fp, unsigned char **data, unsigned int *datalen)
  96. {
  97. char line[LINE_SIZE];
  98. unsigned char iv[LINE_SIZE];
  99. char *b64data = NULL;
  100. unsigned int b64datalen = 0;
  101. int ret;
  102. const LIBSSH2_CRYPT_METHOD *method = NULL;
  103. do {
  104. *line = '\0';
  105. if(readline(line, LINE_SIZE, fp)) {
  106. return -1;
  107. }
  108. }
  109. while(strcmp(line, headerbegin) != 0);
  110. if(readline(line, LINE_SIZE, fp)) {
  111. return -1;
  112. }
  113. if(passphrase &&
  114. memcmp(line, crypt_annotation, strlen(crypt_annotation)) == 0) {
  115. const LIBSSH2_CRYPT_METHOD **all_methods, *cur_method;
  116. int i;
  117. if(readline(line, LINE_SIZE, fp)) {
  118. ret = -1;
  119. goto out;
  120. }
  121. all_methods = libssh2_crypt_methods();
  122. while((cur_method = *all_methods++)) {
  123. if(*cur_method->pem_annotation &&
  124. memcmp(line, cur_method->pem_annotation,
  125. strlen(cur_method->pem_annotation)) == 0) {
  126. method = cur_method;
  127. memcpy(iv, line + strlen(method->pem_annotation) + 1,
  128. 2*method->iv_len);
  129. }
  130. }
  131. /* None of the available crypt methods were able to decrypt the key */
  132. if(method == NULL)
  133. return -1;
  134. /* Decode IV from hex */
  135. for(i = 0; i < method->iv_len; ++i) {
  136. iv[i] = hex_decode(iv[2*i]) << 4;
  137. iv[i] |= hex_decode(iv[2*i + 1]);
  138. }
  139. /* skip to the next line */
  140. if(readline(line, LINE_SIZE, fp)) {
  141. ret = -1;
  142. goto out;
  143. }
  144. }
  145. do {
  146. if(*line) {
  147. char *tmp;
  148. size_t linelen;
  149. linelen = strlen(line);
  150. tmp = LIBSSH2_REALLOC(session, b64data, b64datalen + linelen);
  151. if(!tmp) {
  152. ret = -1;
  153. goto out;
  154. }
  155. memcpy(tmp + b64datalen, line, linelen);
  156. b64data = tmp;
  157. b64datalen += linelen;
  158. }
  159. *line = '\0';
  160. if(readline(line, LINE_SIZE, fp)) {
  161. ret = -1;
  162. goto out;
  163. }
  164. } while(strcmp(line, headerend) != 0);
  165. if(!b64data) {
  166. return -1;
  167. }
  168. if(libssh2_base64_decode(session, (char **) data, datalen,
  169. b64data, b64datalen)) {
  170. ret = -1;
  171. goto out;
  172. }
  173. if(method) {
  174. /* Set up decryption */
  175. int free_iv = 0, free_secret = 0, len_decrypted = 0, padding = 0;
  176. int blocksize = method->blocksize;
  177. void *abstract;
  178. unsigned char secret[2*MD5_DIGEST_LENGTH];
  179. libssh2_md5_ctx fingerprint_ctx;
  180. /* Perform key derivation (PBKDF1/MD5) */
  181. if(!libssh2_md5_init(&fingerprint_ctx)) {
  182. ret = -1;
  183. goto out;
  184. }
  185. libssh2_md5_update(fingerprint_ctx, passphrase,
  186. strlen((char *)passphrase));
  187. libssh2_md5_update(fingerprint_ctx, iv, 8);
  188. libssh2_md5_final(fingerprint_ctx, secret);
  189. if(method->secret_len > MD5_DIGEST_LENGTH) {
  190. if(!libssh2_md5_init(&fingerprint_ctx)) {
  191. ret = -1;
  192. goto out;
  193. }
  194. libssh2_md5_update(fingerprint_ctx, secret, MD5_DIGEST_LENGTH);
  195. libssh2_md5_update(fingerprint_ctx, passphrase,
  196. strlen((char *)passphrase));
  197. libssh2_md5_update(fingerprint_ctx, iv, 8);
  198. libssh2_md5_final(fingerprint_ctx, secret + MD5_DIGEST_LENGTH);
  199. }
  200. /* Initialize the decryption */
  201. if(method->init(session, method, iv, &free_iv, secret,
  202. &free_secret, 0, &abstract)) {
  203. _libssh2_explicit_zero((char *)secret, sizeof(secret));
  204. LIBSSH2_FREE(session, data);
  205. ret = -1;
  206. goto out;
  207. }
  208. if(free_secret) {
  209. _libssh2_explicit_zero((char *)secret, sizeof(secret));
  210. }
  211. /* Do the actual decryption */
  212. if((*datalen % blocksize) != 0) {
  213. _libssh2_explicit_zero((char *)secret, sizeof(secret));
  214. method->dtor(session, &abstract);
  215. _libssh2_explicit_zero(*data, *datalen);
  216. LIBSSH2_FREE(session, *data);
  217. ret = -1;
  218. goto out;
  219. }
  220. while(len_decrypted <= (int)*datalen - blocksize) {
  221. if(method->crypt(session, *data + len_decrypted, blocksize,
  222. &abstract)) {
  223. ret = LIBSSH2_ERROR_DECRYPT;
  224. _libssh2_explicit_zero((char *)secret, sizeof(secret));
  225. method->dtor(session, &abstract);
  226. _libssh2_explicit_zero(*data, *datalen);
  227. LIBSSH2_FREE(session, *data);
  228. goto out;
  229. }
  230. len_decrypted += blocksize;
  231. }
  232. /* Account for padding */
  233. padding = (*data)[*datalen - 1];
  234. memset(&(*data)[*datalen-padding], 0, padding);
  235. *datalen -= padding;
  236. /* Clean up */
  237. _libssh2_explicit_zero((char *)secret, sizeof(secret));
  238. method->dtor(session, &abstract);
  239. }
  240. ret = 0;
  241. out:
  242. if(b64data) {
  243. _libssh2_explicit_zero(b64data, b64datalen);
  244. LIBSSH2_FREE(session, b64data);
  245. }
  246. return ret;
  247. }
  248. int
  249. _libssh2_pem_parse_memory(LIBSSH2_SESSION * session,
  250. const char *headerbegin,
  251. const char *headerend,
  252. const char *filedata, size_t filedata_len,
  253. unsigned char **data, unsigned int *datalen)
  254. {
  255. char line[LINE_SIZE];
  256. char *b64data = NULL;
  257. unsigned int b64datalen = 0;
  258. size_t off = 0;
  259. int ret;
  260. do {
  261. *line = '\0';
  262. if(readline_memory(line, LINE_SIZE, filedata, filedata_len, &off)) {
  263. return -1;
  264. }
  265. }
  266. while(strcmp(line, headerbegin) != 0);
  267. *line = '\0';
  268. do {
  269. if(*line) {
  270. char *tmp;
  271. size_t linelen;
  272. linelen = strlen(line);
  273. tmp = LIBSSH2_REALLOC(session, b64data, b64datalen + linelen);
  274. if(!tmp) {
  275. ret = -1;
  276. goto out;
  277. }
  278. memcpy(tmp + b64datalen, line, linelen);
  279. b64data = tmp;
  280. b64datalen += linelen;
  281. }
  282. *line = '\0';
  283. if(readline_memory(line, LINE_SIZE, filedata, filedata_len, &off)) {
  284. ret = -1;
  285. goto out;
  286. }
  287. } while(strcmp(line, headerend) != 0);
  288. if(!b64data) {
  289. return -1;
  290. }
  291. if(libssh2_base64_decode(session, (char **) data, datalen,
  292. b64data, b64datalen)) {
  293. ret = -1;
  294. goto out;
  295. }
  296. ret = 0;
  297. out:
  298. if(b64data) {
  299. _libssh2_explicit_zero(b64data, b64datalen);
  300. LIBSSH2_FREE(session, b64data);
  301. }
  302. return ret;
  303. }
  304. /* OpenSSH formatted keys */
  305. #define AUTH_MAGIC "openssh-key-v1"
  306. #define OPENSSH_HEADER_BEGIN "-----BEGIN OPENSSH PRIVATE KEY-----"
  307. #define OPENSSH_HEADER_END "-----END OPENSSH PRIVATE KEY-----"
  308. static int
  309. _libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session,
  310. const unsigned char *passphrase,
  311. const char *b64data, size_t b64datalen,
  312. struct string_buf **decrypted_buf)
  313. {
  314. const LIBSSH2_CRYPT_METHOD *method = NULL;
  315. struct string_buf decoded, decrypted, kdf_buf;
  316. unsigned char *ciphername = NULL;
  317. unsigned char *kdfname = NULL;
  318. unsigned char *kdf = NULL;
  319. unsigned char *buf = NULL;
  320. unsigned char *salt = NULL;
  321. uint32_t nkeys, check1, check2;
  322. uint32_t rounds = 0;
  323. unsigned char *key = NULL;
  324. unsigned char *key_part = NULL;
  325. unsigned char *iv_part = NULL;
  326. unsigned char *f = NULL;
  327. unsigned int f_len = 0;
  328. int ret = 0, keylen = 0, ivlen = 0, total_len = 0;
  329. size_t kdf_len = 0, tmp_len = 0, salt_len = 0;
  330. if(decrypted_buf)
  331. *decrypted_buf = NULL;
  332. /* decode file */
  333. if(libssh2_base64_decode(session, (char **)&f, &f_len,
  334. b64data, b64datalen)) {
  335. ret = -1;
  336. goto out;
  337. }
  338. /* Parse the file */
  339. decoded.data = (unsigned char *)f;
  340. decoded.dataptr = (unsigned char *)f;
  341. decoded.len = f_len;
  342. if(decoded.len < strlen(AUTH_MAGIC)) {
  343. ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, "key too short");
  344. goto out;
  345. }
  346. if(strncmp((char *) decoded.dataptr, AUTH_MAGIC,
  347. strlen(AUTH_MAGIC)) != 0) {
  348. ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
  349. "key auth magic mismatch");
  350. goto out;
  351. }
  352. decoded.dataptr += strlen(AUTH_MAGIC) + 1;
  353. if(_libssh2_get_string(&decoded, &ciphername, &tmp_len) ||
  354. tmp_len == 0) {
  355. ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
  356. "ciphername is missing");
  357. goto out;
  358. }
  359. if(_libssh2_get_string(&decoded, &kdfname, &tmp_len) ||
  360. tmp_len == 0) {
  361. ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
  362. "kdfname is missing");
  363. goto out;
  364. }
  365. if(_libssh2_get_string(&decoded, &kdf, &kdf_len)) {
  366. ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
  367. "kdf is missing");
  368. goto out;
  369. }
  370. else {
  371. kdf_buf.data = kdf;
  372. kdf_buf.dataptr = kdf;
  373. kdf_buf.len = kdf_len;
  374. }
  375. if((passphrase == NULL || strlen((const char *)passphrase) == 0) &&
  376. strcmp((const char *)ciphername, "none") != 0) {
  377. /* passphrase required */
  378. ret = LIBSSH2_ERROR_KEYFILE_AUTH_FAILED;
  379. goto out;
  380. }
  381. if(strcmp((const char *)kdfname, "none") != 0 &&
  382. strcmp((const char *)kdfname, "bcrypt") != 0) {
  383. ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
  384. "unknown cipher");
  385. goto out;
  386. }
  387. if(!strcmp((const char *)kdfname, "none") &&
  388. strcmp((const char *)ciphername, "none") != 0) {
  389. ret =_libssh2_error(session, LIBSSH2_ERROR_PROTO,
  390. "invalid format");
  391. goto out;
  392. }
  393. if(_libssh2_get_u32(&decoded, &nkeys) != 0 || nkeys != 1) {
  394. ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
  395. "Multiple keys are unsupported");
  396. goto out;
  397. }
  398. /* unencrypted public key */
  399. if(_libssh2_get_string(&decoded, &buf, &tmp_len) || tmp_len == 0) {
  400. ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
  401. "Invalid private key; "
  402. "expect embedded public key");
  403. goto out;
  404. }
  405. if(_libssh2_get_string(&decoded, &buf, &tmp_len) || tmp_len == 0) {
  406. ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
  407. "Private key data not found");
  408. goto out;
  409. }
  410. /* decode encrypted private key */
  411. decrypted.data = decrypted.dataptr = buf;
  412. decrypted.len = tmp_len;
  413. if(ciphername && strcmp((const char *)ciphername, "none") != 0) {
  414. const LIBSSH2_CRYPT_METHOD **all_methods, *cur_method;
  415. all_methods = libssh2_crypt_methods();
  416. while((cur_method = *all_methods++)) {
  417. if(*cur_method->name &&
  418. memcmp(ciphername, cur_method->name,
  419. strlen(cur_method->name)) == 0) {
  420. method = cur_method;
  421. }
  422. }
  423. /* None of the available crypt methods were able to decrypt the key */
  424. if(method == NULL) {
  425. ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
  426. "No supported cipher found");
  427. goto out;
  428. }
  429. }
  430. if(method) {
  431. int free_iv = 0, free_secret = 0, len_decrypted = 0;
  432. int blocksize;
  433. void *abstract = NULL;
  434. keylen = method->secret_len;
  435. ivlen = method->iv_len;
  436. total_len = keylen + ivlen;
  437. key = LIBSSH2_CALLOC(session, total_len);
  438. if(key == NULL) {
  439. ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
  440. "Could not alloc key");
  441. goto out;
  442. }
  443. if(strcmp((const char *)kdfname, "bcrypt") == 0 &&
  444. passphrase != NULL) {
  445. if((_libssh2_get_string(&kdf_buf, &salt, &salt_len)) ||
  446. (_libssh2_get_u32(&kdf_buf, &rounds) != 0) ) {
  447. ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
  448. "kdf contains unexpected values");
  449. LIBSSH2_FREE(session, key);
  450. goto out;
  451. }
  452. if(_libssh2_bcrypt_pbkdf((const char *)passphrase,
  453. strlen((const char *)passphrase),
  454. salt, salt_len, key,
  455. keylen + ivlen, rounds) < 0) {
  456. ret = _libssh2_error(session, LIBSSH2_ERROR_DECRYPT,
  457. "invalid format");
  458. LIBSSH2_FREE(session, key);
  459. goto out;
  460. }
  461. }
  462. else {
  463. ret = _libssh2_error(session, LIBSSH2_ERROR_KEYFILE_AUTH_FAILED,
  464. "bcrypted without passphrase");
  465. LIBSSH2_FREE(session, key);
  466. goto out;
  467. }
  468. /* Set up decryption */
  469. blocksize = method->blocksize;
  470. key_part = LIBSSH2_CALLOC(session, keylen);
  471. if(key_part == NULL) {
  472. ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
  473. "Could not alloc key part");
  474. goto out;
  475. }
  476. iv_part = LIBSSH2_CALLOC(session, ivlen);
  477. if(iv_part == NULL) {
  478. ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
  479. "Could not alloc iv part");
  480. goto out;
  481. }
  482. memcpy(key_part, key, keylen);
  483. memcpy(iv_part, key + keylen, ivlen);
  484. /* Initialize the decryption */
  485. if(method->init(session, method, iv_part, &free_iv, key_part,
  486. &free_secret, 0, &abstract)) {
  487. ret = LIBSSH2_ERROR_DECRYPT;
  488. goto out;
  489. }
  490. /* Do the actual decryption */
  491. if((decrypted.len % blocksize) != 0) {
  492. method->dtor(session, &abstract);
  493. ret = LIBSSH2_ERROR_DECRYPT;
  494. goto out;
  495. }
  496. while((size_t)len_decrypted <= decrypted.len - blocksize) {
  497. if(method->crypt(session, decrypted.data + len_decrypted,
  498. blocksize,
  499. &abstract)) {
  500. ret = LIBSSH2_ERROR_DECRYPT;
  501. method->dtor(session, &abstract);
  502. goto out;
  503. }
  504. len_decrypted += blocksize;
  505. }
  506. /* No padding */
  507. method->dtor(session, &abstract);
  508. }
  509. /* Check random bytes match */
  510. if(_libssh2_get_u32(&decrypted, &check1) != 0 ||
  511. _libssh2_get_u32(&decrypted, &check2) != 0 ||
  512. check1 != check2) {
  513. _libssh2_error(session, LIBSSH2_ERROR_PROTO,
  514. "Private key unpack failed (correct password?)");
  515. ret = LIBSSH2_ERROR_KEYFILE_AUTH_FAILED;
  516. goto out;
  517. }
  518. if(decrypted_buf != NULL) {
  519. /* copy data to out-going buffer */
  520. struct string_buf *out_buf = _libssh2_string_buf_new(session);
  521. if(!out_buf) {
  522. ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
  523. "Unable to allocate memory for "
  524. "decrypted struct");
  525. goto out;
  526. }
  527. out_buf->data = LIBSSH2_CALLOC(session, decrypted.len);
  528. if(out_buf->data == NULL) {
  529. ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
  530. "Unable to allocate memory for "
  531. "decrypted struct");
  532. _libssh2_string_buf_free(session, out_buf);
  533. goto out;
  534. }
  535. memcpy(out_buf->data, decrypted.data, decrypted.len);
  536. out_buf->dataptr = out_buf->data +
  537. (decrypted.dataptr - decrypted.data);
  538. out_buf->len = decrypted.len;
  539. *decrypted_buf = out_buf;
  540. }
  541. out:
  542. /* Clean up */
  543. if(key) {
  544. _libssh2_explicit_zero(key, total_len);
  545. LIBSSH2_FREE(session, key);
  546. }
  547. if(key_part) {
  548. _libssh2_explicit_zero(key_part, keylen);
  549. LIBSSH2_FREE(session, key_part);
  550. }
  551. if(iv_part) {
  552. _libssh2_explicit_zero(iv_part, ivlen);
  553. LIBSSH2_FREE(session, iv_part);
  554. }
  555. if(f) {
  556. _libssh2_explicit_zero(f, f_len);
  557. LIBSSH2_FREE(session, f);
  558. }
  559. return ret;
  560. }
  561. int
  562. _libssh2_openssh_pem_parse(LIBSSH2_SESSION * session,
  563. const unsigned char *passphrase,
  564. FILE * fp, struct string_buf **decrypted_buf)
  565. {
  566. char line[LINE_SIZE];
  567. char *b64data = NULL;
  568. unsigned int b64datalen = 0;
  569. int ret = 0;
  570. /* read file */
  571. do {
  572. *line = '\0';
  573. if(readline(line, LINE_SIZE, fp)) {
  574. return -1;
  575. }
  576. }
  577. while(strcmp(line, OPENSSH_HEADER_BEGIN) != 0);
  578. if(readline(line, LINE_SIZE, fp)) {
  579. return -1;
  580. }
  581. do {
  582. if(*line) {
  583. char *tmp;
  584. size_t linelen;
  585. linelen = strlen(line);
  586. tmp = LIBSSH2_REALLOC(session, b64data, b64datalen + linelen);
  587. if(!tmp) {
  588. ret = -1;
  589. goto out;
  590. }
  591. memcpy(tmp + b64datalen, line, linelen);
  592. b64data = tmp;
  593. b64datalen += linelen;
  594. }
  595. *line = '\0';
  596. if(readline(line, LINE_SIZE, fp)) {
  597. ret = -1;
  598. goto out;
  599. }
  600. } while(strcmp(line, OPENSSH_HEADER_END) != 0);
  601. if(!b64data) {
  602. return -1;
  603. }
  604. ret = _libssh2_openssh_pem_parse_data(session,
  605. passphrase,
  606. (const char *)b64data,
  607. (size_t)b64datalen,
  608. decrypted_buf);
  609. if(b64data) {
  610. _libssh2_explicit_zero(b64data, b64datalen);
  611. LIBSSH2_FREE(session, b64data);
  612. }
  613. out:
  614. return ret;
  615. }
  616. int
  617. _libssh2_openssh_pem_parse_memory(LIBSSH2_SESSION * session,
  618. const unsigned char *passphrase,
  619. const char *filedata, size_t filedata_len,
  620. struct string_buf **decrypted_buf)
  621. {
  622. char line[LINE_SIZE];
  623. char *b64data = NULL;
  624. unsigned int b64datalen = 0;
  625. size_t off = 0;
  626. int ret;
  627. if(filedata == NULL || filedata_len <= 0) {
  628. return -1;
  629. }
  630. do {
  631. *line = '\0';
  632. if(off >= filedata_len) {
  633. return -1;
  634. }
  635. if(readline_memory(line, LINE_SIZE, filedata, filedata_len, &off)) {
  636. return -1;
  637. }
  638. }
  639. while(strcmp(line, OPENSSH_HEADER_BEGIN) != 0);
  640. *line = '\0';
  641. do {
  642. if (*line) {
  643. char *tmp;
  644. size_t linelen;
  645. linelen = strlen(line);
  646. tmp = LIBSSH2_REALLOC(session, b64data, b64datalen + linelen);
  647. if(!tmp) {
  648. ret = -1;
  649. goto out;
  650. }
  651. memcpy(tmp + b64datalen, line, linelen);
  652. b64data = tmp;
  653. b64datalen += linelen;
  654. }
  655. *line = '\0';
  656. if(off >= filedata_len) {
  657. ret = -1;
  658. goto out;
  659. }
  660. if(readline_memory(line, LINE_SIZE, filedata, filedata_len, &off)) {
  661. ret = -1;
  662. goto out;
  663. }
  664. } while(strcmp(line, OPENSSH_HEADER_END) != 0);
  665. if(!b64data) {
  666. return -1;
  667. }
  668. ret = _libssh2_openssh_pem_parse_data(session, passphrase, b64data,
  669. b64datalen, decrypted_buf);
  670. out:
  671. if(b64data) {
  672. _libssh2_explicit_zero(b64data, b64datalen);
  673. LIBSSH2_FREE(session, b64data);
  674. }
  675. return ret;
  676. }
  677. static int
  678. read_asn1_length(const unsigned char *data,
  679. unsigned int datalen, unsigned int *len)
  680. {
  681. unsigned int lenlen;
  682. int nextpos;
  683. if(datalen < 1) {
  684. return -1;
  685. }
  686. *len = data[0];
  687. if(*len >= 0x80) {
  688. lenlen = *len & 0x7F;
  689. *len = data[1];
  690. if(1 + lenlen > datalen) {
  691. return -1;
  692. }
  693. if(lenlen > 1) {
  694. *len <<= 8;
  695. *len |= data[2];
  696. }
  697. }
  698. else {
  699. lenlen = 0;
  700. }
  701. nextpos = 1 + lenlen;
  702. if(lenlen > 2 || 1 + lenlen + *len > datalen) {
  703. return -1;
  704. }
  705. return nextpos;
  706. }
  707. int
  708. _libssh2_pem_decode_sequence(unsigned char **data, unsigned int *datalen)
  709. {
  710. unsigned int len;
  711. int lenlen;
  712. if(*datalen < 1) {
  713. return -1;
  714. }
  715. if((*data)[0] != '\x30') {
  716. return -1;
  717. }
  718. (*data)++;
  719. (*datalen)--;
  720. lenlen = read_asn1_length(*data, *datalen, &len);
  721. if(lenlen < 0 || lenlen + len != *datalen) {
  722. return -1;
  723. }
  724. *data += lenlen;
  725. *datalen -= lenlen;
  726. return 0;
  727. }
  728. int
  729. _libssh2_pem_decode_integer(unsigned char **data, unsigned int *datalen,
  730. unsigned char **i, unsigned int *ilen)
  731. {
  732. unsigned int len;
  733. int lenlen;
  734. if(*datalen < 1) {
  735. return -1;
  736. }
  737. if((*data)[0] != '\x02') {
  738. return -1;
  739. }
  740. (*data)++;
  741. (*datalen)--;
  742. lenlen = read_asn1_length(*data, *datalen, &len);
  743. if(lenlen < 0 || lenlen + len > *datalen) {
  744. return -1;
  745. }
  746. *data += lenlen;
  747. *datalen -= lenlen;
  748. *i = *data;
  749. *ilen = len;
  750. *data += len;
  751. *datalen -= len;
  752. return 0;
  753. }