Cope with certificate files that have no line breaks.
authorCarl Hetherington <cth@carlh.net>
Fri, 13 Nov 2015 15:30:22 +0000 (15:30 +0000)
committerCarl Hetherington <cth@carlh.net>
Fri, 13 Nov 2015 15:30:22 +0000 (15:30 +0000)
src/certificate.cc
test/certificates_test.cc

index 3eb6e76b0d1daad51a4f365480d765bed4545829..72c53610c54bef9f8b5a78b189c5e272186d2acd 100644 (file)
 using std::list;
 using std::string;
 using std::ostream;
+using std::min;
+using std::stringstream;
 using namespace dcp;
 
+static string const begin_certificate = "-----BEGIN CERTIFICATE-----";
+static string const end_certificate = "-----END CERTIFICATE-----";
+
 /** @param c X509 certificate, which this object will take ownership of */
 Certificate::Certificate (X509* c)
        : _certificate (c)
@@ -75,7 +80,48 @@ Certificate::Certificate (Certificate const & other)
 void
 Certificate::read_string (string cert)
 {
-       BIO* bio = BIO_new_mem_buf (const_cast<char *> (cert.c_str ()), -1);
+       /* Reformat cert so that it has line breaks every 64 characters.
+          See http://comments.gmane.org/gmane.comp.encryption.openssl.user/55593
+       */
+
+       stringstream s (cert);
+       string line;
+
+       /* BEGIN */
+       getline (s, line);
+       boost::algorithm::trim (line);
+       if (line != begin_certificate) {
+               throw MiscError ("missing BEGIN line in certificate");
+       }
+
+       /* The base64 data */
+       bool got_end = false;
+       string base64 = "";
+       while (getline (s, line)) {
+               boost::algorithm::trim (line);
+               if (line == end_certificate) {
+                       got_end = true;
+                       break;
+               }
+               base64 += line;
+       }
+
+       if (!got_end) {
+               throw MiscError ("missing END line in certificate");
+       }
+
+       /* Make up the fixed version */
+
+       string fixed = begin_certificate + "\n";
+       while (!base64.empty ()) {
+               size_t const t = min (size_t(64), base64.length());
+               fixed += base64.substr (0, t) + "\n";
+               base64 = base64.substr (t, base64.length() - t);
+       }
+
+       fixed += end_certificate;
+
+       BIO* bio = BIO_new_mem_buf (const_cast<char *> (fixed.c_str ()), -1);
        if (!bio) {
                throw MiscError ("could not create memory BIO");
        }
@@ -141,8 +187,8 @@ Certificate::certificate (bool with_begin_end) const
        BIO_free (bio);
 
        if (!with_begin_end) {
-               boost::replace_all (s, "-----BEGIN CERTIFICATE-----\n", "");
-               boost::replace_all (s, "\n-----END CERTIFICATE-----\n", "");
+               boost::replace_all (s, begin_certificate + "\n", "");
+               boost::replace_all (s, "\n" + end_certificate + "\n", "");
        }
 
        return s;
index 166ebb2d8057ac5a74b1b94da5bf5e5806253d8b..a78c88d6dcc17af84937127483e7b8ed09e62359 100644 (file)
 #include "certificate.h"
 #include "certificate_chain.h"
 #include "util.h"
+#include "exceptions.h"
+#include "test.h"
 
 using std::list;
 using std::string;
 using boost::shared_ptr;
 
 /** Check that loading certificates from files via strings works */
-BOOST_AUTO_TEST_CASE (certificates)
+BOOST_AUTO_TEST_CASE (certificates1)
 {
        dcp::CertificateChain c;
 
@@ -86,6 +88,15 @@ BOOST_AUTO_TEST_CASE (certificates)
        BOOST_CHECK_EQUAL (test.certificate(), c.root().certificate());
 }
 
+/** Check some more certificate-from-strings */
+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_THROW (dcp::Certificate ("foo"), dcp::MiscError);
+}
+
 /** Check that dcp::CertificateChain::valid() and ::attempt_reorder() basically work */
 BOOST_AUTO_TEST_CASE (certificates_validation)
 {