Commit db929337 authored by johan's avatar johan

Add self signed certificate and certificate fingerprint generation

Add parsing a directory to get all certificates in it
parent 884184c8
......@@ -135,6 +135,54 @@ BELLESIP_EXPORT belle_sip_signing_key_t* belle_sip_signing_key_parse(const char*
*/
BELLESIP_EXPORT belle_sip_certificates_chain_t* belle_sip_certificates_chain_parse_file(const char* path, belle_sip_certificate_raw_format_t format);
/**
* Parse a directory for *.pem file containing a certificate and private key in PEM format or a single DER cert with subject CNAME as given
*
* @param[in] path directory to parse
* @param[in] subject subject CNAME to look for
* @param[out] certificate result certificate, NULL if not found. Is allocated by this function, caller must do a belle_sip_object_unref on it after use
* @param[out] pkey result private key, NULL if not found. Is allocated by this function, caller must do a belle_sip_object_unref on it after use
* @param[in] format either PEM or DER
* @return 0 if we found a certificate and key matching given subject common name
*/
BELLESIP_EXPORT int belle_sip_get_certificate_and_pkey_in_dir(const char *path, const char *subject, belle_sip_certificates_chain_t **certificate, belle_sip_signing_key_t **pkey, belle_sip_certificate_raw_format_t format);
/**
* Generate a self signed certificate and key and save them in a file if a path is given, file will be <subject>.pem
*
* @param[in] path If not NULL a file will be written in the given directory. filename is <subject>.pem
* @param[in] subject used in the CN= field of issuer and subject name
* @param[out] certificate the generated certificate. Must be destroyed using belle_sip_certificates_chain_destroy
* @param[out] key the generated key. Must be destroyed using belle_sip_signing_key_destroy
* @return 0 on success
*/
BELLESIP_EXPORT int belle_sip_generate_self_signed_certificate(const char* path, const char *subject, belle_sip_certificates_chain_t **certificate, belle_sip_signing_key_t **pkey);
/**
* Convert a certificate into a its PEM format string
*
* @param[in] cert The certificate to be converted into PEM format string
* @return the PEM representation of certificate. Buffer is allocated by this function and must be freed by caller
*/
BELLESIP_EXPORT unsigned char *belle_sip_get_certificates_pem(belle_sip_certificates_chain_t *cert);
/**
* Convert a key into a its PEM format string
*
* @param[in] key The key to be converted into PEM format string
* @return the PEM representation of key. Buffer is allocated by this function and must be freed by caller
*/
BELLESIP_EXPORT unsigned char *belle_sip_get_key_pem(belle_sip_signing_key_t *key);
/**
* Generate a certificate fingerprint as described in RFC4572
* Note: only SHA1 signing algo is supported for now
*
* @param[in] certificate The certificate used to generate the fingerprint
* @return The generated fingerprint formatted according to RFC4572 section 5. Is a null terminated string, must be freed by caller
*/
BELLESIP_EXPORT unsigned char *belle_sip_generate_certificate_fingerprint(belle_sip_certificates_chain_t *certificate);
/**
* Parse a pather containing either a private or public rsa key
* @param path file
......@@ -143,9 +191,6 @@ BELLESIP_EXPORT belle_sip_certificates_chain_t* belle_sip_certificates_chain_par
*/
BELLESIP_EXPORT belle_sip_signing_key_t* belle_sip_signing_key_parse_file(const char* path, const char* passwd);
BELLESIP_EXPORT belle_tls_verify_policy_t *belle_tls_verify_policy_new(void);
BELLESIP_EXPORT int belle_tls_verify_policy_set_root_ca(belle_tls_verify_policy_t *obj, const char *path);
#define BELLE_TLS_VERIFY_CN_MISMATCH (1)
......
......@@ -1017,4 +1017,23 @@ BELLE_SIP_DECLARE_CUSTOM_VPTR_END
BELLE_SIP_DECLARE_CUSTOM_VPTR_BEGIN(belle_sip_multipart_body_handler_t,belle_sip_body_handler_t)
BELLE_SIP_DECLARE_CUSTOM_VPTR_END
/**
* file manipulation
*/
/**
* Parse a directory and return all files in it.
*
* @param[in] path The directory to be parsed
* @param[in] file_type if not NULL return only the file with the given extension, must include the '.', ex:".pem"
* @return a belle_sip list containing all found file or NULL if no file were found or directory doesn't exist. List must be destroyed using belle_sip_list_free_with_data(<ret_list>, belle_sip_free)
*/
belle_sip_list_t *belle_sip_parse_directory(const char *path, const char *file_type);
/**
* create a directory if it doesn't already exists
*
* @param[in] path The directory to be created
* @return 0 in case of succes, -1 otherwise, note it returns -1 if the directory already exists
*/
int belle_sip_mkdir(const char *path);
#endif
......@@ -19,13 +19,14 @@
#define _CRT_RAND_S
#include <stdlib.h>
#include <sys/stat.h>
#include "belle_sip_internal.h"
#include "clock_gettime.h" /*for apple*/
#ifndef WIN32
#include <sys/time.h> /*for gettimeofday*/
#include <dirent.h> /* available on POSIX system only */
#endif
static FILE *__log_file=0;
......@@ -1116,3 +1117,48 @@ char* belle_sip_display_name_to_backslashed_escaped_string(const char* buff) {
output_buff[out_buff_index]='\0';
return belle_sip_strdup(output_buff);
}
belle_sip_list_t *belle_sip_parse_directory(const char *path, const char *file_type) {
#ifdef WIN32
/* TODO: implement this function for non POSIX compiler */
return NULL;
#else /* WIN 32 */
DIR *dir;
struct dirent *ent;
belle_sip_list_t* file_list = NULL;
if ((dir = opendir(path)) != NULL) {
/* create a string containing the path, adding a final / */
char *name_with_path = (char *)belle_sip_malloc(strlen(path)+256); /* max filename is 256 bytes in dirent structure */
int path_length = strlen(path);
memcpy(name_with_path, path, strlen(path));
name_with_path[path_length] = '/';
path_length++;
/* loop on all directory files */
while ((ent = readdir (dir)) != NULL) { /* loop on all files present in the given dir */
/* filter on file type if given */
if (file_type==NULL
|| (strncmp(ent->d_name+strlen(ent->d_name)-strlen(file_type), file_type, strlen(file_type))==0) ) {
memcpy(name_with_path+path_length, ent->d_name, strlen(ent->d_name)+1); /* +1 to get the null termination */
/* append the filename to the current list */
file_list = belle_sip_list_append(file_list, belle_sip_strdup(name_with_path));
}
}
belle_sip_free(name_with_path);
closedir(dir);
return file_list;
} else { /* unable to open dir */
printf("non on l'a pas ouvert avec succes\n");
return NULL;
}
#endif /* !WIN32 */
}
int belle_sip_mkdir(const char *path) {
#ifdef WIN32
/* TODO: implement this function for non POSIX compiler */
return -1;
#else /* WIN 32 */
return mkdir(path, 0700);
#endif
}
......@@ -25,8 +25,11 @@
#include <polarssl/ssl.h>
#include <polarssl/version.h>
#include <polarssl/error.h>
#include "polarssl/sha1.h"
#if POLARSSL_VERSION_NUMBER >= 0x01030000
#include <polarssl/x509.h>
#include <polarssl/entropy.h>
#include <polarssl/ctr_drbg.h>
#endif
#endif
......@@ -55,6 +58,27 @@ struct belle_sip_signing_key {
#ifdef HAVE_POLARSSL
/**
* Retrieve key or certificate in a string(PEM format)
*/
unsigned char *belle_sip_get_certificates_pem(belle_sip_certificates_chain_t *cert) {
unsigned char *pem_certificate = NULL;
size_t olen=0;
if (cert == NULL) return NULL;
pem_certificate = (char *)malloc(4096);
pem_write_buffer("-----BEGIN CERTIFICATE-----\n", "-----END CERTIFICATE-----\n", cert->cert.raw.p, cert->cert.raw.len, pem_certificate, 4096, &olen );
return pem_certificate;
}
unsigned char *belle_sip_get_key_pem(belle_sip_signing_key_t *key) {
unsigned char *pem_key;
if (key == NULL) return NULL;
pem_key = (char *)malloc(4096);
pk_write_key_pem( &(key->key), (unsigned char *)pem_key, 4096);
return pem_key;
}
/*************tls********/
static int tls_process_data(belle_sip_channel_t *obj,unsigned int revents);
......@@ -429,13 +453,19 @@ void belle_sip_tls_channel_set_client_certificate_key(belle_sip_tls_channel_t *c
}
#else /*HAVE_POLLAR_SSL*/
#else /*HAVE_POLARSSL*/
void belle_sip_tls_channel_set_client_certificates_chain(belle_sip_tls_channel_t *obj, belle_sip_certificates_chain_t* cert_chain) {
belle_sip_error("belle_sip_channel_set_client_certificate_chain requires TLS");
}
void belle_sip_tls_channel_set_client_certificate_key(belle_sip_tls_channel_t *obj, belle_sip_signing_key_t* key) {
belle_sip_error("belle_sip_channel_set_client_certificate_key requires TLS");
}
unsigned char *belle_sip_get_certificates_pem(belle_sip_certificates_chain_t *cert) {
return NULL;
}
unsigned char *belle_sip_get_key_pem(belle_sip_signing_key_t *key) {
return NULL;
}
#endif
/**************************** belle_sip_certificates_chain_t **/
......@@ -507,6 +537,237 @@ belle_sip_certificates_chain_t* belle_sip_certificates_chain_parse_file(const ch
}
/*
* Parse all *.pem files in a given dir(non recursively) and return the one matching the given subject
*/
int belle_sip_get_certificate_and_pkey_in_dir(const char *path, const char *subject, belle_sip_certificates_chain_t **certificate, belle_sip_signing_key_t **pkey, belle_sip_certificate_raw_format_t format) {
#ifdef HAVE_POLARSSL
#if POLARSSL_VERSION_NUMBER < 0x01030000
return -1;
#else /* POLARSSL_VERSION_NUMBER > 0x01030000 */
/* get all *.pem file from given path */
belle_sip_list_t *file_list = belle_sip_parse_directory(path, ".pem");
char *filename = NULL;
file_list = belle_sip_list_pop_front(file_list, (void **)&filename);
while (filename != NULL) {
belle_sip_certificates_chain_t *found_certificate = belle_sip_certificates_chain_parse_file(filename, format);
if (found_certificate != NULL) { /* there is a certificate in this file */
char *subject_CNAME_begin, *subject_CNAME_end;
belle_sip_signing_key_t *found_key;
char name[500];
memset( name, 0, sizeof(name) );
x509_dn_gets( name, sizeof(name), &(found_certificate->cert.subject)); /* this function is available only in polarssl version >=1.3 */
/* parse subject to find the CN=xxx, field. There may be no , at the and but a \0 */
subject_CNAME_begin = strstr(name, "CN=");
if (subject_CNAME_begin!=NULL) {
subject_CNAME_begin+=3;
subject_CNAME_end = strstr(subject_CNAME_begin, ",");
if (subject_CNAME_end != NULL) {
*subject_CNAME_end = '\0';
}
if (strcmp(subject_CNAME_begin, subject)==0) { /* subject CNAME match the one we are looking for*/
/* do we have a key too ? */
found_key = belle_sip_signing_key_parse_file(filename, NULL);
if (found_key!=NULL) {
*certificate = found_certificate;
*pkey = found_key;
belle_sip_free(filename);
belle_sip_list_free_with_data(file_list, belle_sip_free); /* free possible rest of list */
return 0;
}
}
}
}
belle_sip_free(filename);
file_list = belle_sip_list_pop_front(file_list, (void **)&filename);
}
return -1;
#endif /* POLARSSL_VERSION_NUMBER >= 0x01030000 */
#else /* ! HAVE_POLARSSL */
return -1;
#endif
}
int belle_sip_generate_self_signed_certificate(const char* path, const char *subject, belle_sip_certificates_chain_t **certificate, belle_sip_signing_key_t **pkey) {
#ifdef HAVE_POLARSSL
entropy_context entropy;
ctr_drbg_context ctr_drbg;
int i,ret;
mpi serial;
x509write_cert crt;
FILE *fd;
char file_buffer[8192];
size_t file_buffer_len = 0;
char *name_with_path;
int path_length;
char formatted_subject[512];
/* subject may be a sip URL or linphone-dtls-default-identity, add CN= before it to make a valid name */
memcpy(formatted_subject, "CN=", 3);
memcpy(formatted_subject+3, subject, strlen(subject)+1); /* +1 to get the \0 termination */
/* allocate certificate and key */
*pkey = belle_sip_object_new(belle_sip_signing_key_t);
*certificate = belle_sip_object_new(belle_sip_certificates_chain_t);
entropy_init( &entropy );
if( ( ret = ctr_drbg_init( &ctr_drbg, entropy_func, &entropy, NULL, 0 ) ) != 0 )
{
belle_sip_error("Certificate generation can't init ctr_drbg: -%x", -ret);
return -1;
}
/* generate 3072 bits RSA public/private key */
pk_init( &((*pkey)->key) );
if ( (ret = pk_init_ctx( &((*pkey)->key), pk_info_from_type( POLARSSL_PK_RSA ) )) != 0) {
belle_sip_error("Certificate generation can't init pk_ctx: -%x", -ret);
return -1;
}
if ( ( ret = rsa_gen_key( pk_rsa( (*pkey)->key ), ctr_drbg_random, &ctr_drbg, 3072, 65537 ) ) != 0) {
belle_sip_error("Certificate generation can't generate rsa key: -%x", -ret);
return -1;
}
/* if there is no path, don't write a file */
if (path!=NULL) {
pk_write_key_pem( &((*pkey)->key), (unsigned char *)file_buffer, 4096);
file_buffer_len = strlen(file_buffer);
}
/* generate the certificate */
x509write_crt_init( &crt );
x509write_crt_set_md_alg( &crt, POLARSSL_MD_SHA1 );
mpi_init( &serial );
if ( (ret = mpi_read_string( &serial, 10, "1" ) ) != 0 ) {
belle_sip_error("Certificate generation can't read serial mpi: -%x", -ret);
return -1;
}
x509write_crt_set_subject_key( &crt, &((*pkey)->key) );
x509write_crt_set_issuer_key( &crt, &((*pkey)->key) );
if ( (ret = x509write_crt_set_subject_name( &crt, formatted_subject) ) != 0) {
belle_sip_error("Certificate generation can't set subject name: -%x", -ret);
return -1;
}
if ( (ret = x509write_crt_set_issuer_name( &crt, formatted_subject) ) != 0) {
belle_sip_error("Certificate generation can't set issuer name: -%x", -ret);
return -1;
}
if ( (ret = x509write_crt_set_serial( &crt, &serial ) ) != 0) {
belle_sip_error("Certificate generation can't set serial: -%x", -ret);
return -1;
}
mpi_free(&serial);
if ( (ret = x509write_crt_set_validity( &crt, "20010101000000", "20300101000000" ) ) != 0) {
belle_sip_error("Certificate generation can't set validity: -%x", -ret);
return -1;
}
/* store anyway certificate in pem format in a string even if we do not have file to write as we need it to get it in a x509_crt structure */
if ( (ret = x509write_crt_pem( &crt, (unsigned char *)file_buffer+file_buffer_len, 4096, ctr_drbg_random, &ctr_drbg ) ) != 0) {
belle_sip_error("Certificate generation can't write crt pem: -%x", -ret);
return -1;
}
x509write_crt_free(&crt);
if ( (ret = x509_crt_parse(&((*certificate)->cert), file_buffer, strlen(file_buffer)) ) != 0) {
belle_sip_error("Certificate generation can't parse crt pem: -%x", -ret);
return -1;
}
/* write the file if needed */
if (path!=NULL) {
name_with_path = (char *)malloc(strlen(path)+257); /* max filename is 256 bytes in dirent structure, +1 for / */
path_length = strlen(path);
memcpy(name_with_path, path, path_length);
name_with_path[path_length] = '/';
path_length++;
memcpy(name_with_path+path_length, subject, strlen(subject));
memcpy(name_with_path+path_length+strlen(subject), ".pem", 5);
/* check if directory exists and if not, create it */
belle_sip_mkdir(path);
if ( (fd = fopen(name_with_path, "w") ) == NULL) {
belle_sip_error("Certificate generation can't open/create file %s", name_with_path);
free(name_with_path);
belle_sip_object_unref(*pkey);
belle_sip_object_unref(*certificate);
*pkey = NULL;
*certificate = NULL;
return -1;
}
if ( fwrite(file_buffer, 1, strlen(file_buffer), fd) != strlen(file_buffer) ) {
belle_sip_error("Certificate generation can't write into file %s", name_with_path);
fclose(fd);
belle_sip_object_unref(*pkey);
belle_sip_object_unref(*certificate);
*pkey = NULL;
*certificate = NULL;
free(name_with_path);
return -1;
}
fclose(fd);
free(name_with_path);
}
return 0;
#else /* ! HAVE_POLARSSL */
return -1;
#endif
}
/* Note : this code is duplicated in mediastreamer2/src/voip/dtls_srtp.c but get directly a x509_crt as input parameter */
unsigned char *belle_sip_generate_certificate_fingerprint(belle_sip_certificates_chain_t *certificate) {
#ifdef HAVE_POLARSSL
unsigned char buffer[64]; /* buffer is max length of returned hash, which is 64 in case we use sha-512 */
size_t hash_length = 0;
char hash_alg_string[8]; /* buffer to store the string description of the algo, longest is SHA-512(7 chars + null termination) */
unsigned char *fingerprint = NULL;
x509_crt crt;
if (certificate == NULL) return NULL;
crt = certificate->cert;
/* fingerprint is a hash of the DER formated certificate (found in crt->raw.p) using the same hash function used by certificate signature */
switch (crt.sig_md) {
case POLARSSL_MD_SHA1:
sha1(crt.raw.p, crt.raw.len, buffer);
hash_length = 20;
memcpy(hash_alg_string, "SHA-1", 6);
break;
default:
break;
}
if (hash_length>0) {
int i;
int fingerprint_index = strlen(hash_alg_string);
char prefix=' ';
/* fingerprint will be : hash_alg_string+' '+HEX : separated values: length is strlen(hash_alg_string)+3*hash_lenght + 1 for null termination */
fingerprint = (unsigned char *)malloc(fingerprint_index+3*hash_length+1);
sprintf(fingerprint, "%s", hash_alg_string);
for (i=0; i<hash_length; i++, fingerprint_index+=3) {
sprintf(fingerprint+fingerprint_index,"%c%02X", prefix,buffer[i]);
prefix=':';
}
*(fingerprint+fingerprint_index) = '\0';
}
return fingerprint;
#else /* ! HAVE_POLARSSL */
return NULL;
#endif
}
static void belle_sip_certificates_chain_destroy(belle_sip_certificates_chain_t *certificate){
#ifdef HAVE_POLARSSL
#if POLARSSL_VERSION_NUMBER < 0x01030000
......
......@@ -74,11 +74,74 @@ static void test_proxy_authentication(void) {
}
#define TEMPORARY_CERTIFICATE_DIR "/belle_sip_tester_crt"
static void test_generate_and_parse_certificates(void) {
/* function not available on windows yet - need to add the create and parse directory */
#ifndef WIN32
belle_sip_certificates_chain_t *certificate, *parsed_certificate;
belle_sip_signing_key_t *key, *parsed_key;
unsigned char *pem_certificate, *pem_parsed_certificate, *pem_key, *pem_parsed_key;
int ret = 0;
char *belle_sip_certificate_temporary_dir=belle_sip_malloc(strlen(belle_sip_tester_writable_dir_prefix)+strlen(TEMPORARY_CERTIFICATE_DIR)+1);
strcpy(belle_sip_certificate_temporary_dir, belle_sip_tester_writable_dir_prefix);
memcpy(belle_sip_certificate_temporary_dir+strlen(belle_sip_tester_writable_dir_prefix), TEMPORARY_CERTIFICATE_DIR, strlen(TEMPORARY_CERTIFICATE_DIR)+1);
/* create 2 certificates in ./belle_sip_crt_test directory (TODO : set the directory in a absolute path?? where?)*/
ret = belle_sip_generate_self_signed_certificate(belle_sip_certificate_temporary_dir, "test_certificate1", &certificate, &key);
CU_ASSERT_EQUAL_FATAL(0, ret);
ret = belle_sip_generate_self_signed_certificate(belle_sip_certificate_temporary_dir, "test_certificate2", &certificate, &key);
CU_ASSERT_EQUAL_FATAL(0, ret);
/* parse directory to get the certificate2 */
ret = belle_sip_get_certificate_and_pkey_in_dir(belle_sip_certificate_temporary_dir, "test_certificate2", &parsed_certificate, &parsed_key, BELLE_SIP_CERTIFICATE_RAW_FORMAT_PEM);
belle_sip_free(belle_sip_certificate_temporary_dir);
CU_ASSERT_EQUAL_FATAL(0, ret);
/* get pem version of generated and parsed certificate and compare them */
pem_certificate = belle_sip_get_certificates_pem(certificate);
CU_ASSERT_TRUE_FATAL(pem_certificate!=NULL);
pem_parsed_certificate = belle_sip_get_certificates_pem(parsed_certificate);
CU_ASSERT_TRUE_FATAL(pem_parsed_certificate!=NULL);
CU_ASSERT_STRING_EQUAL(pem_certificate, pem_parsed_certificate);
/* get pem version of generated and parsed key and compare them */
pem_key = belle_sip_get_key_pem(key);
CU_ASSERT_TRUE_FATAL(pem_key!=NULL);
pem_parsed_key = belle_sip_get_key_pem(parsed_key);
CU_ASSERT_TRUE_FATAL(pem_parsed_key!=NULL);
CU_ASSERT_STRING_EQUAL(pem_key, pem_parsed_key);
belle_sip_free(pem_certificate);
belle_sip_free(pem_parsed_certificate);
belle_sip_free(pem_key);
belle_sip_free(pem_parsed_key);
belle_sip_object_unref(certificate);
belle_sip_object_unref(parsed_certificate);
belle_sip_object_unref(key);
belle_sip_object_unref(parsed_key);
#endif /* WIN32 */
}
static void test_certificate_fingerprint(void) {
unsigned char *fingerprint;
/* parse certificate defined in belle_sip_register_tester.c */
belle_sip_certificates_chain_t* cert = belle_sip_certificates_chain_parse(belle_sip_tester_client_cert,strlen(belle_sip_tester_client_cert),BELLE_SIP_CERTIFICATE_RAW_FORMAT_PEM);
/* generate fingerprint */
fingerprint = belle_sip_generate_certificate_fingerprint(cert);
CU_ASSERT_STRING_EQUAL(fingerprint, belle_sip_tester_client_cert_fingerprint);
free(fingerprint);
belle_sip_object_unref(cert);
}
test_t authentication_helper_tests[] = {
{ "Proxy-Authenticate", test_proxy_authentication },
{ "WWW-Authenticate", test_authentication },
{ "WWW-Authenticate (with qop)", test_authentication_qop_auth }
{ "WWW-Authenticate (with qop)", test_authentication_qop_auth },
{ "generate and parse self signed certificates", test_generate_and_parse_certificates},
{ "generate certificate fingerprint", test_certificate_fingerprint}
};
test_suite_t authentication_helper_test_suite = {
......
......@@ -139,6 +139,9 @@ const char* belle_sip_tester_client_cert = /*for URI:sip:tester@client.example.o
"oEncRDdPOA==\n"
"-----END CERTIFICATE-----";
/* fingerprint of certificate generated using openssl x509 -fingerprint */
const char* belle_sip_tester_client_cert_fingerprint =
"SHA-1 79:2F:9E:8B:28:CC:38:53:90:1D:71:DC:8F:70:66:75:E5:34:CE:C4";
const char* belle_sip_tester_private_key =
"-----BEGIN ENCRYPTED PRIVATE KEY-----\n"
......
......@@ -22,6 +22,7 @@
#include <stdio.h>
#include "CUnit/Basic.h"
#include "CUnit/MyMem.h"
#ifdef HAVE_CU_CURSES
#include "CUnit/CUCurses.h"
#endif
......@@ -35,6 +36,12 @@ static test_suite_t **test_suite = NULL;
static int nb_test_suites = 0;
static int belle_sip_tester_use_log_file=0;
#ifdef ANDROID
const char *belle_sip_tester_writable_dir_prefix = "/data/data/org.linphone.tester/cache";
#else
const char *belle_sip_tester_writable_dir_prefix = ".";
#endif
#ifdef HAVE_CU_CURSES
static unsigned char curses = 0;
#endif
......@@ -186,8 +193,13 @@ static void test_complete_message_handler(const CU_pTest pTest,
static void test_all_tests_complete_message_handler(const CU_pFailureRecord pFailure) {
char *result_string;
if (belle_sip_tester_use_log_file) belle_sip_warning("\n\n %s",CU_get_run_results_string());
printf("\n\n %s",CU_get_run_results_string());
result_string = CU_get_run_results_string();
if (result_string != NULL) {
printf("\n\n %s",result_string);
CU_FREE(result_string);
}
}
static void test_suite_init_failure_message_handler(const CU_pSuite pSuite) {
......
......@@ -69,7 +69,9 @@ extern const char * belle_sip_tester_get_root_ca_path(void);
extern void belle_sip_tester_set_root_ca_path(const char *root_ca_path);
extern int belle_sip_tester_run_tests(const char *suite_name, const char *test_name);
extern const char *belle_sip_tester_writable_dir_prefix;
extern const char* belle_sip_tester_client_cert;
extern const char* belle_sip_tester_client_cert_fingerprint;
extern const char* belle_sip_tester_private_key;
extern const char* belle_sip_tester_private_key_passwd;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment