From eae2e6aecaeed14bab121203f3751225754bd4fb Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Sat, 2 Feb 2013 14:45:44 -0600 Subject: [PATCH] add file --- src/switch_core_cert.c | 314 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 314 insertions(+) create mode 100644 src/switch_core_cert.c diff --git a/src/switch_core_cert.c b/src/switch_core_cert.c new file mode 100644 index 0000000000..58c140d3e7 --- /dev/null +++ b/src/switch_core_cert.c @@ -0,0 +1,314 @@ +/* + * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2005-2012, Anthony Minessale II + * + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * + * The Initial Developer of the Original Code is + * Anthony Minessale II + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Anthony Minessale II + * + * switch_cert.c -- Cert Functions + * + */ + +#include + + +static const EVP_MD *get_evp_by_name(const char *name) +{ + if (!strcasecmp(name, "md5")) return EVP_md5(); + if (!strcasecmp(name, "sha1")) return EVP_sha1(); + if (!strcasecmp(name, "sha-256")) return EVP_sha256(); + if (!strcasecmp(name, "sha-512")) return EVP_sha512(); + + return NULL; +} + +SWITCH_DECLARE(int) switch_core_cert_verify(dtls_fingerprint_t *fp) +{ + unsigned char fdata[MAX_FPLEN] = { 0 }; + char *tmp = strdup(fp->str); + char *p = tmp; + int i = 0; + char *v; + + while ((v = strsep(&p, ":")) && (i != (MAX_FPLEN - 1))) { + sscanf(v, "%02x", (uint32_t *) &fdata[i++]); + } + + free(tmp); + + i = !memcmp(fdata, fp->data, i); + + return i; +} + +SWITCH_DECLARE(int) switch_core_cert_expand_fingerprint(dtls_fingerprint_t *fp, const char *str) +{ + char *tmp = strdup(str); + char *p = tmp; + int i = 0; + char *v; + + while ((v = strsep(&p, ":")) && (i != (MAX_FPLEN - 1))) { + sscanf(v, "%02x", (uint32_t *) &fp->data[i++]); + } + + free(tmp); + + return i; +} + +SWITCH_DECLARE(int) switch_core_cert_extract_fingerprint(X509* x509, dtls_fingerprint_t *fp) +{ + const EVP_MD *evp; + int i, j; + + evp = get_evp_by_name(fp->type); + + if (X509_digest(x509, evp, fp->data, &fp->len) != 1 || fp->len <= 0) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FP DIGEST ERR!\n"); + return -1; + } + + for (i = 0, j = 0; i < fp->len; ++i, j += 3){ + sprintf((char*)&fp->str[j], (i == (fp->len - 1)) ? "%.2X" : "%.2X:", fp->data[i]); + } + *(&fp->str[fp->len * 3]) = '\0'; + + return 0; + +} + +SWITCH_DECLARE(int) switch_core_cert_gen_fingerprint(const char *prefix, dtls_fingerprint_t *fp) +{ + X509* x509 = NULL; + BIO* bio = NULL; + int ret = 0; + char *rsa; + + + rsa = switch_mprintf("%s%s%s.crt", SWITCH_GLOBAL_dirs.certs_dir, SWITCH_PATH_SEPARATOR, prefix); + + if (!(bio = BIO_new(BIO_s_file()))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FP BIO ERR!\n"); + goto end; + } + + if (BIO_read_filename(bio, rsa) != 1) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FP FILE ERR!\n"); + goto end; + } + + if (!(x509 = PEM_read_bio_X509(bio, NULL, 0, NULL))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FP READ ERR!\n"); + goto end; + } + + switch_core_cert_extract_fingerprint(x509, fp); + + ret = 1; + + end: + + if (bio) { + BIO_free_all(bio); + } + + free(rsa); + + return ret; +} + + +static int mkcert(X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial, int days); +static int add_ext(X509 *cert, int nid, char *value); + +SWITCH_DECLARE(int) switch_core_gen_certs(const char *prefix) +{ + //BIO *bio_err; + X509 *x509 = NULL; + EVP_PKEY *pkey = NULL; + char *rsa = NULL, *pvt = NULL; + FILE *fp; + + pvt = switch_mprintf("%s%s%s.key", SWITCH_GLOBAL_dirs.certs_dir, SWITCH_PATH_SEPARATOR, prefix); + rsa = switch_mprintf("%s%s%s.crt", SWITCH_GLOBAL_dirs.certs_dir, SWITCH_PATH_SEPARATOR, prefix); + + if (switch_file_exists(pvt, NULL) == SWITCH_STATUS_SUCCESS || switch_file_exists(rsa, NULL) == SWITCH_STATUS_SUCCESS) { + goto end; + } + + CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON); + + //bio_err=BIO_new_fp(stderr, BIO_NOCLOSE); + + mkcert(&x509, &pkey, 512, 0, 365); + + //RSA_print_fp(stdout, pkey->pkey.rsa, 0); + //X509_print_fp(stdout, x509); + + + if ((fp = fopen(pvt, "w"))) { + PEM_write_PrivateKey(fp, pkey, NULL, NULL, 0, NULL, NULL); + } + + fclose(fp); + + if ((fp = fopen(rsa, "w"))) { + PEM_write_X509(fp, x509); + } + + fclose(fp); + + X509_free(x509); + EVP_PKEY_free(pkey); + +#ifndef OPENSSL_NO_ENGINE + ENGINE_cleanup(); +#endif + CRYPTO_cleanup_all_ex_data(); + + //CRYPTO_mem_leaks(bio_err); + //BIO_free(bio_err); + + + end: + + switch_safe_free(pvt); + switch_safe_free(rsa); + + return(0); +} + +static void callback(int p, int n, void *arg) +{ + char c='B'; + + if (p == 0) c='.'; + if (p == 1) c='+'; + if (p == 2) c='*'; + if (p == 3) c='\n'; + fputc(c, stderr); +} + +static int mkcert(X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial, int days) +{ + X509 *x; + EVP_PKEY *pk; + RSA *rsa; + X509_NAME *name=NULL; + + if ((pkeyp == NULL) || (*pkeyp == NULL)) + { + if ((pk=EVP_PKEY_new()) == NULL) + { + abort(); + return(0); + } + } + else + pk= *pkeyp; + + if ((x509p == NULL) || (*x509p == NULL)) + { + if ((x=X509_new()) == NULL) + goto err; + } + else + x= *x509p; + + rsa=RSA_generate_key(bits, RSA_F4, callback, NULL); + if (!EVP_PKEY_assign_RSA(pk, rsa)) + { + abort(); + goto err; + } + rsa=NULL; + + X509_set_version(x, 2); + ASN1_INTEGER_set(X509_get_serialNumber(x), serial); + X509_gmtime_adj(X509_get_notBefore(x), 0); + X509_gmtime_adj(X509_get_notAfter(x), (long)60*60*24*days); + X509_set_pubkey(x, pk); + + name=X509_get_subject_name(x); + + /* This function creates and adds the entry, working out the + * correct string type and performing checks on its length. + * Normally we'd check the return value for errors... + */ + X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, (unsigned char *)"US", -1, -1, 0); + + X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (unsigned char *)"FreeSWITCH", -1, -1, 0); + + + /* Its self signed so set the issuer name to be the same as the + * subject. + */ + X509_set_issuer_name(x, name); + + /* Add various extensions: standard extensions */ + add_ext(x, NID_basic_constraints, "critical, CA:TRUE"); + add_ext(x, NID_key_usage, "critical, keyCertSign, cRLSign"); + + add_ext(x, NID_subject_key_identifier, "hash"); + + /* Some Netscape specific extensions */ + add_ext(x, NID_netscape_cert_type, "sslCA"); + + add_ext(x, NID_netscape_comment, "Self-Signed CERT for DTLS"); + + + if (!X509_sign(x, pk, EVP_md5())) + goto err; + + *x509p=x; + *pkeyp=pk; + return(1); + err: + return(0); +} + +/* Add extension using V3 code: we can set the config file as NULL + * because we wont reference any other sections. + */ + +static int add_ext(X509 *cert, int nid, char *value) +{ + X509_EXTENSION *ex; + X509V3_CTX ctx; + /* This sets the 'context' of the extensions. */ + /* No configuration database */ + X509V3_set_ctx_nodb(&ctx); + /* Issuer and subject certs: both the target since it is self signed, + * no request and no CRL + */ + X509V3_set_ctx(&ctx, cert, cert, NULL, NULL, 0); + ex = X509V3_EXT_conf_nid(NULL, &ctx, nid, value); + if (!ex) + return 0; + + X509_add_ext(cert, ex, -1); + X509_EXTENSION_free(ex); + return 1; +} +