p3dMultifileReader.cxx 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
  1. /**
  2. * PANDA 3D SOFTWARE
  3. * Copyright (c) Carnegie Mellon University. All rights reserved.
  4. *
  5. * All use of this software is subject to the terms of the revised BSD
  6. * license. You should have received a copy of this license along
  7. * with this source code in a file named "LICENSE."
  8. *
  9. * @file p3dMultifileReader.cxx
  10. * @author drose
  11. * @date 2009-06-15
  12. */
  13. #include "p3dMultifileReader.h"
  14. #include "p3dPackage.h"
  15. #include "mkdir_complete.h"
  16. #include "wstring_encode.h"
  17. #include <time.h>
  18. #ifdef _WIN32
  19. #include <direct.h>
  20. #include <io.h>
  21. #endif
  22. using std::ios;
  23. using std::max;
  24. using std::min;
  25. using std::streampos;
  26. using std::streamsize;
  27. using std::string;
  28. // This sequence of bytes begins each Multifile to identify it as a Multifile.
  29. const char P3DMultifileReader::_header[] = "pmf\0\n\r";
  30. const size_t P3DMultifileReader::_header_size = 6;
  31. const int P3DMultifileReader::_current_major_ver = 1;
  32. const int P3DMultifileReader::_current_minor_ver = 1;
  33. /**
  34. *
  35. */
  36. P3DMultifileReader::
  37. P3DMultifileReader() {
  38. _is_open = false;
  39. _read_offset = 0;
  40. }
  41. /**
  42. * Opens the indicated file for reading. Returns true on success, false on
  43. * failure.
  44. */
  45. bool P3DMultifileReader::
  46. open_read(const string &pathname, const int &offset) {
  47. if (_is_open) {
  48. close();
  49. }
  50. _read_offset = offset;
  51. if (!read_header(pathname)) {
  52. return false;
  53. }
  54. _is_open = true;
  55. return true;
  56. }
  57. /**
  58. * Closes the previously-opened file.
  59. */
  60. void P3DMultifileReader::
  61. close() {
  62. _in.close();
  63. _is_open = false;
  64. }
  65. /**
  66. * Reads the multifile, and extracts all the expected extractable components
  67. * within it to the indicated directory. Returns true on success, false on
  68. * failure.
  69. *
  70. * Upates the "step" object with the progress through this operation.
  71. */
  72. bool P3DMultifileReader::
  73. extract_all(const string &to_dir, P3DPackage *package,
  74. P3DPackage::InstallStepThreaded *step) {
  75. assert(_is_open);
  76. if (_in.fail()) {
  77. return false;
  78. }
  79. // Now walk through all of the files, and extract only the ones we expect to
  80. // encounter.
  81. Subfiles::iterator si;
  82. for (si = _subfiles.begin(); si != _subfiles.end(); ++si) {
  83. const Subfile &s = (*si);
  84. FileSpec file;
  85. if (package != nullptr && !package->is_extractable(file, s._filename)) {
  86. continue;
  87. }
  88. string output_pathname = to_dir + "/" + s._filename;
  89. if (!mkfile_complete(output_pathname, nout)) {
  90. return false;
  91. }
  92. ofstream out;
  93. #ifdef _WIN32
  94. std::wstring output_pathname_w;
  95. if (string_to_wstring(output_pathname_w, output_pathname)) {
  96. out.open(output_pathname_w.c_str(), ios::out | ios::binary);
  97. }
  98. #else // _WIN32
  99. out.open(output_pathname.c_str(), ios::out | ios::binary);
  100. #endif // _WIN32
  101. if (!out) {
  102. nout << "Unable to write to " << output_pathname << "\n";
  103. return false;
  104. }
  105. if (!extract_subfile(out, s)) {
  106. return false;
  107. }
  108. out.close();
  109. // Check that the file was extracted correctly (and also set the correct
  110. // timestamp).
  111. if (!file.full_verify(to_dir)) {
  112. nout << "After extracting, " << s._filename << " is still incorrect.\n";
  113. return false;
  114. }
  115. // Be sure to set execute permissions on the file, in case it's a program
  116. // or something.
  117. chmod(output_pathname.c_str(), 0555);
  118. if (step != nullptr && package != nullptr) {
  119. step->thread_add_bytes_done(s._data_length);
  120. }
  121. }
  122. return true;
  123. }
  124. /**
  125. * Reads the multifile, and extracts only the named component to the indicated
  126. * stream. Returns true on success, false on failure.
  127. */
  128. bool P3DMultifileReader::
  129. extract_one(std::ostream &out, const string &filename) {
  130. assert(_is_open);
  131. if (_in.fail()) {
  132. return false;
  133. }
  134. // Look for the named component.
  135. Subfiles::iterator si;
  136. for (si = _subfiles.begin(); si != _subfiles.end(); ++si) {
  137. const Subfile &s = (*si);
  138. if (s._filename == filename) {
  139. return extract_subfile(out, s);
  140. }
  141. }
  142. nout << "Could not extract " << filename << ": not found.\n";
  143. return false;
  144. }
  145. /**
  146. * Returns the number of matching signatures found on the Multifile. These
  147. * signatures may be iterated via get_signature() and related methods.
  148. *
  149. * A signature on this list is guaranteed to match the Multifile contents,
  150. * proving that the Multifile has been unmodified since the signature was
  151. * applied. However, this does not guarantee that the certificate itself is
  152. * actually from who it says it is from; only that it matches the Multifile
  153. * contents. See validate_signature_certificate() to authenticate a
  154. * particular certificate.
  155. */
  156. int P3DMultifileReader::
  157. get_num_signatures() const {
  158. if (_is_open) {
  159. ((P3DMultifileReader *)this)->check_signatures();
  160. }
  161. return _signatures.size();
  162. }
  163. /**
  164. * Returns the nth signature found on the Multifile. See the comments in
  165. * get_num_signatures().
  166. */
  167. const P3DMultifileReader::CertChain &P3DMultifileReader::
  168. get_signature(int n) const {
  169. static CertChain error_chain;
  170. assert(n >= 0 && n < (int)_signatures.size());
  171. return _signatures[n];
  172. }
  173. /**
  174. * Opens the named multifile and reads the header information and index,
  175. * returning true on success, false on failure.
  176. */
  177. bool P3DMultifileReader::
  178. read_header(const string &pathname) {
  179. assert(!_is_open);
  180. _subfiles.clear();
  181. _cert_special.clear();
  182. _signatures.clear();
  183. #ifdef _WIN32
  184. std::wstring pathname_w;
  185. if (string_to_wstring(pathname_w, pathname)) {
  186. _in.open(pathname_w.c_str(), ios::in | ios::binary);
  187. }
  188. #else // _WIN32
  189. _in.open(pathname.c_str(), ios::in | ios::binary);
  190. #endif // _WIN32
  191. if (!_in) {
  192. nout << "Couldn't open " << pathname << "\n";
  193. return false;
  194. }
  195. char this_header[_header_size];
  196. _in.seekg(_read_offset);
  197. // Here's a special case: if the multifile begins with a hash character,
  198. // then we continue reading and discarding lines of ASCII text, until we
  199. // come across a nonempty line that does not begin with a hash character.
  200. // This allows a P3D application (which is a multifile) to be run directly
  201. // on the command line on Unix-based systems.
  202. int ch = _in.get();
  203. if (ch == '#') {
  204. while (ch != EOF && ch == '#') {
  205. // Skip to the end of the line.
  206. while (ch != EOF && ch != '\n') {
  207. ch = _in.get();
  208. }
  209. // Skip to the first non-whitespace character of the line.
  210. while (ch != EOF && (isspace(ch) || ch == '\r')) {
  211. ch = _in.get();
  212. }
  213. }
  214. }
  215. // Now read the actual Multifile header.
  216. this_header[0] = ch;
  217. _in.read(this_header + 1, _header_size - 1);
  218. if (_in.fail() || _in.gcount() != (unsigned)(_header_size - 1)) {
  219. nout << "Unable to read Multifile header: " << pathname << "\n";
  220. return false;
  221. }
  222. if (memcmp(this_header, _header, _header_size) != 0) {
  223. nout << "Failed header check: " << pathname << "\n";
  224. return false;
  225. }
  226. unsigned int major = read_uint16();
  227. unsigned int minor = read_uint16();
  228. if (major != _current_major_ver || minor != _current_minor_ver) {
  229. nout << "Incompatible multifile version: " << pathname << "\n";
  230. return false;
  231. }
  232. unsigned int scale = read_uint32();
  233. if (scale != 1) {
  234. nout << "Unsupported scale factor in " << pathname << "\n";
  235. return false;
  236. }
  237. // We don't care about the overall timestamp.
  238. read_uint32();
  239. if (!read_index()) {
  240. nout << "Error reading multifile index\n";
  241. return false;
  242. }
  243. return true;
  244. }
  245. /**
  246. * Assuming the file stream is positioned at the first record, reads all of
  247. * the records into the _subfiles list. Returns true on success, false on
  248. * failure.
  249. */
  250. bool P3DMultifileReader::
  251. read_index() {
  252. _last_data_byte = 0;
  253. unsigned int next_entry = read_uint32();
  254. if (!_in) {
  255. return false;
  256. }
  257. while (next_entry != 0) {
  258. Subfile s;
  259. s._index_start = (size_t)_in.tellg() - _read_offset;
  260. s._index_length = 0;
  261. s._data_start = read_uint32();
  262. s._data_length = read_uint32();
  263. unsigned int flags = read_uint16();
  264. if ((flags & (SF_compressed | SF_encrypted)) != 0) {
  265. // Skip over the uncompressed length.
  266. read_uint32();
  267. }
  268. s._timestamp = read_uint32();
  269. size_t name_length = read_uint16();
  270. char *buffer = new char[name_length];
  271. _in.read(buffer, name_length);
  272. // The filenames are xored with 0xff just for fun.
  273. for (size_t ni = 0; ni < name_length; ++ni) {
  274. buffer[ni] ^= 0xff;
  275. }
  276. s._filename = string(buffer, name_length);
  277. delete[] buffer;
  278. s._index_length = (size_t)_in.tellg() - s._index_start - _read_offset;
  279. if (flags & SF_signature) {
  280. // A subfile with this bit set is a signature.
  281. _cert_special.push_back(s);
  282. } else {
  283. // Otherwise, it's a regular file.
  284. _last_data_byte = max(_last_data_byte, s.get_last_byte_pos());
  285. if ((flags & SF_ignore) == 0) {
  286. // We can only support subfiles with none of SF_ignore set.
  287. _subfiles.push_back(s);
  288. }
  289. }
  290. _in.seekg(next_entry + _read_offset);
  291. next_entry = read_uint32();
  292. if (!_in) {
  293. return false;
  294. }
  295. }
  296. return true;
  297. }
  298. /**
  299. * Extracts the indicated subfile and writes it to the indicated stream.
  300. * Returns true on success, false on failure.
  301. */
  302. bool P3DMultifileReader::
  303. extract_subfile(std::ostream &out, const Subfile &s) {
  304. _in.seekg(s._data_start + _read_offset);
  305. static const streamsize buffer_size = 4096;
  306. char buffer[buffer_size];
  307. streamsize remaining_data = s._data_length;
  308. _in.read(buffer, min(buffer_size, remaining_data));
  309. streamsize count = _in.gcount();
  310. while (count != 0) {
  311. remaining_data -= count;
  312. out.write(buffer, count);
  313. _in.read(buffer, min(buffer_size, remaining_data));
  314. count = _in.gcount();
  315. }
  316. if (remaining_data != 0) {
  317. nout << "Unable to extract " << s._filename << "\n";
  318. return false;
  319. }
  320. return true;
  321. }
  322. /**
  323. * Walks through the list of _cert_special entries in the Multifile, moving
  324. * any valid signatures found to _signatures. After this call, _cert_special
  325. * will be empty.
  326. *
  327. * This does not check the validity of the certificates themselves. It only
  328. * checks that they correctly sign the Multifile contents.
  329. */
  330. void P3DMultifileReader::
  331. check_signatures() {
  332. Subfiles::iterator pi;
  333. for (pi = _cert_special.begin(); pi != _cert_special.end(); ++pi) {
  334. Subfile *subfile = &(*pi);
  335. // Extract the signature data and certificate separately.
  336. _in.seekg(subfile->_data_start + _read_offset);
  337. size_t sig_size = read_uint32();
  338. char *sig = new char[sig_size];
  339. _in.read(sig, sig_size);
  340. if (_in.gcount() != sig_size) {
  341. nout << "read failure\n";
  342. delete[] sig;
  343. return;
  344. }
  345. size_t num_certs = read_uint32();
  346. // Read the remaining buffer of certificate data.
  347. size_t bytes_read = (size_t)_in.tellg() - subfile->_data_start - _read_offset;
  348. size_t buffer_size = subfile->_data_length - bytes_read;
  349. char *buffer = new char[buffer_size];
  350. _in.read(buffer, buffer_size);
  351. if (_in.gcount() != buffer_size) {
  352. nout << "read failure\n";
  353. delete[] sig;
  354. delete[] buffer;
  355. return;
  356. }
  357. // Now convert each of the certificates to an X509 object, and store it in
  358. // our CertChain.
  359. CertChain chain;
  360. EVP_PKEY *pkey = nullptr;
  361. if (buffer_size > 0) {
  362. #if OPENSSL_VERSION_NUMBER >= 0x00908000L
  363. // Beginning in 0.9.8, d2i_X509() accepted a const unsigned char **.
  364. const unsigned char *bp, *bp_end;
  365. #else
  366. // Prior to 0.9.8, d2i_X509() accepted an unsigned char **.
  367. unsigned char *bp, *bp_end;
  368. #endif
  369. bp = (unsigned char *)&buffer[0];
  370. bp_end = bp + buffer_size;
  371. X509 *x509 = d2i_X509(nullptr, &bp, bp_end - bp);
  372. while (num_certs > 0 && x509 != nullptr) {
  373. chain.push_back(CertRecord(x509));
  374. --num_certs;
  375. x509 = d2i_X509(nullptr, &bp, bp_end - bp);
  376. }
  377. if (num_certs != 0 || x509 != nullptr) {
  378. nout << "Extra data in signature record.\n";
  379. }
  380. }
  381. delete[] buffer;
  382. if (!chain.empty()) {
  383. pkey = X509_get_pubkey(chain[0]._cert);
  384. }
  385. if (pkey != nullptr) {
  386. EVP_MD_CTX *md_ctx;
  387. #if OPENSSL_VERSION_NUMBER >= 0x00907000L
  388. md_ctx = EVP_MD_CTX_create();
  389. #else
  390. md_ctx = new EVP_MD_CTX;
  391. #endif
  392. EVP_VerifyInit(md_ctx, EVP_sha1());
  393. // Read and hash the multifile contents, but only up till
  394. // _last_data_byte.
  395. _in.seekg(_read_offset);
  396. streampos bytes_remaining = (streampos)_last_data_byte;
  397. static const streamsize buffer_size = 4096;
  398. char buffer[buffer_size];
  399. _in.read(buffer, min((streampos)buffer_size, bytes_remaining));
  400. streamsize count = _in.gcount();
  401. while (count != 0) {
  402. assert(count <= buffer_size);
  403. EVP_VerifyUpdate(md_ctx, buffer, (size_t)count);
  404. bytes_remaining -= count;
  405. _in.read(buffer, min((streampos)buffer_size, bytes_remaining));
  406. count = _in.gcount();
  407. }
  408. assert(bytes_remaining == (streampos)0);
  409. // Now check that the signature matches the hash.
  410. int verify_result =
  411. EVP_VerifyFinal(md_ctx, (unsigned char *)sig,
  412. sig_size, pkey);
  413. if (verify_result == 1) {
  414. // The signature matches; save the certificate and its chain.
  415. _signatures.push_back(chain);
  416. }
  417. }
  418. delete[] sig;
  419. }
  420. _cert_special.clear();
  421. }