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