More stringstream removal.
[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         list<string> lines;
107         string line;
108
109         for (size_t i = 0; i < cert.length(); ++i) {
110                 line += cert[i];
111                 if (cert[i] == '\r' || cert[i] == '\n') {
112                         boost::algorithm::trim (line);
113                         lines.push_back (line);
114                         line = "";
115                 }
116         }
117
118         if (!line.empty()) {
119                 boost::algorithm::trim (line);
120                 lines.push_back (line);
121         }
122
123         list<string>::iterator i = lines.begin ();
124
125         /* BEGIN */
126         while (i != lines.end() && *i != begin_certificate) {
127                 ++i;
128         }
129
130         if (i == lines.end()) {
131                 throw MiscError ("missing BEGIN line in certificate");
132         }
133
134         /* Skip over the BEGIN line */
135         ++i;
136
137         /* The base64 data */
138         bool got_end = false;
139         string base64 = "";
140         while (i != lines.end()) {
141                 if (*i == end_certificate) {
142                         got_end = true;
143                         break;
144                 }
145                 base64 += *i;
146                 ++i;
147         }
148
149         if (!got_end) {
150                 throw MiscError ("missing END line in certificate");
151         }
152
153         /* Skip over the END line */
154         ++i;
155
156         /* Make up the fixed version */
157
158         string fixed = begin_certificate + "\n";
159         while (!base64.empty ()) {
160                 size_t const t = min (size_t(64), base64.length());
161                 fixed += base64.substr (0, t) + "\n";
162                 base64 = base64.substr (t, base64.length() - t);
163         }
164
165         fixed += end_certificate;
166
167         BIO* bio = BIO_new_mem_buf (const_cast<char *> (fixed.c_str ()), -1);
168         if (!bio) {
169                 throw MiscError ("could not create memory BIO");
170         }
171
172         _certificate = PEM_read_bio_X509 (bio, 0, 0, 0);
173         if (!_certificate) {
174                 throw MiscError ("could not read X509 certificate from memory BIO");
175         }
176
177         BIO_free (bio);
178
179         /* See if there are any non-blank lines after the certificate that we read */
180         while (i != lines.end() && i->empty()) {
181                 ++i;
182         }
183         return i != lines.end();
184 }
185
186 /** Destructor */
187 Certificate::~Certificate ()
188 {
189         X509_free (_certificate);
190         RSA_free (_public_key);
191 }
192
193 /** operator= for Certificate.
194  *  @param other Certificate to read from.
195  */
196 Certificate &
197 Certificate::operator= (Certificate const & other)
198 {
199         if (this == &other) {
200                 return *this;
201         }
202
203         X509_free (_certificate);
204         _certificate = 0;
205         RSA_free (_public_key);
206         _public_key = 0;
207         _extra_data = other._extra_data;
208
209         read_string (other.certificate (true));
210
211         return *this;
212 }
213
214 /** Return the certificate as a string.
215  *  @param with_begin_end true to include the -----BEGIN CERTIFICATE--- / -----END CERTIFICATE----- markers.
216  *  @return Certificate string.
217  */
218 string
219 Certificate::certificate (bool with_begin_end) const
220 {
221         DCP_ASSERT (_certificate);
222
223         BIO* bio = BIO_new (BIO_s_mem ());
224         if (!bio) {
225                 throw MiscError ("could not create memory BIO");
226         }
227
228         PEM_write_bio_X509 (bio, _certificate);
229
230         string s;
231         char* data;
232         long int const data_length = BIO_get_mem_data (bio, &data);
233         for (long int i = 0; i < data_length; ++i) {
234                 s += data[i];
235         }
236
237         BIO_free (bio);
238
239         if (!with_begin_end) {
240                 boost::replace_all (s, begin_certificate + "\n", "");
241                 boost::replace_all (s, "\n" + end_certificate + "\n", "");
242         }
243
244         return s;
245 }
246
247 /** @return Certificate's issuer, in the form
248  *  dnqualifier=&lt;dnQualififer&gt;,CN=&lt;commonName&gt;,OU=&lt;organizationalUnitName&gt,O=&lt;organizationName&gt;
249  *  and with + signs escaped to \+
250  */
251 string
252 Certificate::issuer () const
253 {
254         DCP_ASSERT (_certificate);
255         return name_for_xml (X509_get_issuer_name (_certificate));
256 }
257
258 string
259 Certificate::asn_to_utf8 (ASN1_STRING* s)
260 {
261         unsigned char* buf = 0;
262         ASN1_STRING_to_UTF8 (&buf, s);
263         string const u (reinterpret_cast<char *> (buf));
264         OPENSSL_free (buf);
265         return u;
266 }
267
268 string
269 Certificate::get_name_part (X509_NAME* n, int nid)
270 {
271         int p = -1;
272         p = X509_NAME_get_index_by_NID (n, nid, p);
273         if (p == -1) {
274                 return "";
275         }
276         return asn_to_utf8 (X509_NAME_ENTRY_get_data (X509_NAME_get_entry (n, p)));
277 }
278
279 string
280 Certificate::name_for_xml (X509_NAME* name)
281 {
282         assert (name);
283
284         BIO* bio = BIO_new (BIO_s_mem ());
285         if (!bio) {
286                 throw MiscError ("could not create memory BIO");
287         }
288
289         X509_NAME_print_ex (bio, name, 0, XN_FLAG_RFC2253);
290         int n = BIO_pending (bio);
291         char* result = new char[n + 1];
292         n = BIO_read (bio, result, n);
293         result[n] = '\0';
294
295         BIO_free (bio);
296
297         string s = result;
298         delete[] result;
299
300         return s;
301 }
302
303 string
304 Certificate::subject () const
305 {
306         DCP_ASSERT (_certificate);
307
308         return name_for_xml (X509_get_subject_name (_certificate));
309 }
310
311 string
312 Certificate::subject_common_name () const
313 {
314         DCP_ASSERT (_certificate);
315
316         return get_name_part (X509_get_subject_name (_certificate), NID_commonName);
317 }
318
319 string
320 Certificate::subject_organization_name () const
321 {
322         DCP_ASSERT (_certificate);
323
324         return get_name_part (X509_get_subject_name (_certificate), NID_organizationName);
325 }
326
327 string
328 Certificate::subject_organizational_unit_name () const
329 {
330         DCP_ASSERT (_certificate);
331
332         return get_name_part (X509_get_subject_name (_certificate), NID_organizationalUnitName);
333 }
334
335 string
336 Certificate::serial () const
337 {
338         DCP_ASSERT (_certificate);
339
340         ASN1_INTEGER* s = X509_get_serialNumber (_certificate);
341         DCP_ASSERT (s);
342
343         BIGNUM* b = ASN1_INTEGER_to_BN (s, 0);
344         char* c = BN_bn2dec (b);
345         BN_free (b);
346
347         string st (c);
348         OPENSSL_free (c);
349
350         return st;
351 }
352
353 string
354 Certificate::thumbprint () const
355 {
356         DCP_ASSERT (_certificate);
357
358         uint8_t buffer[8192];
359         uint8_t* p = buffer;
360         i2d_X509_CINF (_certificate->cert_info, &p);
361         unsigned int const length = p - buffer;
362         if (length > sizeof (buffer)) {
363                 throw MiscError ("buffer too small to generate thumbprint");
364         }
365
366         SHA_CTX sha;
367         SHA1_Init (&sha);
368         SHA1_Update (&sha, buffer, length);
369         uint8_t digest[20];
370         SHA1_Final (digest, &sha);
371
372         char digest_base64[64];
373         return Kumu::base64encode (digest, 20, digest_base64, 64);
374 }
375
376 /** @return RSA public key from this Certificate.  Caller must not free the returned value. */
377 RSA *
378 Certificate::public_key () const
379 {
380         DCP_ASSERT (_certificate);
381
382         if (_public_key) {
383                 return _public_key;
384         }
385
386         EVP_PKEY* key = X509_get_pubkey (_certificate);
387         if (!key) {
388                 throw MiscError ("could not get public key from certificate");
389         }
390
391         _public_key = EVP_PKEY_get1_RSA (key);
392         if (!_public_key) {
393                 throw MiscError (String::compose ("could not get RSA public key (%1)", ERR_error_string (ERR_get_error(), 0)));
394         }
395
396         return _public_key;
397 }
398
399 bool
400 dcp::operator== (Certificate const & a, Certificate const & b)
401 {
402         return a.certificate() == b.certificate();
403 }
404
405 bool
406 dcp::operator< (Certificate const & a, Certificate const & b)
407 {
408         return a.certificate() < b.certificate();
409 }
410
411 ostream&
412 dcp::operator<< (ostream& s, Certificate const & c)
413 {
414         s << c.certificate();
415         return s;
416 }