int initdynstr(dynstr *sout, int isize) { memset(sout,0,sizeof(*sout)); getstr_dynstr(sout).s=pkg_malloc(isize); if (!getstr_dynstr(sout).s) { LOG(L_WARN, "AUTH_IDENTITY:initdynstr: Not enough memory error\n"); return -1; } sout->size=isize; return 0; }
/* Checks the Date header of the message. RFC4474 [5] Step 3 */ static int date_proc(struct sip_msg* msg, char* srt1, char* str2) { str sdate; int iRes; time_t tmsg, tnow; if (glb_authservice_disabled) { LOG(L_WARN, "AUTH_IDENTITY:date_proc: Authentication Service is disabled\n"); return -1; } getstr_dynstr(&glb_sdate).len=0; /* we'd like to get the DATE header of the massage */ iRes=datehdr_proc(&sdate, NULL, msg); switch (iRes) { case AUTH_ERROR: return -1; case AUTH_NOTFOUND: if (append_date(&getstr_dynstr(&glb_sdate), glb_sdate.size, &tmsg, msg)) return -2; break; /* Message has Date header so we check that */ case AUTH_OK: #ifdef HAVE_TIMEGM tmsg=timegm(&get_date(msg)->date); #else tmsg=_timegm(&get_date(msg)->date); #endif if (tmsg < 0) { LOG(L_ERR, "AUTH_IDENTITY:date_proc: timegm error\n"); return -3; } if ((tnow=time(NULL))<0) { LOG(L_ERR, "AUTH_IDENTITY:date_proc: time error\n"); return -4; } /* * If the value of this field contains a time different by more than * ten minutes from the current time noted by the authentication * service then it should reject the message. */ if (tmsg + glb_imsgtime < tnow || tnow + glb_imsgtime < tmsg) { LOG(L_INFO, "AUTH_IDENTITY AUTHORIZER: Date header overdue\n"); return -6; } break; default: /* unknown result */ return -7; } /* * The authentication service MUST verify that the Date header * falls within the validity period of its certificate * RFC 4474 [6] Step 3 */ if (glb_imycertnotafter < tmsg) { LOG(L_INFO, "AUTH_IDENTITY AUTHORIZER: My certificate has been expired\n"); return -8; } return 1; }
/* * Concates the message From, To, Call-ID, Cseq, Date, Contact header fields * and the message body to digest-string, signs with the domain private-key, * BASE64 encodes that, and finally adds it to the message as the 'Identity' * header value. RFC4474 [5] Step 4 * * Adds Identity-Info header to the message which contains an URI from which * its certificate can be acquired. RFC4474 [5] Step 4 */ static int add_identity(struct sip_msg* msg, char* srt1, char* str2) { int iRes; str sstr; if (glb_authservice_disabled) { LOG(L_WARN, "AUTH_IDENTITY:add_identity: Authentication Service is disabled\n"); return -1; } /* check Date */ iRes=datehdr_proc(NULL, NULL, msg); switch (iRes) { case AUTH_ERROR: return -1; case AUTH_NOTFOUND: if (!getstr_dynstr(&glb_sdate).len) { /* * date_proc() must be called before add_identity() because * that function initializes the Date if that not exists * in the SIP message */ LOG(L_ERR, "AUTH_IDENTITY:add_identity: Date header is not found (has auth_date_proc been called?)\n"); return -2; } /* assemble the digest string and the DATE header is missing in the orignal message */ if (digeststr_asm(&glb_sdgst, msg, &getstr_dynstr(&glb_sdate), AUTH_OUTGOING_BODY | AUTH_ADD_DATE)) return -3; break; default: /* assemble the digest string and the DATE header is available in the message */ if (digeststr_asm(&glb_sdgst, msg, NULL, AUTH_OUTGOING_BODY)) return -4; break; } /* calculate the SHA1 hash and encrypt with our provate key */ if (rsa_sha1_enc(&glb_sdgst, &glb_encedmsg, &glb_b64encedmsg, glb_hmyprivkey)) return -5; /* we assemble the value of the Identity haader */ sstr.s=IDENTITY_FIRST_PART; sstr.len=strlen(IDENTITY_FIRST_PART); if (cpy2dynstr(&glb_sidentity, &sstr)) return -6; if (app2dynstr(&glb_sidentity, &getstr_dynstr(&glb_b64encedmsg))) return -7; sstr.s=IDENTITY_LAST_PART; /* +1 : we need the trailing \0 character too */ sstr.len=strlen(IDENTITY_LAST_PART) + 1; if (app2dynstr(&glb_sidentity, &sstr)) return -8; if (append_hf(msg, getstr_dynstr(&glb_sidentity).s, HDR_IDENTITY_T)) return -9; if (append_hf(msg, getstr_dynstr(&glb_sidentityinfo).s, HDR_IDENTITY_INFO_T)) return -10; return 1; }
/* * If the digest-string, assembled from the message, corresponds to the string * decoded from the Identity header by the acquired public key then the message * is valid. RFC 4474 [6] Step 3 */ static int check_validity(struct sip_msg* msg, char* srt1, char* str2) { str sidentity; char sencedsha[HASH_STR_SIZE]; int iencedshalen; #ifndef NEW_RSA_PROC char ssha[HASH_STR_SIZE]; #endif int ishalen; unsigned char sstrcrypted[SHA_DIGEST_LENGTH]; int iRet=1; if (!glb_pcertx509) { LOG(L_ERR, "AUTH_IDENTITY:check_validity: Certificate uninitialized! (has vrfy_get_certificate been called?)\n"); return -1; } do { /* get the value of identity header parsed */ if (identityhdr_proc(&sidentity, NULL, msg)) { iRet=-1; break; } /* the length of identity value should be 172 octets long */ if (sidentity.len > sizeof(sencedsha)) { LOG(L_ERR, "AUTH_IDENTITY:check_validity: Unexpected Identity length (%d)\n", sidentity.len); iRet=-2; break; } /* base64 decode the value of Identity header */ base64decode(sidentity.s, sidentity.len, sencedsha, &iencedshalen); /* assemble the digest string to be able to compare it with decrypted one */ if (digeststr_asm(&glb_sdgst, msg, NULL, AUTH_INCOMING_BODY)) { iRet=-5; break; } /* calculate hash */ SHA1((unsigned char*)getstr_dynstr(&glb_sdgst).s, getstr_dynstr(&glb_sdgst).len, sstrcrypted); #ifdef NEW_RSA_PROC /* decrypt with public key retrieved from the downloaded certificate and compare it with the calculated digest hash */ if (rsa_sha1_dec(sencedsha, iencedshalen, (char *)sstrcrypted, sizeof(sstrcrypted), &ishalen, glb_pcertx509)) { iRet=-3; break; } else LOG(AUTH_DBG_LEVEL, "AUTH_IDENTITY VERIFIER: Identity OK\n"); #else /* decrypt with public key retrieved from the downloaded certificate */ if (rsa_sha1_dec(sencedsha, iencedshalen, ssha, sizeof(ssha), &ishalen, glb_pcertx509)) { iRet=-3; break; } /* check size */ if (ishalen != sizeof(sstrcrypted)) { LOG(L_ERR, "AUTH_IDENTITY:check_validity: Unexpected decrypted hash length (%d != %d)\n", ishalen, SHA_DIGEST_LENGTH); iRet=-4; break; } /* compare */ if (memcmp(sstrcrypted, ssha, ishalen)) { LOG(L_INFO, "AUTH_IDENTITY VERIFIER: comparing hashes failed -> Invalid Identity Header\n"); iRet=-6; break; } else LOG(AUTH_DBG_LEVEL, "AUTH_IDENTITY VERIFIER: Identity OK\n"); #endif } while (0); glb_pcertx509=NULL; return iRet; }