summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2019-12-01 23:13:25 +0100
committerCarl Hetherington <cth@carlh.net>2019-12-01 23:13:25 +0100
commit9a5809be580c1a12864d751a710f6783363d3de7 (patch)
tree2039fc251ed6bb5abcfe2fd6daa2fe572fac144e
parentc78523806e89e4c43015816fcd20db2549992464 (diff)
Check that KDM validity periods are safely within the validity periods
of the signing certificate chain. This does cause problems when you try to create a KDM for a certificate you just made (due to the fact that certificates always have a start-valid time of "now") but hopefully this can be fixed up in another commit.
-rw-r--r--src/decrypted_kdm.cc8
-rw-r--r--src/exceptions.cc11
-rw-r--r--src/exceptions.h13
-rw-r--r--src/local_time.h16
-rw-r--r--src/util.cc34
-rw-r--r--src/util.h3
-rw-r--r--test/encryption_test.cc2
-rw-r--r--test/kdm_test.cc57
-rw-r--r--test/round_trip_test.cc9
-rw-r--r--test/util_test.cc209
10 files changed, 357 insertions, 5 deletions
diff --git a/src/decrypted_kdm.cc b/src/decrypted_kdm.cc
index 4bd9a9d5..9468aabc 100644
--- a/src/decrypted_kdm.cc
+++ b/src/decrypted_kdm.cc
@@ -312,6 +312,14 @@ DecryptedKDM::encrypt (
{
DCP_ASSERT (!_keys.empty ());
+ BOOST_FOREACH (dcp::Certificate i, signer->leaf_to_root()) {
+ if (day_greater_than_or_equal(i.not_before(), _not_valid_before)) {
+ throw BadKDMDateError (true);
+ } else if (day_less_than_or_equal(i.not_after(), _not_valid_after)) {
+ throw BadKDMDateError (false);
+ }
+ }
+
list<pair<string, string> > key_ids;
list<string> keys;
BOOST_FOREACH (DecryptedKDMKey const & i, _keys) {
diff --git a/src/exceptions.cc b/src/exceptions.cc
index 0b8978dc..19422090 100644
--- a/src/exceptions.cc
+++ b/src/exceptions.cc
@@ -138,3 +138,14 @@ EmptyAssetPathError::EmptyAssetPathError (string id)
{
}
+
+BadKDMDateError::BadKDMDateError (bool starts_too_early)
+ : runtime_error (
+ starts_too_early ?
+ "KDM validity period starts before or close to the start of the signing certificate validity period" :
+ "KDM validity ends after or close to the end of the signing certificate's validity period"
+ )
+ , _starts_too_early (starts_too_early)
+{
+
+}
diff --git a/src/exceptions.h b/src/exceptions.h
index 1e9bd2d7..17b18eb2 100644
--- a/src/exceptions.h
+++ b/src/exceptions.h
@@ -234,6 +234,19 @@ public:
EmptyAssetPathError (std::string id);
};
+class BadKDMDateError : public std::runtime_error
+{
+public:
+ BadKDMDateError (bool starts_too_early);
+
+ bool starts_too_early () const {
+ return _starts_too_early;
+ }
+
+private:
+ bool _starts_too_early;
+};
+
}
#endif
diff --git a/src/local_time.h b/src/local_time.h
index 20658eb4..f5723783 100644
--- a/src/local_time.h
+++ b/src/local_time.h
@@ -66,6 +66,22 @@ public:
std::string date () const;
std::string time_of_day (bool with_second, bool with_millisecond) const;
+ int day () const {
+ return _day;
+ }
+
+ int month () const {
+ return _month;
+ }
+
+ int year () const {
+ return _year;
+ }
+
+ void set_year (int y) {
+ _year = y;
+ }
+
bool operator== (LocalTime const & other) const;
bool operator!= (LocalTime const & other) const;
bool operator< (LocalTime const & other) const;
diff --git a/src/util.cc b/src/util.cc
index d5b6cb9f..c6313b4c 100644
--- a/src/util.cc
+++ b/src/util.cc
@@ -376,3 +376,37 @@ dcp::indent (xmlpp::Element* element, int initial)
element->add_child_text (last, "\n" + spaces(initial));
}
}
+
+/** @return true if the day represented by \ref a is less than or
+ * equal to the one represented by \ref b, ignoring the time parts.
+ */
+bool
+dcp::day_less_than_or_equal (struct tm a, LocalTime b)
+{
+ if ((a.tm_year + 1900) != b.year()) {
+ return (a.tm_year + 1900) < b.year();
+ }
+
+ if ((a.tm_mon + 1) != b.month()) {
+ return (a.tm_mon + 1) < b.month();
+ }
+
+ return a.tm_mday <= b.day();
+}
+
+/** @return true if the day represented by \ref a is greater than or
+ * equal to the one represented by \ref b, ignoring the time parts.
+ */
+bool
+dcp::day_greater_than_or_equal (struct tm a, LocalTime b)
+{
+ if ((a.tm_year + 1900) != b.year()) {
+ return (a.tm_year + 1900) > b.year();
+ }
+
+ if ((a.tm_mon + 1) != b.month()) {
+ return (a.tm_mon + 1) > b.month();
+ }
+
+ return a.tm_mday >= b.day();
+}
diff --git a/src/util.h b/src/util.h
index 992c5a61..b2bddd5a 100644
--- a/src/util.h
+++ b/src/util.h
@@ -40,6 +40,7 @@
#include "types.h"
#include "data.h"
+#include "local_time.h"
#include <boost/shared_ptr.hpp>
#include <boost/function.hpp>
#include <boost/filesystem.hpp>
@@ -75,6 +76,8 @@ extern xmlpp::Node* find_child (xmlpp::Node const * node, std::string name);
extern std::string openjpeg_version();
extern std::string spaces (int n);
extern void indent (xmlpp::Element* element, int initial);
+extern bool day_less_than_or_equal (struct tm a, LocalTime b);
+extern bool day_greater_than_or_equal (struct tm a, LocalTime b);
}
diff --git a/test/encryption_test.cc b/test/encryption_test.cc
index 214bc263..c3590751 100644
--- a/test/encryption_test.cc
+++ b/test/encryption_test.cc
@@ -143,7 +143,7 @@ BOOST_AUTO_TEST_CASE (encryption_test)
dcp::DecryptedKDM kdm (
cpl,
key,
- dcp::LocalTime ("2013-01-01T00:00:00+00:00"),
+ dcp::LocalTime ("2016-01-01T00:00:00+00:00"),
dcp::LocalTime ("2017-01-08T00:00:00+00:00"),
"libdcp",
"test",
diff --git a/test/kdm_test.cc b/test/kdm_test.cc
index 8dced8ac..bf5c14c5 100644
--- a/test/kdm_test.cc
+++ b/test/kdm_test.cc
@@ -36,6 +36,13 @@
#include "certificate_chain.h"
#include "util.h"
#include "test.h"
+#include "cpl.h"
+#include "mono_picture_asset.h"
+#include "reel_mono_picture_asset.h"
+#include "reel.h"
+#include "file.h"
+#include "types.h"
+#include "picture_asset_writer.h"
#include <libcxml/cxml.h>
#include <libxml++/libxml++.h>
#include <boost/test/unit_test.hpp>
@@ -227,3 +234,53 @@ BOOST_AUTO_TEST_CASE (kdm_forensic_test5)
cxml::ConstNodePtr forensic = kdm_forensic_test(doc, false, optional<int>());
BOOST_CHECK (!forensic);
}
+
+/** Check that KDM validity periods are checked for being within the certificate validity */
+BOOST_AUTO_TEST_CASE (validity_period_test1)
+{
+ shared_ptr<dcp::CertificateChain> signer(new dcp::CertificateChain(dcp::file_to_string("test/data/certificate_chain")));
+ signer->set_key(dcp::file_to_string("test/data/private.key"));
+
+ shared_ptr<dcp::MonoPictureAsset> asset (new dcp::MonoPictureAsset(dcp::Fraction(24, 1), dcp::SMPTE));
+ asset->set_key (dcp::Key());
+ shared_ptr<dcp::PictureAssetWriter> writer = asset->start_write ("build/test/validity_period_test1.mxf", false);
+ dcp::File frame ("test/data/32x32_red_square.j2c");
+ writer->write (frame.data(), frame.size());
+ shared_ptr<dcp::Reel> reel(new dcp::Reel());
+ reel->add(shared_ptr<dcp::ReelPictureAsset>(new dcp::ReelMonoPictureAsset(asset, 0)));
+ shared_ptr<dcp::CPL> cpl (new dcp::CPL("test", dcp::FEATURE));
+ cpl->add(reel);
+
+ /* This certificate_chain is valid from 26/12/2012 to 24/12/2022 */
+
+ /* Inside */
+ BOOST_CHECK_NO_THROW(
+ dcp::DecryptedKDM(
+ cpl, dcp::Key(dcp::file_to_string("test/data/private.key")), dcp::LocalTime("2015-01-01T00:00:00"), dcp::LocalTime("2017-07-31T00:00:00"), "", "", ""
+ ).encrypt(signer, signer->leaf(), vector<string>(), dcp::MODIFIED_TRANSITIONAL_1, true, optional<int>())
+ );
+
+ /* Starts too early */
+ BOOST_CHECK_THROW(
+ dcp::DecryptedKDM(
+ cpl, dcp::Key(dcp::file_to_string("test/data/private.key")), dcp::LocalTime("1981-01-01T00:00:00"), dcp::LocalTime("2017-07-31T00:00:00"), "", "", ""
+ ).encrypt(signer, signer->leaf(), vector<string>(), dcp::MODIFIED_TRANSITIONAL_1, true, optional<int>()),
+ dcp::BadKDMDateError
+ );
+
+ /* Finishes too late */
+ BOOST_CHECK_THROW(
+ dcp::DecryptedKDM(
+ cpl, dcp::Key(dcp::file_to_string("test/data/private.key")), dcp::LocalTime("2015-01-01T00:00:00"), dcp::LocalTime("2035-07-31T00:00:00"), "", "", ""
+ ).encrypt(signer, signer->leaf(), vector<string>(), dcp::MODIFIED_TRANSITIONAL_1, true, optional<int>()),
+ dcp::BadKDMDateError
+ );
+
+ /* Starts too early and finishes too late */
+ BOOST_CHECK_THROW(
+ dcp::DecryptedKDM(
+ cpl, dcp::Key(dcp::file_to_string("test/data/private.key")), dcp::LocalTime("1981-01-01T00:00:00"), dcp::LocalTime("2035-07-31T00:00:00"), "", "", ""
+ ).encrypt(signer, signer->leaf(), vector<string>(), dcp::MODIFIED_TRANSITIONAL_1, true, optional<int>()),
+ dcp::BadKDMDateError
+ );
+}
diff --git a/test/round_trip_test.cc b/test/round_trip_test.cc
index f2d16333..10b7b6fe 100644
--- a/test/round_trip_test.cc
+++ b/test/round_trip_test.cc
@@ -85,12 +85,17 @@ BOOST_AUTO_TEST_CASE (round_trip_test)
reel->add (shared_ptr<dcp::ReelMonoPictureAsset> (new dcp::ReelMonoPictureAsset (asset_A, 0)));
cpl->add (reel);
+ dcp::LocalTime start;
+ start.set_year (start.year() + 1);
+ dcp::LocalTime end;
+ end.set_year (end.year() + 2);
+
/* A KDM using our certificate chain's leaf key pair */
dcp::DecryptedKDM kdm_A (
cpl,
key,
- dcp::LocalTime ("2013-01-01T00:00:00+00:00"),
- dcp::LocalTime ("2013-01-08T00:00:00+00:00"),
+ start,
+ end,
"libdcp",
"test",
"2012-07-17T04:45:18+00:00"
diff --git a/test/util_test.cc b/test/util_test.cc
index 15851ecd..d85b9b56 100644
--- a/test/util_test.cc
+++ b/test/util_test.cc
@@ -31,9 +31,10 @@
files in the program, then also delete it here.
*/
-#include <fstream>
-#include <boost/test/unit_test.hpp>
#include "util.h"
+#include "local_time.h"
+#include <boost/test/unit_test.hpp>
+#include <fstream>
using std::ifstream;
using std::string;
@@ -136,3 +137,207 @@ BOOST_AUTO_TEST_CASE (private_key_fingerprint_test)
{
BOOST_CHECK_EQUAL (dcp::private_key_fingerprint (dcp::file_to_string ("test/data/private.key")), "Jdz1bFpCcKI7R16Ccx9JHYytag0=");
}
+
+BOOST_AUTO_TEST_CASE (day_less_than_or_equal_test)
+{
+ {
+ /* equal */
+ struct tm a;
+ a.tm_mday = 5;
+ a.tm_mon = 3;
+ a.tm_year = 78;
+
+ dcp::LocalTime b ("1978-04-05T00:00:00");
+ BOOST_CHECK (day_less_than_or_equal(a, b));
+ }
+
+ {
+ /* every part of a less than b */
+ struct tm a;
+ a.tm_mday = 4;
+ a.tm_mon = 2;
+ a.tm_year = 81;
+
+ dcp::LocalTime b ("1985-05-23T00:00:00");
+ BOOST_CHECK (day_less_than_or_equal(a, b));
+ }
+
+ {
+ /* years equal, other parts less */
+ struct tm a;
+ a.tm_mday = 4;
+ a.tm_mon = 2;
+ a.tm_year = 81;
+
+ dcp::LocalTime b ("1981-05-10T00:00:00");
+ BOOST_CHECK (day_less_than_or_equal(a, b));
+ }
+
+ {
+ /* year and month equal, day less */
+ struct tm a;
+ a.tm_mday = 4;
+ a.tm_mon = 2;
+ a.tm_year = 81;
+
+ dcp::LocalTime b ("1981-03-12T00:00:00");
+ BOOST_CHECK (day_less_than_or_equal(a, b));
+ }
+
+ {
+ /* year and month equal, day less */
+ struct tm a;
+ a.tm_mday = 1;
+ a.tm_mon = 2;
+ a.tm_year = 81;
+
+ dcp::LocalTime b ("1981-03-04T00:00:00");
+ BOOST_CHECK (day_less_than_or_equal(a, b));
+ }
+
+ {
+ /* a one day later than b */
+ struct tm a;
+ a.tm_mday = 5;
+ a.tm_mon = 2;
+ a.tm_year = 81;
+
+ dcp::LocalTime b ("1981-03-04T00:00:00");
+ BOOST_CHECK (!day_less_than_or_equal(a, b));
+ }
+
+ {
+ /* year and month same, day much later */
+ struct tm a;
+ a.tm_mday = 22;
+ a.tm_mon = 2;
+ a.tm_year = 81;
+
+ dcp::LocalTime b ("1981-03-04T00:00:00");
+ BOOST_CHECK (!day_less_than_or_equal(a, b));
+ }
+
+ {
+ /* year same, month and day later */
+ struct tm a;
+ a.tm_mday = 22;
+ a.tm_mon = 5;
+ a.tm_year = 81;
+
+ dcp::LocalTime b ("1981-02-04T00:00:00");
+ BOOST_CHECK (!day_less_than_or_equal(a, b));
+ }
+
+ {
+ /* all later */
+ struct tm a;
+ a.tm_mday = 22;
+ a.tm_mon = 5;
+ a.tm_year = 99;
+
+ dcp::LocalTime b ("1981-02-04T00:00:00");
+ BOOST_CHECK (!day_less_than_or_equal(a, b));
+ }
+}
+
+BOOST_AUTO_TEST_CASE (day_greater_than_or_equal_test)
+{
+ {
+ /* equal */
+ struct tm a;
+ a.tm_mday = 5;
+ a.tm_mon = 3;
+ a.tm_year = 78;
+
+ dcp::LocalTime b ("1978-04-05T00:00:00");
+ BOOST_CHECK (day_greater_than_or_equal(a, b));
+ }
+
+ {
+ /* every part of a less than b */
+ struct tm a;
+ a.tm_mday = 4;
+ a.tm_mon = 2;
+ a.tm_year = 81;
+
+ dcp::LocalTime b ("1985-05-23T00:00:00");
+ BOOST_CHECK (!day_greater_than_or_equal(a, b));
+ }
+
+ {
+ /* years equal, other parts less */
+ struct tm a;
+ a.tm_mday = 4;
+ a.tm_mon = 2;
+ a.tm_year = 81;
+
+ dcp::LocalTime b ("1981-05-10T00:00:00");
+ BOOST_CHECK (!day_greater_than_or_equal(a, b));
+ }
+
+ {
+ /* year and month equal, day less */
+ struct tm a;
+ a.tm_mday = 4;
+ a.tm_mon = 2;
+ a.tm_year = 81;
+
+ dcp::LocalTime b ("1981-03-12T00:00:00");
+ BOOST_CHECK (!day_greater_than_or_equal(a, b));
+ }
+
+ {
+ /* year and month equal, day less */
+ struct tm a;
+ a.tm_mday = 1;
+ a.tm_mon = 2;
+ a.tm_year = 81;
+
+ dcp::LocalTime b ("1981-03-04T00:00:00");
+ BOOST_CHECK (!day_greater_than_or_equal(a, b));
+ }
+
+ {
+ /* a one day later than b */
+ struct tm a;
+ a.tm_mday = 5;
+ a.tm_mon = 2;
+ a.tm_year = 81;
+
+ dcp::LocalTime b ("1981-03-04T00:00:00");
+ BOOST_CHECK (day_greater_than_or_equal(a, b));
+ }
+
+ {
+ /* year and month same, day much later */
+ struct tm a;
+ a.tm_mday = 22;
+ a.tm_mon = 2;
+ a.tm_year = 81;
+
+ dcp::LocalTime b ("1981-03-04T00:00:00");
+ BOOST_CHECK (day_greater_than_or_equal(a, b));
+ }
+
+ {
+ /* year same, month and day later */
+ struct tm a;
+ a.tm_mday = 22;
+ a.tm_mon = 5;
+ a.tm_year = 81;
+
+ dcp::LocalTime b ("1981-02-04T00:00:00");
+ BOOST_CHECK (day_greater_than_or_equal(a, b));
+ }
+
+ {
+ /* all later */
+ struct tm a;
+ a.tm_mday = 22;
+ a.tm_mon = 5;
+ a.tm_year = 99;
+
+ dcp::LocalTime b ("1981-02-04T00:00:00");
+ BOOST_CHECK (day_greater_than_or_equal(a, b));
+ }
+}