FreeSWITCH API Documentation  1.7.0
switch_core_cert.c
Go to the documentation of this file.
1 /*
2  * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
3  * Copyright (C) 2005-2014, Anthony Minessale II <anthm@freeswitch.org>
4  *
5  * Version: MPL 1.1
6  *
7  * The contents of this file are subject to the Mozilla Public License Version
8  * 1.1 (the "License"); you may not use this file except in compliance with
9  * the License. You may obtain a copy of the License at
10  * http://www.mozilla.org/MPL/
11  *
12  * Software distributed under the License is distributed on an "AS IS" basis,
13  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14  * for the specific language governing rights and limitations under the
15  * License.
16  *
17  * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
18  *
19  * The Initial Developer of the Original Code is
20  * Anthony Minessale II <anthm@freeswitch.org>
21  * Portions created by the Initial Developer are Copyright (C)
22  * the Initial Developer. All Rights Reserved.
23  *
24  * Contributor(s):
25  *
26  * Anthony Minessale II <anthm@freeswitch.org>
27  *
28  * switch_cert.c -- Cert Functions
29  *
30  */
31 
32 #include <switch.h>
33 #include <switch_ssl.h>
34 
37 static int ssl_count = 0;
38 
39 static inline void switch_ssl_ssl_lock_callback(int mode, int type, char *file, int line)
40 {
41  if (mode & CRYPTO_LOCK) {
43  }
44  else {
46  }
47 }
48 
49 static inline unsigned long switch_ssl_ssl_thread_id(void)
50 {
51  return (unsigned long) switch_thread_self();
52 }
53 
55 {
56 
57  int i, num;
58 
59  if (ssl_count == 0) {
60  num = CRYPTO_num_locks();
61 
62  ssl_mutexes = OPENSSL_malloc(CRYPTO_num_locks() * sizeof(switch_mutex_t*));
63  switch_assert(ssl_mutexes != NULL);
64 
66 
67  for (i = 0; i < num; i++) {
69  switch_assert(ssl_mutexes[i] != NULL);
70  }
71 
72  CRYPTO_set_id_callback(switch_ssl_ssl_thread_id);
73  CRYPTO_set_locking_callback((void (*)(int, int, const char*, int))switch_ssl_ssl_lock_callback);
74  }
75 
76  ssl_count++;
77 }
78 
80 {
81  int i;
82 
83  if (ssl_count == 1) {
84  CRYPTO_set_locking_callback(NULL);
85  for (i = 0; i < CRYPTO_num_locks(); i++) {
86  if (ssl_mutexes[i]) {
88  }
89  }
90 
91  OPENSSL_free(ssl_mutexes);
92  ssl_count--;
93  }
94 }
95 
96 static const EVP_MD *get_evp_by_name(const char *name)
97 {
98  if (!strcasecmp(name, "md5")) return EVP_md5();
99  if (!strcasecmp(name, "sha1")) return EVP_sha1();
100  if (!strcasecmp(name, "sha-1")) return EVP_sha1();
101  if (!strcasecmp(name, "sha-256")) return EVP_sha256();
102  if (!strcasecmp(name, "sha-512")) return EVP_sha512();
103 
104  return NULL;
105 }
106 #if defined(_MSC_VER) || (defined(__SunOS_5_10) && defined(__SUNPRO_C))
107 /*
108  * Visual C do not have strsep?
109  *
110  * Solaris 10 with the Sun Studio compilers doesn't have strsep in the
111  * C library either.
112  */
113 char *strsep(char **stringp, const char *delim)
114 {
115  char *res;
116 
117  if (!stringp || !*stringp || !**stringp)
118  return (char *) 0;
119 
120  res = *stringp;
121  while (**stringp && !strchr(delim, **stringp))
122  ++(*stringp);
123 
124  if (**stringp) {
125  **stringp = '\0';
126  ++(*stringp);
127  }
128 
129  return res;
130 }
131 #endif
132 
134 {
135  unsigned char fdata[MAX_FPLEN] = { 0 };
136  char *tmp = strdup(fp->str);
137  char *p = tmp;
138  int i = 0;
139  char *v;
140 
141  while ((v = strsep(&p, ":")) && (i != (MAX_FPLEN - 1))) {
142  sscanf(v, "%02x", (uint32_t *) &fdata[i++]);
143  }
144 
145  free(tmp);
146 
147  i = !memcmp(fdata, fp->data, i);
148 
149  return i;
150 }
151 
153 {
154  char *tmp = strdup(str);
155  char *p = tmp;
156  int i = 0;
157  char *v;
158 
159  while ((v = strsep(&p, ":")) && (i != (MAX_FPLEN - 1))) {
160  sscanf(v, "%02x", (uint32_t *) &fp->data[i++]);
161  }
162 
163  free(tmp);
164 
165  return i;
166 }
167 
169 {
170  const EVP_MD *evp;
171  unsigned int i, j;
172 
173  evp = get_evp_by_name(fp->type);
174 
175  if (X509_digest(x509, evp, fp->data, &fp->len) != 1 || fp->len <= 0) {
177  return -1;
178  }
179 
180  for (i = 0, j = 0; i < fp->len; ++i, j += 3){
181  sprintf((char*)&fp->str[j], (i == (fp->len - 1)) ? "%.2X" : "%.2X:", fp->data[i]);
182  }
183  *(&fp->str[fp->len * 3]) = '\0';
184 
185  return 0;
186 
187 }
188 
190 {
191  X509* x509 = NULL;
192  BIO* bio = NULL;
193  int ret = 0;
194  char *rsa;
195 
197 
198  if (switch_file_exists(rsa, NULL) != SWITCH_STATUS_SUCCESS) {
199  free(rsa);
201  }
202 
203  if (!(bio = BIO_new(BIO_s_file()))) {
205  goto end;
206  }
207 
208  if (BIO_read_filename(bio, rsa) != 1) {
210  goto end;
211  }
212 
213  if (!(x509 = PEM_read_bio_X509(bio, NULL, 0, NULL))) {
215  goto end;
216  }
217 
219 
220  ret = 1;
221 
222  end:
223 
224  if (bio) {
225  BIO_free_all(bio);
226  }
227 
228  if (x509) {
229  X509_free(x509);
230  }
231 
232  free(rsa);
233 
234  return ret;
235 }
236 
237 
238 static int mkcert(X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial, int days);
239 
240 SWITCH_DECLARE(int) switch_core_gen_certs(const char *prefix)
241 {
242  //BIO *bio_err;
243  X509 *x509 = NULL;
244  EVP_PKEY *pkey = NULL;
245  char *rsa = NULL, *pvt = NULL;
246  FILE *fp;
247  char *pem = NULL;
248 
249  if (switch_stristr(".pem", prefix)) {
250 
251  if (switch_is_file_path(prefix)) {
252  pem = strdup(prefix);
253  } else {
255  }
256 
257  if (switch_file_exists(pem, NULL) == SWITCH_STATUS_SUCCESS) {
258  goto end;
259  }
260  } else {
261  if (switch_is_file_path(prefix)) {
262  pvt = switch_mprintf("%s.key", prefix);
263  rsa = switch_mprintf("%s.crt", prefix);
264  } else {
267  }
268 
270  goto end;
271  }
272  }
273 
274  CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
275 
276  //bio_err=BIO_new_fp(stderr, BIO_NOCLOSE);
277 
278  mkcert(&x509, &pkey, 1024, 0, 36500);
279 
280  //RSA_print_fp(stdout, pkey->pkey.rsa, 0);
281  //X509_print_fp(stdout, x509);
282 
283  if (pem) {
284  if ((fp = fopen(pem, "w"))) {
285  PEM_write_PrivateKey(fp, pkey, NULL, NULL, 0, NULL, NULL);
286  PEM_write_X509(fp, x509);
287  fclose(fp);
288  }
289 
290  } else {
291  if (pvt && (fp = fopen(pvt, "w"))) {
292  PEM_write_PrivateKey(fp, pkey, NULL, NULL, 0, NULL, NULL);
293  fclose(fp);
294  }
295 
296  if (rsa && (fp = fopen(rsa, "w"))) {
297  PEM_write_X509(fp, x509);
298  fclose(fp);
299  }
300  }
301 
302  X509_free(x509);
303  EVP_PKEY_free(pkey);
304 
305 #ifndef OPENSSL_NO_ENGINE
306  ENGINE_cleanup();
307 #endif
308  CRYPTO_cleanup_all_ex_data();
309 
310  //CRYPTO_mem_leaks(bio_err);
311  //BIO_free(bio_err);
312 
313 
314  end:
315 
316  switch_safe_free(pvt);
317  switch_safe_free(rsa);
318  switch_safe_free(pem);
319 
320  return(0);
321 }
322 
323 #if 0
324 static void callback(int p, int n, void *arg)
325 {
326  char c='B';
327 
328  if (p == 0) c='.';
329  if (p == 1) c='+';
330  if (p == 2) c='*';
331  if (p == 3) c='\n';
332  fputc(c, stderr);
333 }
334 #endif
335 
336 static int mkcert(X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial, int days)
337 {
338  X509 *x;
339  EVP_PKEY *pk;
340  RSA *rsa;
341  X509_NAME *name=NULL;
342 
343  switch_assert(pkeyp);
344  switch_assert(x509p);
345 
346  if (*pkeyp == NULL) {
347  if ((pk = EVP_PKEY_new()) == NULL) {
348  abort();
349  }
350  } else {
351  pk = *pkeyp;
352  }
353 
354  if (*x509p == NULL) {
355  if ((x = X509_new()) == NULL) {
356  goto err;
357  }
358  } else {
359  x = *x509p;
360  }
361 
362  rsa = RSA_generate_key(bits, RSA_F4, NULL, NULL);
363 
364  if (!EVP_PKEY_assign_RSA(pk, rsa)) {
365  abort();
366  goto err;
367  }
368 
369  rsa = NULL;
370 
371  X509_set_version(x, 0);
372  ASN1_INTEGER_set(X509_get_serialNumber(x), serial);
373  X509_gmtime_adj(X509_get_notBefore(x), -(long)60*60*24*7);
374  X509_gmtime_adj(X509_get_notAfter(x), (long)60*60*24*days);
375  X509_set_pubkey(x, pk);
376 
377  name = X509_get_subject_name(x);
378 
379  /* This function creates and adds the entry, working out the
380  * correct string type and performing checks on its length.
381  * Normally we'd check the return value for errors...
382  */
383  X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, (unsigned char *)"US", -1, -1, 0);
384  X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (unsigned char *)"FreeSWITCH", -1, -1, 0);
385 
386 
387  /* Its self signed so set the issuer name to be the same as the
388  * subject.
389  */
390  X509_set_issuer_name(x, name);
391 
392  if (!X509_sign(x, pk, EVP_sha1()))
393  goto err;
394 
395  *x509p = x;
396  *pkeyp = pk;
397  return(1);
398  err:
399  return(0);
400 }
401 
402 /* For Emacs:
403  * Local Variables:
404  * mode:c
405  * indent-tabs-mode:t
406  * tab-width:4
407  * c-basic-offset:4
408  * End:
409  * For VIM:
410  * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
411  */
#define switch_core_new_memory_pool(p)
Create a new sub memory pool from the core's master pool.
Definition: switch_core.h:631
char name[CACHE_DB_LEN]
switch_status_t switch_mutex_destroy(switch_mutex_t *lock)
Definition: switch_apr.c:280
#define SWITCH_CHANNEL_LOG
static int ssl_count
switch_cache_db_handle_type_t type
void switch_ssl_init_ssl_locks(void)
int switch_core_gen_certs(const char *prefix)
static unsigned long switch_ssl_ssl_thread_id(void)
int switch_core_cert_expand_fingerprint(dtls_fingerprint_t *fp, const char *str)
static switch_mutex_t ** ssl_mutexes
switch_status_t switch_mutex_unlock(switch_mutex_t *lock)
Definition: switch_apr.c:290
#define SWITCH_MUTEX_NESTED
Definition: switch_apr.h:318
int switch_core_cert_verify(dtls_fingerprint_t *fp)
#define SWITCH_PATH_SEPARATOR
Definition: switch_types.h:122
int switch_core_cert_gen_fingerprint(const char *prefix, dtls_fingerprint_t *fp)
switch_status_t switch_mutex_lock(switch_mutex_t *lock)
Definition: switch_apr.c:285
void switch_ssl_destroy_ssl_locks(void)
#define switch_safe_free(it)
Free a pointer and set it to NULL unless it already is NULL.
Definition: switch_utils.h:789
switch_status_t switch_mutex_init(switch_mutex_t **lock, unsigned int flags, switch_memory_pool_t *pool)
Definition: switch_apr.c:270
switch_byte_t switch_byte_t uint32_t switch_bitpack_mode_t mode
int switch_core_cert_extract_fingerprint(X509 *x509, dtls_fingerprint_t *fp)
switch_directories SWITCH_GLOBAL_dirs
Definition: switch_core.c:60
switch_status_t switch_file_exists(const char *filename, switch_memory_pool_t *pool)
Definition: switch_apr.c:496
struct apr_thread_mutex_t switch_mutex_t
Definition: switch_apr.h:314
Main Library Header.
static switch_bool_t switch_is_file_path(const char *file)
#define SWITCH_DECLARE(type)
struct apr_pool_t switch_memory_pool_t
void switch_log_printf(_In_ switch_text_channel_t channel, _In_z_ const char *file, _In_z_ const char *func, _In_ int line, _In_opt_z_ const char *userdata, _In_ switch_log_level_t level, _In_z_ _Printf_format_string_ const char *fmt,...) PRINTF_FUNCTION(7
Write log data to the logging engine.
const char * switch_stristr(const char *instr, const char *str)
switch_thread_id_t switch_thread_self(void)
Definition: switch_apr.c:79
static void switch_ssl_ssl_lock_callback(int mode, int type, char *file, int line)
static switch_memory_pool_t * ssl_pool
#define switch_assert(expr)
static int mkcert(X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial, int days)
SWITCH_BEGIN_EXTERN_C char * switch_mprintf(const char *zFormat,...)
static const EVP_MD * get_evp_by_name(const char *name)
#define MAX_FPLEN
Definition: switch_core.h:147