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
gst_dtls_certificate_class_init(GstDtlsCertificateClass * klass)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
gst_dtls_certificate_init(GstDtlsCertificate * self)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
gst_dtls_certificate_finalize(GObject * gobject)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
gst_dtls_certificate_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)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
gst_dtls_certificate_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)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 void
init_generated(GstDtlsCertificate * self)183 init_generated (GstDtlsCertificate * self)
184 {
185   GstDtlsCertificatePrivate *priv = self->priv;
186   RSA *rsa;
187   X509_NAME *name = NULL;
188 
189   g_return_if_fail (!priv->x509);
190   g_return_if_fail (!priv->private_key);
191 
192   priv->private_key = EVP_PKEY_new ();
193 
194   if (!priv->private_key) {
195     GST_WARNING_OBJECT (self, "failed to create private key");
196     return;
197   }
198 
199   priv->x509 = X509_new ();
200 
201   if (!priv->x509) {
202     GST_WARNING_OBJECT (self, "failed to create certificate");
203     EVP_PKEY_free (priv->private_key);
204     priv->private_key = NULL;
205     return;
206   }
207 
208   /* XXX: RSA_generate_key is actually deprecated in 0.9.8 */
209 #if OPENSSL_VERSION_NUMBER < 0x10100001L
210   rsa = RSA_generate_key (2048, RSA_F4, NULL, NULL);
211 #else
212   rsa = RSA_new ();
213   if (rsa != NULL) {
214     BIGNUM *e = BN_new ();
215     if (e == NULL || !BN_set_word (e, RSA_F4)
216         || !RSA_generate_key_ex (rsa, 2048, e, NULL)) {
217       RSA_free (rsa);
218       rsa = NULL;
219     }
220     if (e)
221       BN_free (e);
222   }
223 #endif
224 
225   if (!rsa) {
226     GST_WARNING_OBJECT (self, "failed to generate RSA");
227     EVP_PKEY_free (priv->private_key);
228     priv->private_key = NULL;
229     X509_free (priv->x509);
230     priv->x509 = NULL;
231     return;
232   }
233 
234   if (!EVP_PKEY_assign_RSA (priv->private_key, rsa)) {
235     GST_WARNING_OBJECT (self, "failed to assign RSA");
236     RSA_free (rsa);
237     rsa = NULL;
238     EVP_PKEY_free (priv->private_key);
239     priv->private_key = NULL;
240     X509_free (priv->x509);
241     priv->x509 = NULL;
242     return;
243   }
244   rsa = NULL;
245 
246   X509_set_version (priv->x509, 2);
247   ASN1_INTEGER_set (X509_get_serialNumber (priv->x509), 0);
248   X509_gmtime_adj (X509_getm_notBefore (priv->x509), 0);
249   X509_gmtime_adj (X509_getm_notAfter (priv->x509), 31536000L); /* A year */
250   X509_set_pubkey (priv->x509, priv->private_key);
251 
252   name = X509_get_subject_name (priv->x509);
253   X509_NAME_add_entry_by_txt (name, "C", MBSTRING_ASC, (unsigned char *) "SE",
254       -1, -1, 0);
255   X509_NAME_add_entry_by_txt (name, "CN", MBSTRING_ASC,
256       (unsigned char *) "OpenWebRTC", -1, -1, 0);
257   X509_set_issuer_name (priv->x509, name);
258   name = NULL;
259 
260   if (!X509_sign (priv->x509, priv->private_key, EVP_sha256 ())) {
261     GST_WARNING_OBJECT (self, "failed to sign certificate");
262     EVP_PKEY_free (priv->private_key);
263     priv->private_key = NULL;
264     X509_free (priv->x509);
265     priv->x509 = NULL;
266     return;
267   }
268 
269   self->priv->pem = _gst_dtls_x509_to_pem (priv->x509);
270 }
271 
272 static void
init_from_pem_string(GstDtlsCertificate * self,const gchar * pem)273 init_from_pem_string (GstDtlsCertificate * self, const gchar * pem)
274 {
275   GstDtlsCertificatePrivate *priv = self->priv;
276   BIO *bio;
277 
278   g_return_if_fail (pem);
279   g_return_if_fail (!priv->x509);
280   g_return_if_fail (!priv->private_key);
281 
282   bio = BIO_new_mem_buf ((gpointer) pem, -1);
283   g_return_if_fail (bio);
284 
285   priv->x509 = PEM_read_bio_X509 (bio, NULL, NULL, NULL);
286 
287   if (!priv->x509) {
288     GST_WARNING_OBJECT (self, "failed to read certificate from pem string");
289     return;
290   }
291 
292   (void) BIO_reset (bio);
293 
294   priv->private_key = PEM_read_bio_PrivateKey (bio, NULL, NULL, NULL);
295 
296   BIO_free (bio);
297   bio = NULL;
298 
299   if (!priv->private_key) {
300     GST_WARNING_OBJECT (self, "failed to read private key from pem string");
301     X509_free (priv->x509);
302     priv->x509 = NULL;
303     return;
304   }
305 
306   self->priv->pem = g_strdup (pem);
307 }
308 
309 gchar *
_gst_dtls_x509_to_pem(gpointer x509)310 _gst_dtls_x509_to_pem (gpointer x509)
311 {
312 #define GST_DTLS_BIO_BUFFER_SIZE 4096
313   BIO *bio;
314   gchar buffer[GST_DTLS_BIO_BUFFER_SIZE] = { 0 };
315   gint len;
316   gchar *pem = NULL;
317 
318   bio = BIO_new (BIO_s_mem ());
319   g_return_val_if_fail (bio, NULL);
320 
321   if (!PEM_write_bio_X509 (bio, (X509 *) x509)) {
322     g_warn_if_reached ();
323     goto beach;
324   }
325 
326   len = BIO_read (bio, buffer, GST_DTLS_BIO_BUFFER_SIZE);
327   if (!len) {
328     g_warn_if_reached ();
329     goto beach;
330   }
331 
332   pem = g_strndup (buffer, len);
333 
334 beach:
335   BIO_free (bio);
336 
337   return pem;
338 }
339 
340 GstDtlsCertificateInternalCertificate
_gst_dtls_certificate_get_internal_certificate(GstDtlsCertificate * self)341 _gst_dtls_certificate_get_internal_certificate (GstDtlsCertificate * self)
342 {
343   g_return_val_if_fail (GST_IS_DTLS_CERTIFICATE (self), NULL);
344   return self->priv->x509;
345 }
346 
347 GstDtlsCertificateInternalKey
_gst_dtls_certificate_get_internal_key(GstDtlsCertificate * self)348 _gst_dtls_certificate_get_internal_key (GstDtlsCertificate * self)
349 {
350   g_return_val_if_fail (GST_IS_DTLS_CERTIFICATE (self), NULL);
351   return self->priv->private_key;
352 }
353