Check for trailing data when loading certificates.
authorCarl Hetherington <cth@carlh.net>
Wed, 27 Jan 2016 21:06:26 +0000 (21:06 +0000)
committerCarl Hetherington <cth@carlh.net>
Wed, 27 Jan 2016 21:06:26 +0000 (21:06 +0000)
src/certificate.cc
src/certificate.h
test/certificates_test.cc

index 36aef7f9c375c78ba83111cf65d85781be94ccbc..fd767fa7ea78a42f6c48cccc2c99bb79d9f81127 100644 (file)
@@ -34,6 +34,7 @@
 #include <openssl/err.h>
 #include <boost/algorithm/string.hpp>
 #include <cerrno>
+#include <iostream>
 #include <algorithm>
 
 using std::list;
@@ -50,6 +51,7 @@ static string const end_certificate = "-----END CERTIFICATE-----";
 Certificate::Certificate (X509* c)
        : _certificate (c)
        , _public_key (0)
+       , _extra_data (false)
 {
 
 }
@@ -61,7 +63,7 @@ Certificate::Certificate (string cert)
        : _certificate (0)
        , _public_key (0)
 {
-       read_string (cert);
+       _extra_data = read_string (cert);
 }
 
 /** Copy constructor.
@@ -70,6 +72,7 @@ Certificate::Certificate (string cert)
 Certificate::Certificate (Certificate const & other)
        : _certificate (0)
        , _public_key (0)
+       , _extra_data (other._extra_data)
 {
        if (other._certificate) {
                read_string (other.certificate (true));
@@ -78,8 +81,9 @@ Certificate::Certificate (Certificate const & other)
 
 /** 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.
  */
-void
+bool
 Certificate::read_string (string cert)
 {
        /* Reformat cert so that it has line breaks every 64 characters.
@@ -137,6 +141,12 @@ Certificate::read_string (string cert)
        }
 
        BIO_free (bio);
+
+       line.clear ();
+       if (s.good ()) {
+               getline (s, line);
+       }
+       return !line.empty();
 }
 
 /** Destructor */
@@ -160,6 +170,7 @@ Certificate::operator= (Certificate const & other)
        _certificate = 0;
        RSA_free (_public_key);
        _public_key = 0;
+       _extra_data = other._extra_data;
 
        read_string (other.certificate (true));
 
index 6225cf31012c424b02990ae1cfb5669e6478b694..438d998069a8763f669e9f076f73c391ae25bb0e 100644 (file)
@@ -76,8 +76,12 @@ public:
 
        std::string thumbprint () const;
 
+       bool extra_data () const {
+               return _extra_data;
+       }
+
 private:
-       void read_string (std::string);
+       bool read_string (std::string);
 
        static std::string name_for_xml (X509_NAME *);
        static std::string asn_to_utf8 (ASN1_STRING *);
@@ -85,6 +89,10 @@ private:
 
        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);
index 9592ae2f6e5f919521926eccf1d234602772aaaf..9be2e7facf1847825a21c4bb129f7777c2015c7c 100644 (file)
 
 */
 
-#include <boost/test/unit_test.hpp>
 #include "certificate.h"
 #include "certificate_chain.h"
 #include "util.h"
 #include "exceptions.h"
 #include "test.h"
+#include <boost/test/unit_test.hpp>
+#include <iostream>
 
 using std::list;
 using std::string;
@@ -54,6 +55,8 @@ BOOST_AUTO_TEST_CASE (certificates1)
                "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 */
@@ -67,6 +70,8 @@ BOOST_AUTO_TEST_CASE (certificates1)
                "dnQualifier=6eat8r33US71avuQEojmH\\+bjk84=,CN=.smpte-430-2.INTERMEDIATE.NOT_FOR_PRODUCTION,OU=example.org,O=example.org"
                );
 
+       BOOST_CHECK (!i->extra_data ());
+
        ++i;
 
        /* Root */
@@ -83,6 +88,8 @@ BOOST_AUTO_TEST_CASE (certificates1)
                "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());
@@ -94,11 +101,18 @@ BOOST_AUTO_TEST_CASE (certificates2)
        {
                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 ());
        }
 
        BOOST_CHECK_THROW (dcp::Certificate (dcp::file_to_string (private_test / "no-begin.pem")), dcp::MiscError);