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
48 #include <openssl/bn.h>
49 #include <openssl/rsa.h>
50 #include <openssl/ssl.h>
52 #if OPENSSL_VERSION_NUMBER < 0x10100000L
53 #define X509_getm_notBefore X509_get_notBefore
54 #define X509_getm_notAfter X509_get_notAfter
57 GST_DEBUG_CATEGORY_STATIC (gst_dtls_certificate_debug);
58 #define GST_CAT_DEFAULT gst_dtls_certificate_debug
67 static GParamSpec *properties[NUM_PROPERTIES];
69 #define DEFAULT_PEM NULL
71 struct _GstDtlsCertificatePrivate
74 EVP_PKEY *private_key;
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"));
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 *);
90 static void init_generated (GstDtlsCertificate *);
91 static void init_from_pem_string (GstDtlsCertificate *, const gchar * pem);
94 gst_dtls_certificate_class_init (GstDtlsCertificateClass * klass)
96 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
98 gobject_class->set_property = gst_dtls_certificate_set_property;
99 gobject_class->get_property = gst_dtls_certificate_get_property;
101 properties[PROP_PEM] =
102 g_param_spec_string ("pem",
104 "A string containing a X509 certificate and RSA private key in PEM format",
106 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
108 g_object_class_install_properties (gobject_class, NUM_PROPERTIES, properties);
110 _gst_dtls_init_openssl ();
112 gobject_class->finalize = gst_dtls_certificate_finalize;
116 gst_dtls_certificate_init (GstDtlsCertificate * self)
118 GstDtlsCertificatePrivate *priv;
120 self->priv = priv = gst_dtls_certificate_get_instance_private (self);
123 priv->private_key = NULL;
128 gst_dtls_certificate_finalize (GObject * gobject)
130 GstDtlsCertificatePrivate *priv = GST_DTLS_CERTIFICATE (gobject)->priv;
132 X509_free (priv->x509);
135 EVP_PKEY_free (priv->private_key);
136 priv->private_key = NULL;
142 G_OBJECT_CLASS (gst_dtls_certificate_parent_class)->finalize (gobject);
146 gst_dtls_certificate_set_property (GObject * object, guint prop_id,
147 const GValue * value, GParamSpec * pspec)
149 GstDtlsCertificate *self = GST_DTLS_CERTIFICATE (object);
154 pem = g_value_get_string (value);
156 init_from_pem_string (self, pem);
158 init_generated (self);
162 G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
167 gst_dtls_certificate_get_property (GObject * object, guint prop_id,
168 GValue * value, GParamSpec * pspec)
170 GstDtlsCertificate *self = GST_DTLS_CERTIFICATE (object);
174 g_return_if_fail (self->priv->pem);
175 g_value_set_string (value, self->priv->pem);
178 G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
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', '+', '/'
191 init_generated (GstDtlsCertificate * self)
193 GstDtlsCertificatePrivate *priv = self->priv;
195 BIGNUM *serial_number;
196 ASN1_INTEGER *asn1_serial_number;
197 X509_NAME *name = NULL;
198 gchar common_name[9] = { 0, };
201 g_return_if_fail (!priv->x509);
202 g_return_if_fail (!priv->private_key);
204 priv->private_key = EVP_PKEY_new ();
206 if (!priv->private_key) {
207 GST_WARNING_OBJECT (self, "failed to create private key");
211 priv->x509 = X509_new ();
214 GST_WARNING_OBJECT (self, "failed to create certificate");
215 EVP_PKEY_free (priv->private_key);
216 priv->private_key = NULL;
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);
226 BIGNUM *e = BN_new ();
227 if (e == NULL || !BN_set_word (e, RSA_F4)
228 || !RSA_generate_key_ex (rsa, 2048, e, NULL)) {
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);
246 if (!EVP_PKEY_assign_RSA (priv->private_key, rsa)) {
247 GST_WARNING_OBJECT (self, "failed to assign RSA");
250 EVP_PKEY_free (priv->private_key);
251 priv->private_key = NULL;
252 X509_free (priv->x509);
258 X509_set_version (priv->x509, 2);
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);
267 /* Set a random 8 byte base64 string as issuer/subject */
268 name = X509_NAME_new ();
269 for (i = 0; i < 8; 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);
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);
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);
292 self->priv->pem = _gst_dtls_x509_to_pem (priv->x509);
296 init_from_pem_string (GstDtlsCertificate * self, const gchar * pem)
298 GstDtlsCertificatePrivate *priv = self->priv;
301 g_return_if_fail (pem);
302 g_return_if_fail (!priv->x509);
303 g_return_if_fail (!priv->private_key);
305 bio = BIO_new_mem_buf ((gpointer) pem, -1);
306 g_return_if_fail (bio);
308 priv->x509 = PEM_read_bio_X509 (bio, NULL, NULL, NULL);
311 GST_WARNING_OBJECT (self, "failed to read certificate from pem string");
315 (void) BIO_reset (bio);
317 priv->private_key = PEM_read_bio_PrivateKey (bio, NULL, NULL, NULL);
322 if (!priv->private_key) {
323 GST_WARNING_OBJECT (self, "failed to read private key from pem string");
324 X509_free (priv->x509);
329 self->priv->pem = g_strdup (pem);
333 _gst_dtls_x509_to_pem (gpointer x509)
335 #define GST_DTLS_BIO_BUFFER_SIZE 4096
337 gchar buffer[GST_DTLS_BIO_BUFFER_SIZE] = { 0 };
341 bio = BIO_new (BIO_s_mem ());
342 g_return_val_if_fail (bio, NULL);
344 if (!PEM_write_bio_X509 (bio, (X509 *) x509)) {
345 g_warn_if_reached ();
349 len = BIO_read (bio, buffer, GST_DTLS_BIO_BUFFER_SIZE);
351 g_warn_if_reached ();
355 pem = g_strndup (buffer, len);
363 GstDtlsCertificateInternalCertificate
364 _gst_dtls_certificate_get_internal_certificate (GstDtlsCertificate * self)
366 g_return_val_if_fail (GST_IS_DTLS_CERTIFICATE (self), NULL);
367 return self->priv->x509;
370 GstDtlsCertificateInternalKey
371 _gst_dtls_certificate_get_internal_key (GstDtlsCertificate * self)
373 g_return_val_if_fail (GST_IS_DTLS_CERTIFICATE (self), NULL);
374 return self->priv->private_key;