diff --git a/apps/app_osplookup.c b/apps/app_osplookup.c index c6e11e8234..7c553b5736 100644 --- a/apps/app_osplookup.c +++ b/apps/app_osplookup.c @@ -39,6 +39,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include #include +#include #include "asterisk/paths.h" #include "asterisk/lock.h" @@ -55,6 +56,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") /* OSP Buffer Sizes */ #define OSP_INTSTR_SIZE ((unsigned int)16) /* OSP signed/unsigned int string buffer size */ #define OSP_NORSTR_SIZE ((unsigned int)256) /* OSP normal string buffer size */ +#define OSP_KEYSTR_SIZE ((unsigned int)1024) /* OSP certificate string buffer size */ #define OSP_TOKSTR_SIZE ((unsigned int)4096) /* OSP token string buffer size */ #define OSP_TECHSTR_SIZE ((unsigned int)32) /* OSP signed/unsigned int string buffer size */ #define OSP_UUID_SIZE ((unsigned int)16) /* UUID size */ @@ -127,7 +129,7 @@ struct osp_provider { char privatekey[OSP_NORSTR_SIZE]; /* OSP private key file name */ char localcert[OSP_NORSTR_SIZE]; /* OSP local cert file name */ unsigned int cacount; /* Number of cacerts */ - char cacerts[OSP_MAX_CERTS][OSP_NORSTR_SIZE]; /* Cacert file names */ + char cacerts[OSP_MAX_CERTS][OSP_NORSTR_SIZE]; /* Cacert file names */ unsigned int spcount; /* Number of service points */ char srvpoints[OSP_MAX_SRVS][OSP_NORSTR_SIZE]; /* Service point URLs */ int maxconnections; /* Max number of connections */ @@ -167,9 +169,15 @@ struct osp_result { AST_MUTEX_DEFINE_STATIC(osplock); /* Lock of OSP provider list */ static int osp_initialized = 0; /* Init flag */ static int osp_hardware = 0; /* Hardware accelleration flag */ +static int osp_security = 0; /* Using security features flag */ static struct osp_provider* ospproviders = NULL; /* OSP provider list */ static unsigned int osp_tokenformat = TOKEN_ALGO_SIGNED; /* Token format supported */ +/* OSP default certificates */ +const char* B64PKey = "MIIBOgIBAAJBAK8t5l+PUbTC4lvwlNxV5lpl+2dwSZGW46dowTe6y133XyVEwNiiRma2YNk3xKs/TJ3Wl9Wpns2SYEAJsFfSTukCAwEAAQJAPz13vCm2GmZ8Zyp74usTxLCqSJZNyMRLHQWBM0g44Iuy4wE3vpi7Wq+xYuSOH2mu4OddnxswCP4QhaXVQavTAQIhAOBVCKXtppEw9UaOBL4vW0Ed/6EA/1D8hDW6St0h7EXJAiEAx+iRmZKhJD6VT84dtX5ZYNVk3j3dAcIOovpzUj9a0CECIEduTCapmZQ5xqAEsLXuVlxRtQgLTUD4ZxDElPn8x0MhAiBE2HlcND0+qDbvtwJQQOUzDgqg5xk3w8capboVdzAlQQIhAMC+lDL7+gDYkNAft5Mu+NObJmQs4Cr+DkDFsKqoxqrm"; +const char* B64LCert = "MIIBeTCCASMCEHqkOHVRRWr+1COq3CR/xsowDQYJKoZIhvcNAQEEBQAwOzElMCMGA1UEAxMcb3NwdGVzdHNlcnZlci50cmFuc25leHVzLmNvbTESMBAGA1UEChMJT1NQU2VydmVyMB4XDTA1MDYyMzAwMjkxOFoXDTA2MDYyNDAwMjkxOFowRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQCvLeZfj1G0wuJb8JTcVeZaZftncEmRluOnaME3ustd918lRMDYokZmtmDZN8SrP0yd1pfVqZ7NkmBACbBX0k7pAgMBAAEwDQYJKoZIhvcNAQEEBQADQQDnV8QNFVVJx/+7IselU0wsepqMurivXZzuxOmTEmTVDzCJx1xhA8jd3vGAj7XDIYiPub1PV23eY5a2ARJuw5w9"; +const char* B64CACert = "MIIBYDCCAQoCAQEwDQYJKoZIhvcNAQEEBQAwOzElMCMGA1UEAxMcb3NwdGVzdHNlcnZlci50cmFuc25leHVzLmNvbTESMBAGA1UEChMJT1NQU2VydmVyMB4XDTAyMDIwNDE4MjU1MloXDTEyMDIwMzE4MjU1MlowOzElMCMGA1UEAxMcb3NwdGVzdHNlcnZlci50cmFuc25leHVzLmNvbTESMBAGA1UEChMJT1NQU2VydmVyMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAPGeGwV41EIhX0jEDFLRXQhDEr50OUQPq+f55VwQd0TQNts06BP29+UiNdRW3c3IRHdZcJdC1Cg68ME9cgeq0h8CAwEAATANBgkqhkiG9w0BAQQFAANBAGkzBSj1EnnmUxbaiG1N4xjIuLAWydun7o3bFk2tV8dBIhnuh445obYyk1EnQ27kI7eACCILBZqi2MHDOIMnoN0="; + /* OSP Client Wrapper APIs */ /*! @@ -190,7 +198,10 @@ static int osp_create_provider( OSPT_CERT cacerts[OSP_MAX_CERTS]; const OSPT_CERT* pcacerts[OSP_MAX_CERTS]; const char* psrvpoints[OSP_MAX_SRVS]; - int t, i, j, error = OSPC_ERR_NO_ERROR; + unsigned char privatekeydata[OSP_KEYSTR_SIZE]; + unsigned char localcertdata[OSP_KEYSTR_SIZE]; + unsigned char cacertdata[OSP_KEYSTR_SIZE]; + int i, t, error = OSPC_ERR_NO_ERROR; if (!(p = ast_calloc(1, sizeof(*p)))) { ast_log(LOG_ERROR, "Out of memory\n"); @@ -213,30 +224,36 @@ static int osp_create_provider( v = ast_variable_browse(cfg, provider); while(v) { if (!strcasecmp(v->name, "privatekey")) { - if (v->value[0] == '/') { - ast_copy_string(p->privatekey, v->value, sizeof(p->privatekey)); - } else { - snprintf(p->privatekey, sizeof(p->privatekey), "%s/%s", ast_config_AST_KEY_DIR, v->value); - } - ast_debug(1, "OSP: privatekey '%s'\n", p->privatekey); - } else if (!strcasecmp(v->name, "localcert")) { - if (v->value[0] == '/') { - ast_copy_string(p->localcert, v->value, sizeof(p->localcert)); - } else { - snprintf(p->localcert, sizeof(p->localcert), "%s/%s", ast_config_AST_KEY_DIR, v->value); - } - ast_debug(1, "OSP: localcert '%s'\n", p->localcert); - } else if (!strcasecmp(v->name, "cacert")) { - if (p->cacount < OSP_MAX_CERTS) { + if (osp_security) { if (v->value[0] == '/') { - ast_copy_string(p->cacerts[p->cacount], v->value, sizeof(p->cacerts[0])); + ast_copy_string(p->privatekey, v->value, sizeof(p->privatekey)); } else { - snprintf(p->cacerts[p->cacount], sizeof(p->cacerts[0]), "%s/%s", ast_config_AST_KEY_DIR, v->value); + snprintf(p->privatekey, sizeof(p->privatekey), "%s/%s", ast_config_AST_KEY_DIR, v->value); + } + ast_debug(1, "OSP: privatekey '%s'\n", p->privatekey); + } + } else if (!strcasecmp(v->name, "localcert")) { + if (osp_security) { + if (v->value[0] == '/') { + ast_copy_string(p->localcert, v->value, sizeof(p->localcert)); + } else { + snprintf(p->localcert, sizeof(p->localcert), "%s/%s", ast_config_AST_KEY_DIR, v->value); + } + ast_debug(1, "OSP: localcert '%s'\n", p->localcert); + } + } else if (!strcasecmp(v->name, "cacert")) { + if (osp_security) { + if (p->cacount < OSP_MAX_CERTS) { + if (v->value[0] == '/') { + ast_copy_string(p->cacerts[p->cacount], v->value, sizeof(p->cacerts[0])); + } else { + snprintf(p->cacerts[p->cacount], sizeof(p->cacerts[0]), "%s/%s", ast_config_AST_KEY_DIR, v->value); + } + ast_debug(1, "OSP: cacerts[%d]: '%s'\n", p->cacount, p->cacerts[p->cacount]); + p->cacount++; + } else { + ast_log(LOG_WARNING, "OSP: Too many CA Certificates at line %d\n", v->lineno); } - ast_debug(1, "OSP: cacert[%d]: '%s'\n", p->cacount, p->cacerts[p->cacount]); - p->cacount++; - } else { - ast_log(LOG_WARNING, "OSP: Too many CA Certificates at line %d\n", v->lineno); } } else if (!strcasecmp(v->name, "servicepoint")) { if (p->spcount < OSP_MAX_SRVS) { @@ -307,95 +324,109 @@ static int osp_create_provider( v = v->next; } - error = OSPPUtilLoadPEMPrivateKey((unsigned char*)p->privatekey, &privatekey); - if (error != OSPC_ERR_NO_ERROR) { - ast_log(LOG_WARNING, "OSP: Unable to load privatekey '%s', error '%d'\n", p->privatekey, error); - ast_free(p); - return 0; - } - - error = OSPPUtilLoadPEMCert((unsigned char*)p->localcert, &localcert); - if (error != OSPC_ERR_NO_ERROR) { - ast_log(LOG_WARNING, "OSP: Unable to load localcert '%s', error '%d'\n", p->localcert, error); - if (privatekey.PrivateKeyData) { - ast_free(privatekey.PrivateKeyData); - } - ast_free(p); - return 0; - } - - if (p->cacount < 1) { - snprintf(p->cacerts[p->cacount], sizeof(p->cacerts[0]), "%s/%s-cacert.pem", ast_config_AST_KEY_DIR, provider); - ast_debug(1, "OSP: cacert[%d]: '%s'\n", p->cacount, p->cacerts[p->cacount]); - p->cacount++; - } - for (i = 0; i < p->cacount; i++) { - error = OSPPUtilLoadPEMCert((unsigned char*)p->cacerts[i], &cacerts[i]); - if (error != OSPC_ERR_NO_ERROR) { - ast_log(LOG_WARNING, "OSP: Unable to load cacert '%s', error '%d'\n", p->cacerts[i], error); - for (j = 0; j < i; j++) { - if (cacerts[j].CertData) { - ast_free(cacerts[j].CertData); - } - } - if (localcert.CertData) { - ast_free(localcert.CertData); - } - if (privatekey.PrivateKeyData) { - ast_free(privatekey.PrivateKeyData); - } - ast_free(p); - return 0; - } - pcacerts[i] = &cacerts[i]; + if (p->cacount == 0) { + p->cacount = 1; } for (i = 0; i < p->spcount; i++) { psrvpoints[i] = p->srvpoints[i]; } - error = OSPPProviderNew( - p->spcount, - psrvpoints, - NULL, - OSP_AUDIT_URL, - &privatekey, - &localcert, - p->cacount, - pcacerts, - OSP_LOCAL_VALIDATION, - OSP_SSL_LIFETIME, - p->maxconnections, - OSP_HTTP_PERSISTENCE, - p->retrydelay, - p->retrylimit, - p->timeout, - OSP_CUSTOMER_ID, - OSP_DEVICE_ID, - &p->handle); - if (error != OSPC_ERR_NO_ERROR) { - ast_log(LOG_WARNING, "OSP: Unable to create provider '%s', error '%d'\n", provider, error); - ast_free(p); - res = -1; - } else { - ast_debug(1, "OSP: provider '%s'\n", provider); - ast_mutex_lock(&osplock); - p->next = ospproviders; - ospproviders = p; - ast_mutex_unlock(&osplock); - res = 1; - } + if (osp_security) { + privatekey.PrivateKeyData = NULL; + privatekey.PrivateKeyLength = 0; - for (i = 0; i < p->cacount; i++) { - if (cacerts[i].CertData) { - ast_free(cacerts[i].CertData); + localcert.CertData = NULL; + localcert.CertDataLength = 0; + + for (i = 0; i < p->cacount; i++) { + cacerts[i].CertData = NULL; + cacerts[i].CertDataLength = 0; + } + + if ((error = OSPPUtilLoadPEMPrivateKey((unsigned char*)p->privatekey, &privatekey)) != OSPC_ERR_NO_ERROR) { + ast_log(LOG_WARNING, "OSP: Unable to load privatekey '%s', error '%d'\n", p->privatekey, error); + } else if ((error = OSPPUtilLoadPEMCert((unsigned char*)p->localcert, &localcert)) != OSPC_ERR_NO_ERROR) { + ast_log(LOG_WARNING, "OSP: Unable to load localcert '%s', error '%d'\n", p->localcert, error); + } else { + for (i = 0; i < p->cacount; i++) { + if ((error = OSPPUtilLoadPEMCert((unsigned char*)p->cacerts[i], &cacerts[i])) != OSPC_ERR_NO_ERROR) { + ast_log(LOG_WARNING, "OSP: Unable to load cacert '%s', error '%d'\n", p->cacerts[i], error); + break; + } else { + pcacerts[i] = &cacerts[i]; + } + } + } + } else { + privatekey.PrivateKeyData = privatekeydata; + privatekey.PrivateKeyLength = sizeof(privatekeydata); + + localcert.CertData = localcertdata; + localcert.CertDataLength = sizeof(localcertdata); + + cacerts[0].CertData = cacertdata; + cacerts[0].CertDataLength = sizeof(cacertdata); + pcacerts[0] = &cacerts[0]; + + if ((error = OSPPBase64Decode(B64PKey, strlen(B64PKey), privatekey.PrivateKeyData, &privatekey.PrivateKeyLength)) != OSPC_ERR_NO_ERROR) { + ast_log(LOG_WARNING, "OSP: Unable to decode private key, error '%d'\n", error); + } else if ((error = OSPPBase64Decode(B64LCert, strlen(B64LCert), localcert.CertData, &localcert.CertDataLength)) != OSPC_ERR_NO_ERROR) { + ast_log(LOG_WARNING, "OSP: Unable to decode local cert, error '%d'\n", error); + } else if ((error = OSPPBase64Decode(B64CACert, strlen(B64CACert), cacerts[0].CertData, &cacerts[0].CertDataLength)) != OSPC_ERR_NO_ERROR) { + ast_log(LOG_WARNING, "OSP: Unable to decode cacert, error '%d'\n", error); } } - if (localcert.CertData) { - ast_free(localcert.CertData); + + if (error == OSPC_ERR_NO_ERROR) { + error = OSPPProviderNew( + p->spcount, + psrvpoints, + NULL, + OSP_AUDIT_URL, + &privatekey, + &localcert, + p->cacount, + pcacerts, + OSP_LOCAL_VALIDATION, + OSP_SSL_LIFETIME, + p->maxconnections, + OSP_HTTP_PERSISTENCE, + p->retrydelay, + p->retrylimit, + p->timeout, + OSP_CUSTOMER_ID, + OSP_DEVICE_ID, + &p->handle); + if (error != OSPC_ERR_NO_ERROR) { + ast_log(LOG_WARNING, "OSP: Unable to create provider '%s', error '%d'\n", provider, error); + res = -1; + } else { + ast_debug(1, "OSP: provider '%s'\n", provider); + ast_mutex_lock(&osplock); + p->next = ospproviders; + ospproviders = p; + ast_mutex_unlock(&osplock); + res = 1; + } } - if (privatekey.PrivateKeyData) { - ast_free(privatekey.PrivateKeyData); + + if (osp_security) { + for (i = 0; i < p->cacount; i++) { + if (cacerts[i].CertData) { + ast_free(cacerts[i].CertData); + } + } + if (localcert.CertData) { + ast_free(localcert.CertData); + } + if (privatekey.PrivateKeyData) { + ast_free(privatekey.PrivateKeyData); + } + } + + if (res != 1) { + ast_free(p); } return res; @@ -1821,6 +1852,12 @@ static int osp_load(int reload) } ast_debug(1, "OSP: osp_hardware '%d'\n", osp_hardware); + t = ast_variable_retrieve(cfg, OSP_GENERAL_CAT, "securityfeatures"); + if (t && ast_true(t)) { + osp_security = 1; + } + ast_debug(1, "OSP: osp_security '%d'\n", osp_security); + t = ast_variable_retrieve(cfg, OSP_GENERAL_CAT, "tokenformat"); if (t) { if ((sscanf(t, "%d", &v) == 1) && @@ -1874,6 +1911,7 @@ static int osp_unload(void) OSPPCleanup(); osp_tokenformat = TOKEN_ALGO_SIGNED; + osp_security = 0; osp_hardware = 0; osp_initialized = 0; } @@ -1916,8 +1954,11 @@ static char *handle_cli_osp_show(struct ast_cli_entry *e, int cmd, struct ast_cl tokenalgo = "Signed"; break; } - ast_cli(a->fd, "OSP: %s %s %s\n", - osp_initialized ? "Initialized" : "Uninitialized", osp_hardware ? "Accelerated" : "Normal", tokenalgo); + ast_cli(a->fd, "OSP: %s/%s/%s/%s\n", + osp_initialized ? "Initialized" : "Uninitialized", + osp_hardware ? "Accelerated" : "Normal", + osp_security ? "Enabled" : "Disabled", + tokenalgo); } ast_mutex_lock(&osplock); @@ -1928,10 +1969,12 @@ static char *handle_cli_osp_show(struct ast_cli_entry *e, int cmd, struct ast_cl ast_cli(a->fd, "\n"); } ast_cli(a->fd, " == OSP Provider '%s' == \n", p->name); - ast_cli(a->fd, "Local Private Key: %s\n", p->privatekey); - ast_cli(a->fd, "Local Certificate: %s\n", p->localcert); - for (i = 0; i < p->cacount; i++) { - ast_cli(a->fd, "CA Certificate %d: %s\n", i + 1, p->cacerts[i]); + if (osp_security) { + ast_cli(a->fd, "Local Private Key: %s\n", p->privatekey); + ast_cli(a->fd, "Local Certificate: %s\n", p->localcert); + for (i = 0; i < p->cacount; i++) { + ast_cli(a->fd, "CA Certificate %d: %s\n", i + 1, p->cacerts[i]); + } } for (i = 0; i < p->spcount; i++) { ast_cli(a->fd, "Service Point %d: %s\n", i + 1, p->srvpoints[i]); diff --git a/configs/osp.conf.sample b/configs/osp.conf.sample index e3423373d4..5eccf85d51 100644 --- a/configs/osp.conf.sample +++ b/configs/osp.conf.sample @@ -12,14 +12,23 @@ [general] ; ; Enable cryptographic acceleration hardware. +; The default value is no. ; ;accelerate=no ; +; Enable security features. +; If security features are disabled, Asterisk cannot validate signed tokens and +; all certificate file name parameters are ignored. +; The default value is no. +; +;securityfeatures=no +; ; Defines the status of tokens that Asterisk will validate. ; 0 - signed tokens only ; 1 - unsigned tokens only ; 2 - both signed and unsigned ; The default value is 0, i.e. the Asterisk will only validate signed tokens. +; If securityfeatures are disabled, Asterisk cannot validate signed tokens. ; ;tokenformat=0 ; @@ -43,6 +52,7 @@ ; If this parameter is unspecified or not present, the default name will be the ; osp.conf section name followed by "-privatekey.pem" (for example: ; default-privatekey.pem) +; If securityfeatures are disabled, this parameter is ignored. ; ;privatekey=pkey.pem ; @@ -50,6 +60,7 @@ ; If this parameter is unspecified or not present, the default name will be the ; osp.conf section name followed by "- localcert.pem " (for example: ; default-localcert.pem) +; If securityfeatures are disabled, this parameter is ignored. ; ;localcert=localcert.pem ; @@ -57,6 +68,7 @@ ; a single Certificate Authority key file name is added with the default name of ; the osp.conf section name followed by "-cacert_0.pem " (for example: ; default-cacert_0.pem) +; If securityfeatures are disabled, this parameter is ignored. ; ;cacert=cacert_0.pem ; @@ -81,6 +93,7 @@ ; 2 - EXCLUSIVE - Accept calls with valid token. Block calls with invalid token ; or no token. ; Default is 1, +; If securityfeatures are disabled, Asterisk cannot validate signed tokens. ; ;authpolicy=1 ;