mirror of
https://github.com/signalwire/freeswitch.git
synced 2026-10-07 12:14:00 +00:00
* [Core, mod_commands] Interface allowlist (#3086) * [core] Add interface allowlist to gate module app/api registration Adds an optional, presence-activated allowlist in switch.conf.xml that controls which modules may register application / api / json_api / chat-application interfaces. With no <interface-allowlist> configured nothing is enforced; when at least one <allow> entry is present, only listed interfaces register at load time and all others are refused (the module still loads and switch_loadable_module_process still returns SUCCESS -- the blocked interface is simply never exposed). Entries match at three levels of precision: mod_commands - whole module mod_commands.system - any interface named "system" mod_commands.system.api - a specific type (app|api|json_api|chat_app) Enforcement lives in switch_loadable_module_process() so every module, at boot and at runtime `load`, is subject to the same policy. This gives operators a way to disable the "system"/"spawn" shell-exec API commands (and equivalents) system-wide. Also adds the `interface_allowlist_dump [modules] [plain]` API, which walks the loaded modules and prints their interfaces in the allowlist key format so the current state can be captured and pruned offline into config. * [mod_commands] Add tests for the interface allowlist New test_interface_allowlist boots the core with an active <interface-allowlist> (conf_interface_allowlist/) that permits only a couple of mod_commands interfaces, then loads mod_commands and verifies: - listed commands register and run (status, version) while unlisted and shell-exec commands are refused (system, spawn, uptime) -- refusal surfaces as switch_api_execute returning FALSE / command-not-found, with the command function never invoked; - a "module.name.type" entry gates by type: the API "status" loads while the JSON API of the same name stays blocked; - interface_allowlist_dump prints the config format in its xml, modules and plain variants, and reflects module capabilities (system appears in the dump even though it was blocked from registering). * [config] Fix interior -- in interface-allowlist comment breaking XML parse The explanatory comment used -- as em-dash pairs. The XML parser treats -- inside a comment as the comment close, causing an "unclosed <!--" error that prevents the whole freeswitch.xml from parsing (boot and reloadxml both fail). Replace the -- pairs with ordinary punctuation. * update .gitignore * [core] Warn when interface-allowlist section is present but parses no entries Co-authored-by: Chris Rienzo <chris@signalwire.com> * Merge commit from fork Add `switch_stun_packet_verify_integrity()`, an HMAC-SHA1 MESSAGE-INTEGRITY verifier that is const and non-mutating: it runs over a private copy of the pristine network-order packet, so the caller's buffer and byte order stay untouched, and walks attributes with its own unsigned bounded helper `stun_wire_attr_bounds()` instead of the host-order iterator macros. A trailing MESSAGE-INTEGRITY-SHA256 or FINGERPRINT after MESSAGE-INTEGRITY is tolerated; any other trailing attribute is rejected. Gate it in `handle_ice()` behind `ice->verify_integrity`: verify before any ICE state is touched, keyed by message type (local `ice->pass` for a request, remote `ice->rpass` for a response or error response), and drop on failure. Keepalive indications carry no MESSAGE-INTEGRITY and are ignored. `ice->verify_integrity` is read from the `ice_verify_message_integrity` channel variable in `switch_rtp_activate_ice()` and defaults off, so receive-path behavior is unchanged unless it is enabled. Adds unit tests in `tests/unit/switch_stun.c`. * Merge commit from fork * [core] Verify DTLS client cert against SDP fingerprint (server role) Add opt-in verification of the client certificate when FreeSWITCH is the DTLS server, mirroring the binding the client role already performs on the server certificate: match the peer certificate against the SDP `a=fingerprint` in `dtls_state_setup()`. Selected per call by the `rtp_dtls_client_cert_verify_mode` channel variable (`dtls_client_cert_verify_t`). An unset variable keeps the default `DTLS_CLIENT_CERT_VERIFY_NONE`, so existing behavior is unchanged: - `none`: the server does not request a client certificate. - `fingerprint`: request it (`SSL_VERIFY_PEER` + `dtls_accept_any_cert`) and require its fingerprint to match the SDP value; a self-signed certificate is accepted at the TLS layer and the match provides authenticity. - `full`: additionally let OpenSSL enforce the certificate chain. An unrecognized mode string falls back to `fingerprint` (fail closed) with a warning. The mode is set per `SSL` object in `switch_rtp_add_dtls()`. Verification fails (`DS_FAIL`, no SRTP keys derived) when the client presents no certificate, its fingerprint does not match, or the peer advertised no usable `a=fingerprint`: `get_evp_by_name()` returns `NULL` for a missing or empty hash type and `switch_core_cert_extract_fingerprint()` rejects a `NULL` algorithm rather than passing it to `X509_digest()`. `conf/vanilla/vars.xml` documents the knob as a disabled example. Tests in `tests/unit/switch_rtp.c` cover matching, mismatched, absent-cert, absent-fingerprint, `none`, and unrecognized-mode cases. --------- Co-authored-by: Andrey Volk <andywolk@gmail.com> Co-authored-by: Chris Rienzo <chris@signalwire.com>
542 lines
12 KiB
C
542 lines
12 KiB
C
/*
|
|
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
|
* Copyright (C) 2005-2014, Anthony Minessale II <anthm@freeswitch.org>
|
|
*
|
|
* 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 <anthm@freeswitch.org>
|
|
* Portions created by the Initial Developer are Copyright (C)
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
*
|
|
* Anthony Minessale II <anthm@freeswitch.org>
|
|
*
|
|
* switch_cert.c -- Cert Functions
|
|
*
|
|
*/
|
|
|
|
#include <switch.h>
|
|
#include <switch_ssl.h>
|
|
|
|
static switch_mutex_t **ssl_mutexes;
|
|
static switch_memory_pool_t *ssl_pool = NULL;
|
|
static int ssl_count = 0;
|
|
|
|
#if OPENSSL_VERSION_NUMBER <= 0x10100000
|
|
|
|
static inline void switch_ssl_ssl_lock_callback(int mode, int type, char *file, int line)
|
|
{
|
|
if (mode & CRYPTO_LOCK) {
|
|
switch_mutex_lock(ssl_mutexes[type]);
|
|
}
|
|
else {
|
|
switch_mutex_unlock(ssl_mutexes[type]);
|
|
}
|
|
}
|
|
|
|
static inline void switch_ssl_ssl_thread_id(CRYPTO_THREADID *id)
|
|
{
|
|
CRYPTO_THREADID_set_numeric(id, (unsigned long)switch_thread_self());
|
|
}
|
|
|
|
#endif
|
|
|
|
SWITCH_DECLARE(void) switch_ssl_init_ssl_locks(void)
|
|
{
|
|
|
|
int i, num;
|
|
|
|
if (ssl_count == 0) {
|
|
num = CRYPTO_num_locks();
|
|
|
|
ssl_mutexes = OPENSSL_malloc(CRYPTO_num_locks() * sizeof(switch_mutex_t*));
|
|
switch_assert(ssl_mutexes != NULL);
|
|
|
|
switch_core_new_memory_pool(&ssl_pool);
|
|
|
|
for (i = 0; i < num; i++) {
|
|
switch_mutex_init(&(ssl_mutexes[i]), SWITCH_MUTEX_NESTED, ssl_pool);
|
|
switch_assert(ssl_mutexes[i] != NULL);
|
|
}
|
|
|
|
#if OPENSSL_VERSION_NUMBER <= 0x10100000
|
|
CRYPTO_THREADID_set_callback(switch_ssl_ssl_thread_id);
|
|
CRYPTO_set_locking_callback((void (*)(int, int, const char*, int))switch_ssl_ssl_lock_callback);
|
|
#endif
|
|
}
|
|
|
|
ssl_count++;
|
|
}
|
|
|
|
SWITCH_DECLARE(void) switch_ssl_destroy_ssl_locks(void)
|
|
{
|
|
int i;
|
|
|
|
if (ssl_count == 1) {
|
|
CRYPTO_set_locking_callback(NULL);
|
|
for (i = 0; i < CRYPTO_num_locks(); i++) {
|
|
if (ssl_mutexes[i]) {
|
|
switch_mutex_destroy(ssl_mutexes[i]);
|
|
}
|
|
}
|
|
|
|
OPENSSL_free(ssl_mutexes);
|
|
ssl_count--;
|
|
}
|
|
|
|
if (ssl_pool) {
|
|
switch_core_destroy_memory_pool(&ssl_pool);
|
|
}
|
|
}
|
|
|
|
static const EVP_MD *get_evp_by_name(const char *name)
|
|
{
|
|
if (zstr(name)) {
|
|
return NULL;
|
|
}
|
|
|
|
if (!strcasecmp(name, "md5")) return EVP_md5();
|
|
if (!strcasecmp(name, "sha1")) return EVP_sha1();
|
|
if (!strcasecmp(name, "sha-1")) return EVP_sha1();
|
|
if (!strcasecmp(name, "sha-256")) return EVP_sha256();
|
|
if (!strcasecmp(name, "sha-512")) return EVP_sha512();
|
|
|
|
return NULL;
|
|
}
|
|
#if defined(_MSC_VER) || (defined(__SunOS_5_10) && defined(__SUNPRO_C))
|
|
/*
|
|
* Visual C do not have strsep?
|
|
*
|
|
* Solaris 10 with the Sun Studio compilers doesn't have strsep in the
|
|
* C library either.
|
|
*/
|
|
char *strsep(char **stringp, const char *delim)
|
|
{
|
|
char *res;
|
|
|
|
if (!stringp || !*stringp || !**stringp)
|
|
return (char *) 0;
|
|
|
|
res = *stringp;
|
|
while (**stringp && !strchr(delim, **stringp))
|
|
++(*stringp);
|
|
|
|
if (**stringp) {
|
|
**stringp = '\0';
|
|
++(*stringp);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
#endif
|
|
|
|
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;
|
|
unsigned int i, j;
|
|
|
|
evp = get_evp_by_name(fp->type);
|
|
|
|
if (!evp) {
|
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing or unsupported fingerprint hash type\n");
|
|
return -1;
|
|
}
|
|
|
|
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.pem", SWITCH_GLOBAL_dirs.certs_dir, SWITCH_PATH_SEPARATOR, prefix);
|
|
|
|
if (switch_file_exists(rsa, NULL) != SWITCH_STATUS_SUCCESS) {
|
|
free(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);
|
|
}
|
|
|
|
if (x509) {
|
|
X509_free(x509);
|
|
}
|
|
|
|
free(rsa);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
static int mkcert(X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial, int days);
|
|
|
|
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;
|
|
char *pem = NULL;
|
|
|
|
if (switch_stristr(".pem", prefix)) {
|
|
|
|
if (switch_is_file_path(prefix)) {
|
|
pem = strdup(prefix);
|
|
} else {
|
|
pem = switch_mprintf("%s%s%s", SWITCH_GLOBAL_dirs.certs_dir, SWITCH_PATH_SEPARATOR, prefix);
|
|
}
|
|
|
|
if (switch_file_exists(pem, NULL) == SWITCH_STATUS_SUCCESS) {
|
|
goto end;
|
|
}
|
|
} else {
|
|
if (switch_is_file_path(prefix)) {
|
|
pvt = switch_mprintf("%s.key", prefix);
|
|
rsa = switch_mprintf("%s.crt", prefix);
|
|
} else {
|
|
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;
|
|
}
|
|
}
|
|
|
|
#ifdef CRYPTO_MEM_CHECK_ON
|
|
CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
|
|
#endif
|
|
|
|
//bio_err=BIO_new_fp(stderr, BIO_NOCLOSE);
|
|
|
|
if (!mkcert(&x509, &pkey, 4096, 0, 36500)) {
|
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Certificate generation failed\n");
|
|
goto end;
|
|
}
|
|
|
|
//RSA_print_fp(stdout, pkey->pkey.rsa, 0);
|
|
//X509_print_fp(stdout, x509);
|
|
|
|
if (pem) {
|
|
if ((fp = fopen(pem, "w"))) {
|
|
PEM_write_PrivateKey(fp, pkey, NULL, NULL, 0, NULL, NULL);
|
|
PEM_write_X509(fp, x509);
|
|
fclose(fp);
|
|
}
|
|
|
|
} else {
|
|
if (pvt && (fp = fopen(pvt, "w"))) {
|
|
PEM_write_PrivateKey(fp, pkey, NULL, NULL, 0, NULL, NULL);
|
|
fclose(fp);
|
|
}
|
|
|
|
if (rsa && (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);
|
|
switch_safe_free(pem);
|
|
|
|
return(0);
|
|
}
|
|
|
|
SWITCH_DECLARE(switch_bool_t) switch_core_check_dtls_pem(const char *file)
|
|
{
|
|
char *pem = NULL, *old_pem = NULL;
|
|
FILE *fp = NULL;
|
|
EVP_PKEY *pkey = NULL;
|
|
int bits = 0;
|
|
|
|
if (switch_is_file_path(file)) {
|
|
pem = strdup(file);
|
|
} else {
|
|
pem = switch_mprintf("%s%s%s", SWITCH_GLOBAL_dirs.certs_dir, SWITCH_PATH_SEPARATOR, file);
|
|
}
|
|
|
|
if (switch_file_exists(pem, NULL) != SWITCH_STATUS_SUCCESS) {
|
|
switch_safe_free(pem);
|
|
|
|
return SWITCH_FALSE;
|
|
}
|
|
|
|
fp = fopen(pem, "r");
|
|
if (!fp) {
|
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot open %s: %s\n", pem, strerror(errno));
|
|
goto rename_pem;
|
|
}
|
|
|
|
pkey = PEM_read_PrivateKey(fp, NULL, NULL, NULL);
|
|
fclose(fp);
|
|
|
|
if (!pkey) {
|
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot read key %s: %s\n", pem, ERR_error_string(ERR_get_error(), NULL));
|
|
goto rename_pem;
|
|
}
|
|
|
|
bits = EVP_PKEY_bits(pkey);
|
|
EVP_PKEY_free(pkey);
|
|
|
|
if (bits < 4096) {
|
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "%s cryptographic length is too short (%d), it will be regenerated\n", pem, bits);
|
|
goto rename_pem;
|
|
}
|
|
|
|
switch_safe_free(pem);
|
|
|
|
return SWITCH_TRUE;
|
|
|
|
rename_pem:
|
|
|
|
old_pem = switch_mprintf("%s.old", pem);
|
|
|
|
if (rename(pem, old_pem) != -1) {
|
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Renamed %s to %s\n", pem, old_pem);
|
|
} else {
|
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not rename %s: %s\n", pem, strerror(errno));
|
|
}
|
|
|
|
switch_safe_free(old_pem);
|
|
switch_safe_free(pem);
|
|
|
|
return SWITCH_FALSE;
|
|
}
|
|
|
|
#if 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);
|
|
}
|
|
#endif
|
|
|
|
static int mkcert(X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial, int days)
|
|
{
|
|
X509 *x;
|
|
EVP_PKEY *pk;
|
|
#if OPENSSL_VERSION_NUMBER < 0x30000000
|
|
RSA *rsa;
|
|
#endif
|
|
X509_NAME *name=NULL;
|
|
|
|
switch_assert(pkeyp);
|
|
switch_assert(x509p);
|
|
|
|
if (*pkeyp == NULL) {
|
|
if ((pk = EVP_PKEY_new()) == NULL) {
|
|
abort();
|
|
}
|
|
} else {
|
|
pk = *pkeyp;
|
|
}
|
|
|
|
if (*x509p == NULL) {
|
|
if ((x = X509_new()) == NULL) {
|
|
goto err;
|
|
}
|
|
} else {
|
|
x = *x509p;
|
|
}
|
|
|
|
#if OPENSSL_VERSION_NUMBER >= 0x30000000
|
|
{
|
|
EVP_PKEY_CTX *ctx;
|
|
|
|
ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
|
|
/* Setup the key context */
|
|
if ((!ctx) || (EVP_PKEY_keygen_init(ctx) <= 0) || (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, bits) <= 0)) {
|
|
abort();
|
|
goto err;
|
|
}
|
|
|
|
/* Generate key */
|
|
if (EVP_PKEY_generate(ctx, &pk) <= 0) {
|
|
abort();
|
|
goto err;
|
|
}
|
|
|
|
EVP_PKEY_CTX_free(ctx);
|
|
}
|
|
#elif OPENSSL_VERSION_NUMBER >= 0x10100000
|
|
rsa = RSA_new();
|
|
{
|
|
static const BN_ULONG ULONG_RSA_F4 = RSA_F4;
|
|
BIGNUM* BN_value_RSA_F4 = BN_new();
|
|
if (!BN_value_RSA_F4) {
|
|
abort();
|
|
goto err;
|
|
}
|
|
BN_set_word(BN_value_RSA_F4,ULONG_RSA_F4);
|
|
RSA_generate_key_ex(rsa, bits, BN_value_RSA_F4, NULL);
|
|
BN_free(BN_value_RSA_F4);
|
|
}
|
|
#else
|
|
rsa = RSA_generate_key(bits, RSA_F4, NULL, NULL);
|
|
#endif
|
|
|
|
#if OPENSSL_VERSION_NUMBER < 0x30000000
|
|
if (!EVP_PKEY_assign_RSA(pk, rsa)) {
|
|
abort();
|
|
}
|
|
|
|
rsa = NULL;
|
|
#endif
|
|
|
|
X509_set_version(x, 2);
|
|
ASN1_INTEGER_set(X509_get_serialNumber(x), serial);
|
|
X509_gmtime_adj(X509_get_notBefore(x), -(long)60*60*24*7);
|
|
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);
|
|
|
|
#if OPENSSL_VERSION_NUMBER >= 0x30000000
|
|
if (!X509_sign(x, pk, EVP_sha256())) {
|
|
#else
|
|
if (!X509_sign(x, pk, EVP_sha1())) {
|
|
#endif
|
|
goto err;
|
|
}
|
|
|
|
*x509p = x;
|
|
*pkeyp = pk;
|
|
|
|
return(1);
|
|
err:
|
|
ERR_print_errors_fp(stdout);
|
|
|
|
return(0);
|
|
}
|
|
|
|
/* For Emacs:
|
|
* Local Variables:
|
|
* mode:c
|
|
* indent-tabs-mode:t
|
|
* tab-width:4
|
|
* c-basic-offset:4
|
|
* End:
|
|
* For VIM:
|
|
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
|
|
*/
|