Merge branch '1.0' of git.carlh.net:git/libdcp into 1.0
[libdcp.git] / src / certificate.cc
1 /*
2     Copyright (C) 2012-2015 Carl Hetherington <cth@carlh.net>
3
4     This file is part of libdcp.
5
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.
10
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.
15
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/>.
18
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
23     including the two.
24
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.
32 */
33
34 /** @file  src/certificate.cc
35  *  @brief Certificate class.
36  */
37
38 #include "certificate.h"
39 #include "compose.hpp"
40 #include "exceptions.h"
41 #include "util.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>
50 #include <cerrno>
51 #include <iostream>
52 #include <algorithm>
53
54 using std::list;
55 using std::string;
56 using std::ostream;
57 using std::min;
58 using namespace dcp;
59
60 static string const begin_certificate = "-----BEGIN CERTIFICATE-----";
61 static string const end_certificate = "-----END CERTIFICATE-----";
62
63 /** @param c X509 certificate, which this object will take ownership of */
64 Certificate::Certificate (X509* c)
65         : _certificate (c)
66         , _public_key (0)
67         , _extra_data (false)
68 {
69
70 }
71
72 /** Load an X509 certificate from a string.
73  *  @param cert String to read from.
74  */
75 Certificate::Certificate (string cert)
76         : _certificate (0)
77         , _public_key (0)
78 {
79         _extra_data = read_string (cert);
80 }
81
82 /** Copy constructor.
83  *  @param other Certificate to copy.
84  */
85 Certificate::Certificate (Certificate const & other)
86         : _certificate (0)
87         , _public_key (0)
88         , _extra_data (other._extra_data)
89 {
90         if (other._certificate) {
91                 read_string (other.certificate (true));
92         }
93 }
94
95 /** Read a certificate from a string.
96  *  @param cert String to read.
97  *  @return true if there is extra stuff after the end of the certificate, false if not.
98  */
99 bool
100 Certificate::read_string (string cert)
101 {
102         /* Reformat cert so that it has line breaks every 64 characters.
103            See http://comments.gmane.org/gmane.comp.encryption.openssl.user/55593
104         */
105
106         locked_stringstream s (cert);
107         string line;
108
109         /* BEGIN */
110         do {
111                 getline (s, line);
112                 boost::algorithm::trim (line);
113         } while (s.good() && line != begin_certificate);
114
115         if (line != begin_certificate) {
116                 throw MiscError ("missing BEGIN line in certificate");
117         }
118
119         /* The base64 data */
120         bool got_end = false;
121         string base64 = "";
122         while (getline (s, line)) {
123                 boost::algorithm::trim (line);
124                 if (line == end_certificate) {
125                         got_end = true;
126                         break;
127                 }
128                 base64 += line;
129         }
130
131         if (!got_end) {
132                 throw MiscError ("missing END line in certificate");
133         }
134
135         /* Make up the fixed version */
136
137         string fixed = begin_certificate + "\n";
138         while (!base64.empty ()) {
139                 size_t const t = min (size_t(64), base64.length());
140                 fixed += base64.substr (0, t) + "\n";
141                 base64 = base64.substr (t, base64.length() - t);
142         }
143
144         fixed += end_certificate;
145
146         BIO* bio = BIO_new_mem_buf (const_cast<char *> (fixed.c_str ()), -1);
147         if (!bio) {
148                 throw MiscError ("could not create memory BIO");
149         }
150
151         _certificate = PEM_read_bio_X509 (bio, 0, 0, 0);
152         if (!_certificate) {
153                 throw MiscError ("could not read X509 certificate from memory BIO");
154         }
155
156         BIO_free (bio);
157
158         /* See if there are any non-blank lines after the certificate that we read */
159         line.clear ();
160         while (s.good() && line.empty()) {
161                 getline (s, line);
162         }
163         return (s.good() && !line.empty());
164 }
165
166 /** Destructor */
167 Certificate::~Certificate ()
168 {
169         X509_free (_certificate);
170         RSA_free (_public_key);
171 }
172
173 /** operator= for Certificate.
174  *  @param other Certificate to read from.
175  */
176 Certificate &
177 Certificate::operator= (Certificate const & other)
178 {
179         if (this == &other) {
180                 return *this;
181         }
182
183         X509_free (_certificate);
184         _certificate = 0;
185         RSA_free (_public_key);
186         _public_key = 0;
187         _extra_data = other._extra_data;
188
189         read_string (other.certificate (true));
190
191         return *this;
192 }
193
194 /** Return the certificate as a string.
195  *  @param with_begin_end true to include the -----BEGIN CERTIFICATE--- / -----END CERTIFICATE----- markers.
196  *  @return Certificate string.
197  */
198 string
199 Certificate::certificate (bool with_begin_end) const
200 {
201         DCP_ASSERT (_certificate);
202
203         BIO* bio = BIO_new (BIO_s_mem ());
204         if (!bio) {
205                 throw MiscError ("could not create memory BIO");
206         }
207
208         PEM_write_bio_X509 (bio, _certificate);
209
210         string s;
211         char* data;
212         long int const data_length = BIO_get_mem_data (bio, &data);
213         for (long int i = 0; i < data_length; ++i) {
214                 s += data[i];
215         }
216
217         BIO_free (bio);
218
219         if (!with_begin_end) {
220                 boost::replace_all (s, begin_certificate + "\n", "");
221                 boost::replace_all (s, "\n" + end_certificate + "\n", "");
222         }
223
224         return s;
225 }
226
227 /** @return Certificate's issuer, in the form
228  *  dnqualifier=&lt;dnQualififer&gt;,CN=&lt;commonName&gt;,OU=&lt;organizationalUnitName&gt,O=&lt;organizationName&gt;
229  *  and with + signs escaped to \+
230  */
231 string
232 Certificate::issuer () const
233 {
234         DCP_ASSERT (_certificate);
235         return name_for_xml (X509_get_issuer_name (_certificate));
236 }
237
238 string
239 Certificate::asn_to_utf8 (ASN1_STRING* s)
240 {
241         unsigned char* buf = 0;
242         ASN1_STRING_to_UTF8 (&buf, s);
243         string const u (reinterpret_cast<char *> (buf));
244         OPENSSL_free (buf);
245         return u;
246 }
247
248 string
249 Certificate::get_name_part (X509_NAME* n, int nid)
250 {
251         int p = -1;
252         p = X509_NAME_get_index_by_NID (n, nid, p);
253         if (p == -1) {
254                 return "";
255         }
256         return asn_to_utf8 (X509_NAME_ENTRY_get_data (X509_NAME_get_entry (n, p)));
257 }
258
259 string
260 Certificate::name_for_xml (X509_NAME* name)
261 {
262         assert (name);
263
264         BIO* bio = BIO_new (BIO_s_mem ());
265         if (!bio) {
266                 throw MiscError ("could not create memory BIO");
267         }
268
269         X509_NAME_print_ex (bio, name, 0, XN_FLAG_RFC2253);
270         int n = BIO_pending (bio);
271         char* result = new char[n + 1];
272         n = BIO_read (bio, result, n);
273         result[n] = '\0';
274
275         BIO_free (bio);
276
277         string s = result;
278         delete[] result;
279
280         return s;
281 }
282
283 string
284 Certificate::subject () const
285 {
286         DCP_ASSERT (_certificate);
287
288         return name_for_xml (X509_get_subject_name (_certificate));
289 }
290
291 string
292 Certificate::subject_common_name () const
293 {
294         DCP_ASSERT (_certificate);
295
296         return get_name_part (X509_get_subject_name (_certificate), NID_commonName);
297 }
298
299 string
300 Certificate::subject_organization_name () const
301 {
302         DCP_ASSERT (_certificate);
303
304         return get_name_part (X509_get_subject_name (_certificate), NID_organizationName);
305 }
306
307 string
308 Certificate::subject_organizational_unit_name () const
309 {
310         DCP_ASSERT (_certificate);
311
312         return get_name_part (X509_get_subject_name (_certificate), NID_organizationalUnitName);
313 }
314
315 string
316 Certificate::serial () const
317 {
318         DCP_ASSERT (_certificate);
319
320         ASN1_INTEGER* s = X509_get_serialNumber (_certificate);
321         DCP_ASSERT (s);
322
323         BIGNUM* b = ASN1_INTEGER_to_BN (s, 0);
324         char* c = BN_bn2dec (b);
325         BN_free (b);
326
327         string st (c);
328         OPENSSL_free (c);
329
330         return st;
331 }
332
333 string
334 Certificate::thumbprint () const
335 {
336         DCP_ASSERT (_certificate);
337
338         uint8_t buffer[8192];
339         uint8_t* p = buffer;
340         i2d_X509_CINF (_certificate->cert_info, &p);
341         unsigned int const length = p - buffer;
342         if (length > sizeof (buffer)) {
343                 throw MiscError ("buffer too small to generate thumbprint");
344         }
345
346         SHA_CTX sha;
347         SHA1_Init (&sha);
348         SHA1_Update (&sha, buffer, length);
349         uint8_t digest[20];
350         SHA1_Final (digest, &sha);
351
352         char digest_base64[64];
353         return Kumu::base64encode (digest, 20, digest_base64, 64);
354 }
355
356 /** @return RSA public key from this Certificate.  Caller must not free the returned value. */
357 RSA *
358 Certificate::public_key () const
359 {
360         DCP_ASSERT (_certificate);
361
362         if (_public_key) {
363                 return _public_key;
364         }
365
366         EVP_PKEY* key = X509_get_pubkey (_certificate);
367         if (!key) {
368                 throw MiscError ("could not get public key from certificate");
369         }
370
371         _public_key = EVP_PKEY_get1_RSA (key);
372         if (!_public_key) {
373                 throw MiscError (String::compose ("could not get RSA public key (%1)", ERR_error_string (ERR_get_error(), 0)));
374         }
375
376         return _public_key;
377 }
378
379 bool
380 dcp::operator== (Certificate const & a, Certificate const & b)
381 {
382         return a.certificate() == b.certificate();
383 }
384
385 bool
386 dcp::operator< (Certificate const & a, Certificate const & b)
387 {
388         return a.certificate() < b.certificate();
389 }
390
391 ostream&
392 dcp::operator<< (ostream& s, Certificate const & c)
393 {
394         s << c.certificate();
395         return s;
396 }