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