Move files from gst-plugins-bad into the "subprojects/gst-plugins-bad/" subdir
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-bad / ext / dtls / gstdtlscertificate.c
1 /*
2  * Copyright (c) 2014, Ericsson AB. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without modification,
5  * are permitted provided that the following conditions are met:
6  *
7  * 1. Redistributions of source code must retain the above copyright notice, this
8  * list of conditions and the following disclaimer.
9  *
10  * 2. Redistributions in binary form must reproduce the above copyright notice, this
11  * list of conditions and the following disclaimer in the documentation and/or other
12  * materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
18  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
21  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
23  * OF SUCH DAMAGE.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29
30 #include <gst/gst.h>
31
32 #include "gstdtlscertificate.h"
33
34 #include "gstdtlsagent.h"
35
36 #ifdef __APPLE__
37 # define __AVAILABILITYMACROS__
38 # define DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER
39 #endif
40
41 #ifdef G_OS_WIN32
42 #include <windows.h>
43 #ifdef X509_NAME
44 #undef X509_NAME
45 #endif
46 #endif
47
48 #include <openssl/bn.h>
49 #include <openssl/rsa.h>
50 #include <openssl/ssl.h>
51
52 #if OPENSSL_VERSION_NUMBER < 0x10100000L
53 #define X509_getm_notBefore X509_get_notBefore
54 #define X509_getm_notAfter X509_get_notAfter
55 #endif
56
57 GST_DEBUG_CATEGORY_STATIC (gst_dtls_certificate_debug);
58 #define GST_CAT_DEFAULT gst_dtls_certificate_debug
59
60 enum
61 {
62   PROP_0,
63   PROP_PEM,
64   NUM_PROPERTIES
65 };
66
67 static GParamSpec *properties[NUM_PROPERTIES];
68
69 #define DEFAULT_PEM NULL
70
71 struct _GstDtlsCertificatePrivate
72 {
73   X509 *x509;
74   EVP_PKEY *private_key;
75
76   gchar *pem;
77 };
78
79 G_DEFINE_TYPE_WITH_CODE (GstDtlsCertificate, gst_dtls_certificate,
80     G_TYPE_OBJECT, G_ADD_PRIVATE (GstDtlsCertificate)
81     GST_DEBUG_CATEGORY_INIT (gst_dtls_certificate_debug,
82         "dtlscertificate", 0, "DTLS Certificate"));
83
84 static void gst_dtls_certificate_finalize (GObject * gobject);
85 static void gst_dtls_certificate_set_property (GObject *, guint prop_id,
86     const GValue *, GParamSpec *);
87 static void gst_dtls_certificate_get_property (GObject *, guint prop_id,
88     GValue *, GParamSpec *);
89
90 static void init_generated (GstDtlsCertificate *);
91 static void init_from_pem_string (GstDtlsCertificate *, const gchar * pem);
92
93 static void
94 gst_dtls_certificate_class_init (GstDtlsCertificateClass * klass)
95 {
96   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
97
98   gobject_class->set_property = gst_dtls_certificate_set_property;
99   gobject_class->get_property = gst_dtls_certificate_get_property;
100
101   properties[PROP_PEM] =
102       g_param_spec_string ("pem",
103       "Pem string",
104       "A string containing a X509 certificate and RSA private key in PEM format",
105       DEFAULT_PEM,
106       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
107
108   g_object_class_install_properties (gobject_class, NUM_PROPERTIES, properties);
109
110   _gst_dtls_init_openssl ();
111
112   gobject_class->finalize = gst_dtls_certificate_finalize;
113 }
114
115 static void
116 gst_dtls_certificate_init (GstDtlsCertificate * self)
117 {
118   GstDtlsCertificatePrivate *priv;
119
120   self->priv = priv = gst_dtls_certificate_get_instance_private (self);
121
122   priv->x509 = NULL;
123   priv->private_key = NULL;
124   priv->pem = NULL;
125 }
126
127 static void
128 gst_dtls_certificate_finalize (GObject * gobject)
129 {
130   GstDtlsCertificatePrivate *priv = GST_DTLS_CERTIFICATE (gobject)->priv;
131
132   X509_free (priv->x509);
133   priv->x509 = NULL;
134
135   EVP_PKEY_free (priv->private_key);
136   priv->private_key = NULL;
137
138
139   g_free (priv->pem);
140   priv->pem = NULL;
141
142   G_OBJECT_CLASS (gst_dtls_certificate_parent_class)->finalize (gobject);
143 }
144
145 static void
146 gst_dtls_certificate_set_property (GObject * object, guint prop_id,
147     const GValue * value, GParamSpec * pspec)
148 {
149   GstDtlsCertificate *self = GST_DTLS_CERTIFICATE (object);
150   const gchar *pem;
151
152   switch (prop_id) {
153     case PROP_PEM:
154       pem = g_value_get_string (value);
155       if (pem) {
156         init_from_pem_string (self, pem);
157       } else {
158         init_generated (self);
159       }
160       break;
161     default:
162       G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
163   }
164 }
165
166 static void
167 gst_dtls_certificate_get_property (GObject * object, guint prop_id,
168     GValue * value, GParamSpec * pspec)
169 {
170   GstDtlsCertificate *self = GST_DTLS_CERTIFICATE (object);
171
172   switch (prop_id) {
173     case PROP_PEM:
174       g_return_if_fail (self->priv->pem);
175       g_value_set_string (value, self->priv->pem);
176       break;
177     default:
178       G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
179   }
180 }
181
182 static const gchar base64_alphabet[64] = {
183   'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
184   'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
185   'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
186   'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
187   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
188 };
189
190 static void
191 init_generated (GstDtlsCertificate * self)
192 {
193   GstDtlsCertificatePrivate *priv = self->priv;
194   RSA *rsa;
195   BIGNUM *serial_number;
196   ASN1_INTEGER *asn1_serial_number;
197   X509_NAME *name = NULL;
198   gchar common_name[9] = { 0, };
199   gint i;
200
201   g_return_if_fail (!priv->x509);
202   g_return_if_fail (!priv->private_key);
203
204   priv->private_key = EVP_PKEY_new ();
205
206   if (!priv->private_key) {
207     GST_WARNING_OBJECT (self, "failed to create private key");
208     return;
209   }
210
211   priv->x509 = X509_new ();
212
213   if (!priv->x509) {
214     GST_WARNING_OBJECT (self, "failed to create certificate");
215     EVP_PKEY_free (priv->private_key);
216     priv->private_key = NULL;
217     return;
218   }
219
220   /* XXX: RSA_generate_key is actually deprecated in 0.9.8 */
221 #if OPENSSL_VERSION_NUMBER < 0x10100001L
222   rsa = RSA_generate_key (2048, RSA_F4, NULL, NULL);
223 #else
224   rsa = RSA_new ();
225   if (rsa != NULL) {
226     BIGNUM *e = BN_new ();
227     if (e == NULL || !BN_set_word (e, RSA_F4)
228         || !RSA_generate_key_ex (rsa, 2048, e, NULL)) {
229       RSA_free (rsa);
230       rsa = NULL;
231     }
232     if (e)
233       BN_free (e);
234   }
235 #endif
236
237   if (!rsa) {
238     GST_WARNING_OBJECT (self, "failed to generate RSA");
239     EVP_PKEY_free (priv->private_key);
240     priv->private_key = NULL;
241     X509_free (priv->x509);
242     priv->x509 = NULL;
243     return;
244   }
245
246   if (!EVP_PKEY_assign_RSA (priv->private_key, rsa)) {
247     GST_WARNING_OBJECT (self, "failed to assign RSA");
248     RSA_free (rsa);
249     rsa = NULL;
250     EVP_PKEY_free (priv->private_key);
251     priv->private_key = NULL;
252     X509_free (priv->x509);
253     priv->x509 = NULL;
254     return;
255   }
256   rsa = NULL;
257
258   X509_set_version (priv->x509, 2);
259
260   /* Set a random 64 bit integer as serial number */
261   serial_number = BN_new ();
262   BN_pseudo_rand (serial_number, 64, 0, 0);
263   asn1_serial_number = X509_get_serialNumber (priv->x509);
264   BN_to_ASN1_INTEGER (serial_number, asn1_serial_number);
265   BN_free (serial_number);
266
267   /* Set a random 8 byte base64 string as issuer/subject */
268   name = X509_NAME_new ();
269   for (i = 0; i < 8; i++)
270     common_name[i] =
271         base64_alphabet[g_random_int_range (0, G_N_ELEMENTS (base64_alphabet))];
272   X509_NAME_add_entry_by_NID (name, NID_commonName, MBSTRING_ASC,
273       (const guchar *) common_name, -1, -1, 0);
274   X509_set_subject_name (priv->x509, name);
275   X509_set_issuer_name (priv->x509, name);
276   X509_NAME_free (name);
277
278   /* Set expiry in a year */
279   X509_gmtime_adj (X509_getm_notBefore (priv->x509), 0);
280   X509_gmtime_adj (X509_getm_notAfter (priv->x509), 31536000L); /* A year */
281   X509_set_pubkey (priv->x509, priv->private_key);
282
283   if (!X509_sign (priv->x509, priv->private_key, EVP_sha256 ())) {
284     GST_WARNING_OBJECT (self, "failed to sign certificate");
285     EVP_PKEY_free (priv->private_key);
286     priv->private_key = NULL;
287     X509_free (priv->x509);
288     priv->x509 = NULL;
289     return;
290   }
291
292   self->priv->pem = _gst_dtls_x509_to_pem (priv->x509);
293 }
294
295 static void
296 init_from_pem_string (GstDtlsCertificate * self, const gchar * pem)
297 {
298   GstDtlsCertificatePrivate *priv = self->priv;
299   BIO *bio;
300
301   g_return_if_fail (pem);
302   g_return_if_fail (!priv->x509);
303   g_return_if_fail (!priv->private_key);
304
305   bio = BIO_new_mem_buf ((gpointer) pem, -1);
306   g_return_if_fail (bio);
307
308   priv->x509 = PEM_read_bio_X509 (bio, NULL, NULL, NULL);
309
310   if (!priv->x509) {
311     GST_WARNING_OBJECT (self, "failed to read certificate from pem string");
312     return;
313   }
314
315   (void) BIO_reset (bio);
316
317   priv->private_key = PEM_read_bio_PrivateKey (bio, NULL, NULL, NULL);
318
319   BIO_free (bio);
320   bio = NULL;
321
322   if (!priv->private_key) {
323     GST_WARNING_OBJECT (self, "failed to read private key from pem string");
324     X509_free (priv->x509);
325     priv->x509 = NULL;
326     return;
327   }
328
329   self->priv->pem = g_strdup (pem);
330 }
331
332 gchar *
333 _gst_dtls_x509_to_pem (gpointer x509)
334 {
335 #define GST_DTLS_BIO_BUFFER_SIZE 4096
336   BIO *bio;
337   gchar buffer[GST_DTLS_BIO_BUFFER_SIZE] = { 0 };
338   gint len;
339   gchar *pem = NULL;
340
341   bio = BIO_new (BIO_s_mem ());
342   g_return_val_if_fail (bio, NULL);
343
344   if (!PEM_write_bio_X509 (bio, (X509 *) x509)) {
345     g_warn_if_reached ();
346     goto beach;
347   }
348
349   len = BIO_read (bio, buffer, GST_DTLS_BIO_BUFFER_SIZE);
350   if (!len) {
351     g_warn_if_reached ();
352     goto beach;
353   }
354
355   pem = g_strndup (buffer, len);
356
357 beach:
358   BIO_free (bio);
359
360   return pem;
361 }
362
363 GstDtlsCertificateInternalCertificate
364 _gst_dtls_certificate_get_internal_certificate (GstDtlsCertificate * self)
365 {
366   g_return_val_if_fail (GST_IS_DTLS_CERTIFICATE (self), NULL);
367   return self->priv->x509;
368 }
369
370 GstDtlsCertificateInternalKey
371 _gst_dtls_certificate_get_internal_key (GstDtlsCertificate * self)
372 {
373   g_return_val_if_fail (GST_IS_DTLS_CERTIFICATE (self), NULL);
374   return self->priv->private_key;
375 }