X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Fcertificate.cc;h=8064e4abf0265dda905d56b0c33dde237fc7e9c5;hb=0e6a2f77c5a91fe03900d12ddb6b31a222d192e0;hp=7d80e3009a9a280c4d95d373025d598f92ae91c0;hpb=f9cba324c8160a70b108d9e5b60a4ccad6ee9be2;p=libdcp.git diff --git a/src/certificate.cc b/src/certificate.cc index 7d80e300..8064e4ab 100644 --- a/src/certificate.cc +++ b/src/certificate.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2015 Carl Hetherington + Copyright (C) 2012-2016 Carl Hetherington This file is part of libdcp. @@ -16,18 +16,31 @@ You should have received a copy of the GNU General Public License along with libdcp. If not, see . + In addition, as a special exception, the copyright holders give + permission to link the code of portions of this program with the + OpenSSL library under certain conditions as described in each + individual source file, and distribute linked combinations + including the two. + + You must obey the GNU General Public License in all respects + for all of the code used other than OpenSSL. If you modify + file(s) with this exception, you may extend this exception to your + version of the file(s), but you are not obligated to do so. If you + do not wish to do so, delete this exception statement from your + version. If you delete this exception statement from all source + files in the program, then also delete it here. */ /** @file src/certificate.cc * @brief Certificate class. */ -#include "KM_util.h" #include "certificate.h" #include "compose.hpp" #include "exceptions.h" #include "util.h" #include "dcp_assert.h" +#include #include #include #include @@ -42,7 +55,6 @@ 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-----"; @@ -52,7 +64,6 @@ static string const end_certificate = "-----END CERTIFICATE-----"; Certificate::Certificate (X509* c) : _certificate (c) , _public_key (0) - , _extra_data (false) { } @@ -64,7 +75,10 @@ Certificate::Certificate (string cert) : _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. @@ -73,7 +87,6 @@ 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)); @@ -82,44 +95,65 @@ 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. + * @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. See http://comments.gmane.org/gmane.comp.encryption.openssl.user/55593 */ - stringstream s (cert); + list lines; string line; - /* BEGIN */ - do { - getline (s, line); + for (size_t i = 0; i < cert.length(); ++i) { + line += cert[i]; + if (cert[i] == '\r' || cert[i] == '\n') { + boost::algorithm::trim (line); + lines.push_back (line); + line = ""; + } + } + + if (!line.empty()) { boost::algorithm::trim (line); - } while (s.good() && line != begin_certificate); + lines.push_back (line); + } + + list::iterator i = lines.begin (); - if (line != begin_certificate) { + /* BEGIN */ + while (i != lines.end() && *i != begin_certificate) { + ++i; + } + + if (i == lines.end()) { throw MiscError ("missing BEGIN line in certificate"); } + /* Skip over the BEGIN line */ + ++i; + /* The base64 data */ bool got_end = false; string base64 = ""; - while (getline (s, line)) { - boost::algorithm::trim (line); - if (line == end_certificate) { + while (i != lines.end()) { + if (*i == end_certificate) { got_end = true; break; } - base64 += line; + base64 += *i; + ++i; } if (!got_end) { throw MiscError ("missing END line in certificate"); } + /* Skip over the END line */ + ++i; + /* Make up the fixed version */ string fixed = begin_certificate + "\n"; @@ -143,12 +177,16 @@ Certificate::read_string (string cert) BIO_free (bio); - /* See if there are any non-blank lines after the certificate that we read */ - line.clear (); - while (s.good() && line.empty()) { - getline (s, line); + string extra; + + while (i != lines.end()) { + if (!i->empty()) { + extra += *i + "\n"; + } + ++i; } - return (s.good() && !line.empty()); + + return extra; } /** Destructor */ @@ -172,7 +210,6 @@ Certificate::operator= (Certificate const & other) _certificate = 0; RSA_free (_public_key); _public_key = 0; - _extra_data = other._extra_data; read_string (other.certificate (true)); @@ -318,6 +355,7 @@ Certificate::serial () const return st; } +/** @return thumbprint of the to-be-signed portion of this certificate */ string Certificate::thumbprint () const { @@ -325,7 +363,13 @@ Certificate::thumbprint () const uint8_t buffer[8192]; uint8_t* p = buffer; + +#if OPENSSL_VERSION_NUMBER > 0x10100000L +#warning "Using new OpenSSL API" + i2d_re_X509_tbs(_certificate, &p); +#else i2d_X509_CINF (_certificate->cert_info, &p); +#endif unsigned int const length = p - buffer; if (length > sizeof (buffer)) { throw MiscError ("buffer too small to generate thumbprint"); @@ -364,6 +408,22 @@ Certificate::public_key () const return _public_key; } +static bool string_is_utf8 (X509_NAME* n, int nid) +{ + int p = -1; + p = X509_NAME_get_index_by_NID (n, nid, p); + return p != -1 && X509_NAME_ENTRY_get_data(X509_NAME_get_entry(n, p))->type == V_ASN1_UTF8STRING; +} + +bool +Certificate::has_utf8_strings () const +{ + X509_NAME* n = X509_get_subject_name (_certificate); + return string_is_utf8(n, NID_commonName) || + string_is_utf8(n, NID_organizationName) || + string_is_utf8(n, NID_organizationalUnitName); +} + bool dcp::operator== (Certificate const & a, Certificate const & b) {