gstdtlscertificate: Define _WINSOCKAPI_ before including windows.h
[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 #define _WINSOCKAPI_
43 #include <windows.h>
44 #ifdef X509_NAME
45 #undef X509_NAME
46 #endif
47 #endif
48
49 #include <openssl/bn.h>
50 #include <openssl/rsa.h>
51 #include <openssl/ssl.h>
52
53 #if OPENSSL_VERSION_NUMBER < 0x10100000L
54 #define X509_getm_notBefore X509_get_notBefore
55 #define X509_getm_notAfter X509_get_notAfter
56 #endif
57
58 GST_DEBUG_CATEGORY_STATIC (gst_dtls_certificate_debug);
59 #define GST_CAT_DEFAULT gst_dtls_certificate_debug
60
61 enum
62 {
63   PROP_0,
64   PROP_PEM,
65   NUM_PROPERTIES
66 };
67
68 static GParamSpec *properties[NUM_PROPERTIES];
69
70 #define DEFAULT_PEM NULL
71
72 struct _GstDtlsCertificatePrivate
73 {
74   X509 *x509;
75   EVP_PKEY *private_key;
76
77   gchar *pem;
78 };
79
80 G_DEFINE_TYPE_WITH_CODE (GstDtlsCertificate, gst_dtls_certificate,
81     G_TYPE_OBJECT, G_ADD_PRIVATE (GstDtlsCertificate)
82     GST_DEBUG_CATEGORY_INIT (gst_dtls_certificate_debug,
83         "dtlscertificate", 0, "DTLS Certificate"));
84
85 static void gst_dtls_certificate_finalize (GObject * gobject);
86 static void gst_dtls_certificate_set_property (GObject *, guint prop_id,
87     const GValue *, GParamSpec *);
88 static void gst_dtls_certificate_get_property (GObject *, guint prop_id,
89     GValue *, GParamSpec *);
90
91 static void init_generated (GstDtlsCertificate *);
92 static void init_from_pem_string (GstDtlsCertificate *, const gchar * pem);
93
94 static void
95 gst_dtls_certificate_class_init (GstDtlsCertificateClass * klass)
96 {
97   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
98
99   gobject_class->set_property = gst_dtls_certificate_set_property;
100   gobject_class->get_property = gst_dtls_certificate_get_property;
101
102   properties[PROP_PEM] =
103       g_param_spec_string ("pem",
104       "Pem string",
105       "A string containing a X509 certificate and RSA private key in PEM format",
106       DEFAULT_PEM,
107       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
108
109   g_object_class_install_properties (gobject_class, NUM_PROPERTIES, properties);
110
111   _gst_dtls_init_openssl ();
112
113   gobject_class->finalize = gst_dtls_certificate_finalize;
114 }
115
116 static void
117 gst_dtls_certificate_init (GstDtlsCertificate * self)
118 {
119   GstDtlsCertificatePrivate *priv;
120
121   self->priv = priv = gst_dtls_certificate_get_instance_private (self);
122
123   priv->x509 = NULL;
124   priv->private_key = NULL;
125   priv->pem = NULL;
126 }
127
128 static void
129 gst_dtls_certificate_finalize (GObject * gobject)
130 {
131   GstDtlsCertificatePrivate *priv = GST_DTLS_CERTIFICATE (gobject)->priv;
132
133   X509_free (priv->x509);
134   priv->x509 = NULL;
135
136   EVP_PKEY_free (priv->private_key);
137   priv->private_key = NULL;
138
139
140   g_free (priv->pem);
141   priv->pem = NULL;
142
143   G_OBJECT_CLASS (gst_dtls_certificate_parent_class)->finalize (gobject);
144 }
145
146 static void
147 gst_dtls_certificate_set_property (GObject * object, guint prop_id,
148     const GValue * value, GParamSpec * pspec)
149 {
150   GstDtlsCertificate *self = GST_DTLS_CERTIFICATE (object);
151   const gchar *pem;
152
153   switch (prop_id) {
154     case PROP_PEM:
155       pem = g_value_get_string (value);
156       if (pem) {
157         init_from_pem_string (self, pem);
158       } else {
159         init_generated (self);
160       }
161       break;
162     default:
163       G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
164   }
165 }
166
167 static void
168 gst_dtls_certificate_get_property (GObject * object, guint prop_id,
169     GValue * value, GParamSpec * pspec)
170 {
171   GstDtlsCertificate *self = GST_DTLS_CERTIFICATE (object);
172
173   switch (prop_id) {
174     case PROP_PEM:
175       g_return_if_fail (self->priv->pem);
176       g_value_set_string (value, self->priv->pem);
177       break;
178     default:
179       G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
180   }
181 }
182
183 static const gchar base64_alphabet[64] = {
184   'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
185   'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
186   'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
187   'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
188   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
189 };
190
191 static void
192 init_generated (GstDtlsCertificate * self)
193 {
194   GstDtlsCertificatePrivate *priv = self->priv;
195   RSA *rsa;
196   BIGNUM *serial_number;
197   ASN1_INTEGER *asn1_serial_number;
198   X509_NAME *name = NULL;
199   gchar common_name[9] = { 0, };
200   gint i;
201
202   g_return_if_fail (!priv->x509);
203   g_return_if_fail (!priv->private_key);
204
205   priv->private_key = EVP_PKEY_new ();
206
207   if (!priv->private_key) {
208     GST_WARNING_OBJECT (self, "failed to create private key");
209     return;
210   }
211
212   priv->x509 = X509_new ();
213
214   if (!priv->x509) {
215     GST_WARNING_OBJECT (self, "failed to create certificate");
216     EVP_PKEY_free (priv->private_key);
217     priv->private_key = NULL;
218     return;
219   }
220
221   /* XXX: RSA_generate_key is actually deprecated in 0.9.8 */
222 #if OPENSSL_VERSION_NUMBER < 0x10100001L
223   rsa = RSA_generate_key (2048, RSA_F4, NULL, NULL);
224 #else
225   /*
226    * OpenSSL 3.0 deprecated all low-level APIs, so we need to rewrite this code
227    * to get rid of the warnings. The porting guide explicitly recommends
228    * disabling the warnings if this is not feasible, so let's do that for now:
229    * https://wiki.openssl.org/index.php/OpenSSL_3.0#Upgrading_to_OpenSSL_3.0_from_OpenSSL_1.1.1
230    */
231   G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
232   rsa = RSA_new ();
233   G_GNUC_END_IGNORE_DEPRECATIONS;
234   if (rsa != NULL) {
235     BIGNUM *e = BN_new ();
236     G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
237     if (e == NULL || !BN_set_word (e, RSA_F4)
238         || !RSA_generate_key_ex (rsa, 2048, e, NULL)) {
239       RSA_free (rsa);
240       rsa = NULL;
241     }
242     G_GNUC_END_IGNORE_DEPRECATIONS;
243     if (e)
244       BN_free (e);
245   }
246 #endif
247
248   if (!rsa) {
249     GST_WARNING_OBJECT (self, "failed to generate RSA");
250     G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
251     EVP_PKEY_free (priv->private_key);
252     G_GNUC_END_IGNORE_DEPRECATIONS;
253     priv->private_key = NULL;
254     X509_free (priv->x509);
255     priv->x509 = NULL;
256     return;
257   }
258
259   G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
260   if (!EVP_PKEY_assign_RSA (priv->private_key, rsa)) {
261     GST_WARNING_OBJECT (self, "failed to assign RSA");
262     RSA_free (rsa);
263     G_GNUC_END_IGNORE_DEPRECATIONS;
264     rsa = NULL;
265     EVP_PKEY_free (priv->private_key);
266     priv->private_key = NULL;
267     X509_free (priv->x509);
268     priv->x509 = NULL;
269     return;
270   }
271   rsa = NULL;
272
273   X509_set_version (priv->x509, 2);
274
275   /* Set a random 64 bit integer as serial number */
276   serial_number = BN_new ();
277   G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
278   BN_pseudo_rand (serial_number, 64, 0, 0);
279   G_GNUC_END_IGNORE_DEPRECATIONS;
280   asn1_serial_number = X509_get_serialNumber (priv->x509);
281   BN_to_ASN1_INTEGER (serial_number, asn1_serial_number);
282   BN_free (serial_number);
283
284   /* Set a random 8 byte base64 string as issuer/subject */
285   name = X509_NAME_new ();
286   for (i = 0; i < 8; i++)
287     common_name[i] =
288         base64_alphabet[g_random_int_range (0, G_N_ELEMENTS (base64_alphabet))];
289   X509_NAME_add_entry_by_NID (name, NID_commonName, MBSTRING_ASC,
290       (const guchar *) common_name, -1, -1, 0);
291   X509_set_subject_name (priv->x509, name);
292   X509_set_issuer_name (priv->x509, name);
293   X509_NAME_free (name);
294
295   /* Set expiry in a year */
296   X509_gmtime_adj (X509_getm_notBefore (priv->x509), 0);
297   X509_gmtime_adj (X509_getm_notAfter (priv->x509), 31536000L); /* A year */
298   X509_set_pubkey (priv->x509, priv->private_key);
299
300   if (!X509_sign (priv->x509, priv->private_key, EVP_sha256 ())) {
301     GST_WARNING_OBJECT (self, "failed to sign certificate");
302     EVP_PKEY_free (priv->private_key);
303     priv->private_key = NULL;
304     X509_free (priv->x509);
305     priv->x509 = NULL;
306     return;
307   }
308
309   self->priv->pem = _gst_dtls_x509_to_pem (priv->x509);
310 }
311
312 static void
313 init_from_pem_string (GstDtlsCertificate * self, const gchar * pem)
314 {
315   GstDtlsCertificatePrivate *priv = self->priv;
316   BIO *bio;
317
318   g_return_if_fail (pem);
319   g_return_if_fail (!priv->x509);
320   g_return_if_fail (!priv->private_key);
321
322   bio = BIO_new_mem_buf ((gpointer) pem, -1);
323   g_return_if_fail (bio);
324
325   priv->x509 = PEM_read_bio_X509 (bio, NULL, NULL, NULL);
326
327   if (!priv->x509) {
328     GST_WARNING_OBJECT (self, "failed to read certificate from pem string");
329     return;
330   }
331
332   (void) BIO_reset (bio);
333
334   priv->private_key = PEM_read_bio_PrivateKey (bio, NULL, NULL, NULL);
335
336   BIO_free (bio);
337   bio = NULL;
338
339   if (!priv->private_key) {
340     GST_WARNING_OBJECT (self, "failed to read private key from pem string");
341     X509_free (priv->x509);
342     priv->x509 = NULL;
343     return;
344   }
345
346   self->priv->pem = g_strdup (pem);
347 }
348
349 gchar *
350 _gst_dtls_x509_to_pem (gpointer x509)
351 {
352 #define GST_DTLS_BIO_BUFFER_SIZE 4096
353   BIO *bio;
354   gchar buffer[GST_DTLS_BIO_BUFFER_SIZE] = { 0 };
355   gint len;
356   gchar *pem = NULL;
357
358   bio = BIO_new (BIO_s_mem ());
359   g_return_val_if_fail (bio, NULL);
360
361   if (!PEM_write_bio_X509 (bio, (X509 *) x509)) {
362     g_warn_if_reached ();
363     goto beach;
364   }
365
366   len = BIO_read (bio, buffer, GST_DTLS_BIO_BUFFER_SIZE);
367   if (!len) {
368     g_warn_if_reached ();
369     goto beach;
370   }
371
372   pem = g_strndup (buffer, len);
373
374 beach:
375   BIO_free (bio);
376
377   return pem;
378 }
379
380 GstDtlsCertificateInternalCertificate
381 _gst_dtls_certificate_get_internal_certificate (GstDtlsCertificate * self)
382 {
383   g_return_val_if_fail (GST_IS_DTLS_CERTIFICATE (self), NULL);
384   return self->priv->x509;
385 }
386
387 GstDtlsCertificateInternalKey
388 _gst_dtls_certificate_get_internal_key (GstDtlsCertificate * self)
389 {
390   g_return_val_if_fail (GST_IS_DTLS_CERTIFICATE (self), NULL);
391   return self->priv->private_key;
392 }