}
+bool
+pkl_has_encrypted_assets (shared_ptr<DCP> dcp, shared_ptr<PKL> pkl)
+{
+ vector<string> encrypted;
+ for (auto i: dcp->cpls()) {
+ for (auto j: i->reel_mxfs()) {
+ if (j->asset_ref().resolved()) {
+ /* It's a bit surprising / broken but Interop subtitle assets are represented
+ * in reels by ReelSubtitleAsset which inherits ReelMXF, so it's possible for
+ * ReelMXFs to have assets which are not MXFs.
+ */
+ if (auto asset = dynamic_pointer_cast<MXF>(j->asset_ref().asset())) {
+ if (asset->encrypted()) {
+ encrypted.push_back(j->asset_ref().id());
+ }
+ }
+ }
+ }
+ }
+
+ for (auto i: pkl->asset_list()) {
+ if (find(encrypted.begin(), encrypted.end(), i->id()) != encrypted.end()) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
vector<VerificationNote>
dcp::verify (
vector<boost::filesystem::path> directories,
for (auto pkl: dcp->pkls()) {
stage ("Checking PKL", pkl->file());
validate_xml (pkl->file().get(), xsd_dtd_directory, notes);
+ if (pkl_has_encrypted_assets(dcp, pkl)) {
+ cxml::Document doc ("PackingList");
+ doc.read_file (pkl->file().get());
+ if (!doc.optional_node_child("Signature")) {
+ notes.push_back ({VerificationNote::VERIFY_BV21_ERROR, VerificationNote::PKL_WITH_ENCRYPTED_CONTENT_NOT_SIGNED, pkl->file().get()});
+ }
+ }
}
if (dcp->asset_map_path()) {
return String::compose("The <ExtensionMetadata> is malformed in some way: %1", note.note().get());
case dcp::VerificationNote::CPL_WITH_ENCRYPTED_CONTENT_NOT_SIGNED:
return String::compose("The CPL %1, which has encrypted content, is not signed", note.file()->filename());
+ case dcp::VerificationNote::PKL_WITH_ENCRYPTED_CONTENT_NOT_SIGNED:
+ return String::compose("The PKL %1, which has encrypted content, is not signed", note.file()->filename());
case dcp::VerificationNote::PKL_ANNOTATION_TEXT_DOES_NOT_MATCH_CPL_CONTENT_TITLE_TEXT:
return String::compose("The PKL %1 has only one CPL but its <AnnotationText> does not match the CPL's <ContentTitleText>", note.file()->filename());
}
INVALID_EXTENSION_METADATA,
/** CPLs containing encrypted content must be signed Bv2.1_8.7 */
CPL_WITH_ENCRYPTED_CONTENT_NOT_SIGNED,
+ /** PKLs containing encrypted content must be signed Bv2.1_8.7 */
+ PKL_WITH_ENCRYPTED_CONTENT_NOT_SIGNED,
/** If a PKL has one CPL its <ContentTitleText> must be the same as the PKL's <AnnotationText> */
PKL_ANNOTATION_TEXT_DOES_NOT_MATCH_CPL_CONTENT_TITLE_TEXT
};
check_verify_result (vector<boost::filesystem::path> dir, vector<dcp::VerificationNote> test_notes)
{
auto notes = dcp::verify ({dir}, &stage, &progress, xsd_test);
+ dump_notes (notes);
BOOST_REQUIRE_EQUAL (notes.size(), test_notes.size());
}
});
}
+
+BOOST_AUTO_TEST_CASE (verify_encrypted_pkl_is_signed)
+{
+ boost::filesystem::path dir = "build/test/verify_encrypted_pkl_is_signed";
+ prepare_directory (dir);
+ for (auto i: boost::filesystem::directory_iterator("test/ref/DCP/encryption_test")) {
+ boost::filesystem::copy_file (i.path(), dir / i.path().filename());
+ }
+
+ {
+ Editor e (dir / "pkl_93182bd2-b1e8-41a3-b5c8-6e6564273bff.xml");
+ e.delete_lines ("<dsig:Signature", "</dsig:Signature>");
+ }
+
+ check_verify_result (
+ {dir},
+ {
+ { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::PKL_ANNOTATION_TEXT_DOES_NOT_MATCH_CPL_CONTENT_TITLE_TEXT },
+ { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::MISSING_FFEC_IN_FEATURE },
+ { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::MISSING_FFMC_IN_FEATURE },
+ { dcp::VerificationNote::VERIFY_WARNING, dcp::VerificationNote::MISSING_FFOC },
+ { dcp::VerificationNote::VERIFY_WARNING, dcp::VerificationNote::MISSING_LFOC },
+ { dcp::VerificationNote::VERIFY_WARNING, dcp::VerificationNote::MISSING_CPL_METADATA },
+ { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::PKL_WITH_ENCRYPTED_CONTENT_NOT_SIGNED }
+ });
+}
+
+
+BOOST_AUTO_TEST_CASE (verify_unencrypted_pkl_can_be_unsigned)
+{
+ boost::filesystem::path dir = "build/test/verify_unencrypted_pkl_can_be_unsigned";
+ prepare_directory (dir);
+ for (auto i: boost::filesystem::directory_iterator("test/ref/DCP/dcp_test1")) {
+ boost::filesystem::copy_file (i.path(), dir / i.path().filename());
+ }
+
+ {
+ Editor e (dir / "pkl_2b9b857f-ab4a-440e-a313-1ace0f1cfc95.xml");
+ e.delete_lines ("<dsig:Signature", "</dsig:Signature>");
+ }
+
+ check_verify_result ({dir}, {});
+}
+