2 Copyright (C) 2012-2015 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.
39 #include "certificate.h"
40 #include "compose.hpp"
41 #include "exceptions.h"
43 #include "dcp_assert.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>
58 using std::stringstream;
61 static string const begin_certificate = "-----BEGIN CERTIFICATE-----";
62 static string const end_certificate = "-----END CERTIFICATE-----";
64 /** @param c X509 certificate, which this object will take ownership of */
65 Certificate::Certificate (X509* c)
73 /** Load an X509 certificate from a string.
74 * @param cert String to read from.
76 Certificate::Certificate (string cert)
80 _extra_data = read_string (cert);
84 * @param other Certificate to copy.
86 Certificate::Certificate (Certificate const & other)
89 , _extra_data (other._extra_data)
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 true if there is extra stuff after the end of the certificate, false if not.
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
107 stringstream s (cert);
113 boost::algorithm::trim (line);
114 } while (s.good() && line != begin_certificate);
116 if (line != begin_certificate) {
117 throw MiscError ("missing BEGIN line in certificate");
120 /* The base64 data */
121 bool got_end = false;
123 while (getline (s, line)) {
124 boost::algorithm::trim (line);
125 if (line == end_certificate) {
133 throw MiscError ("missing END line in certificate");
136 /* Make up the fixed version */
138 string fixed = begin_certificate + "\n";
139 while (!base64.empty ()) {
140 size_t const t = min (size_t(64), base64.length());
141 fixed += base64.substr (0, t) + "\n";
142 base64 = base64.substr (t, base64.length() - t);
145 fixed += end_certificate;
147 BIO* bio = BIO_new_mem_buf (const_cast<char *> (fixed.c_str ()), -1);
149 throw MiscError ("could not create memory BIO");
152 _certificate = PEM_read_bio_X509 (bio, 0, 0, 0);
154 throw MiscError ("could not read X509 certificate from memory BIO");
159 /* See if there are any non-blank lines after the certificate that we read */
161 while (s.good() && line.empty()) {
164 return (s.good() && !line.empty());
168 Certificate::~Certificate ()
170 X509_free (_certificate);
171 RSA_free (_public_key);
174 /** operator= for Certificate.
175 * @param other Certificate to read from.
178 Certificate::operator= (Certificate const & other)
180 if (this == &other) {
184 X509_free (_certificate);
186 RSA_free (_public_key);
188 _extra_data = other._extra_data;
190 read_string (other.certificate (true));
195 /** Return the certificate as a string.
196 * @param with_begin_end true to include the -----BEGIN CERTIFICATE--- / -----END CERTIFICATE----- markers.
197 * @return Certificate string.
200 Certificate::certificate (bool with_begin_end) const
202 DCP_ASSERT (_certificate);
204 BIO* bio = BIO_new (BIO_s_mem ());
206 throw MiscError ("could not create memory BIO");
209 PEM_write_bio_X509 (bio, _certificate);
213 long int const data_length = BIO_get_mem_data (bio, &data);
214 for (long int i = 0; i < data_length; ++i) {
220 if (!with_begin_end) {
221 boost::replace_all (s, begin_certificate + "\n", "");
222 boost::replace_all (s, "\n" + end_certificate + "\n", "");
228 /** @return Certificate's issuer, in the form
229 * dnqualifier=<dnQualififer>,CN=<commonName>,OU=<organizationalUnitName>,O=<organizationName>
230 * and with + signs escaped to \+
233 Certificate::issuer () const
235 DCP_ASSERT (_certificate);
236 return name_for_xml (X509_get_issuer_name (_certificate));
240 Certificate::asn_to_utf8 (ASN1_STRING* s)
242 unsigned char* buf = 0;
243 ASN1_STRING_to_UTF8 (&buf, s);
244 string const u (reinterpret_cast<char *> (buf));
250 Certificate::get_name_part (X509_NAME* n, int nid)
253 p = X509_NAME_get_index_by_NID (n, nid, p);
257 return asn_to_utf8 (X509_NAME_ENTRY_get_data (X509_NAME_get_entry (n, p)));
261 Certificate::name_for_xml (X509_NAME* name)
265 BIO* bio = BIO_new (BIO_s_mem ());
267 throw MiscError ("could not create memory BIO");
270 X509_NAME_print_ex (bio, name, 0, XN_FLAG_RFC2253);
271 int n = BIO_pending (bio);
272 char* result = new char[n + 1];
273 n = BIO_read (bio, result, n);
285 Certificate::subject () const
287 DCP_ASSERT (_certificate);
289 return name_for_xml (X509_get_subject_name (_certificate));
293 Certificate::subject_common_name () const
295 DCP_ASSERT (_certificate);
297 return get_name_part (X509_get_subject_name (_certificate), NID_commonName);
301 Certificate::subject_organization_name () const
303 DCP_ASSERT (_certificate);
305 return get_name_part (X509_get_subject_name (_certificate), NID_organizationName);
309 Certificate::subject_organizational_unit_name () const
311 DCP_ASSERT (_certificate);
313 return get_name_part (X509_get_subject_name (_certificate), NID_organizationalUnitName);
317 Certificate::serial () const
319 DCP_ASSERT (_certificate);
321 ASN1_INTEGER* s = X509_get_serialNumber (_certificate);
324 BIGNUM* b = ASN1_INTEGER_to_BN (s, 0);
325 char* c = BN_bn2dec (b);
335 Certificate::thumbprint () const
337 DCP_ASSERT (_certificate);
339 uint8_t buffer[8192];
341 i2d_X509_CINF (_certificate->cert_info, &p);
342 unsigned int const length = p - buffer;
343 if (length > sizeof (buffer)) {
344 throw MiscError ("buffer too small to generate thumbprint");
349 SHA1_Update (&sha, buffer, length);
351 SHA1_Final (digest, &sha);
353 char digest_base64[64];
354 return Kumu::base64encode (digest, 20, digest_base64, 64);
357 /** @return RSA public key from this Certificate. Caller must not free the returned value. */
359 Certificate::public_key () const
361 DCP_ASSERT (_certificate);
367 EVP_PKEY* key = X509_get_pubkey (_certificate);
369 throw MiscError ("could not get public key from certificate");
372 _public_key = EVP_PKEY_get1_RSA (key);
374 throw MiscError (String::compose ("could not get RSA public key (%1)", ERR_error_string (ERR_get_error(), 0)));
381 dcp::operator== (Certificate const & a, Certificate const & b)
383 return a.certificate() == b.certificate();
387 dcp::operator< (Certificate const & a, Certificate const & b)
389 return a.certificate() < b.certificate();
393 dcp::operator<< (ostream& s, Certificate const & c)
395 s << c.certificate();