sshpubk.c 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192
  1. /*
  2. * Generic SSH public-key handling operations. In particular,
  3. * reading of SSH public-key files, and also the generic `sign'
  4. * operation for SSH-2 (which checks the type of the key and
  5. * dispatches to the appropriate key-type specific function).
  6. */
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <assert.h>
  10. #include "putty.h"
  11. #include "ssh.h"
  12. #include "misc.h"
  13. #define rsa_signature "SSH PRIVATE KEY FILE FORMAT 1.1\n"
  14. #define BASE64_TOINT(x) ( (x)-'A'<26 ? (x)-'A'+0 :\
  15. (x)-'a'<26 ? (x)-'a'+26 :\
  16. (x)-'0'<10 ? (x)-'0'+52 :\
  17. (x)=='+' ? 62 : \
  18. (x)=='/' ? 63 : 0 )
  19. static int loadrsakey_main(FILE * fp, struct RSAKey *key, int pub_only,
  20. char **commentptr, char *passphrase,
  21. const char **error)
  22. {
  23. unsigned char buf[16384];
  24. unsigned char keybuf[16];
  25. int len;
  26. int i, j, ciphertype;
  27. int ret = 0;
  28. struct MD5Context md5c;
  29. char *comment;
  30. *error = NULL;
  31. /* Slurp the whole file (minus the header) into a buffer. */
  32. len = fread(buf, 1, sizeof(buf), fp);
  33. fclose(fp);
  34. if (len < 0 || len == sizeof(buf)) {
  35. *error = "error reading file";
  36. goto end; /* file too big or not read */
  37. }
  38. i = 0;
  39. *error = "file format error";
  40. /*
  41. * A zero byte. (The signature includes a terminating NUL.)
  42. */
  43. if (len - i < 1 || buf[i] != 0)
  44. goto end;
  45. i++;
  46. /* One byte giving encryption type, and one reserved uint32. */
  47. if (len - i < 1)
  48. goto end;
  49. ciphertype = buf[i];
  50. if (ciphertype != 0 && ciphertype != SSH_CIPHER_3DES)
  51. goto end;
  52. i++;
  53. if (len - i < 4)
  54. goto end; /* reserved field not present */
  55. if (buf[i] != 0 || buf[i + 1] != 0 || buf[i + 2] != 0
  56. || buf[i + 3] != 0) goto end; /* reserved field nonzero, panic! */
  57. i += 4;
  58. /* Now the serious stuff. An ordinary SSH-1 public key. */
  59. j = makekey(buf + i, len - i, key, NULL, 1);
  60. if (j < 0)
  61. goto end; /* overran */
  62. i += j;
  63. /* Next, the comment field. */
  64. j = toint(GET_32BIT(buf + i));
  65. i += 4;
  66. if (j < 0 || len - i < j)
  67. goto end;
  68. comment = snewn(j + 1, char);
  69. if (comment) {
  70. memcpy(comment, buf + i, j);
  71. comment[j] = '\0';
  72. }
  73. i += j;
  74. if (commentptr)
  75. *commentptr = dupstr(comment);
  76. if (key)
  77. key->comment = comment;
  78. else
  79. sfree(comment);
  80. if (pub_only) {
  81. ret = 1;
  82. goto end;
  83. }
  84. if (!key) {
  85. ret = ciphertype != 0;
  86. *error = NULL;
  87. goto end;
  88. }
  89. /*
  90. * Decrypt remainder of buffer.
  91. */
  92. if (ciphertype) {
  93. MD5Init(&md5c);
  94. MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase));
  95. MD5Final(keybuf, &md5c);
  96. des3_decrypt_pubkey(keybuf, buf + i, (len - i + 7) & ~7);
  97. smemclr(keybuf, sizeof(keybuf)); /* burn the evidence */
  98. }
  99. /*
  100. * We are now in the secret part of the key. The first four
  101. * bytes should be of the form a, b, a, b.
  102. */
  103. if (len - i < 4)
  104. goto end;
  105. if (buf[i] != buf[i + 2] || buf[i + 1] != buf[i + 3]) {
  106. *error = "wrong passphrase";
  107. ret = -1;
  108. goto end;
  109. }
  110. i += 4;
  111. /*
  112. * After that, we have one further bignum which is our
  113. * decryption exponent, and then the three auxiliary values
  114. * (iqmp, q, p).
  115. */
  116. j = makeprivate(buf + i, len - i, key);
  117. if (j < 0) goto end;
  118. i += j;
  119. j = ssh1_read_bignum(buf + i, len - i, &key->iqmp);
  120. if (j < 0) goto end;
  121. i += j;
  122. j = ssh1_read_bignum(buf + i, len - i, &key->q);
  123. if (j < 0) goto end;
  124. i += j;
  125. j = ssh1_read_bignum(buf + i, len - i, &key->p);
  126. if (j < 0) goto end;
  127. i += j;
  128. if (!rsa_verify(key)) {
  129. *error = "rsa_verify failed";
  130. freersakey(key);
  131. ret = 0;
  132. } else
  133. ret = 1;
  134. end:
  135. smemclr(buf, sizeof(buf)); /* burn the evidence */
  136. return ret;
  137. }
  138. int loadrsakey(const Filename *filename, struct RSAKey *key, char *passphrase,
  139. const char **errorstr)
  140. {
  141. FILE *fp;
  142. char buf[64];
  143. int ret = 0;
  144. const char *error = NULL;
  145. fp = f_open(filename, "rb", FALSE);
  146. if (!fp) {
  147. error = "can't open file";
  148. goto end;
  149. }
  150. /*
  151. * Read the first line of the file and see if it's a v1 private
  152. * key file.
  153. */
  154. if (fgets(buf, sizeof(buf), fp) && !strcmp(buf, rsa_signature)) {
  155. /*
  156. * This routine will take care of calling fclose() for us.
  157. */
  158. ret = loadrsakey_main(fp, key, FALSE, NULL, passphrase, &error);
  159. fp = NULL;
  160. goto end;
  161. }
  162. /*
  163. * Otherwise, we have nothing. Return empty-handed.
  164. */
  165. error = "not an SSH-1 RSA file";
  166. end:
  167. if (fp)
  168. fclose(fp);
  169. if ((ret != 1) && errorstr)
  170. *errorstr = error;
  171. return ret;
  172. }
  173. /*
  174. * See whether an RSA key is encrypted. Return its comment field as
  175. * well.
  176. */
  177. int rsakey_encrypted(const Filename *filename, char **comment)
  178. {
  179. FILE *fp;
  180. char buf[64];
  181. fp = f_open(filename, "rb", FALSE);
  182. if (!fp)
  183. return 0; /* doesn't even exist */
  184. /*
  185. * Read the first line of the file and see if it's a v1 private
  186. * key file.
  187. */
  188. if (fgets(buf, sizeof(buf), fp) && !strcmp(buf, rsa_signature)) {
  189. const char *dummy;
  190. /*
  191. * This routine will take care of calling fclose() for us.
  192. */
  193. return loadrsakey_main(fp, NULL, FALSE, comment, NULL, &dummy);
  194. }
  195. fclose(fp);
  196. return 0; /* wasn't the right kind of file */
  197. }
  198. /*
  199. * Return a malloc'ed chunk of memory containing the public blob of
  200. * an RSA key, as given in the agent protocol (modulus bits,
  201. * exponent, modulus).
  202. */
  203. int rsakey_pubblob(const Filename *filename, void **blob, int *bloblen,
  204. char **commentptr, const char **errorstr)
  205. {
  206. FILE *fp;
  207. char buf[64];
  208. struct RSAKey key;
  209. int ret;
  210. const char *error = NULL;
  211. /* Default return if we fail. */
  212. *blob = NULL;
  213. *bloblen = 0;
  214. ret = 0;
  215. fp = f_open(filename, "rb", FALSE);
  216. if (!fp) {
  217. error = "can't open file";
  218. goto end;
  219. }
  220. /*
  221. * Read the first line of the file and see if it's a v1 private
  222. * key file.
  223. */
  224. if (fgets(buf, sizeof(buf), fp) && !strcmp(buf, rsa_signature)) {
  225. memset(&key, 0, sizeof(key));
  226. if (loadrsakey_main(fp, &key, TRUE, commentptr, NULL, &error)) {
  227. *blob = rsa_public_blob(&key, bloblen);
  228. freersakey(&key);
  229. ret = 1;
  230. }
  231. fp = NULL; /* loadrsakey_main unconditionally closes fp */
  232. } else {
  233. error = "not an SSH-1 RSA file";
  234. }
  235. end:
  236. if (fp)
  237. fclose(fp);
  238. if ((ret != 1) && errorstr)
  239. *errorstr = error;
  240. return ret;
  241. }
  242. /*
  243. * Save an RSA key file. Return nonzero on success.
  244. */
  245. int saversakey(const Filename *filename, struct RSAKey *key, char *passphrase)
  246. {
  247. unsigned char buf[16384];
  248. unsigned char keybuf[16];
  249. struct MD5Context md5c;
  250. unsigned char *p, *estart;
  251. FILE *fp;
  252. /*
  253. * Write the initial signature.
  254. */
  255. p = buf;
  256. memcpy(p, rsa_signature, sizeof(rsa_signature));
  257. p += sizeof(rsa_signature);
  258. /*
  259. * One byte giving encryption type, and one reserved (zero)
  260. * uint32.
  261. */
  262. *p++ = (passphrase ? SSH_CIPHER_3DES : 0);
  263. PUT_32BIT(p, 0);
  264. p += 4;
  265. /*
  266. * An ordinary SSH-1 public key consists of: a uint32
  267. * containing the bit count, then two bignums containing the
  268. * modulus and exponent respectively.
  269. */
  270. PUT_32BIT(p, bignum_bitcount(key->modulus));
  271. p += 4;
  272. p += ssh1_write_bignum(p, key->modulus);
  273. p += ssh1_write_bignum(p, key->exponent);
  274. /*
  275. * A string containing the comment field.
  276. */
  277. if (key->comment) {
  278. PUT_32BIT(p, strlen(key->comment));
  279. p += 4;
  280. memcpy(p, key->comment, strlen(key->comment));
  281. p += strlen(key->comment);
  282. } else {
  283. PUT_32BIT(p, 0);
  284. p += 4;
  285. }
  286. /*
  287. * The encrypted portion starts here.
  288. */
  289. estart = p;
  290. /*
  291. * Two bytes, then the same two bytes repeated.
  292. */
  293. *p++ = random_byte();
  294. *p++ = random_byte();
  295. p[0] = p[-2];
  296. p[1] = p[-1];
  297. p += 2;
  298. /*
  299. * Four more bignums: the decryption exponent, then iqmp, then
  300. * q, then p.
  301. */
  302. p += ssh1_write_bignum(p, key->private_exponent);
  303. p += ssh1_write_bignum(p, key->iqmp);
  304. p += ssh1_write_bignum(p, key->q);
  305. p += ssh1_write_bignum(p, key->p);
  306. /*
  307. * Now write zeros until the encrypted portion is a multiple of
  308. * 8 bytes.
  309. */
  310. while ((p - estart) % 8)
  311. *p++ = '\0';
  312. /*
  313. * Now encrypt the encrypted portion.
  314. */
  315. if (passphrase) {
  316. MD5Init(&md5c);
  317. MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase));
  318. MD5Final(keybuf, &md5c);
  319. des3_encrypt_pubkey(keybuf, estart, p - estart);
  320. smemclr(keybuf, sizeof(keybuf)); /* burn the evidence */
  321. }
  322. /*
  323. * Done. Write the result to the file.
  324. */
  325. fp = f_open(filename, "wb", TRUE);
  326. if (fp) {
  327. int ret = (fwrite(buf, 1, p - buf, fp) == (size_t) (p - buf));
  328. if (fclose(fp))
  329. ret = 0;
  330. return ret;
  331. } else
  332. return 0;
  333. }
  334. /* ----------------------------------------------------------------------
  335. * SSH-2 private key load/store functions.
  336. */
  337. /*
  338. * PuTTY's own format for SSH-2 keys is as follows:
  339. *
  340. * The file is text. Lines are terminated by CRLF, although CR-only
  341. * and LF-only are tolerated on input.
  342. *
  343. * The first line says "PuTTY-User-Key-File-2: " plus the name of the
  344. * algorithm ("ssh-dss", "ssh-rsa" etc).
  345. *
  346. * The next line says "Encryption: " plus an encryption type.
  347. * Currently the only supported encryption types are "aes256-cbc"
  348. * and "none".
  349. *
  350. * The next line says "Comment: " plus the comment string.
  351. *
  352. * Next there is a line saying "Public-Lines: " plus a number N.
  353. * The following N lines contain a base64 encoding of the public
  354. * part of the key. This is encoded as the standard SSH-2 public key
  355. * blob (with no initial length): so for RSA, for example, it will
  356. * read
  357. *
  358. * string "ssh-rsa"
  359. * mpint exponent
  360. * mpint modulus
  361. *
  362. * Next, there is a line saying "Private-Lines: " plus a number N,
  363. * and then N lines containing the (potentially encrypted) private
  364. * part of the key. For the key type "ssh-rsa", this will be
  365. * composed of
  366. *
  367. * mpint private_exponent
  368. * mpint p (the larger of the two primes)
  369. * mpint q (the smaller prime)
  370. * mpint iqmp (the inverse of q modulo p)
  371. * data padding (to reach a multiple of the cipher block size)
  372. *
  373. * And for "ssh-dss", it will be composed of
  374. *
  375. * mpint x (the private key parameter)
  376. * [ string hash 20-byte hash of mpints p || q || g only in old format ]
  377. *
  378. * Finally, there is a line saying "Private-MAC: " plus a hex
  379. * representation of a HMAC-SHA-1 of:
  380. *
  381. * string name of algorithm ("ssh-dss", "ssh-rsa")
  382. * string encryption type
  383. * string comment
  384. * string public-blob
  385. * string private-plaintext (the plaintext version of the
  386. * private part, including the final
  387. * padding)
  388. *
  389. * The key to the MAC is itself a SHA-1 hash of:
  390. *
  391. * data "putty-private-key-file-mac-key"
  392. * data passphrase
  393. *
  394. * (An empty passphrase is used for unencrypted keys.)
  395. *
  396. * If the key is encrypted, the encryption key is derived from the
  397. * passphrase by means of a succession of SHA-1 hashes. Each hash
  398. * is the hash of:
  399. *
  400. * uint32 sequence-number
  401. * data passphrase
  402. *
  403. * where the sequence-number increases from zero. As many of these
  404. * hashes are used as necessary.
  405. *
  406. * For backwards compatibility with snapshots between 0.51 and
  407. * 0.52, we also support the older key file format, which begins
  408. * with "PuTTY-User-Key-File-1" (version number differs). In this
  409. * format the Private-MAC: field only covers the private-plaintext
  410. * field and nothing else (and without the 4-byte string length on
  411. * the front too). Moreover, the Private-MAC: field can be replaced
  412. * with a Private-Hash: field which is a plain SHA-1 hash instead of
  413. * an HMAC (this was generated for unencrypted keys).
  414. */
  415. static int read_header(FILE * fp, char *header)
  416. {
  417. int len = 39;
  418. int c;
  419. while (1) {
  420. c = fgetc(fp);
  421. if (c == '\n' || c == '\r' || c == EOF)
  422. return 0; /* failure */
  423. if (c == ':') {
  424. c = fgetc(fp);
  425. if (c != ' ')
  426. return 0;
  427. *header = '\0';
  428. return 1; /* success! */
  429. }
  430. if (len == 0)
  431. return 0; /* failure */
  432. *header++ = c;
  433. len--;
  434. }
  435. return 0; /* failure */
  436. }
  437. static char *read_body(FILE * fp)
  438. {
  439. char *text;
  440. int len;
  441. int size;
  442. int c;
  443. size = 128;
  444. text = snewn(size, char);
  445. len = 0;
  446. text[len] = '\0';
  447. while (1) {
  448. c = fgetc(fp);
  449. if (c == '\r' || c == '\n' || c == EOF) {
  450. if (c != EOF) {
  451. c = fgetc(fp);
  452. if (c != '\r' && c != '\n')
  453. ungetc(c, fp);
  454. }
  455. return text;
  456. }
  457. if (len + 1 >= size) {
  458. size += 128;
  459. text = sresize(text, size, char);
  460. }
  461. text[len++] = c;
  462. text[len] = '\0';
  463. }
  464. }
  465. static unsigned char *read_blob(FILE * fp, int nlines, int *bloblen)
  466. {
  467. unsigned char *blob;
  468. char *line;
  469. int linelen, len;
  470. int i, j, k;
  471. /* We expect at most 64 base64 characters, ie 48 real bytes, per line. */
  472. blob = snewn(48 * nlines, unsigned char);
  473. len = 0;
  474. for (i = 0; i < nlines; i++) {
  475. line = read_body(fp);
  476. if (!line) {
  477. sfree(blob);
  478. return NULL;
  479. }
  480. linelen = strlen(line);
  481. if (linelen % 4 != 0 || linelen > 64) {
  482. sfree(blob);
  483. sfree(line);
  484. return NULL;
  485. }
  486. for (j = 0; j < linelen; j += 4) {
  487. k = base64_decode_atom(line + j, blob + len);
  488. if (!k) {
  489. sfree(line);
  490. sfree(blob);
  491. return NULL;
  492. }
  493. len += k;
  494. }
  495. sfree(line);
  496. }
  497. *bloblen = len;
  498. return blob;
  499. }
  500. /*
  501. * Magic error return value for when the passphrase is wrong.
  502. */
  503. struct ssh2_userkey ssh2_wrong_passphrase = {
  504. NULL, NULL, NULL
  505. };
  506. const struct ssh_signkey *find_pubkey_alg(const char *name)
  507. {
  508. if (!strcmp(name, "ssh-rsa"))
  509. return &ssh_rsa;
  510. else if (!strcmp(name, "ssh-dss"))
  511. return &ssh_dss;
  512. else
  513. return NULL;
  514. }
  515. struct ssh2_userkey *ssh2_load_userkey(const Filename *filename,
  516. char *passphrase, const char **errorstr)
  517. {
  518. FILE *fp;
  519. char header[40], *b, *encryption, *comment, *mac;
  520. const struct ssh_signkey *alg;
  521. struct ssh2_userkey *ret;
  522. int cipher, cipherblk;
  523. unsigned char *public_blob, *private_blob;
  524. int public_blob_len, private_blob_len;
  525. int i, is_mac, old_fmt;
  526. int passlen = passphrase ? strlen(passphrase) : 0;
  527. const char *error = NULL;
  528. ret = NULL; /* return NULL for most errors */
  529. encryption = comment = mac = NULL;
  530. public_blob = private_blob = NULL;
  531. fp = f_open(filename, "rb", FALSE);
  532. if (!fp) {
  533. error = "can't open file";
  534. goto error;
  535. }
  536. /* Read the first header line which contains the key type. */
  537. if (!read_header(fp, header))
  538. goto error;
  539. if (0 == strcmp(header, "PuTTY-User-Key-File-2")) {
  540. old_fmt = 0;
  541. } else if (0 == strcmp(header, "PuTTY-User-Key-File-1")) {
  542. /* this is an old key file; warn and then continue */
  543. old_keyfile_warning();
  544. old_fmt = 1;
  545. } else if (0 == strncmp(header, "PuTTY-User-Key-File-", 20)) {
  546. /* this is a key file FROM THE FUTURE; refuse it, but with a
  547. * more specific error message than the generic one below */
  548. error = "PuTTY key format too new";
  549. goto error;
  550. } else {
  551. error = "not a PuTTY SSH-2 private key";
  552. goto error;
  553. }
  554. error = "file format error";
  555. if ((b = read_body(fp)) == NULL)
  556. goto error;
  557. /* Select key algorithm structure. */
  558. alg = find_pubkey_alg(b);
  559. if (!alg) {
  560. sfree(b);
  561. goto error;
  562. }
  563. sfree(b);
  564. /* Read the Encryption header line. */
  565. if (!read_header(fp, header) || 0 != strcmp(header, "Encryption"))
  566. goto error;
  567. if ((encryption = read_body(fp)) == NULL)
  568. goto error;
  569. if (!strcmp(encryption, "aes256-cbc")) {
  570. cipher = 1;
  571. cipherblk = 16;
  572. } else if (!strcmp(encryption, "none")) {
  573. cipher = 0;
  574. cipherblk = 1;
  575. } else {
  576. goto error;
  577. }
  578. /* Read the Comment header line. */
  579. if (!read_header(fp, header) || 0 != strcmp(header, "Comment"))
  580. goto error;
  581. if ((comment = read_body(fp)) == NULL)
  582. goto error;
  583. /* Read the Public-Lines header line and the public blob. */
  584. if (!read_header(fp, header) || 0 != strcmp(header, "Public-Lines"))
  585. goto error;
  586. if ((b = read_body(fp)) == NULL)
  587. goto error;
  588. i = atoi(b);
  589. sfree(b);
  590. if ((public_blob = read_blob(fp, i, &public_blob_len)) == NULL)
  591. goto error;
  592. /* Read the Private-Lines header line and the Private blob. */
  593. if (!read_header(fp, header) || 0 != strcmp(header, "Private-Lines"))
  594. goto error;
  595. if ((b = read_body(fp)) == NULL)
  596. goto error;
  597. i = atoi(b);
  598. sfree(b);
  599. if ((private_blob = read_blob(fp, i, &private_blob_len)) == NULL)
  600. goto error;
  601. /* Read the Private-MAC or Private-Hash header line. */
  602. if (!read_header(fp, header))
  603. goto error;
  604. if (0 == strcmp(header, "Private-MAC")) {
  605. if ((mac = read_body(fp)) == NULL)
  606. goto error;
  607. is_mac = 1;
  608. } else if (0 == strcmp(header, "Private-Hash") && old_fmt) {
  609. if ((mac = read_body(fp)) == NULL)
  610. goto error;
  611. is_mac = 0;
  612. } else
  613. goto error;
  614. fclose(fp);
  615. fp = NULL;
  616. /*
  617. * Decrypt the private blob.
  618. */
  619. if (cipher) {
  620. unsigned char key[40];
  621. SHA_State s;
  622. if (!passphrase)
  623. goto error;
  624. if (private_blob_len % cipherblk)
  625. goto error;
  626. SHA_Init(&s);
  627. SHA_Bytes(&s, "\0\0\0\0", 4);
  628. SHA_Bytes(&s, passphrase, passlen);
  629. SHA_Final(&s, key + 0);
  630. SHA_Init(&s);
  631. SHA_Bytes(&s, "\0\0\0\1", 4);
  632. SHA_Bytes(&s, passphrase, passlen);
  633. SHA_Final(&s, key + 20);
  634. aes256_decrypt_pubkey(key, private_blob, private_blob_len);
  635. }
  636. /*
  637. * Verify the MAC.
  638. */
  639. {
  640. char realmac[41];
  641. unsigned char binary[20];
  642. unsigned char *macdata;
  643. int maclen;
  644. int free_macdata;
  645. if (old_fmt) {
  646. /* MAC (or hash) only covers the private blob. */
  647. macdata = private_blob;
  648. maclen = private_blob_len;
  649. free_macdata = 0;
  650. } else {
  651. unsigned char *p;
  652. int namelen = strlen(alg->name);
  653. int enclen = strlen(encryption);
  654. int commlen = strlen(comment);
  655. maclen = (4 + namelen +
  656. 4 + enclen +
  657. 4 + commlen +
  658. 4 + public_blob_len +
  659. 4 + private_blob_len);
  660. macdata = snewn(maclen, unsigned char);
  661. p = macdata;
  662. #define DO_STR(s,len) PUT_32BIT(p,(len));memcpy(p+4,(s),(len));p+=4+(len)
  663. DO_STR(alg->name, namelen);
  664. DO_STR(encryption, enclen);
  665. DO_STR(comment, commlen);
  666. DO_STR(public_blob, public_blob_len);
  667. DO_STR(private_blob, private_blob_len);
  668. free_macdata = 1;
  669. }
  670. if (is_mac) {
  671. SHA_State s;
  672. unsigned char mackey[20];
  673. char header[] = "putty-private-key-file-mac-key";
  674. SHA_Init(&s);
  675. SHA_Bytes(&s, header, sizeof(header)-1);
  676. if (cipher && passphrase)
  677. SHA_Bytes(&s, passphrase, passlen);
  678. SHA_Final(&s, mackey);
  679. hmac_sha1_simple(mackey, 20, macdata, maclen, binary);
  680. smemclr(mackey, sizeof(mackey));
  681. smemclr(&s, sizeof(s));
  682. } else {
  683. SHA_Simple(macdata, maclen, binary);
  684. }
  685. if (free_macdata) {
  686. smemclr(macdata, maclen);
  687. sfree(macdata);
  688. }
  689. for (i = 0; i < 20; i++)
  690. sprintf(realmac + 2 * i, "%02x", binary[i]);
  691. if (strcmp(mac, realmac)) {
  692. /* An incorrect MAC is an unconditional Error if the key is
  693. * unencrypted. Otherwise, it means Wrong Passphrase. */
  694. if (cipher) {
  695. error = "wrong passphrase";
  696. ret = SSH2_WRONG_PASSPHRASE;
  697. } else {
  698. error = "MAC failed";
  699. ret = NULL;
  700. }
  701. goto error;
  702. }
  703. }
  704. sfree(mac);
  705. mac = NULL;
  706. /*
  707. * Create and return the key.
  708. */
  709. ret = snew(struct ssh2_userkey);
  710. ret->alg = alg;
  711. ret->comment = comment;
  712. ret->data = alg->createkey(public_blob, public_blob_len,
  713. private_blob, private_blob_len);
  714. if (!ret->data) {
  715. sfree(ret);
  716. ret = NULL;
  717. error = "createkey failed";
  718. goto error;
  719. }
  720. sfree(public_blob);
  721. smemclr(private_blob, private_blob_len);
  722. sfree(private_blob);
  723. sfree(encryption);
  724. if (errorstr)
  725. *errorstr = NULL;
  726. return ret;
  727. /*
  728. * Error processing.
  729. */
  730. error:
  731. if (fp)
  732. fclose(fp);
  733. if (comment)
  734. sfree(comment);
  735. if (encryption)
  736. sfree(encryption);
  737. if (mac)
  738. sfree(mac);
  739. if (public_blob)
  740. sfree(public_blob);
  741. if (private_blob) {
  742. smemclr(private_blob, private_blob_len);
  743. sfree(private_blob);
  744. }
  745. if (errorstr)
  746. *errorstr = error;
  747. return ret;
  748. }
  749. unsigned char *ssh2_userkey_loadpub(const Filename *filename, char **algorithm,
  750. int *pub_blob_len, char **commentptr,
  751. const char **errorstr)
  752. {
  753. FILE *fp;
  754. char header[40], *b;
  755. const struct ssh_signkey *alg;
  756. unsigned char *public_blob;
  757. int public_blob_len;
  758. int i;
  759. const char *error = NULL;
  760. char *comment = NULL;
  761. public_blob = NULL;
  762. fp = f_open(filename, "rb", FALSE);
  763. if (!fp) {
  764. error = "can't open file";
  765. goto error;
  766. }
  767. /* Read the first header line which contains the key type. */
  768. if (!read_header(fp, header)
  769. || (0 != strcmp(header, "PuTTY-User-Key-File-2") &&
  770. 0 != strcmp(header, "PuTTY-User-Key-File-1"))) {
  771. if (0 == strncmp(header, "PuTTY-User-Key-File-", 20))
  772. error = "PuTTY key format too new";
  773. else
  774. error = "not a PuTTY SSH-2 private key";
  775. goto error;
  776. }
  777. error = "file format error";
  778. if ((b = read_body(fp)) == NULL)
  779. goto error;
  780. /* Select key algorithm structure. */
  781. alg = find_pubkey_alg(b);
  782. sfree(b);
  783. if (!alg) {
  784. goto error;
  785. }
  786. /* Read the Encryption header line. */
  787. if (!read_header(fp, header) || 0 != strcmp(header, "Encryption"))
  788. goto error;
  789. if ((b = read_body(fp)) == NULL)
  790. goto error;
  791. sfree(b); /* we don't care */
  792. /* Read the Comment header line. */
  793. if (!read_header(fp, header) || 0 != strcmp(header, "Comment"))
  794. goto error;
  795. if ((comment = read_body(fp)) == NULL)
  796. goto error;
  797. if (commentptr)
  798. *commentptr = comment;
  799. else
  800. sfree(comment);
  801. /* Read the Public-Lines header line and the public blob. */
  802. if (!read_header(fp, header) || 0 != strcmp(header, "Public-Lines"))
  803. goto error;
  804. if ((b = read_body(fp)) == NULL)
  805. goto error;
  806. i = atoi(b);
  807. sfree(b);
  808. if ((public_blob = read_blob(fp, i, &public_blob_len)) == NULL)
  809. goto error;
  810. fclose(fp);
  811. if (pub_blob_len)
  812. *pub_blob_len = public_blob_len;
  813. if (algorithm)
  814. *algorithm = alg->name;
  815. return public_blob;
  816. /*
  817. * Error processing.
  818. */
  819. error:
  820. if (fp)
  821. fclose(fp);
  822. if (public_blob)
  823. sfree(public_blob);
  824. if (errorstr)
  825. *errorstr = error;
  826. if (comment && commentptr) {
  827. sfree(comment);
  828. *commentptr = NULL;
  829. }
  830. return NULL;
  831. }
  832. int ssh2_userkey_encrypted(const Filename *filename, char **commentptr)
  833. {
  834. FILE *fp;
  835. char header[40], *b, *comment;
  836. int ret;
  837. if (commentptr)
  838. *commentptr = NULL;
  839. fp = f_open(filename, "rb", FALSE);
  840. if (!fp)
  841. return 0;
  842. if (!read_header(fp, header)
  843. || (0 != strcmp(header, "PuTTY-User-Key-File-2") &&
  844. 0 != strcmp(header, "PuTTY-User-Key-File-1"))) {
  845. fclose(fp);
  846. return 0;
  847. }
  848. if ((b = read_body(fp)) == NULL) {
  849. fclose(fp);
  850. return 0;
  851. }
  852. sfree(b); /* we don't care about key type here */
  853. /* Read the Encryption header line. */
  854. if (!read_header(fp, header) || 0 != strcmp(header, "Encryption")) {
  855. fclose(fp);
  856. return 0;
  857. }
  858. if ((b = read_body(fp)) == NULL) {
  859. fclose(fp);
  860. return 0;
  861. }
  862. /* Read the Comment header line. */
  863. if (!read_header(fp, header) || 0 != strcmp(header, "Comment")) {
  864. fclose(fp);
  865. sfree(b);
  866. return 1;
  867. }
  868. if ((comment = read_body(fp)) == NULL) {
  869. fclose(fp);
  870. sfree(b);
  871. return 1;
  872. }
  873. if (commentptr)
  874. *commentptr = comment;
  875. else
  876. sfree(comment);
  877. fclose(fp);
  878. if (!strcmp(b, "aes256-cbc"))
  879. ret = 1;
  880. else
  881. ret = 0;
  882. sfree(b);
  883. return ret;
  884. }
  885. int base64_lines(int datalen)
  886. {
  887. /* When encoding, we use 64 chars/line, which equals 48 real chars. */
  888. return (datalen + 47) / 48;
  889. }
  890. void base64_encode(FILE * fp, unsigned char *data, int datalen, int cpl)
  891. {
  892. int linelen = 0;
  893. char out[4];
  894. int n, i;
  895. while (datalen > 0) {
  896. n = (datalen < 3 ? datalen : 3);
  897. base64_encode_atom(data, n, out);
  898. data += n;
  899. datalen -= n;
  900. for (i = 0; i < 4; i++) {
  901. if (linelen >= cpl) {
  902. linelen = 0;
  903. fputc('\n', fp);
  904. }
  905. fputc(out[i], fp);
  906. linelen++;
  907. }
  908. }
  909. fputc('\n', fp);
  910. }
  911. int ssh2_save_userkey(const Filename *filename, struct ssh2_userkey *key,
  912. char *passphrase)
  913. {
  914. FILE *fp;
  915. unsigned char *pub_blob, *priv_blob, *priv_blob_encrypted;
  916. int pub_blob_len, priv_blob_len, priv_encrypted_len;
  917. int passlen;
  918. int cipherblk;
  919. int i;
  920. char *cipherstr;
  921. unsigned char priv_mac[20];
  922. /*
  923. * Fetch the key component blobs.
  924. */
  925. pub_blob = key->alg->public_blob(key->data, &pub_blob_len);
  926. priv_blob = key->alg->private_blob(key->data, &priv_blob_len);
  927. if (!pub_blob || !priv_blob) {
  928. sfree(pub_blob);
  929. sfree(priv_blob);
  930. return 0;
  931. }
  932. /*
  933. * Determine encryption details, and encrypt the private blob.
  934. */
  935. if (passphrase) {
  936. cipherstr = "aes256-cbc";
  937. cipherblk = 16;
  938. } else {
  939. cipherstr = "none";
  940. cipherblk = 1;
  941. }
  942. priv_encrypted_len = priv_blob_len + cipherblk - 1;
  943. priv_encrypted_len -= priv_encrypted_len % cipherblk;
  944. priv_blob_encrypted = snewn(priv_encrypted_len, unsigned char);
  945. memset(priv_blob_encrypted, 0, priv_encrypted_len);
  946. memcpy(priv_blob_encrypted, priv_blob, priv_blob_len);
  947. /* Create padding based on the SHA hash of the unpadded blob. This prevents
  948. * too easy a known-plaintext attack on the last block. */
  949. SHA_Simple(priv_blob, priv_blob_len, priv_mac);
  950. assert(priv_encrypted_len - priv_blob_len < 20);
  951. memcpy(priv_blob_encrypted + priv_blob_len, priv_mac,
  952. priv_encrypted_len - priv_blob_len);
  953. /* Now create the MAC. */
  954. {
  955. unsigned char *macdata;
  956. int maclen;
  957. unsigned char *p;
  958. int namelen = strlen(key->alg->name);
  959. int enclen = strlen(cipherstr);
  960. int commlen = strlen(key->comment);
  961. SHA_State s;
  962. unsigned char mackey[20];
  963. char header[] = "putty-private-key-file-mac-key";
  964. maclen = (4 + namelen +
  965. 4 + enclen +
  966. 4 + commlen +
  967. 4 + pub_blob_len +
  968. 4 + priv_encrypted_len);
  969. macdata = snewn(maclen, unsigned char);
  970. p = macdata;
  971. #define DO_STR(s,len) PUT_32BIT(p,(len));memcpy(p+4,(s),(len));p+=4+(len)
  972. DO_STR(key->alg->name, namelen);
  973. DO_STR(cipherstr, enclen);
  974. DO_STR(key->comment, commlen);
  975. DO_STR(pub_blob, pub_blob_len);
  976. DO_STR(priv_blob_encrypted, priv_encrypted_len);
  977. SHA_Init(&s);
  978. SHA_Bytes(&s, header, sizeof(header)-1);
  979. if (passphrase)
  980. SHA_Bytes(&s, passphrase, strlen(passphrase));
  981. SHA_Final(&s, mackey);
  982. hmac_sha1_simple(mackey, 20, macdata, maclen, priv_mac);
  983. smemclr(macdata, maclen);
  984. sfree(macdata);
  985. smemclr(mackey, sizeof(mackey));
  986. smemclr(&s, sizeof(s));
  987. }
  988. if (passphrase) {
  989. unsigned char key[40];
  990. SHA_State s;
  991. passlen = strlen(passphrase);
  992. SHA_Init(&s);
  993. SHA_Bytes(&s, "\0\0\0\0", 4);
  994. SHA_Bytes(&s, passphrase, passlen);
  995. SHA_Final(&s, key + 0);
  996. SHA_Init(&s);
  997. SHA_Bytes(&s, "\0\0\0\1", 4);
  998. SHA_Bytes(&s, passphrase, passlen);
  999. SHA_Final(&s, key + 20);
  1000. aes256_encrypt_pubkey(key, priv_blob_encrypted,
  1001. priv_encrypted_len);
  1002. smemclr(key, sizeof(key));
  1003. smemclr(&s, sizeof(s));
  1004. }
  1005. fp = f_open(filename, "w", TRUE);
  1006. if (!fp) {
  1007. sfree(pub_blob);
  1008. smemclr(priv_blob, priv_blob_len);
  1009. sfree(priv_blob);
  1010. smemclr(priv_blob_encrypted, priv_blob_len);
  1011. sfree(priv_blob_encrypted);
  1012. return 0;
  1013. }
  1014. fprintf(fp, "PuTTY-User-Key-File-2: %s\n", key->alg->name);
  1015. fprintf(fp, "Encryption: %s\n", cipherstr);
  1016. fprintf(fp, "Comment: %s\n", key->comment);
  1017. fprintf(fp, "Public-Lines: %d\n", base64_lines(pub_blob_len));
  1018. base64_encode(fp, pub_blob, pub_blob_len, 64);
  1019. fprintf(fp, "Private-Lines: %d\n", base64_lines(priv_encrypted_len));
  1020. base64_encode(fp, priv_blob_encrypted, priv_encrypted_len, 64);
  1021. fprintf(fp, "Private-MAC: ");
  1022. for (i = 0; i < 20; i++)
  1023. fprintf(fp, "%02x", priv_mac[i]);
  1024. fprintf(fp, "\n");
  1025. fclose(fp);
  1026. sfree(pub_blob);
  1027. smemclr(priv_blob, priv_blob_len);
  1028. sfree(priv_blob);
  1029. smemclr(priv_blob_encrypted, priv_blob_len);
  1030. sfree(priv_blob_encrypted);
  1031. return 1;
  1032. }
  1033. /* ----------------------------------------------------------------------
  1034. * A function to determine the type of a private key file. Returns
  1035. * 0 on failure, 1 or 2 on success.
  1036. */
  1037. int key_type(const Filename *filename)
  1038. {
  1039. FILE *fp;
  1040. char buf[32];
  1041. const char putty2_sig[] = "PuTTY-User-Key-File-";
  1042. const char sshcom_sig[] = "---- BEGIN SSH2 ENCRYPTED PRIVAT";
  1043. const char openssh_sig[] = "-----BEGIN ";
  1044. int i;
  1045. fp = f_open(filename, "r", FALSE);
  1046. if (!fp)
  1047. return SSH_KEYTYPE_UNOPENABLE;
  1048. i = fread(buf, 1, sizeof(buf), fp);
  1049. fclose(fp);
  1050. if (i < 0)
  1051. return SSH_KEYTYPE_UNOPENABLE;
  1052. if (i < 32)
  1053. return SSH_KEYTYPE_UNKNOWN;
  1054. if (!memcmp(buf, rsa_signature, sizeof(rsa_signature)-1))
  1055. return SSH_KEYTYPE_SSH1;
  1056. if (!memcmp(buf, putty2_sig, sizeof(putty2_sig)-1))
  1057. return SSH_KEYTYPE_SSH2;
  1058. if (!memcmp(buf, openssh_sig, sizeof(openssh_sig)-1))
  1059. return SSH_KEYTYPE_OPENSSH;
  1060. if (!memcmp(buf, sshcom_sig, sizeof(sshcom_sig)-1))
  1061. return SSH_KEYTYPE_SSHCOM;
  1062. return SSH_KEYTYPE_UNKNOWN; /* unrecognised or EOF */
  1063. }
  1064. /*
  1065. * Convert the type word to a string, for `wrong type' error
  1066. * messages.
  1067. */
  1068. char *key_type_to_str(int type)
  1069. {
  1070. switch (type) {
  1071. case SSH_KEYTYPE_UNOPENABLE: return "unable to open file"; break;
  1072. case SSH_KEYTYPE_UNKNOWN: return "not a private key"; break;
  1073. case SSH_KEYTYPE_SSH1: return "SSH-1 private key"; break;
  1074. case SSH_KEYTYPE_SSH2: return "PuTTY SSH-2 private key"; break;
  1075. case SSH_KEYTYPE_OPENSSH: return "OpenSSH SSH-2 private key"; break;
  1076. case SSH_KEYTYPE_SSHCOM: return "ssh.com SSH-2 private key"; break;
  1077. default: return "INTERNAL ERROR"; break;
  1078. }
  1079. }