Use an enum class for Marker.
[libdcp.git] / src / certificate.cc
1 /*
2     Copyright (C) 2012-2016 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 {
68
69 }
70
71 /** Load an X509 certificate from a string.
72  *  @param cert String to read from.
73  */
74 Certificate::Certificate (string cert)
75         : _certificate (0)
76         , _public_key (0)
77 {
78         string const s = read_string (cert);
79         if (!s.empty ()) {
80                 throw MiscError ("unexpected data after certificate");
81         }
82 }
83
84 /** Copy constructor.
85  *  @param other Certificate to copy.
86  */
87 Certificate::Certificate (Certificate const & other)
88         : _certificate (0)
89         , _public_key (0)
90 {
91         if (other._certificate) {
92                 read_string (other.certificate (true));
93         }
94 }
95
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.
99  */
100 string
101 Certificate::read_string (string cert)
102 {
103         /* Reformat cert so that it has line breaks every 64 characters.
104            See http://comments.gmane.org/gmane.comp.encryption.openssl.user/55593
105         */
106
107         list<string> lines;
108         string line;
109
110         for (size_t i = 0; i < cert.length(); ++i) {
111                 line += cert[i];
112                 if (cert[i] == '\r' || cert[i] == '\n') {
113                         boost::algorithm::trim (line);
114                         lines.push_back (line);
115                         line = "";
116                 }
117         }
118
119         if (!line.empty()) {
120                 boost::algorithm::trim (line);
121                 lines.push_back (line);
122         }
123
124         list<string>::iterator i = lines.begin ();
125
126         /* BEGIN */
127         while (i != lines.end() && *i != begin_certificate) {
128                 ++i;
129         }
130
131         if (i == lines.end()) {
132                 throw MiscError ("missing BEGIN line in certificate");
133         }
134
135         /* Skip over the BEGIN line */
136         ++i;
137
138         /* The base64 data */
139         bool got_end = false;
140         string base64 = "";
141         while (i != lines.end()) {
142                 if (*i == end_certificate) {
143                         got_end = true;
144                         break;
145                 }
146                 base64 += *i;
147                 ++i;
148         }
149
150         if (!got_end) {
151                 throw MiscError ("missing END line in certificate");
152         }
153
154         /* Skip over the END line */
155         ++i;
156
157         /* Make up the fixed version */
158
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);
164         }
165
166         fixed += end_certificate;
167
168         BIO* bio = BIO_new_mem_buf (const_cast<char *> (fixed.c_str ()), -1);
169         if (!bio) {
170                 throw MiscError ("could not create memory BIO");
171         }
172
173         _certificate = PEM_read_bio_X509 (bio, 0, 0, 0);
174         if (!_certificate) {
175                 throw MiscError ("could not read X509 certificate from memory BIO");
176         }
177
178         BIO_free (bio);
179
180         string extra;
181
182         while (i != lines.end()) {
183                 if (!i->empty()) {
184                         extra += *i + "\n";
185                 }
186                 ++i;
187         }
188
189         return extra;
190 }
191
192 /** Destructor */
193 Certificate::~Certificate ()
194 {
195         X509_free (_certificate);
196         RSA_free (_public_key);
197 }
198
199 /** operator= for Certificate.
200  *  @param other Certificate to read from.
201  */
202 Certificate &
203 Certificate::operator= (Certificate const & other)
204 {
205         if (this == &other) {
206                 return *this;
207         }
208
209         X509_free (_certificate);
210         _certificate = 0;
211         RSA_free (_public_key);
212         _public_key = 0;
213
214         read_string (other.certificate (true));
215
216         return *this;
217 }
218
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.
222  */
223 string
224 Certificate::certificate (bool with_begin_end) const
225 {
226         DCP_ASSERT (_certificate);
227
228         BIO* bio = BIO_new (BIO_s_mem ());
229         if (!bio) {
230                 throw MiscError ("could not create memory BIO");
231         }
232
233         PEM_write_bio_X509 (bio, _certificate);
234
235         string s;
236         char* data;
237         long int const data_length = BIO_get_mem_data (bio, &data);
238         for (long int i = 0; i < data_length; ++i) {
239                 s += data[i];
240         }
241
242         BIO_free (bio);
243
244         if (!with_begin_end) {
245                 boost::replace_all (s, begin_certificate + "\n", "");
246                 boost::replace_all (s, "\n" + end_certificate + "\n", "");
247         }
248
249         return s;
250 }
251
252 /** @return Certificate's issuer, in the form
253  *  dnqualifier=&lt;dnQualififer&gt;,CN=&lt;commonName&gt;,OU=&lt;organizationalUnitName&gt,O=&lt;organizationName&gt;
254  *  and with + signs escaped to \+
255  */
256 string
257 Certificate::issuer () const
258 {
259         DCP_ASSERT (_certificate);
260         return name_for_xml (X509_get_issuer_name (_certificate));
261 }
262
263 string
264 Certificate::asn_to_utf8 (ASN1_STRING* s)
265 {
266         unsigned char* buf = 0;
267         ASN1_STRING_to_UTF8 (&buf, s);
268         string const u (reinterpret_cast<char *> (buf));
269         OPENSSL_free (buf);
270         return u;
271 }
272
273 string
274 Certificate::get_name_part (X509_NAME* n, int nid)
275 {
276         int p = -1;
277         p = X509_NAME_get_index_by_NID (n, nid, p);
278         if (p == -1) {
279                 return "";
280         }
281         return asn_to_utf8 (X509_NAME_ENTRY_get_data (X509_NAME_get_entry (n, p)));
282 }
283
284 string
285 Certificate::name_for_xml (X509_NAME* name)
286 {
287         assert (name);
288
289         BIO* bio = BIO_new (BIO_s_mem ());
290         if (!bio) {
291                 throw MiscError ("could not create memory BIO");
292         }
293
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);
298         result[n] = '\0';
299
300         BIO_free (bio);
301
302         string s = result;
303         delete[] result;
304
305         return s;
306 }
307
308 string
309 Certificate::subject () const
310 {
311         DCP_ASSERT (_certificate);
312
313         return name_for_xml (X509_get_subject_name (_certificate));
314 }
315
316 string
317 Certificate::subject_common_name () const
318 {
319         DCP_ASSERT (_certificate);
320
321         return get_name_part (X509_get_subject_name (_certificate), NID_commonName);
322 }
323
324 string
325 Certificate::subject_organization_name () const
326 {
327         DCP_ASSERT (_certificate);
328
329         return get_name_part (X509_get_subject_name (_certificate), NID_organizationName);
330 }
331
332 string
333 Certificate::subject_organizational_unit_name () const
334 {
335         DCP_ASSERT (_certificate);
336
337         return get_name_part (X509_get_subject_name (_certificate), NID_organizationalUnitName);
338 }
339
340 static
341 struct tm
342 convert_time (ASN1_TIME const * time)
343 {
344         struct tm t;
345         char const * s = (char const *) time->data;
346
347         if (time->type == V_ASN1_UTCTIME) {
348                 sscanf(s, "%2d%2d%2d%2d%2d%2d", &t.tm_year, &t.tm_mon, &t.tm_mday, &t.tm_hour, &t.tm_min, &t.tm_sec);
349                 if (t.tm_year < 70) {
350                         t.tm_year += 100;
351                 }
352         } else if (time->type == V_ASN1_GENERALIZEDTIME) {
353                 sscanf(s, "%4d%2d%2d%2d%2d%2d", &t.tm_year, &t.tm_mon, &t.tm_mday, &t.tm_hour, &t.tm_min, &t.tm_sec);
354                 t.tm_year -= 1900;
355         }
356
357         t.tm_mon--;
358
359         return t;
360 }
361
362 struct tm
363 Certificate::not_before () const
364 {
365         DCP_ASSERT (_certificate);
366 #if OPENSSL_VERSION_NUMBER > 0x10100000L
367         return convert_time(X509_get0_notBefore(_certificate));
368 #else
369         return convert_time(X509_get_notBefore(_certificate));
370 #endif
371 }
372
373 struct tm
374 Certificate::not_after () const
375 {
376         DCP_ASSERT (_certificate);
377 #if OPENSSL_VERSION_NUMBER > 0x10100000L
378         return convert_time(X509_get0_notAfter(_certificate));
379 #else
380         return convert_time(X509_get_notAfter(_certificate));
381 #endif
382 }
383
384 string
385 Certificate::serial () const
386 {
387         DCP_ASSERT (_certificate);
388
389         ASN1_INTEGER* s = X509_get_serialNumber (_certificate);
390         DCP_ASSERT (s);
391
392         BIGNUM* b = ASN1_INTEGER_to_BN (s, 0);
393         char* c = BN_bn2dec (b);
394         BN_free (b);
395
396         string st (c);
397         OPENSSL_free (c);
398
399         return st;
400 }
401
402 /** @return thumbprint of the to-be-signed portion of this certificate */
403 string
404 Certificate::thumbprint () const
405 {
406         DCP_ASSERT (_certificate);
407
408         uint8_t buffer[8192];
409         uint8_t* p = buffer;
410
411 #if OPENSSL_VERSION_NUMBER > 0x10100000L
412         i2d_re_X509_tbs(_certificate, &p);
413 #else
414         i2d_X509_CINF (_certificate->cert_info, &p);
415 #endif
416         unsigned int const length = p - buffer;
417         if (length > sizeof (buffer)) {
418                 throw MiscError ("buffer too small to generate thumbprint");
419         }
420
421         SHA_CTX sha;
422         SHA1_Init (&sha);
423         SHA1_Update (&sha, buffer, length);
424         uint8_t digest[20];
425         SHA1_Final (digest, &sha);
426
427         char digest_base64[64];
428         return Kumu::base64encode (digest, 20, digest_base64, 64);
429 }
430
431 /** @return RSA public key from this Certificate.  Caller must not free the returned value. */
432 RSA *
433 Certificate::public_key () const
434 {
435         DCP_ASSERT (_certificate);
436
437         if (_public_key) {
438                 return _public_key;
439         }
440
441         EVP_PKEY* key = X509_get_pubkey (_certificate);
442         if (!key) {
443                 throw MiscError ("could not get public key from certificate");
444         }
445
446         _public_key = EVP_PKEY_get1_RSA (key);
447         if (!_public_key) {
448                 throw MiscError (String::compose ("could not get RSA public key (%1)", ERR_error_string (ERR_get_error(), 0)));
449         }
450
451         return _public_key;
452 }
453
454 static bool string_is_utf8 (X509_NAME* n, int nid)
455 {
456         int p = -1;
457         p = X509_NAME_get_index_by_NID (n, nid, p);
458         return p != -1 && X509_NAME_ENTRY_get_data(X509_NAME_get_entry(n, p))->type == V_ASN1_UTF8STRING;
459 }
460
461 bool
462 Certificate::has_utf8_strings () const
463 {
464         X509_NAME* n = X509_get_subject_name (_certificate);
465         return string_is_utf8(n, NID_commonName) ||
466                 string_is_utf8(n, NID_organizationName) ||
467                 string_is_utf8(n, NID_organizationalUnitName);
468 }
469
470 bool
471 dcp::operator== (Certificate const & a, Certificate const & b)
472 {
473         return a.certificate() == b.certificate();
474 }
475
476 bool
477 dcp::operator< (Certificate const & a, Certificate const & b)
478 {
479         return a.certificate() < b.certificate();
480 }
481
482 ostream&
483 dcp::operator<< (ostream& s, Certificate const & c)
484 {
485         s << c.certificate();
486         return s;
487 }