2 Copyright (C) 2012-2016 Carl Hetherington <cth@carlh.net>
4 This file is part of libdcp.
6 libdcp is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 libdcp is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with libdcp. If not, see <http://www.gnu.org/licenses/>.
19 In addition, as a special exception, the copyright holders give
20 permission to link the code of portions of this program with the
21 OpenSSL library under certain conditions as described in each
22 individual source file, and distribute linked combinations
25 You must obey the GNU General Public License in all respects
26 for all of the code used other than OpenSSL. If you modify
27 file(s) with this exception, you may extend this exception to your
28 version of the file(s), but you are not obligated to do so. If you
29 do not wish to do so, delete this exception statement from your
30 version. If you delete this exception statement from all source
31 files in the program, then also delete it here.
34 /** @file src/certificate.cc
35 * @brief Certificate class.
38 #include "certificate.h"
39 #include "compose.hpp"
40 #include "exceptions.h"
42 #include "dcp_assert.h"
43 #include <asdcp/KM_util.h>
44 #include <libxml++/nodes/element.h>
45 #include <openssl/x509.h>
46 #include <openssl/ssl.h>
47 #include <openssl/asn1.h>
48 #include <openssl/err.h>
49 #include <boost/algorithm/string.hpp>
60 static string const begin_certificate = "-----BEGIN CERTIFICATE-----";
61 static string const end_certificate = "-----END CERTIFICATE-----";
63 /** @param c X509 certificate, which this object will take ownership of */
64 Certificate::Certificate (X509* c)
71 /** Load an X509 certificate from a string.
72 * @param cert String to read from.
74 Certificate::Certificate (string cert)
78 string const s = read_string (cert);
80 throw MiscError ("unexpected data after certificate");
85 * @param other Certificate to copy.
87 Certificate::Certificate (Certificate const & other)
91 if (other._certificate) {
92 read_string (other.certificate (true));
96 /** Read a certificate from a string.
97 * @param cert String to read.
98 * @return remaining part of the input string after the certificate which was read.
101 Certificate::read_string (string cert)
103 /* Reformat cert so that it has line breaks every 64 characters.
104 See http://comments.gmane.org/gmane.comp.encryption.openssl.user/55593
110 for (size_t i = 0; i < cert.length(); ++i) {
112 if (cert[i] == '\r' || cert[i] == '\n') {
113 boost::algorithm::trim (line);
114 lines.push_back (line);
120 boost::algorithm::trim (line);
121 lines.push_back (line);
124 list<string>::iterator i = lines.begin ();
127 while (i != lines.end() && *i != begin_certificate) {
131 if (i == lines.end()) {
132 throw MiscError ("missing BEGIN line in certificate");
135 /* Skip over the BEGIN line */
138 /* The base64 data */
139 bool got_end = false;
141 while (i != lines.end()) {
142 if (*i == end_certificate) {
151 throw MiscError ("missing END line in certificate");
154 /* Skip over the END line */
157 /* Make up the fixed version */
159 string fixed = begin_certificate + "\n";
160 while (!base64.empty ()) {
161 size_t const t = min (size_t(64), base64.length());
162 fixed += base64.substr (0, t) + "\n";
163 base64 = base64.substr (t, base64.length() - t);
166 fixed += end_certificate;
168 BIO* bio = BIO_new_mem_buf (const_cast<char *> (fixed.c_str ()), -1);
170 throw MiscError ("could not create memory BIO");
173 _certificate = PEM_read_bio_X509 (bio, 0, 0, 0);
175 throw MiscError ("could not read X509 certificate from memory BIO");
182 while (i != lines.end()) {
193 Certificate::~Certificate ()
195 X509_free (_certificate);
196 RSA_free (_public_key);
199 /** operator= for Certificate.
200 * @param other Certificate to read from.
203 Certificate::operator= (Certificate const & other)
205 if (this == &other) {
209 X509_free (_certificate);
211 RSA_free (_public_key);
214 read_string (other.certificate (true));
219 /** Return the certificate as a string.
220 * @param with_begin_end true to include the -----BEGIN CERTIFICATE--- / -----END CERTIFICATE----- markers.
221 * @return Certificate string.
224 Certificate::certificate (bool with_begin_end) const
226 DCP_ASSERT (_certificate);
228 BIO* bio = BIO_new (BIO_s_mem ());
230 throw MiscError ("could not create memory BIO");
233 PEM_write_bio_X509 (bio, _certificate);
237 long int const data_length = BIO_get_mem_data (bio, &data);
238 for (long int i = 0; i < data_length; ++i) {
244 if (!with_begin_end) {
245 boost::replace_all (s, begin_certificate + "\n", "");
246 boost::replace_all (s, "\n" + end_certificate + "\n", "");
252 /** @return Certificate's issuer, in the form
253 * dnqualifier=<dnQualififer>,CN=<commonName>,OU=<organizationalUnitName>,O=<organizationName>
254 * and with + signs escaped to \+
257 Certificate::issuer () const
259 DCP_ASSERT (_certificate);
260 return name_for_xml (X509_get_issuer_name (_certificate));
264 Certificate::asn_to_utf8 (ASN1_STRING* s)
266 unsigned char* buf = 0;
267 ASN1_STRING_to_UTF8 (&buf, s);
268 string const u (reinterpret_cast<char *> (buf));
274 Certificate::get_name_part (X509_NAME* n, int nid)
277 p = X509_NAME_get_index_by_NID (n, nid, p);
281 return asn_to_utf8 (X509_NAME_ENTRY_get_data (X509_NAME_get_entry (n, p)));
285 Certificate::name_for_xml (X509_NAME* name)
289 BIO* bio = BIO_new (BIO_s_mem ());
291 throw MiscError ("could not create memory BIO");
294 X509_NAME_print_ex (bio, name, 0, XN_FLAG_RFC2253);
295 int n = BIO_pending (bio);
296 char* result = new char[n + 1];
297 n = BIO_read (bio, result, n);
309 Certificate::subject () const
311 DCP_ASSERT (_certificate);
313 return name_for_xml (X509_get_subject_name (_certificate));
317 Certificate::subject_common_name () const
319 DCP_ASSERT (_certificate);
321 return get_name_part (X509_get_subject_name (_certificate), NID_commonName);
325 Certificate::subject_organization_name () const
327 DCP_ASSERT (_certificate);
329 return get_name_part (X509_get_subject_name (_certificate), NID_organizationName);
333 Certificate::subject_organizational_unit_name () const
335 DCP_ASSERT (_certificate);
337 return get_name_part (X509_get_subject_name (_certificate), NID_organizationalUnitName);
341 Certificate::serial () const
343 DCP_ASSERT (_certificate);
345 ASN1_INTEGER* s = X509_get_serialNumber (_certificate);
348 BIGNUM* b = ASN1_INTEGER_to_BN (s, 0);
349 char* c = BN_bn2dec (b);
358 /** @return thumbprint of the to-be-signed portion of this certificate */
360 Certificate::thumbprint () const
362 DCP_ASSERT (_certificate);
364 uint8_t buffer[8192];
367 #if OPENSSL_VERSION_NUMBER > 0x10100000L
368 i2d_re_X509_tbs(_certificate, &p);
370 i2d_X509_CINF (_certificate->cert_info, &p);
372 unsigned int const length = p - buffer;
373 if (length > sizeof (buffer)) {
374 throw MiscError ("buffer too small to generate thumbprint");
379 SHA1_Update (&sha, buffer, length);
381 SHA1_Final (digest, &sha);
383 char digest_base64[64];
384 return Kumu::base64encode (digest, 20, digest_base64, 64);
387 /** @return RSA public key from this Certificate. Caller must not free the returned value. */
389 Certificate::public_key () const
391 DCP_ASSERT (_certificate);
397 EVP_PKEY* key = X509_get_pubkey (_certificate);
399 throw MiscError ("could not get public key from certificate");
402 _public_key = EVP_PKEY_get1_RSA (key);
404 throw MiscError (String::compose ("could not get RSA public key (%1)", ERR_error_string (ERR_get_error(), 0)));
410 static bool string_is_utf8 (X509_NAME* n, int nid)
413 p = X509_NAME_get_index_by_NID (n, nid, p);
414 return p != -1 && X509_NAME_ENTRY_get_data(X509_NAME_get_entry(n, p))->type == V_ASN1_UTF8STRING;
418 Certificate::has_utf8_strings () const
420 X509_NAME* n = X509_get_subject_name (_certificate);
421 return string_is_utf8(n, NID_commonName) ||
422 string_is_utf8(n, NID_organizationName) ||
423 string_is_utf8(n, NID_organizationalUnitName);
427 dcp::operator== (Certificate const & a, Certificate const & b)
429 return a.certificate() == b.certificate();
433 dcp::operator< (Certificate const & a, Certificate const & b)
435 return a.certificate() < b.certificate();
439 dcp::operator<< (ostream& s, Certificate const & c)
441 s << c.certificate();