media: mux RTP and RTCP when using TCP connection
[siplcs.git] / src / core / sipe-cert-crypto-openssl.c
blobe38c18526dfefdbe9f72100ab1398f26247f4f08
1 /**
2 * @file sipe-cert-crypto-openssl.c
4 * pidgin-sipe
6 * Copyright (C) 2013 SIPE Project <http://sipe.sourceforge.net/>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 /**
24 * Certificate routines implementation based on OpenSSL.
27 #include <openssl/evp.h>
28 #include <openssl/rsa.h>
29 #include <openssl/x509.h>
31 #include <time.h>
33 #include <glib.h>
35 #include "sipe-backend.h"
36 #include "sipe-cert-crypto.h"
38 struct sipe_cert_crypto {
39 RSA *key;
43 * This data structure is used in two different modes
45 * a) certificate generated by the server from our Certificate Request
47 * key - reference to client RSA key, don't free!
48 * decoded - certificate as OpenSSL data structure, must be freed
49 * raw - certificate as DER encoded binary, must be freed
50 * length - length of DER binary
52 * b) server certificate
54 * key - reference to server public key, must be freed
55 * decoded - certificate as OpenSSL data structure, must be freed
56 * raw - NULL
57 * length - modulus length of server public key
59 struct certificate_openssl {
60 RSA *key;
61 EVP_PKEY *public;
62 X509 *decoded;
63 guchar *raw;
64 gsize length;
67 struct sipe_cert_crypto *sipe_cert_crypto_init(void)
69 struct sipe_cert_crypto *scc = g_new0(struct sipe_cert_crypto, 1);
71 /* RSA parameters - should those be configurable? */
72 SIPE_DEBUG_INFO_NOFORMAT("sipe_cert_crypto_init: generate key pair, this might take a while...");
73 scc->key = RSA_generate_key(2048, 65537, NULL, NULL);
75 if (scc->key) {
76 SIPE_DEBUG_INFO_NOFORMAT("sipe_cert_crypto_init: key pair generated");
77 return(scc);
80 SIPE_DEBUG_ERROR_NOFORMAT("sipe_cert_crypto_init: key generation failed");
81 g_free(scc);
82 return(NULL);
85 void sipe_cert_crypto_free(struct sipe_cert_crypto *scc)
87 if (scc) {
88 if (scc->key)
89 RSA_free(scc->key);
90 g_free(scc);
95 gchar *sipe_cert_crypto_request(struct sipe_cert_crypto *scc,
96 const gchar *subject)
98 gchar *base64 = NULL;
99 EVP_PKEY *pkey;
101 if (!scc || !subject)
102 return(NULL);
104 if ((pkey = EVP_PKEY_new()) != NULL) {
105 X509_REQ *x509_req;
107 if ((x509_req = X509_REQ_new()) != NULL) {
108 X509_NAME *name;
110 EVP_PKEY_set1_RSA(pkey, scc->key);
112 X509_REQ_set_version(x509_req, 2);
113 X509_REQ_set_pubkey(x509_req, pkey);
115 name = X509_REQ_get_subject_name(x509_req);
116 X509_NAME_add_entry_by_txt(name,
117 "CN",
118 MBSTRING_ASC,
119 (guchar *) subject,
120 -1, -1, 0);
122 if (X509_REQ_sign(x509_req, pkey, EVP_sha1())) {
123 gsize length;
124 guchar *buf, *tmp;
127 * Encode into DER format
129 * NOTE: i2d_X509(a, b) autoincrements b!
131 length = i2d_X509_REQ(x509_req, NULL);
132 tmp = buf = g_malloc(length);
133 i2d_X509_REQ(x509_req, &tmp);
135 base64 = g_base64_encode(buf, length);
136 g_free(buf);
138 } else {
139 SIPE_DEBUG_ERROR_NOFORMAT("sipe_cert_crypto_request: can't sign certificate request");
142 X509_REQ_free(x509_req);
143 } else {
144 SIPE_DEBUG_ERROR_NOFORMAT("sipe_cert_crypto_request: can't create x509 request data structure");
147 EVP_PKEY_free(pkey);
148 } else {
149 SIPE_DEBUG_ERROR_NOFORMAT("sipe_cert_crypto_request: can't create private key data structure");
152 return(base64);
155 void sipe_cert_crypto_destroy(gpointer certificate)
157 struct certificate_openssl *co = certificate;
159 if (co) {
160 /* imported server certificate - mode (b) */
161 if (!co->raw && co->key)
162 RSA_free(co->key);
163 if (co->decoded)
164 X509_free(co->decoded);
165 g_free(co->raw);
166 g_free(co);
170 /* generates certificate_openssl in mode (a) */
171 gpointer sipe_cert_crypto_decode(struct sipe_cert_crypto *scc,
172 const gchar *base64)
174 struct certificate_openssl *co = g_new0(struct certificate_openssl, 1);
175 const guchar *tmp;
177 /* NOTE: d2i_X509(NULL, &in, len) autoincrements "in" */
178 tmp = co->raw = g_base64_decode(base64, &co->length);
179 co->decoded = d2i_X509(NULL, &tmp, co->length);
181 if (!co->decoded) {
182 sipe_cert_crypto_destroy(co);
183 return(NULL);
186 co->key = scc->key;
188 return(co);
191 /* generates certificate_openssl in mode (b) */
192 gpointer sipe_cert_crypto_import(const guchar *raw,
193 gsize length)
195 struct certificate_openssl *co = g_new0(struct certificate_openssl, 1);
196 EVP_PKEY *pkey;
198 /* co->raw not needed as this is a server certificate */
199 /* NOTE: d2i_X509(NULL, in, len) autoincrements "in" */
200 co->decoded = d2i_X509(NULL, &raw, length);
202 if (!co->decoded) {
203 sipe_cert_crypto_destroy(co);
204 return(NULL);
207 pkey = X509_get_pubkey(co->decoded);
209 if (!pkey) {
210 sipe_cert_crypto_destroy(co);
211 return(NULL);
214 co->key = EVP_PKEY_get1_RSA(pkey);
215 co->length = EVP_PKEY_size(pkey);
216 EVP_PKEY_free(pkey);
218 if (!co->key) {
219 sipe_cert_crypto_destroy(co);
220 return(NULL);
223 return(co);
226 gboolean sipe_cert_crypto_valid(gpointer certificate,
227 guint offset)
229 struct certificate_openssl *co = certificate;
230 time_t compare = time(NULL) + offset;
232 return(co &&
233 (X509_cmp_time(X509_get_notAfter(co->decoded),
234 &compare) > 0));
237 guint sipe_cert_crypto_expires(gpointer certificate)
239 struct certificate_openssl *co = certificate;
240 guint min;
241 guint max;
243 /* make sure certificate hasn't expired already */
244 if (!sipe_cert_crypto_valid(co, 0))
245 return(0);
248 * I can't believe this, but it's true...
250 * OpenSSL doesn't have a public API to convert an ASN1_TIME
251 * to seconds since epoch :-(
253 * @TODO: latest OpenSSL API has ASN1_TIME_diff()
255 * <30000 seconds (~8 hours) seems to be the most common expiration
256 * value. Run a bisect to determine the real expiration value.
258 min = 0;
259 max = 30000;
260 while (1) {
261 guint offset = (max - min) / 2 + min;
263 if (offset == min) {
264 break;
265 } else if (sipe_cert_crypto_valid(co, offset)) {
266 min = offset;
267 } else {
268 max = offset;
272 return(min);
275 gsize sipe_cert_crypto_raw_length(gpointer certificate)
277 return(((struct certificate_openssl *) certificate)->length);
280 const guchar *sipe_cert_crypto_raw(gpointer certificate)
282 return(((struct certificate_openssl *) certificate)->raw);
285 gpointer sipe_cert_crypto_public_key(gpointer certificate)
287 return(((struct certificate_openssl *) certificate)->key);
290 gsize sipe_cert_crypto_modulus_length(gpointer certificate)
292 return(((struct certificate_openssl *) certificate)->length);
295 gpointer sipe_cert_crypto_private_key(gpointer certificate)
297 return(((struct certificate_openssl *) certificate)->key);
300 /* Create test certificate for internal key pair (ONLY USE FOR TEST CODE!!!) */
301 gpointer sipe_cert_crypto_test_certificate(struct sipe_cert_crypto *scc)
303 struct certificate_openssl *co = NULL;
304 EVP_PKEY *pkey;
306 if ((pkey = EVP_PKEY_new()) != NULL) {
307 X509 *x509;
309 if ((x509 = X509_new()) != NULL) {
310 X509_NAME *name;
312 EVP_PKEY_set1_RSA(pkey, scc->key);
314 X509_set_version(x509, 2);
315 ASN1_INTEGER_set(X509_get_serialNumber(x509), 0);
316 X509_gmtime_adj(X509_get_notBefore(x509), 0);
317 X509_gmtime_adj(X509_get_notAfter(x509), (long) 60*60*24);
318 X509_set_pubkey(x509, pkey);
320 name = X509_get_subject_name(x509);
321 X509_NAME_add_entry_by_txt(name,
322 "CN",
323 MBSTRING_ASC,
324 (guchar *) "test@test.com",
325 -1, -1, 0);
326 X509_set_issuer_name(x509, name);
328 if (X509_sign(x509, pkey, EVP_sha1())) {
329 guchar *buf;
331 co = g_new0(struct certificate_openssl, 1);
332 co->decoded = x509;
333 co->key = scc->key;
336 * Encode into DER format
338 * NOTE: i2d_X509(a, b) autoincrements b!
340 co->length = i2d_X509(x509, NULL);
341 co->raw = buf = g_malloc(co->length);
342 i2d_X509(x509, &buf);
344 } else {
345 SIPE_DEBUG_ERROR_NOFORMAT("sipe_cert_crypto_test_certificate: can't sign certificate");
346 X509_free(x509);
348 } else {
349 SIPE_DEBUG_ERROR_NOFORMAT("sipe_cert_crypto_test_certificate: can't create x509 data structure");
352 EVP_PKEY_free(pkey);
353 } else {
354 SIPE_DEBUG_ERROR_NOFORMAT("sipe_cert_crypto_test_certificate: can't create private key data structure");
357 return(co);
361 Local Variables:
362 mode: c
363 c-file-style: "bsd"
364 indent-tabs-mode: t
365 tab-width: 8
366 End: