RTS API Documentation  1.10.11
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 #if OPENSSL_VERSION_NUMBER <= 0x10100000
40 
41 static inline void switch_ssl_ssl_lock_callback(int mode, int type, char *file, int line)
42 {
43  if (mode & CRYPTO_LOCK) {
45  }
46  else {
48  }
49 }
50 
51 static inline void switch_ssl_ssl_thread_id(CRYPTO_THREADID *id)
52 {
53  CRYPTO_THREADID_set_numeric(id, (unsigned long)switch_thread_self());
54 }
55 
56 #endif
57 
59 {
60 
61  int i, num;
62 
63  if (ssl_count == 0) {
64  num = CRYPTO_num_locks();
65 
66  ssl_mutexes = OPENSSL_malloc(CRYPTO_num_locks() * sizeof(switch_mutex_t*));
67  switch_assert(ssl_mutexes != NULL);
68 
70 
71  for (i = 0; i < num; i++) {
73  switch_assert(ssl_mutexes[i] != NULL);
74  }
75 
76 #if OPENSSL_VERSION_NUMBER <= 0x10100000
77  CRYPTO_THREADID_set_callback(switch_ssl_ssl_thread_id);
78  CRYPTO_set_locking_callback((void (*)(int, int, const char*, int))switch_ssl_ssl_lock_callback);
79 #endif
80  }
81 
82  ssl_count++;
83 }
84 
86 {
87  int i;
88 
89  if (ssl_count == 1) {
90  CRYPTO_set_locking_callback(NULL);
91  for (i = 0; i < CRYPTO_num_locks(); i++) {
92  if (ssl_mutexes[i]) {
94  }
95  }
96 
97  OPENSSL_free(ssl_mutexes);
98  ssl_count--;
99  }
100 
101  if (ssl_pool) {
103  }
104 }
105 
106 static const EVP_MD *get_evp_by_name(const char *name)
107 {
108  if (!strcasecmp(name, "md5")) return EVP_md5();
109  if (!strcasecmp(name, "sha1")) return EVP_sha1();
110  if (!strcasecmp(name, "sha-1")) return EVP_sha1();
111  if (!strcasecmp(name, "sha-256")) return EVP_sha256();
112  if (!strcasecmp(name, "sha-512")) return EVP_sha512();
113 
114  return NULL;
115 }
116 #if defined(_MSC_VER) || (defined(__SunOS_5_10) && defined(__SUNPRO_C))
117 /*
118  * Visual C do not have strsep?
119  *
120  * Solaris 10 with the Sun Studio compilers doesn't have strsep in the
121  * C library either.
122  */
123 char *strsep(char **stringp, const char *delim)
124 {
125  char *res;
126 
127  if (!stringp || !*stringp || !**stringp)
128  return (char *) 0;
129 
130  res = *stringp;
131  while (**stringp && !strchr(delim, **stringp))
132  ++(*stringp);
133 
134  if (**stringp) {
135  **stringp = '\0';
136  ++(*stringp);
137  }
138 
139  return res;
140 }
141 #endif
142 
144 {
145  unsigned char fdata[MAX_FPLEN] = { 0 };
146  char *tmp = strdup(fp->str);
147  char *p = tmp;
148  int i = 0;
149  char *v;
150 
151  while ((v = strsep(&p, ":")) && (i != (MAX_FPLEN - 1))) {
152  sscanf(v, "%02x", (uint32_t *) &fdata[i++]);
153  }
154 
155  free(tmp);
156 
157  i = !memcmp(fdata, fp->data, i);
158 
159  return i;
160 }
161 
163 {
164  char *tmp = strdup(str);
165  char *p = tmp;
166  int i = 0;
167  char *v;
168 
169  while ((v = strsep(&p, ":")) && (i != (MAX_FPLEN - 1))) {
170  sscanf(v, "%02x", (uint32_t *) &fp->data[i++]);
171  }
172 
173  free(tmp);
174 
175  return i;
176 }
177 
179 {
180  const EVP_MD *evp;
181  unsigned int i, j;
182 
183  evp = get_evp_by_name(fp->type);
184 
185  if (X509_digest(x509, evp, fp->data, &fp->len) != 1 || fp->len <= 0) {
187  return -1;
188  }
189 
190  for (i = 0, j = 0; i < fp->len; ++i, j += 3){
191  sprintf((char*)&fp->str[j], (i == (fp->len - 1)) ? "%.2X" : "%.2X:", fp->data[i]);
192  }
193  *(&fp->str[fp->len * 3]) = '\0';
194 
195  return 0;
196 
197 }
198 
200 {
201  X509* x509 = NULL;
202  BIO* bio = NULL;
203  int ret = 0;
204  char *rsa;
205 
207 
208  if (switch_file_exists(rsa, NULL) != SWITCH_STATUS_SUCCESS) {
209  free(rsa);
211  }
212 
213  if (!(bio = BIO_new(BIO_s_file()))) {
215  goto end;
216  }
217 
218  if (BIO_read_filename(bio, rsa) != 1) {
220  goto end;
221  }
222 
223  if (!(x509 = PEM_read_bio_X509(bio, NULL, 0, NULL))) {
225  goto end;
226  }
227 
229 
230  ret = 1;
231 
232  end:
233 
234  if (bio) {
235  BIO_free_all(bio);
236  }
237 
238  if (x509) {
239  X509_free(x509);
240  }
241 
242  free(rsa);
243 
244  return ret;
245 }
246 
247 
248 static int mkcert(X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial, int days);
249 
250 SWITCH_DECLARE(int) switch_core_gen_certs(const char *prefix)
251 {
252  //BIO *bio_err;
253  X509 *x509 = NULL;
254  EVP_PKEY *pkey = NULL;
255  char *rsa = NULL, *pvt = NULL;
256  FILE *fp;
257  char *pem = NULL;
258 
259  if (switch_stristr(".pem", prefix)) {
260 
261  if (switch_is_file_path(prefix)) {
262  pem = strdup(prefix);
263  } else {
265  }
266 
267  if (switch_file_exists(pem, NULL) == SWITCH_STATUS_SUCCESS) {
268  goto end;
269  }
270  } else {
271  if (switch_is_file_path(prefix)) {
272  pvt = switch_mprintf("%s.key", prefix);
273  rsa = switch_mprintf("%s.crt", prefix);
274  } else {
277  }
278 
280  goto end;
281  }
282  }
283 
284 #ifdef CRYPTO_MEM_CHECK_ON
285  CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
286 #endif
287 
288  //bio_err=BIO_new_fp(stderr, BIO_NOCLOSE);
289 
290  if (!mkcert(&x509, &pkey, 4096, 0, 36500)) {
291  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Certificate generation failed\n");
292  goto end;
293  }
294 
295  //RSA_print_fp(stdout, pkey->pkey.rsa, 0);
296  //X509_print_fp(stdout, x509);
297 
298  if (pem) {
299  if ((fp = fopen(pem, "w"))) {
300  PEM_write_PrivateKey(fp, pkey, NULL, NULL, 0, NULL, NULL);
301  PEM_write_X509(fp, x509);
302  fclose(fp);
303  }
304 
305  } else {
306  if (pvt && (fp = fopen(pvt, "w"))) {
307  PEM_write_PrivateKey(fp, pkey, NULL, NULL, 0, NULL, NULL);
308  fclose(fp);
309  }
310 
311  if (rsa && (fp = fopen(rsa, "w"))) {
312  PEM_write_X509(fp, x509);
313  fclose(fp);
314  }
315  }
316 
317  X509_free(x509);
318  EVP_PKEY_free(pkey);
319 
320 #ifndef OPENSSL_NO_ENGINE
321  ENGINE_cleanup();
322 #endif
323  CRYPTO_cleanup_all_ex_data();
324 
325  //CRYPTO_mem_leaks(bio_err);
326  //BIO_free(bio_err);
327 
328 
329  end:
330 
331  switch_safe_free(pvt);
332  switch_safe_free(rsa);
333  switch_safe_free(pem);
334 
335  return(0);
336 }
337 
339 {
340  char *pem = NULL, *old_pem = NULL;
341  FILE *fp = NULL;
342  EVP_PKEY *pkey = NULL;
343  int bits = 0;
344 
345  if (switch_is_file_path(file)) {
346  pem = strdup(file);
347  } else {
349  }
350 
351  if (switch_file_exists(pem, NULL) != SWITCH_STATUS_SUCCESS) {
352  switch_safe_free(pem);
353 
354  return SWITCH_FALSE;
355  }
356 
357  fp = fopen(pem, "r");
358  if (!fp) {
359  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot open %s: %s\n", pem, strerror(errno));
360  goto rename_pem;
361  }
362 
363  pkey = PEM_read_PrivateKey(fp, NULL, NULL, NULL);
364  fclose(fp);
365 
366  if (!pkey) {
367  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot read key %s: %s\n", pem, ERR_error_string(ERR_get_error(), NULL));
368  goto rename_pem;
369  }
370 
371  bits = EVP_PKEY_bits(pkey);
372  EVP_PKEY_free(pkey);
373 
374  if (bits < 4096) {
375  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "%s cryptographic length is too short (%d), it will be regenerated\n", pem, bits);
376  goto rename_pem;
377  }
378 
379  switch_safe_free(pem);
380 
381  return SWITCH_TRUE;
382 
383 rename_pem:
384 
385  old_pem = switch_mprintf("%s.old", pem);
386 
387  if (rename(pem, old_pem) != -1) {
388  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Renamed %s to %s\n", pem, old_pem);
389  } else {
390  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not rename %s: %s\n", pem, strerror(errno));
391  }
392 
393  switch_safe_free(old_pem);
394  switch_safe_free(pem);
395 
396  return SWITCH_FALSE;
397 }
398 
399 #if 0
400 static void callback(int p, int n, void *arg)
401 {
402  char c='B';
403 
404  if (p == 0) c='.';
405  if (p == 1) c='+';
406  if (p == 2) c='*';
407  if (p == 3) c='\n';
408  fputc(c, stderr);
409 }
410 #endif
411 
412 static int mkcert(X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial, int days)
413 {
414  X509 *x;
415  EVP_PKEY *pk;
416 #if OPENSSL_VERSION_NUMBER < 0x30000000
417  RSA *rsa;
418 #endif
419  X509_NAME *name=NULL;
420 
421  switch_assert(pkeyp);
422  switch_assert(x509p);
423 
424  if (*pkeyp == NULL) {
425  if ((pk = EVP_PKEY_new()) == NULL) {
426  abort();
427  }
428  } else {
429  pk = *pkeyp;
430  }
431 
432  if (*x509p == NULL) {
433  if ((x = X509_new()) == NULL) {
434  goto err;
435  }
436  } else {
437  x = *x509p;
438  }
439 
440 #if OPENSSL_VERSION_NUMBER >= 0x30000000
441  {
442  EVP_PKEY_CTX *ctx;
443 
444  ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
445  /* Setup the key context */
446  if ((!ctx) || (EVP_PKEY_keygen_init(ctx) <= 0) || (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, bits) <= 0)) {
447  abort();
448  goto err;
449  }
450 
451  /* Generate key */
452  if (EVP_PKEY_generate(ctx, &pk) <= 0) {
453  abort();
454  goto err;
455  }
456 
457  EVP_PKEY_CTX_free(ctx);
458  }
459 #elif OPENSSL_VERSION_NUMBER >= 0x10100000
460  rsa = RSA_new();
461  {
462  static const BN_ULONG ULONG_RSA_F4 = RSA_F4;
463  BIGNUM* BN_value_RSA_F4 = BN_new();
464  if (!BN_value_RSA_F4) {
465  abort();
466  goto err;
467  }
468  BN_set_word(BN_value_RSA_F4,ULONG_RSA_F4);
469  RSA_generate_key_ex(rsa, bits, BN_value_RSA_F4, NULL);
470  BN_free(BN_value_RSA_F4);
471  }
472 #else
473  rsa = RSA_generate_key(bits, RSA_F4, NULL, NULL);
474 #endif
475 
476 #if OPENSSL_VERSION_NUMBER < 0x30000000
477  if (!EVP_PKEY_assign_RSA(pk, rsa)) {
478  abort();
479  }
480 
481  rsa = NULL;
482 #endif
483 
484  X509_set_version(x, 2);
485  ASN1_INTEGER_set(X509_get_serialNumber(x), serial);
486  X509_gmtime_adj(X509_get_notBefore(x), -(long)60*60*24*7);
487  X509_gmtime_adj(X509_get_notAfter(x), (long)60*60*24*days);
488  X509_set_pubkey(x, pk);
489 
490  name = X509_get_subject_name(x);
491 
492  /* This function creates and adds the entry, working out the
493  * correct string type and performing checks on its length.
494  * Normally we'd check the return value for errors...
495  */
496  X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, (unsigned char *)"US", -1, -1, 0);
497  X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (unsigned char *)"FreeSWITCH", -1, -1, 0);
498 
499 
500  /* Its self signed so set the issuer name to be the same as the
501  * subject.
502  */
503  X509_set_issuer_name(x, name);
504 
505 #if OPENSSL_VERSION_NUMBER >= 0x30000000
506  if (!X509_sign(x, pk, EVP_sha256())) {
507 #else
508  if (!X509_sign(x, pk, EVP_sha1())) {
509 #endif
510  goto err;
511  }
512 
513  *x509p = x;
514  *pkeyp = pk;
515 
516  return(1);
517 err:
518  ERR_print_errors_fp(stdout);
519 
520  return(0);
521 }
522 
523 /* For Emacs:
524  * Local Variables:
525  * mode:c
526  * indent-tabs-mode:t
527  * tab-width:4
528  * c-basic-offset:4
529  * End:
530  * For VIM:
531  * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
532  */
#define switch_core_new_memory_pool(p)
Create a new sub memory pool from the core&#39;s master pool.
Definition: switch_core.h:633
static void switch_ssl_ssl_thread_id(CRYPTO_THREADID *id)
switch_status_t switch_mutex_destroy(switch_mutex_t *lock)
Definition: switch_apr.c:303
#define SWITCH_CHANNEL_LOG
static int ssl_count
switch_cache_db_handle_type_t type
switch_bool_t
Definition: switch_types.h:437
#define switch_core_destroy_memory_pool(p)
Returns a subpool back to the main pool.
Definition: switch_core.h:642
char str[MAX_FPSTRLEN]
Definition: switch_core.h:156
void switch_ssl_init_ssl_locks(void)
int switch_core_gen_certs(const char *prefix)
int switch_core_cert_expand_fingerprint(dtls_fingerprint_t *fp, const char *str)
static switch_mutex_t ** ssl_mutexes
char * type
Definition: switch_core.h:155
switch_status_t switch_mutex_unlock(switch_mutex_t *lock)
Definition: switch_apr.c:313
#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:124
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:308
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:885
switch_status_t switch_mutex_init(switch_mutex_t **lock, unsigned int flags, switch_memory_pool_t *pool)
Definition: switch_apr.c:293
switch_byte_t switch_byte_t uint32_t switch_bitpack_mode_t mode
uint8_t data[MAX_FPLEN+1]
Definition: switch_core.h:154
switch_bool_t switch_core_check_dtls_pem(const char *file)
int switch_core_cert_extract_fingerprint(X509 *x509, dtls_fingerprint_t *fp)
switch_directories SWITCH_GLOBAL_dirs
Definition: switch_core.c:82
struct fspr_thread_mutex_t switch_mutex_t
Definition: switch_apr.h:314
switch_status_t switch_file_exists(const char *filename, switch_memory_pool_t *pool)
Definition: switch_apr.c:519
uint32_t len
Definition: switch_core.h:153
Main Library Header.
static switch_bool_t switch_is_file_path(const char *file)
#define SWITCH_DECLARE(type)
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)
struct fspr_pool_t switch_memory_pool_t
const char *const name
Definition: switch_cJSON.h:250
switch_thread_id_t switch_thread_self(void)
Definition: switch_apr.c:102
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:149