auth_identity.c

Go to the documentation of this file.
00001 /*
00002  * $Id$
00003  *
00004  * Copyright (c) 2007 iptelorg GmbH
00005  *
00006  * This file is part of sip-router, a free SIP server.
00007  *
00008  * sip-router is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version
00012  *
00013  * sip-router is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software
00020  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  */
00022 
00040 #include <stdio.h>
00041 #include <time.h>
00042 #include <stdlib.h>
00043 #include <string.h>
00044 
00045 #include <openssl/pem.h>
00046 #include <openssl/err.h>
00047 #include <openssl/sha.h>
00048 
00049 #include <curl/curl.h>
00050 #include <curl/easy.h>
00051 
00052 #include "../../dprint.h"
00053 #include "../../ut.h"
00054 #include "../../sr_module.h"
00055 #include "../../mem/mem.h"
00056 #include "../../parser/parse_from.h"
00057 #include "../../parser/parse_cseq.h"
00058 #include "../../parser/parse_content.h"
00059 #include "../../parser/parse_uri.h"
00060 #include "../../parser/contact/parse_contact.h"
00061 #include "../../timer.h"
00062 
00063 #include "auth_identity.h"
00064 
00065 MODULE_VERSION;
00066 
00067 static int mod_init(void); /* Module initialization function */
00068 static void mod_deinit(void);
00069 static int add_identity(struct sip_msg* msg, char* srt1, char* str2);
00070 static int get_certificate(struct sip_msg* msg, char* srt1, char* str2);
00071 static int check_validity(struct sip_msg* msg, char* srt1, char* str2);
00072 static int check_date(struct sip_msg* msg, char* srt1, char* str2);
00073 static int check_callid(struct sip_msg* msg, char* srt1, char* str2);
00074 static int date_proc(struct sip_msg* msg, char* srt1, char* str2);
00075 static int check_certificate(struct sip_msg* msg, char* srt1, char* str2);
00076 void callid_gc(unsigned int tick, void *param);
00077 
00078 /*
00079  * Module parameter variables
00080  */
00081 char    *glb_sprivkeypath="";   /* private key of the authentication service */
00082 char    *glb_sservercerturl=""; /* URL of the certificate of the authentication service */
00083 char    *glb_sservercertpath=""; /* Path of the certificate of the authentication service */
00084 int             glb_icertlimit=CERTIFICATE_TABLE_ITEM_LIMIT;
00085 char    *glb_scainfo="";
00086 int             glb_iauthval=AUTH_MSG_VALIDITY_TIME;    /* Message validity time in seconds (verification service)*/
00087 int             glb_imsgtime=AUTH_MSG_TO_AUTH_VALIDITY_TIME;    /* Message validity time in seconds (authentication service)*/
00088 int     glb_icallidlimit=CALLID_TABLE_ITEM_LIMIT;
00089 
00090 CURL    *glb_hcurl;             /* global cURL handle */
00091 X509    *glb_pcertx509=NULL;
00092 X509_STORE *glb_cacerts=NULL;
00093 
00094 RSA     *glb_hmyprivkey=NULL;   /* private key of the authentication service */
00095 time_t  glb_imycertnotafter=0;
00096 
00097 int     glb_authservice_disabled=0;
00098 int     glb_acceptpem=0;
00099 
00100 dynstr  glb_sdgst={{0,0},0}; /* Digest string */
00101 dynstr  glb_sidentity={{0,0},0}; /* Identity message header */
00102 dynstr  glb_sidentityinfo={{0,0},0}; /* Identity-info message header */
00103 dynstr  glb_sdate={{0,0},0}; /* Date  message header */
00104 
00105 dynstr  glb_encedmsg={{0,0},0}; /* buffer for rsa encrypted string */
00106 dynstr  glb_b64encedmsg={{0,0},0}; /* buffer for base64, rsa encrypted string */
00107 
00108 ttable *glb_tcert_table=0;                              /* Certificate Table */
00109 char glb_certisdownloaded=0;
00110 tcert_item glb_tcert={{0,0},{0,0},0};   /* Actually Used Certificate */
00111 
00112 ttable *glb_tcallid_table=0;                    /* Certificate Table */
00113 typedef struct timeparams { /* sturct of the callid garbage collector */
00114         int ibnow;      /* the actual bucket we've not checked yet */
00115         int ibnum;  /* number of the buckets we've to check */
00116         int ibcir;  /* timer function's called this times during the whole table check */
00117 } ttimeparams;
00118 ttimeparams glb_ttimeparams={0,0,0};
00119 
00120 /*
00121  * Exported functions
00122  */
00123 static cmd_export_t glb_cmds[] = {
00124         {"auth_date_proc", date_proc, 0, 0, REQUEST_ROUTE},
00125         {"auth_add_identity", add_identity, 0, 0, REQUEST_ROUTE},
00126         {"vrfy_get_certificate", get_certificate, 0, 0, REQUEST_ROUTE},
00127         {"vrfy_check_msgvalidity", check_validity, 0, 0, REQUEST_ROUTE},
00128         {"vrfy_check_certificate", check_certificate, 0, 0, REQUEST_ROUTE},
00129         {"vrfy_check_date", check_date, 0, 0, REQUEST_ROUTE},
00130         {"vrfy_check_callid", check_callid, 0, 0, REQUEST_ROUTE},
00131         {0, 0, 0, 0, 0}
00132 };
00133 
00134 
00135 /*
00136  * Exported parameters
00137  */
00138 static param_export_t glb_params[] = {
00139         {"privatekey_path",             PARAM_STRING,   &glb_sprivkeypath},
00140         {"certificate_url",             PARAM_STRING,   &glb_sservercerturl},
00141         {"certificate_cache_limit", PARAM_INT,          &glb_icertlimit},
00142         {"callid_cache_limit",          PARAM_INT,              &glb_icallidlimit},
00143         {"certificate_path",            PARAM_STRING,   &glb_sservercertpath},
00144         {"auth_validity_time",          PARAM_INT,      &glb_iauthval},
00145         {"msg_timeout",                         PARAM_INT,              &glb_imsgtime},
00146         {"cainfo_path",                         PARAM_STRING,   &glb_scainfo},
00147         {"accept_pem_certs",            PARAM_INT,              &glb_acceptpem},
00148         {0, 0, 0}
00149 };
00150 
00151 
00152 /*
00153  * Module interface
00154  */
00155 struct module_exports exports = {
00156         "auth_identity",
00157         glb_cmds,   /* Exported functions */
00158         0,          /* RPC methods */
00159         glb_params, /* Exported parameters */
00160         mod_init,   /* module initialization function */
00161         0,          /* response function */
00162         mod_deinit, /* destroy function */
00163         0,          /* oncancel function */
00164         0                       /* child initialization function */
00165 };
00166 
00167 
00168 static int mod_init(void)
00169 {
00170         CURLcode iRet;
00171         str sstr;
00172         FILE *hpemfile;
00173         char serr[160];
00174         X509 *pmycert=NULL;             /* certificate of the authentication service */
00175         time_t tnow, ttmp;
00176 
00177         /*
00178          *
00179          * Parameter check
00180          *
00181          */
00182         if (glb_sprivkeypath[0]==0) {
00183                 LOG(L_WARN, "AUTH_IDENTITY:mod_init: Private key path is missing! Authorization service is disabled\n");
00184                 glb_authservice_disabled=1;
00185         }
00186         if (!glb_authservice_disabled && glb_sservercerturl[0]==0) {
00187                 LOG(L_WARN, "AUTH_IDENTITY:mod_init: URL of certificate of the server is missing! Authorization service is disabled\n");
00188                 glb_authservice_disabled=1;
00189         }
00190         if (!glb_authservice_disabled && glb_sservercertpath[0]==0) {
00191                 LOG(L_WARN, "AUTH_IDENTITY:mod_init: Path of certificate of the server is missing! Authorization service is disabled\n");
00192                 glb_authservice_disabled=1;
00193         }
00194 
00195         /*
00196          *
00197          * Init the curl session and download buffer
00198          *
00199          */
00200         curl_global_init(CURL_GLOBAL_ALL);
00201         if ((glb_hcurl=curl_easy_init())==NULL) {
00202                 LOG(L_ERR, "AUTH_IDENTITY:mod_init: Unable to init cURL library!\n");
00203                 return -1;
00204         }
00205         /* send all data to this function  */
00206         if ((iRet=curl_easy_setopt(glb_hcurl, CURLOPT_WRITEFUNCTION, curlmem_cb))!=0) {
00207                 LOG(L_ERR,
00208                         "AUTH_IDENTITY:mod_init: Unable to set cURL write function option: %s\n",
00209                         curl_easy_strerror(iRet));
00210                 return -2;
00211         }
00212         /* we pass our 'glb_tcert' struct to the callback function */
00213         if ((iRet=curl_easy_setopt(glb_hcurl, CURLOPT_WRITEDATA, (void *)&glb_tcert.scertpem))!=0) {
00214                 LOG(L_ERR,
00215                         "AUTH_IDENTITY:mod_init: Unable to set cURL writedata option: %s\n",
00216                         curl_easy_strerror(iRet));
00217                 return -4;
00218         }
00219         if (!(glb_tcert.scertpem.s=pkg_malloc(CERTIFICATE_LENGTH))) {
00220                 LOG(L_ERR, "AUTH_IDENTITY:mod_init: Not enough memory error\n");
00221                 return -3;
00222         }
00223         /* some servers don't like requests that are made without a user-agent
00224            field, so we provide one */
00225         if ((iRet=curl_easy_setopt(glb_hcurl, CURLOPT_USERAGENT, "ser-agent/1.0"))!=0) {
00226                 LOG(L_WARN,
00227                         "AUTH_IDENTITY:mod_init: Unable to set cURL useragent option: %s\n",
00228                         curl_easy_strerror(iRet));
00229         }
00230         if ((iRet=curl_easy_setopt(glb_hcurl, CURLOPT_SSL_VERIFYPEER, 1))!=0) {
00231                 LOG(L_WARN,
00232                         "AUTH_IDENTITY:mod_init: Unable to set cURL verifypeer option: %s\n",
00233                         curl_easy_strerror(iRet));
00234         }
00235         if ((iRet=curl_easy_setopt(glb_hcurl, CURLOPT_SSL_VERIFYHOST, 2))!=0) {
00236                 LOG(L_WARN,
00237                         "AUTH_IDENTITY:mod_init: Unable to set cURL verifyhost option: %s\n",
00238                         curl_easy_strerror(iRet));
00239         }
00240 
00241         /* cainfo_path module parameter's been set */
00242         if (glb_scainfo[0]) {
00243                 if ((iRet=curl_easy_setopt(glb_hcurl, CURLOPT_CAINFO, glb_scainfo))!=0) {
00244                         LOG(L_WARN,
00245                                 "AUTH_IDENTITY:mod_init: Unable to set cURL cainfo option: %s\n",
00246                                 curl_easy_strerror(iRet));
00247                 }
00248         }
00249 
00250 
00251         /*
00252          *
00253          * OpenSSL certificate verification initialization
00254          *
00255          */
00256         OpenSSL_add_all_algorithms();
00257         if (!(glb_cacerts=X509_STORE_new())) {
00258                 LOG(L_ERR, "AUTH_IDENTITY:mod_init: unable to initialize X509 store\n");
00259                 return -16;
00260         }
00261         if (X509_STORE_set_default_paths(glb_cacerts)!=1) {
00262                 LOG(L_ERR, "AUTH_IDENTITY:mod_init: unable to set X509 store default path\n");
00263                 return -17;
00264         }
00265         if (glb_scainfo[0]
00266                    && X509_STORE_load_locations(glb_cacerts, glb_scainfo, NULL) != 1)
00267                 LOG(L_WARN, "AUTH_IDENTITY:mod_init: unable to load X509 store location\n");
00268 
00269 
00270         /*
00271          *
00272          * Init the Date, Digest-String, Identity and Identity-Info
00273          *
00274          */
00275         if (initdynstr(&glb_sdgst, DGST_STR_INIT_SIZE))
00276                 return -5;
00277 
00278         /*
00279          * Init certificate table
00280          */
00281         if (init_table(&glb_tcert_table,
00282                                    CERTIFICATE_TABLE_ENTRIES,
00283                                    glb_icertlimit,
00284                                    cert_item_cmp,
00285                                    cert_item_init,
00286                                    cert_item_least,
00287                                    cert_item_free,
00288                                    NULL))
00289                 return -5;
00290 
00291         /*
00292          * Init call-id table
00293          */
00294         if (init_table(&glb_tcallid_table,
00295                                    CALLID_TABLE_ITEM_LIMIT,
00296                                    glb_icallidlimit,
00297                                    cid_item_cmp,
00298                                    cid_item_init,
00299                                    cid_item_least,
00300                                    cid_item_free,
00301                                    cid_item_gc))
00302                 return -5;
00303 
00304         glb_ttimeparams.ibnow=0;
00305         /* we've to check the whole table in glb_imsgtime, so the number of
00306            buckets we've to check in every timer call is
00307            CALLID_TABLE_ENTRIES/glb_imsgtime/CALLID_GARBAGE_COLLECTOR_INTERVAL */
00308         glb_ttimeparams.ibcir=glb_iauthval/CALLID_GARBAGE_COLLECTOR_INTERVAL;
00309         if (!glb_ttimeparams.ibcir)
00310                 glb_ttimeparams.ibcir=1;
00311         glb_ttimeparams.ibnum=CALLID_TABLE_ENTRIES/glb_ttimeparams.ibcir;
00312 
00313         if (register_timer(callid_gc, (void*)&glb_ttimeparams /* param*/, CALLID_GARBAGE_COLLECTOR_INTERVAL  /* period */) < 0 ) {
00314                 LOG(L_ERR, "AUTH_IDENTITY:mod_init: Can not register timer\n");
00315                 return -5;
00316         }
00317 
00318         /*
00319          * If there were not enough parameter set then we could not initialize
00320          * the authorizer part
00321          */
00322         if (glb_authservice_disabled)
00323                 return 0;
00324 
00325 
00326         if (initdynstr(&glb_sidentity, DGST_STR_INIT_SIZE))
00327                 return -6;
00328 
00329         if (initdynstr(&glb_sdate, AUTH_TIME_LENGTH))
00330                 return -7;
00331 
00332         if (initdynstr(&glb_sidentityinfo, AUTH_URL_LENGTH))
00333                 return -8;
00334 
00335         /* we initialize indentity info header */
00336         sstr.s=IDENTITY_INFO_FIRST_PART; sstr.len=strlen(IDENTITY_INFO_FIRST_PART);
00337         if (cpy2dynstr(&glb_sidentityinfo, &sstr))
00338                 return -9;
00339         sstr.s=glb_sservercerturl; sstr.len=strlen(glb_sservercerturl);
00340         if (app2dynstr(&glb_sidentityinfo, &sstr))
00341                 return -10;
00342         sstr.s=IDENTITY_INFO_LAST_PART;
00343         /* we copy the trailing \0 because append_hf expects strings */
00344         sstr.len=strlen(IDENTITY_INFO_LAST_PART) + 1;
00345         if (app2dynstr(&glb_sidentityinfo, &sstr))
00346                 return -11;
00347 
00348         /*
00349          * Get my certificate
00350          */
00351         if (!(hpemfile=fopen(glb_sservercertpath, "r"))) {
00352                 LOG(L_ERR, "AUTH_IDENTITY:mod_init: unable to open certificate '%s'\n", strerror(errno));
00353                 return -12;
00354         }
00355         if (!(pmycert=PEM_read_X509(hpemfile, NULL, NULL, NULL))) {
00356                 ERR_error_string_n(ERR_get_error(), serr, sizeof serr);
00357                 LOG(L_ERR, "AUTH_IDENTITY:mod_init: '%s'\n", serr);
00358                 fclose(hpemfile);
00359                 return -13;
00360         }
00361         if (x509_get_notafter(&glb_imycertnotafter, pmycert)) {
00362                 LOG(L_ERR, "AUTH_IDENTITY:mod_init: Error getting certificate expiration date\n");
00363                 return -13;
00364         }
00365         if (x509_get_notbefore(&ttmp, pmycert)) {
00366                 LOG(L_ERR, "AUTH_IDENTITY:mod_init: Error getting certificate validity date\n");
00367                 return -13;
00368         }
00369         if ((tnow=time(0)) < 0) {
00370                 LOG(L_ERR, "AUTH_IDENTITY:mod_init: time error %s\n", strerror(errno));
00371                 return -13;
00372         }
00373         if (tnow < ttmp || tnow > glb_imycertnotafter) {
00374                 LOG(L_ERR, "AUTH_IDENTITY:mod_init: Date of certificate is invalid (%s)\n", glb_sservercertpath);
00375                 return -14;
00376         }
00377 
00378         if (fclose(hpemfile))
00379                 LOG(L_ERR, "AUTH_IDENTITY:mod_init: unable to close file\n");
00380         X509_free(pmycert);
00381 
00382         /*
00383          *
00384          * Init RSA-SHA1 encoder
00385          *
00386          */
00387         hpemfile=fopen(glb_sprivkeypath, "r");
00388         if (!hpemfile)
00389         {
00390                 LOG(L_ERR, "AUTH_IDENTITY:mod_init: unable to open private key '%s'\n", strerror(errno));
00391                 return -12;
00392         }
00393         glb_hmyprivkey=PEM_read_RSAPrivateKey(hpemfile, NULL, NULL, NULL);
00394         if (!glb_hmyprivkey)
00395         {
00396                 ERR_error_string_n(ERR_get_error(), serr, sizeof serr);
00397                 LOG(L_ERR, "AUTH_IDENTITY:mod_init: '%s'\n", serr);
00398                 fclose(hpemfile);
00399                 return -13;
00400         }
00401         if (fclose(hpemfile))
00402                 LOG(L_ERR, "AUTH_IDENTITY:mod_init: unable to close file\n");
00403 
00404         /* we encrypt the digest string hash to this buffer */
00405         if (initdynstr(&glb_encedmsg, RSA_size(glb_hmyprivkey)))
00406                 return -14;
00407 
00408         /* we base64 encode the encrypted digest string hash to this buffer */
00409         if (initdynstr(&glb_b64encedmsg, (RSA_size(glb_hmyprivkey)/3+1)*4))
00410                 return -15;
00411 
00412         return 0;
00413 }
00414 
00415 
00416 static void mod_deinit(void)
00417 {
00418         curl_easy_cleanup(glb_hcurl);
00419         if (glb_tcert.scertpem.s)
00420                 pkg_free(glb_tcert.scertpem.s);
00421         free_dynstr(&glb_sdgst);
00422         free_dynstr(&glb_sidentity);
00423         free_dynstr(&glb_sdate);
00424         free_table(glb_tcert_table);
00425         free_table(glb_tcallid_table);
00426 
00427         if (glb_cacerts)
00428                 X509_STORE_free(glb_cacerts);
00429 }
00430 
00431 
00432 /*
00433  *
00434  *      VERIFIER FUNCTIONS
00435  *
00436  */
00437 
00438 
00439 static int get_certificate(struct sip_msg* msg, char* srt1, char* str2)
00440 {
00441         if (identityinfohdr_proc(&glb_tcert.surl, NULL, msg))
00442                 return -3;
00443 
00444         /* we support rsa-sha1 only (alg.len==0 then we use rsa-sha1) */
00445         if (get_identityinfo(msg)->alg.len
00446                 && (get_identityinfo(msg)->alg.len != strlen("rsa-sha1")
00447                     || strncasecmp("rsa-sha1",
00448                                                         get_identityinfo(msg)->alg.s,
00449                                                         get_identityinfo(msg)->alg.len ))) {
00450                 LOG(L_ERR, "AUTH_IDENTITY:get_certificate: Unsupported Identity-Info algorithm\n");
00451                 return -5;
00452         }
00453 
00454         /* this case ivalidbefore==0 singns that this certificate was downloaded */
00455         glb_tcert.ivalidbefore=0;
00456 
00457         /* chech whether this certificate is our certificate table */
00458         if (get_cert_from_table(glb_tcert_table, &glb_tcert.surl, &glb_tcert)) {
00459                 /* we did not found it in the table, so we've to download it */
00460                 /* we reset the PEM buffer */
00461                 glb_tcert.scertpem.len=0;
00462                 if (download_cer(&glb_tcert.surl, glb_hcurl))
00463                         return -6;
00464                 glb_certisdownloaded=1;
00465         } else
00466                 glb_certisdownloaded=0;
00467 
00468         if (retrieve_x509(&glb_pcertx509, &glb_tcert.scertpem, glb_acceptpem))
00469                 return -7;
00470 
00471 
00472         return 1;
00473 }
00474 
00475 /*
00476  * If the digest-string, assembled from the message, corresponds to the string
00477  * decoded from the Identity header by the acquired public key then the message
00478  * is valid. RFC 4474 [6] Step 3
00479  */
00480 static int check_validity(struct sip_msg* msg, char* srt1, char* str2)
00481 {
00482         str sidentity;
00483         char sencedsha[HASH_STR_SIZE];
00484         int iencedshalen;
00485 #ifndef NEW_RSA_PROC
00486         char ssha[HASH_STR_SIZE];
00487 #endif
00488         int ishalen;
00489         unsigned char sstrcrypted[SHA_DIGEST_LENGTH];
00490         int iRet=1;
00491 
00492 
00493         if (!glb_pcertx509) {
00494                 LOG(L_ERR, "AUTH_IDENTITY:check_validity: Certificate uninitialized! (has vrfy_get_certificate been called?)\n");
00495                 return -1;
00496         }
00497 
00498         do {
00499                 /* get the value of identity header parsed */
00500                 if (identityhdr_proc(&sidentity, NULL, msg)) {
00501                         iRet=-1;
00502                         break;
00503                 }
00504 
00505                 /* the length of identity value should be 172 octets long */
00506                 if (sidentity.len > sizeof(sencedsha)) {
00507                         LOG(L_ERR, "AUTH_IDENTITY:check_validity: Unexpected Identity length (%d)\n", sidentity.len);
00508                         iRet=-2;
00509                         break;
00510                 }
00511 
00512                 /* base64 decode the value of Identity header */
00513                 base64decode(sidentity.s, sidentity.len, sencedsha, &iencedshalen);
00514 
00515                 /* assemble the digest string to be able to compare it with decrypted one */
00516                 if (digeststr_asm(&glb_sdgst, msg, NULL, AUTH_INCOMING_BODY)) {
00517                         iRet=-5;
00518                         break;
00519                 }
00520                 /* calculate hash */
00521                 SHA1((unsigned char*)getstr_dynstr(&glb_sdgst).s,
00522                           getstr_dynstr(&glb_sdgst).len,
00523                           sstrcrypted);
00524 
00525 #ifdef NEW_RSA_PROC
00526                 /* decrypt with public key retrieved from the downloaded certificate
00527                    and compare it with the calculated digest hash */
00528                 if (rsa_sha1_dec(sencedsha, iencedshalen,
00529                                                  (char *)sstrcrypted, sizeof(sstrcrypted), &ishalen,
00530                                                  glb_pcertx509)) {
00531                         iRet=-3;
00532                         break;
00533                 } else
00534                         LOG(AUTH_DBG_LEVEL, "AUTH_IDENTITY VERIFIER: Identity OK\n");
00535 #else
00536                 /* decrypt with public key retrieved from the downloaded certificate */
00537                 if (rsa_sha1_dec(sencedsha, iencedshalen,
00538                                                  ssha, sizeof(ssha), &ishalen,
00539                                                  glb_pcertx509)) {
00540                         iRet=-3;
00541                         break;
00542                 }
00543 
00544                 /* check size */
00545                 if (ishalen != sizeof(sstrcrypted)) {
00546                         LOG(L_ERR, "AUTH_IDENTITY:check_validity: Unexpected decrypted hash length (%d != %d)\n", ishalen, SHA_DIGEST_LENGTH);
00547                         iRet=-4;
00548                         break;
00549                 }
00550                 /* compare */
00551                 if (memcmp(sstrcrypted, ssha, ishalen)) {
00552                         LOG(L_INFO, "AUTH_IDENTITY VERIFIER: comparing hashes failed -> Invalid Identity Header\n");
00553                         iRet=-6;
00554                         break;
00555                 } else
00556                         LOG(AUTH_DBG_LEVEL, "AUTH_IDENTITY VERIFIER: Identity OK\n");
00557 #endif
00558         } while (0);
00559 
00560         glb_pcertx509=NULL;
00561 
00562         return iRet;
00563 }
00564 
00565 /*
00566  * The Date header must indicate a time within 3600 seconds of the receipt of a
00567  * message. RFC 4474 [6] Step 4
00568  */
00569 static int check_date(struct sip_msg* msg, char* srt1, char* str2)
00570 {
00571         time_t tnow, tmsg;
00572         int ires;
00573 
00574         ires=datehdr_proc(NULL, NULL, msg);
00575         if (ires)
00576                 return -1;
00577 
00578 
00579 #ifdef HAVE_TIMEGM
00580         tmsg=timegm(&get_date(msg)->date);
00581 #else
00582         tmsg=_timegm(&get_date(msg)->date);
00583 #endif
00584         if (tmsg < 0) {
00585                 LOG(L_ERR, "AUTH_IDENTITY:check_date: timegm error\n");
00586                 return -2;
00587         }
00588 
00589         if ((tnow=time(0)) < 0) {
00590                 LOG(L_ERR, "AUTH_IDENTITY:check_date: time error %s\n", strerror(errno));
00591                 return -3;
00592         }
00593 
00594         if (tnow > tmsg + glb_iauthval) {
00595                 LOG(L_INFO, "AUTH_IDENTITY VERIFIER: Outdated date header value (%ld sec)\n", tnow - tmsg + glb_iauthval);
00596                 return -4;
00597         } else
00598                 LOG(AUTH_DBG_LEVEL, "AUTH_IDENTITY VERIFIER: Date header value OK\n");
00599 
00600         return 1;
00601 }
00602 
00603 
00604 int check_certificate(struct sip_msg* msg, char* srt1, char* str2) {
00605         struct sip_uri tfrom_uri;
00606         str suri;
00607 
00608         if (!glb_pcertx509) {
00609                 LOG(L_ERR, "AUTH_IDENTITY:check_certificate: Certificate uninitialized! (has vrfy_get_certificate been called?)\n");
00610                 return -1;
00611         }
00612         /* this certificate was downloaded so we've to verify and add it to table */
00613         if (glb_certisdownloaded) {
00614                 if (fromhdr_proc(&suri, NULL, msg))
00615                         return -1;
00616 
00617                 if (parse_uri(suri.s, suri.len, &tfrom_uri)) {
00618                         LOG(L_ERR, "AUTH_IDENTITY:get_certificate: Error while parsing FROM URI\n");
00619                         return -2;
00620                 }
00621 
00622                 if (verify_x509(glb_pcertx509, glb_cacerts))
00623                         return -3;
00624 
00625                 if (check_x509_subj(glb_pcertx509, &tfrom_uri.host))
00626                         return -4;
00627 
00628                 /* we retrieve expiration date from the certificate (it needs for
00629                    certificate table garbage collector) */
00630                 if (x509_get_notafter(&glb_tcert.ivalidbefore, glb_pcertx509))
00631                         return -5;
00632 
00633                 if (addcert2table(glb_tcert_table, &glb_tcert))
00634                         return -6;
00635         }
00636         return 1;
00637 }
00638 
00639 static int check_callid(struct sip_msg* msg, char* srt1, char* str2)
00640 {
00641         str scid, sftag, scseqnum;
00642         unsigned int ucseq;
00643         int ires;
00644         time_t ivalidbefore;
00645 
00646 
00647         if (callidhdr_proc(&scid, NULL, msg))
00648                 return -1;
00649 
00650         if (cseqhdr_proc(&scseqnum, NULL, msg))
00651                 return -2;
00652         if (str2int(&scseqnum, &ucseq))
00653                 return -3;
00654 
00655         if (fromhdr_proc(NULL, &sftag, msg))
00656                 return -4;
00657 
00658         if ((ivalidbefore=time(0)) < 0) {
00659                 LOG(L_ERR, "AUTH_IDENTITY:check_callid: time error %s\n", strerror(errno));
00660                 return -5;
00661         }
00662 
00663         ires=proc_cid(glb_tcallid_table,
00664                                   &scid,
00665                                   &sftag,
00666                                   ucseq,
00667                                   ivalidbefore + glb_iauthval);
00668         if (ires) {
00669                 if (ires==AUTH_FOUND)
00670                         LOG(L_INFO, "AUTH_IDENTITY VERIFIER: Call is replayed!\n");
00671                 return -6;
00672         }
00673 
00674         return 1;
00675 }
00676 
00677 
00678 void callid_gc(unsigned int tick, void *param)
00679 {
00680         /* check the last slice */
00681         if (((ttimeparams*)param)->ibnow + 1 == ((ttimeparams*)param)->ibcir) {
00682                 garbage_collect(glb_tcallid_table,
00683                                                  (((ttimeparams*)param)->ibnow)*((ttimeparams*)param)->ibnum,
00684                                                  CALLID_TABLE_ENTRIES-1);
00685                 /* we step to the first slice */
00686                 ((ttimeparams*)param)->ibnow=0;
00687         } else {
00688                 garbage_collect(glb_tcallid_table,
00689                                                  (((ttimeparams*)param)->ibnow)*((ttimeparams*)param)->ibnum,
00690                                                  ((((ttimeparams*)param)->ibnow+1)*((ttimeparams*)param)->ibnum)-1);
00691                 /* we step to the next slice */
00692                 ((ttimeparams*)param)->ibnow++;
00693         }
00694 }
00695 
00696 /*
00697  *
00698  *      AUTHORIZER FUNCTIONS
00699  *
00700  */
00701 
00702 /* Checks the Date header of the message. RFC4474 [5] Step 3 */
00703 static int date_proc(struct sip_msg* msg, char* srt1, char* str2)
00704 {
00705         str sdate;
00706         int iRes;
00707         time_t tmsg, tnow;
00708 
00709         if (glb_authservice_disabled) {
00710                 LOG(L_WARN, "AUTH_IDENTITY:date_proc: Authentication Service is disabled\n");
00711                 return -1;
00712         }
00713 
00714         getstr_dynstr(&glb_sdate).len=0;
00715 
00716         /* we'd like to get the DATE header of the massage */
00717         iRes=datehdr_proc(&sdate, NULL, msg);
00718         switch (iRes) {
00719                 case AUTH_ERROR:
00720                         return -1;
00721                 case AUTH_NOTFOUND:
00722                         if (append_date(&getstr_dynstr(&glb_sdate), glb_sdate.size, &tmsg, msg))
00723                                 return -2;
00724                         break;
00725                 /* Message has Date header so we check that */
00726                 case AUTH_OK:
00727 #ifdef HAVE_TIMEGM
00728                         tmsg=timegm(&get_date(msg)->date);
00729 #else
00730                         tmsg=_timegm(&get_date(msg)->date);
00731 #endif
00732                         if (tmsg < 0) {
00733                                 LOG(L_ERR, "AUTH_IDENTITY:date_proc: timegm error\n");
00734                                 return -3;
00735                         }
00736                         if ((tnow=time(NULL))<0) {
00737                                 LOG(L_ERR, "AUTH_IDENTITY:date_proc: time error\n");
00738                                 return -4;
00739                         }
00740                         /*
00741                          * If the value of this field contains a time different by more than
00742                          * ten minutes from the current time noted by the authentication
00743                          * service then it should reject the message.
00744                          */
00745                         if (tmsg + glb_imsgtime < tnow || tnow + glb_imsgtime < tmsg) {
00746                                 LOG(L_INFO, "AUTH_IDENTITY AUTHORIZER: Date header overdue\n");
00747                                 return -6;
00748                         }
00749                         break;
00750                 default:
00751                         /* unknown result */
00752                         return -7;
00753         }
00754 
00755         /*
00756          * The authentication service MUST verify that the Date header
00757          * falls within the validity period of its certificate
00758          * RFC 4474 [6] Step 3
00759          */
00760         if (glb_imycertnotafter < tmsg) {
00761                 LOG(L_INFO, "AUTH_IDENTITY AUTHORIZER: My certificate has been expired\n");
00762                 return -8;
00763         }
00764 
00765         return 1;
00766 }
00767 
00768 /*
00769  * Concates the message From, To, Call-ID, Cseq, Date,  Contact header fields
00770  * and the message body to digest-string, signs with the domain private-key,
00771  * BASE64 encodes that, and finally adds it to the message as the 'Identity'
00772  * header value. RFC4474 [5] Step 4
00773  *
00774  * Adds Identity-Info header to the message which contains an URI from which
00775  * its certificate can be acquired. RFC4474 [5] Step 4
00776  */
00777 static int add_identity(struct sip_msg* msg, char* srt1, char* str2)
00778 {
00779         int iRes;
00780         str sstr;
00781 
00782 
00783         if (glb_authservice_disabled) {
00784                 LOG(L_WARN, "AUTH_IDENTITY:add_identity: Authentication Service is disabled\n");
00785                 return -1;
00786         }
00787 
00788         /* check Date */
00789         iRes=datehdr_proc(NULL, NULL, msg);
00790         switch (iRes) {
00791                 case AUTH_ERROR:
00792                         return -1;
00793                 case AUTH_NOTFOUND:
00794                         if (!getstr_dynstr(&glb_sdate).len) {
00795                                 /*
00796                                  * date_proc() must be called before add_identity() because
00797                                  * that function initializes the Date if that not exists
00798                                  * in the SIP message
00799                                  */
00800                                 LOG(L_ERR, "AUTH_IDENTITY:add_identity: Date header is not found (has auth_date_proc been called?)\n");
00801                                 return -2;
00802                         }
00803                         /*  assemble the digest string and the DATE header is missing in the orignal message */
00804                         if (digeststr_asm(&glb_sdgst,
00805                                                           msg,
00806                                                           &getstr_dynstr(&glb_sdate),
00807                                                           AUTH_OUTGOING_BODY | AUTH_ADD_DATE))
00808                                 return -3;
00809                         break;
00810                 default:
00811                         /*  assemble the digest string and the DATE header is available in the message */
00812                         if (digeststr_asm(&glb_sdgst, msg, NULL, AUTH_OUTGOING_BODY))
00813                                 return -4;
00814                         break;
00815         }
00816 
00817         /* calculate the SHA1 hash and encrypt with our provate key */
00818         if (rsa_sha1_enc(&glb_sdgst, &glb_encedmsg, &glb_b64encedmsg, glb_hmyprivkey))
00819                 return -5;
00820 
00821         /* we assemble the value of the Identity haader */
00822         sstr.s=IDENTITY_FIRST_PART; sstr.len=strlen(IDENTITY_FIRST_PART);
00823         if (cpy2dynstr(&glb_sidentity, &sstr))
00824                 return -6;
00825 
00826         if (app2dynstr(&glb_sidentity, &getstr_dynstr(&glb_b64encedmsg)))
00827                 return -7;
00828 
00829         sstr.s=IDENTITY_LAST_PART;
00830         /* +1 : we need the trailing \0 character too */
00831         sstr.len=strlen(IDENTITY_LAST_PART) + 1;
00832         if (app2dynstr(&glb_sidentity, &sstr))
00833                 return -8;
00834 
00835         if (append_hf(msg, getstr_dynstr(&glb_sidentity).s, HDR_IDENTITY_T))
00836                 return -9;
00837 
00838         if (append_hf(msg, getstr_dynstr(&glb_sidentityinfo).s, HDR_IDENTITY_INFO_T))
00839                 return -10;
00840 
00841         return 1;
00842 }