/*
- Copyright (C) 2012-2015 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2016 Carl Hetherington <cth@carlh.net>
This file is part of libdcp.
Certificate::Certificate (X509* c)
: _certificate (c)
, _public_key (0)
- , _extra_data (false)
{
}
: _certificate (0)
, _public_key (0)
{
- _extra_data = read_string (cert);
+ string const s = read_string (cert);
+ if (!s.empty ()) {
+ throw MiscError ("unexpected data after certificate");
+ }
}
/** Copy constructor.
Certificate::Certificate (Certificate const & other)
: _certificate (0)
, _public_key (0)
- , _extra_data (other._extra_data)
{
if (other._certificate) {
read_string (other.certificate (true));
/** Read a certificate from a string.
* @param cert String to read.
- * @return true if there is extra stuff after the end of the certificate, false if not.
+ * @return remaining part of the input string after the certificate which was read.
*/
-bool
+string
Certificate::read_string (string cert)
{
/* Reformat cert so that it has line breaks every 64 characters.
BIO_free (bio);
- /* See if there are any non-blank lines after the certificate that we read */
- while (i != lines.end() && i->empty()) {
+ string extra;
+
+ while (i != lines.end()) {
+ if (!i->empty()) {
+ extra += *i + "\n";
+ }
++i;
}
- return i != lines.end();
+
+ return extra;
}
/** Destructor */
_certificate = 0;
RSA_free (_public_key);
_public_key = 0;
- _extra_data = other._extra_data;
read_string (other.certificate (true));
/*
- Copyright (C) 2012-2015 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2016 Carl Hetherington <cth@carlh.net>
This file is part of libdcp.
Certificate ()
: _certificate (0)
, _public_key (0)
- , _extra_data (false)
{}
explicit Certificate (std::string);
Certificate& operator= (Certificate const &);
+ std::string read_string (std::string);
+
std::string certificate (bool with_begin_end = false) const;
std::string serial () const;
std::string thumbprint () const;
- bool extra_data () const {
- return _extra_data;
- }
-
private:
- bool read_string (std::string);
static std::string name_for_xml (X509_NAME *);
static std::string asn_to_utf8 (ASN1_STRING *);
X509* _certificate;
mutable RSA* _public_key;
- /** true if extra data was found when this certificate was read
- from a string.
- */
- bool _extra_data;
};
bool operator== (Certificate const & a, Certificate const & b);
#include <boost/algorithm/string.hpp>
#include <boost/foreach.hpp>
#include <fstream>
+#include <iostream>
using std::string;
using std::ofstream;
boost::filesystem::remove_all (directory);
}
+CertificateChain::CertificateChain (string s)
+{
+ while (true) {
+ try {
+ Certificate c;
+ s = c.read_string (s);
+ _certificates.push_back (c);
+ } catch (MiscError& e) {
+ /* Failed to read a certificate, just stop */
+ break;
+ }
+ }
+
+ if (!attempt_reorder ()) {
+ throw MiscError ("could not find certificate chain order");
+ }
+}
+
/** @return Root certificate */
Certificate
CertificateChain::root () const
std::string leaf_common_name = "CS.smpte-430-2.LEAF.NOT_FOR_PRODUCTION"
);
+ explicit CertificateChain (std::string);
+
void add (Certificate c);
void remove (Certificate c);
void remove (int);
"dnQualifier=QFVlym7fuql6bPOnY38aaO1ZPW4=,CN=CS.smpte-430-2.LEAF.NOT_FOR_PRODUCTION,OU=example.org,O=example.org"
);
- BOOST_CHECK (!c.leaf().extra_data ());
-
++i;
/* Intermediate */
"dnQualifier=6eat8r33US71avuQEojmH\\+bjk84=,CN=.smpte-430-2.INTERMEDIATE.NOT_FOR_PRODUCTION,OU=example.org,O=example.org"
);
- BOOST_CHECK (!i->extra_data ());
-
++i;
/* Root */
"dnQualifier=DCnRdHFbcv4ANVUq2\\+wMVALFSec=,CN=.smpte-430-2.ROOT.NOT_FOR_PRODUCTION,OU=example.org,O=example.org"
);
- BOOST_CHECK (!c.root().extra_data ());
-
/* Check that reconstruction from a string works */
dcp::Certificate test (c.root().certificate (true));
BOOST_CHECK_EQUAL (test.certificate(), c.root().certificate());
{
dcp::Certificate c (dcp::file_to_string (private_test / "CA.GDC-TECH.COM_SA2100_A14903.crt.crt"));
BOOST_CHECK_EQUAL (c.certificate(true), dcp::file_to_string (private_test / "CA.GDC-TECH.COM_SA2100_A14903.crt.crt.reformatted"));
- BOOST_CHECK (!c.extra_data ());
}
{
dcp::Certificate c (dcp::file_to_string (private_test / "usl-cert.pem"));
BOOST_CHECK_EQUAL (c.certificate(true), dcp::file_to_string (private_test / "usl-cert.pem.trimmed"));
- BOOST_CHECK (!c.extra_data ());
}
{
- dcp::Certificate c (dcp::file_to_string (private_test / "chain.pem"));
- BOOST_CHECK (c.extra_data ());
+ /* This is a chain, not an individual certificate, so it should throw an exception */
+ BOOST_CHECK_THROW (dcp::Certificate (dcp::file_to_string (private_test / "chain.pem")), dcp::MiscError);
}
BOOST_CHECK_THROW (dcp::Certificate (dcp::file_to_string (private_test / "no-begin.pem")), dcp::MiscError);
BOOST_CHECK (chain.valid ());
/* Put in an unrelated key and the signer should no longer be valid */
- dcp::CertificateChain another_chain ("openssl");
+ dcp::CertificateChain another_chain (boost::filesystem::path ("openssl"));
chain.set_key (another_chain.key().get ());
BOOST_CHECK (!chain.valid ());
}
+
+/** Check reading of a certificate chain from a string */
+BOOST_AUTO_TEST_CASE (certificate_chain_from_string)
+{
+ dcp::CertificateChain a (dcp::file_to_string (private_test / "chain.pem"));
+ BOOST_CHECK_EQUAL (a.root_to_leaf().size(), 3);
+
+ dcp::CertificateChain b (dcp::file_to_string ("test/ref/crypt/leaf.signed.pem"));
+ BOOST_CHECK_EQUAL (b.root_to_leaf().size(), 1);
+}
/** Build an encrypted picture asset and a KDM for it and check that the KDM can be decrypted */
BOOST_AUTO_TEST_CASE (round_trip_test)
{
- shared_ptr<dcp::CertificateChain> signer (new dcp::CertificateChain ("openssl"));
+ shared_ptr<dcp::CertificateChain> signer (new dcp::CertificateChain (boost::filesystem::path ("openssl")));
boost::filesystem::path work_dir = "build/test/round_trip_test";
boost::filesystem::create_directory (work_dir);