a83d800d3f934e78c70e0f61aadf1e837efb5d0c
[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 string
341 Certificate::serial () const
342 {
343         DCP_ASSERT (_certificate);
344
345         ASN1_INTEGER* s = X509_get_serialNumber (_certificate);
346         DCP_ASSERT (s);
347
348         BIGNUM* b = ASN1_INTEGER_to_BN (s, 0);
349         char* c = BN_bn2dec (b);
350         BN_free (b);
351
352         string st (c);
353         OPENSSL_free (c);
354
355         return st;
356 }
357
358 /** @return thumbprint of the to-be-signed portion of this certificate */
359 string
360 Certificate::thumbprint () const
361 {
362         DCP_ASSERT (_certificate);
363
364         uint8_t buffer[8192];
365         uint8_t* p = buffer;
366
367 #if OPENSSL_VERSION_NUMBER > 0x10100000L
368         i2d_re_X509_tbs(_certificate, &p);
369 #else
370         i2d_X509_CINF (_certificate->cert_info, &p);
371 #endif
372         unsigned int const length = p - buffer;
373         if (length > sizeof (buffer)) {
374                 throw MiscError ("buffer too small to generate thumbprint");
375         }
376
377         SHA_CTX sha;
378         SHA1_Init (&sha);
379         SHA1_Update (&sha, buffer, length);
380         uint8_t digest[20];
381         SHA1_Final (digest, &sha);
382
383         char digest_base64[64];
384         return Kumu::base64encode (digest, 20, digest_base64, 64);
385 }
386
387 /** @return RSA public key from this Certificate.  Caller must not free the returned value. */
388 RSA *
389 Certificate::public_key () const
390 {
391         DCP_ASSERT (_certificate);
392
393         if (_public_key) {
394                 return _public_key;
395         }
396
397         EVP_PKEY* key = X509_get_pubkey (_certificate);
398         if (!key) {
399                 throw MiscError ("could not get public key from certificate");
400         }
401
402         _public_key = EVP_PKEY_get1_RSA (key);
403         if (!_public_key) {
404                 throw MiscError (String::compose ("could not get RSA public key (%1)", ERR_error_string (ERR_get_error(), 0)));
405         }
406
407         return _public_key;
408 }
409
410 static bool string_is_utf8 (X509_NAME* n, int nid)
411 {
412         int p = -1;
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;
415 }
416
417 bool
418 Certificate::has_utf8_strings () const
419 {
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);
424 }
425
426 bool
427 dcp::operator== (Certificate const & a, Certificate const & b)
428 {
429         return a.certificate() == b.certificate();
430 }
431
432 bool
433 dcp::operator< (Certificate const & a, Certificate const & b)
434 {
435         return a.certificate() < b.certificate();
436 }
437
438 ostream&
439 dcp::operator<< (ostream& s, Certificate const & c)
440 {
441         s << c.certificate();
442         return s;
443 }