multitape_metadata.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523
  1. #include "platform.h"
  2. #include <sys/types.h>
  3. #include <assert.h>
  4. #include <stdint.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include "chunks.h"
  8. #include "crypto.h"
  9. #include "crypto_verify_bytes.h"
  10. #include "storage.h"
  11. #include "sysendian.h"
  12. #include "warnp.h"
  13. #include "multitape_internal.h"
  14. /**
  15. * Metadata format:
  16. * <NUL-terminated name>
  17. * <64-bit little-endian creation time>
  18. * <32-bit little-endian argc>
  19. * argc * <NUL-terminated argv entry>
  20. * SHA256(metaindex)
  21. * <64-bit metaindex length>
  22. * RSA_SIGN(all the metadata before this signature)
  23. */
  24. static int multitape_metadata_enc(const struct tapemetadata *, uint8_t **,
  25. size_t *);
  26. static int multitape_metadata_dec(struct tapemetadata *, uint8_t *, size_t);
  27. static int multitape_metadata_get(STORAGE_R *, CHUNKS_S *,
  28. struct tapemetadata *, const uint8_t[32], const char *, int);
  29. /**
  30. * multitape_metadata_ispresent(S, tapename):
  31. * Return 1 if there is already a metadata file for the specified archive
  32. * name, 0 if not, or -1 on error.
  33. */
  34. int
  35. multitape_metadata_ispresent(STORAGE_W * S, const char * tapename)
  36. {
  37. uint8_t hbuf[32]; /* HMAC of tapename. */
  38. /* Compute the hash of the tape name. */
  39. if (crypto_hash_data(CRYPTO_KEY_HMAC_NAME,
  40. (const uint8_t *)tapename, strlen(tapename), hbuf))
  41. goto err0;
  42. /* Ask the storage layer if the metadata file exists. */
  43. return (storage_write_fexist(S, 'm', hbuf));
  44. err0:
  45. /* Failure! */
  46. return (-1);
  47. }
  48. /**
  49. * multitape_metadata_enc(mdat, bufp, buflenp):
  50. * Encode a struct tapemetadata into a buffer. Return the buffer and its
  51. * length via ${bufp} and ${buflenp} respectively.
  52. */
  53. static int
  54. multitape_metadata_enc(const struct tapemetadata * mdat, uint8_t ** bufp,
  55. size_t * buflenp)
  56. {
  57. uint8_t * buf; /* Encoded metadata. */
  58. size_t buflen; /* Encoded metadata size. */
  59. uint8_t * p;
  60. int i;
  61. /* Sanity check. */
  62. assert((mdat->argc >= 0) && ((uintmax_t)mdat->argc <= UINT32_MAX));
  63. /* Add up the lengths of various pieces of metadata. */
  64. buflen = strlen(mdat->name) + 1; /* name */
  65. buflen += 8; /* ctime */
  66. buflen += 4; /* argc */
  67. for (i = 0; i < mdat->argc; i++) /* argv */
  68. buflen += strlen(mdat->argv[i]) + 1;
  69. buflen += 32; /* indexhash */
  70. buflen += 8; /* index length */
  71. buflen += 256; /* 2048-bit RSA signature */
  72. /* Allocate memory. */
  73. if ((p = buf = malloc(buflen)) == NULL)
  74. goto err0;
  75. /* Copy name. */
  76. memcpy(p, mdat->name, strlen(mdat->name) + 1);
  77. p += strlen(mdat->name) + 1;
  78. /* Encode ctime and argc. */
  79. le64enc(p, (uint64_t)mdat->ctime);
  80. p += 8;
  81. le32enc(p, (uint32_t)mdat->argc);
  82. p += 4;
  83. /* Copy argv. */
  84. for (i = 0; i < mdat->argc; i++) {
  85. memcpy(p, mdat->argv[i], strlen(mdat->argv[i]) + 1);
  86. p += strlen(mdat->argv[i]) + 1;
  87. }
  88. /* Copy index hash. */
  89. memcpy(p, mdat->indexhash, 32);
  90. p += 32;
  91. /* Encode index length. */
  92. le64enc(p, mdat->indexlen);
  93. p += 8;
  94. /* Generate signature. */
  95. if (crypto_rsa_sign(CRYPTO_KEY_SIGN_PRIV, buf, (size_t)(p - buf), p,
  96. 256))
  97. goto err1;
  98. /* Return buffer and length. */
  99. *bufp = buf;
  100. *buflenp = buflen;
  101. /* Success! */
  102. return (0);
  103. err1:
  104. free(buf);
  105. err0:
  106. /* Failure! */
  107. return (-1);
  108. }
  109. /**
  110. * multitape_metadata_put(S, C, mdat):
  111. * Store archive metadata. Call chunks_write_extrastats on ${C} and the
  112. * metadata file length.
  113. */
  114. int
  115. multitape_metadata_put(STORAGE_W * S, CHUNKS_W * C,
  116. struct tapemetadata * mdat)
  117. {
  118. uint8_t hbuf[32]; /* HMAC of tape name. */
  119. uint8_t * buf; /* Encoded metadata. */
  120. size_t buflen; /* Encoded metadata size. */
  121. /* Construct metadata file. */
  122. if (multitape_metadata_enc(mdat, &buf, &buflen))
  123. goto err0;
  124. /* Compute hash of tape name. */
  125. if (crypto_hash_data(CRYPTO_KEY_HMAC_NAME,
  126. (uint8_t *)mdat->name, strlen(mdat->name), hbuf))
  127. goto err1;
  128. /* Store the archive metadata. */
  129. if (storage_write_file(S, buf, buflen, 'm', hbuf))
  130. goto err1;
  131. chunks_write_extrastats(C, buflen);
  132. /* Free metadata buffer. */
  133. free(buf);
  134. /* Success! */
  135. return (0);
  136. err1:
  137. free(buf);
  138. err0:
  139. /* Failure! */
  140. return (-1);
  141. }
  142. /**
  143. * multitape_metadata_dec(mdat, buf, buflen):
  144. * Parse a buffer into a struct tapemetadata. Return 0 on success, 1 if the
  145. * metadata is corrupt, or -1 on error.
  146. */
  147. static int
  148. multitape_metadata_dec(struct tapemetadata * mdat, uint8_t * buf,
  149. size_t buflen)
  150. {
  151. uint8_t * p;
  152. size_t i;
  153. int arg;
  154. /* Start at the beginning... */
  155. p = buf;
  156. /* Make sure the archive name is NUL-terminated. */
  157. for (i = 0; i < buflen; i++)
  158. if (p[i] == '\0')
  159. break;
  160. if (i == buflen)
  161. goto bad0;
  162. /* Copy the archive name and move on to next field. */
  163. if ((mdat->name = strdup((char *)p)) == NULL)
  164. goto err0;
  165. buflen -= strlen((char *)p) + 1;
  166. p += strlen((char *)p) + 1;
  167. /* Parse ctime and argc. */
  168. if (buflen < 8)
  169. goto bad1;
  170. mdat->ctime = (time_t)le64dec(p);
  171. buflen -= 8;
  172. p += 8;
  173. if (buflen < 4)
  174. goto bad1;
  175. mdat->argc = (int)le32dec(p);
  176. buflen -= 4;
  177. p += 4;
  178. /* Sanity-check argc. */
  179. if ((mdat->argc < 0) || ((uintmax_t)mdat->argc > SIZE_MAX) ||
  180. ((size_t)(mdat->argc) > buflen))
  181. goto bad1;
  182. /* Allocate space for argv. */
  183. if ((mdat->argv = malloc((size_t)mdat->argc * sizeof(char *))) == NULL)
  184. goto err1;
  185. /* Parse argv. */
  186. for (arg = 0; arg < mdat->argc; arg++)
  187. mdat->argv[arg] = NULL;
  188. for (arg = 0; arg < mdat->argc; arg++) {
  189. /* Make sure argument is NUL-terminated. */
  190. for (i = 0; i < buflen; i++)
  191. if (p[i] == '\0')
  192. break;
  193. if (i == buflen)
  194. goto bad2;
  195. /* Copy argument and move on to next field. */
  196. if ((mdat->argv[arg] = strdup((char *)p)) == NULL)
  197. goto err2;
  198. buflen -= strlen((char *)p) + 1;
  199. p += strlen((char *)p) + 1;
  200. }
  201. /* Copy indexhash. */
  202. if (buflen < 32)
  203. goto bad2;
  204. memcpy(mdat->indexhash, p, 32);
  205. buflen -= 32;
  206. p += 32;
  207. /* Parse index length. */
  208. if (buflen < 8)
  209. goto bad2;
  210. mdat->indexlen = le64dec(p);
  211. buflen -= 8;
  212. p += 8;
  213. /* Validate signature. */
  214. if (buflen < 256)
  215. goto bad2;
  216. switch (crypto_rsa_verify(CRYPTO_KEY_SIGN_PUB,
  217. buf, (size_t)(p - buf), p, 256)) {
  218. case -1:
  219. /* Error in crypto_rsa_verify. */
  220. goto err2;
  221. case 1:
  222. /* Bad signature. */
  223. goto bad2;
  224. case 0:
  225. /* Signature is good. */
  226. break;
  227. }
  228. buflen -= 256;
  229. p += 256;
  230. (void)p; /* not used beyond this point. */
  231. /* We should be at the end of the metadata now. */
  232. if (buflen != 0)
  233. goto bad2;
  234. /* Success! */
  235. return (0);
  236. bad2:
  237. for (arg = 0; arg < mdat->argc; arg++)
  238. free(mdat->argv[arg]);
  239. free(mdat->argv);
  240. bad1:
  241. free(mdat->name);
  242. bad0:
  243. /* Metadata is corrupt. */
  244. return (1);
  245. err2:
  246. for (arg = 0; arg < mdat->argc; arg++)
  247. free(mdat->argv[arg]);
  248. free(mdat->argv);
  249. err1:
  250. free(mdat->name);
  251. err0:
  252. /* Failure! */
  253. return (-1);
  254. }
  255. static int
  256. multitape_metadata_get(STORAGE_R * S, CHUNKS_S * C,
  257. struct tapemetadata * mdat,
  258. const uint8_t tapehash[32], const char * tapename, int quiet)
  259. {
  260. uint8_t hbuf[32];
  261. uint8_t * mbuf;
  262. size_t mdlen;
  263. /* Read the tape metadata. */
  264. switch (storage_read_file_alloc(S, &mbuf, &mdlen, 'm', tapehash)) {
  265. case -1:
  266. /* Internal error. */
  267. goto err1;
  268. case 1:
  269. /* ENOENT. */
  270. goto notpresent;
  271. case 2:
  272. /* Corrupt metadata file. */
  273. goto corrupt;
  274. }
  275. /* Adjust chunk statistics. */
  276. if (C != NULL)
  277. chunks_stats_extrastats(C, mdlen);
  278. /* Parse the tape metadata. */
  279. switch (multitape_metadata_dec(mdat, mbuf, mdlen)) {
  280. case 1:
  281. /* Metadata is corrupt. */
  282. goto corrupt1;
  283. case -1:
  284. /* Error. */
  285. goto err2;
  286. }
  287. /* Store metadata length. */
  288. mdat->metadatalen = mdlen;
  289. /* Free tape metadata. */
  290. free(mbuf);
  291. /*
  292. * Make sure the name stored in the archive metadata matches the
  293. * name of the metadata file.
  294. */
  295. if (crypto_hash_data(CRYPTO_KEY_HMAC_NAME,
  296. (uint8_t *)mdat->name, strlen(mdat->name), hbuf))
  297. goto err0;
  298. if (crypto_verify_bytes(tapehash, hbuf, 32))
  299. goto corrupt;
  300. /* Success! */
  301. return (0);
  302. corrupt1:
  303. free(mbuf);
  304. corrupt:
  305. if (quiet == 0) {
  306. if (tapename)
  307. warn0("Archive metadata is corrupt: %s", tapename);
  308. else
  309. warn0("Archive metadata file is corrupt");
  310. }
  311. /* File is corrupt. */
  312. return (2);
  313. notpresent:
  314. if (quiet == 0) {
  315. if (tapename)
  316. warn0("Archive does not exist: %s", tapename);
  317. else
  318. warn0("Cannot read archive metadata file");
  319. }
  320. /* ENOENT. */
  321. return (1);
  322. err2:
  323. free(mbuf);
  324. err1:
  325. warnp("Error reading archive metadata");
  326. err0:
  327. /* Failure! */
  328. return (-1);
  329. }
  330. /**
  331. * multitape_metadata_get_byhash(S, C, mdat, tapehash, quiet):
  332. * Read and parse metadata for the archive for which the metadata file is
  333. * named ${tapehash}. If ${C} is non-NULL, call chunks_stats_extrastats on
  334. * ${C} and the length of the metadata file. If ${quiet}, don't print any
  335. * warnings about corrupt or missing files. Return 0 on success, 1 if the
  336. * metadata file does not exist, 2 if the metadata file is corrupt, or -1 on
  337. * error.
  338. */
  339. int
  340. multitape_metadata_get_byhash(STORAGE_R * S, CHUNKS_S * C,
  341. struct tapemetadata * mdat, const uint8_t tapehash[32], int quiet)
  342. {
  343. /* Let multitape_metadata_get do the work. */
  344. return (multitape_metadata_get(S, C, mdat, tapehash, NULL, quiet));
  345. }
  346. /**
  347. * multitape_metadata_get_byname(S, C, mdat, tapename, quiet):
  348. * Read and parse metadata for the archive named ${tapename}. If ${C} is
  349. * non-NULL, call chunks_stats_extrastats on ${C} and the length of the
  350. * metadata file. If ${quiet}, don't print any warnings about corrupt or
  351. * missing files. Return 0 on success, 1 if the metadata file does not
  352. * exist, 2 if the metadata file is corrupt, or -1 on error.
  353. */
  354. int
  355. multitape_metadata_get_byname(STORAGE_R * S, CHUNKS_S * C,
  356. struct tapemetadata * mdat, const char * tapename, int quiet)
  357. {
  358. uint8_t hbuf[32];
  359. /* Compute the hash of the tape name. */
  360. if (crypto_hash_data(CRYPTO_KEY_HMAC_NAME,
  361. (const uint8_t *)tapename, strlen(tapename), hbuf))
  362. goto err0;
  363. /* Let multitape_metadata_get do the work. */
  364. return (multitape_metadata_get(S, C, mdat, hbuf, tapename, quiet));
  365. err0:
  366. /* Failure! */
  367. return (-1);
  368. }
  369. /**
  370. * multitape_metadata_free(mdat):
  371. * Free pointers within ${mdat} (but not ${mdat} itself).
  372. */
  373. void
  374. multitape_metadata_free(struct tapemetadata * mdat)
  375. {
  376. int arg;
  377. /* Behave consistently with free(NULL). */
  378. if (mdat == NULL)
  379. return;
  380. /* Free arguments. */
  381. for (arg = 0; arg < mdat->argc; arg++)
  382. free(mdat->argv[arg]);
  383. free(mdat->argv);
  384. /* Free archive name. */
  385. free(mdat->name);
  386. }
  387. /**
  388. * multitape_metadata_recrypt(obuf, obuflen, nbuf, nbuflen):
  389. * Decrypt and re-encrypt the provided metadata file.
  390. */
  391. int
  392. multitape_metadata_recrypt(uint8_t * obuf, size_t obuflen, uint8_t ** nbuf,
  393. size_t * nbuflen)
  394. {
  395. struct tapemetadata mdat;
  396. /* Parse the metadata file. */
  397. switch (multitape_metadata_dec(&mdat, obuf, obuflen)) {
  398. case 1:
  399. warn0("Metadata file is corrupt");
  400. goto err0;
  401. case -1:
  402. warnp("Error parsing metadata file");
  403. goto err0;
  404. }
  405. /* Construct a new metadata file. */
  406. if (multitape_metadata_enc(&mdat, nbuf, nbuflen)) {
  407. warnp("Error constructing metadata file");
  408. goto err1;
  409. }
  410. /* Free the metadata we parsed. */
  411. multitape_metadata_free(&mdat);
  412. /* Success! */
  413. return (0);
  414. err1:
  415. multitape_metadata_free(&mdat);
  416. err0:
  417. /* Failure! */
  418. return (-1);
  419. }
  420. /**
  421. * multitape_metadata_delete(S, C, mdat):
  422. * Delete specified metadata file; ${mdat} must have been initialized by a
  423. * call to multitape_metadata_get_by(hash|name). Call
  424. * chunks_delete_extrastats on ${C} and the metadata file length.
  425. */
  426. int
  427. multitape_metadata_delete(STORAGE_D * S, CHUNKS_D * C,
  428. struct tapemetadata * mdat)
  429. {
  430. uint8_t hbuf[32];
  431. if (crypto_hash_data(CRYPTO_KEY_HMAC_NAME,
  432. (uint8_t *)mdat->name, strlen(mdat->name), hbuf))
  433. goto err0;
  434. if (storage_delete_file(S, 'm', hbuf))
  435. goto err0;
  436. chunks_delete_extrastats(C, mdat->metadatalen);
  437. /* Success! */
  438. return (0);
  439. err0:
  440. /* Failure! */
  441. return (-1);
  442. }