2 * Copyright (c) 2014, Ericsson AB. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without modification,
5 * are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright notice, this
8 * list of conditions and the following disclaimer.
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.
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
32 #include "gstdtlscertificate.h"
34 #include "gstdtlsagent.h"
37 # define __AVAILABILITYMACROS__
38 # define DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER
49 #include <openssl/bn.h>
50 #include <openssl/rsa.h>
51 #include <openssl/ssl.h>
53 #if OPENSSL_VERSION_NUMBER < 0x10100000L
54 #define X509_getm_notBefore X509_get_notBefore
55 #define X509_getm_notAfter X509_get_notAfter
58 GST_DEBUG_CATEGORY_STATIC (gst_dtls_certificate_debug);
59 #define GST_CAT_DEFAULT gst_dtls_certificate_debug
68 static GParamSpec *properties[NUM_PROPERTIES];
70 #define DEFAULT_PEM NULL
72 struct _GstDtlsCertificatePrivate
75 EVP_PKEY *private_key;
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"));
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 *);
91 static void init_generated (GstDtlsCertificate *);
92 static void init_from_pem_string (GstDtlsCertificate *, const gchar * pem);
95 gst_dtls_certificate_class_init (GstDtlsCertificateClass * klass)
97 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
99 gobject_class->set_property = gst_dtls_certificate_set_property;
100 gobject_class->get_property = gst_dtls_certificate_get_property;
102 properties[PROP_PEM] =
103 g_param_spec_string ("pem",
105 "A string containing a X509 certificate and RSA private key in PEM format",
107 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
109 g_object_class_install_properties (gobject_class, NUM_PROPERTIES, properties);
111 _gst_dtls_init_openssl ();
113 gobject_class->finalize = gst_dtls_certificate_finalize;
117 gst_dtls_certificate_init (GstDtlsCertificate * self)
119 GstDtlsCertificatePrivate *priv;
121 self->priv = priv = gst_dtls_certificate_get_instance_private (self);
124 priv->private_key = NULL;
129 gst_dtls_certificate_finalize (GObject * gobject)
131 GstDtlsCertificatePrivate *priv = GST_DTLS_CERTIFICATE (gobject)->priv;
133 X509_free (priv->x509);
136 EVP_PKEY_free (priv->private_key);
137 priv->private_key = NULL;
143 G_OBJECT_CLASS (gst_dtls_certificate_parent_class)->finalize (gobject);
147 gst_dtls_certificate_set_property (GObject * object, guint prop_id,
148 const GValue * value, GParamSpec * pspec)
150 GstDtlsCertificate *self = GST_DTLS_CERTIFICATE (object);
155 pem = g_value_get_string (value);
157 init_from_pem_string (self, pem);
159 init_generated (self);
163 G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
168 gst_dtls_certificate_get_property (GObject * object, guint prop_id,
169 GValue * value, GParamSpec * pspec)
171 GstDtlsCertificate *self = GST_DTLS_CERTIFICATE (object);
175 g_return_if_fail (self->priv->pem);
176 g_value_set_string (value, self->priv->pem);
179 G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
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', '+', '/'
192 init_generated (GstDtlsCertificate * self)
194 GstDtlsCertificatePrivate *priv = self->priv;
196 BIGNUM *serial_number;
197 ASN1_INTEGER *asn1_serial_number;
198 X509_NAME *name = NULL;
199 gchar common_name[9] = { 0, };
202 g_return_if_fail (!priv->x509);
203 g_return_if_fail (!priv->private_key);
205 priv->private_key = EVP_PKEY_new ();
207 if (!priv->private_key) {
208 GST_WARNING_OBJECT (self, "failed to create private key");
212 priv->x509 = X509_new ();
215 GST_WARNING_OBJECT (self, "failed to create certificate");
216 EVP_PKEY_free (priv->private_key);
217 priv->private_key = NULL;
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);
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
231 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
233 G_GNUC_END_IGNORE_DEPRECATIONS;
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)) {
242 G_GNUC_END_IGNORE_DEPRECATIONS;
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);
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");
263 G_GNUC_END_IGNORE_DEPRECATIONS;
265 EVP_PKEY_free (priv->private_key);
266 priv->private_key = NULL;
267 X509_free (priv->x509);
273 X509_set_version (priv->x509, 2);
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);
284 /* Set a random 8 byte base64 string as issuer/subject */
285 name = X509_NAME_new ();
286 for (i = 0; i < 8; 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);
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);
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);
309 self->priv->pem = _gst_dtls_x509_to_pem (priv->x509);
313 init_from_pem_string (GstDtlsCertificate * self, const gchar * pem)
315 GstDtlsCertificatePrivate *priv = self->priv;
318 g_return_if_fail (pem);
319 g_return_if_fail (!priv->x509);
320 g_return_if_fail (!priv->private_key);
322 bio = BIO_new_mem_buf ((gpointer) pem, -1);
323 g_return_if_fail (bio);
325 priv->x509 = PEM_read_bio_X509 (bio, NULL, NULL, NULL);
328 GST_WARNING_OBJECT (self, "failed to read certificate from pem string");
332 (void) BIO_reset (bio);
334 priv->private_key = PEM_read_bio_PrivateKey (bio, NULL, NULL, NULL);
339 if (!priv->private_key) {
340 GST_WARNING_OBJECT (self, "failed to read private key from pem string");
341 X509_free (priv->x509);
346 self->priv->pem = g_strdup (pem);
350 _gst_dtls_x509_to_pem (gpointer x509)
352 #define GST_DTLS_BIO_BUFFER_SIZE 4096
354 gchar buffer[GST_DTLS_BIO_BUFFER_SIZE] = { 0 };
358 bio = BIO_new (BIO_s_mem ());
359 g_return_val_if_fail (bio, NULL);
361 if (!PEM_write_bio_X509 (bio, (X509 *) x509)) {
362 g_warn_if_reached ();
366 len = BIO_read (bio, buffer, GST_DTLS_BIO_BUFFER_SIZE);
368 g_warn_if_reached ();
372 pem = g_strndup (buffer, len);
380 GstDtlsCertificateInternalCertificate
381 _gst_dtls_certificate_get_internal_certificate (GstDtlsCertificate * self)
383 g_return_val_if_fail (GST_IS_DTLS_CERTIFICATE (self), NULL);
384 return self->priv->x509;
387 GstDtlsCertificateInternalKey
388 _gst_dtls_certificate_get_internal_key (GstDtlsCertificate * self)
390 g_return_val_if_fail (GST_IS_DTLS_CERTIFICATE (self), NULL);
391 return self->priv->private_key;