source: verona/libeXosip2/src/jauth.c @ 268:a190752a5256

Last change on this file since 268:a190752a5256 was 268:a190752a5256, checked in by Vadim Lebedev <vadim@…>, 22 months ago

exosip COVERITY fixes

File size: 29.3 KB
Line 
1/*
2  eXosip - This is the eXtended osip library.
3  Copyright (C) 2002,2003,2004,2005,2006,2007  Aymeric MOIZARD  - jack@atosc.org
4 
5  eXosip is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9 
10  eXosip is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program; if not, write to the Free Software
17  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18*/
19
20
21#ifdef ENABLE_MPATROL
22#include <mpatrol.h>
23#endif
24
25#include "eXosip2.h"
26#include <eXosip2/eXosip.h>
27
28#include <osip2/osip_mt.h>
29#include <osip2/osip_condv.h>
30
31/* #include <osip2/global.h> */
32#include <osipparser2/osip_md5.h>
33#include "milenage.h"
34
35/* TAKEN from rcf2617.txt */
36
37#define HASHLEN 16
38typedef char HASH[HASHLEN];
39
40#define HASHHEXLEN 32
41typedef char HASHHEX[HASHHEXLEN + 1];
42
43#define IN
44#define OUT
45
46/* AKA */
47#define MAX_HEADER_LEN  2049
48#define KLEN 16
49typedef u_char K[KLEN];
50#define RANDLEN 16
51typedef u_char RAND[RANDLEN];
52#define AUTNLEN 16
53typedef u_char AUTN[AUTNLEN];
54
55#define AKLEN 6
56typedef u_char AK[AKLEN];
57#define AMFLEN 2
58typedef u_char AMF[AMFLEN];
59#define MACLEN 8
60typedef u_char MAC[MACLEN];
61#define CKLEN 16
62typedef u_char CK[CKLEN];
63#define IKLEN 16
64typedef u_char IK[IKLEN];
65#define SQNLEN 6
66typedef u_char SQN[SQNLEN];
67#define AUTSLEN 14
68typedef char AUTS[AUTSLEN];
69#define AUTS64LEN 21
70typedef char AUTS64[AUTS64LEN];
71#define RESLEN 8
72typedef unsigned char RES[RESLEN];
73#define RESHEXLEN 17
74typedef char RESHEX[RESHEXLEN];
75typedef char RESHEXAKA2[RESHEXLEN + IKLEN * 2 + CKLEN * 2];
76
77AMF amf = "\0\0";
78AMF amfstar = "\0\0";
79
80/* end AKA */
81
82extern eXosip_t eXosip;
83
84/* Private functions */
85void CvtHex(IN HASH Bin, OUT HASHHEX Hex);
86static void DigestCalcHA1(IN const char *pszAlg, IN const char *pszUserName,
87                                                  IN const char *pszRealm,
88                                                  IN const char *pszPassword,
89                                                  IN const char *pszNonce, IN const char *pszCNonce,
90                                                  OUT HASHHEX SessionKey);
91static void DigestCalcResponse(IN HASHHEX HA1, IN const char *pszNonce,
92                                                           IN const char *pszNonceCount,
93                                                           IN const char *pszCNonce,
94                                                           IN const char *pszQop,
95                                                           IN int Aka,
96                                                           IN const char *pszMethod,
97                                                           IN const char *pszDigestUri,
98                                                           IN HASHHEX HEntity, OUT HASHHEX Response);
99static void DigestCalcResponseAka(IN const char *pszPassword,
100                                                                  IN const char *pszNonce,
101                                                                  IN const char *pszCNonce,
102                                                                  IN const char *pszQop,
103                                                                  IN const char *pszMethod,
104                                                                  IN const char *pszDigestUri,
105                                                                  IN int version, OUT HASHHEX Response);
106
107void CvtHex(IN HASH Bin, OUT HASHHEX Hex)
108{
109        unsigned short i;
110        unsigned char j;
111
112        for (i = 0; i < HASHLEN; i++) {
113                j = (Bin[i] >> 4) & 0xf;
114                if (j <= 9)
115                        Hex[i * 2] = (j + '0');
116                else
117                        Hex[i * 2] = (j + 'a' - 10);
118                j = Bin[i] & 0xf;
119                if (j <= 9)
120                        Hex[i * 2 + 1] = (j + '0');
121                else
122                        Hex[i * 2 + 1] = (j + 'a' - 10);
123        };
124        Hex[HASHHEXLEN] = '\0';
125}
126
127/* calculate H(A1) as per spec */
128static void
129DigestCalcHA1(IN const char *pszAlg,
130                          IN const char *pszUserName,
131                          IN const char *pszRealm,
132                          IN const char *pszPassword,
133                          IN const char *pszNonce,
134                          IN const char *pszCNonce, OUT HASHHEX SessionKey)
135{
136        osip_MD5_CTX Md5Ctx;
137        HASH HA1;
138
139        osip_MD5Init(&Md5Ctx);
140        osip_MD5Update(&Md5Ctx, (unsigned char *) pszUserName, strlen(pszUserName));
141        osip_MD5Update(&Md5Ctx, (unsigned char *) ":", 1);
142        osip_MD5Update(&Md5Ctx, (unsigned char *) pszRealm, strlen(pszRealm));
143        osip_MD5Update(&Md5Ctx, (unsigned char *) ":", 1);
144        osip_MD5Update(&Md5Ctx, (unsigned char *) pszPassword, strlen(pszPassword));
145        osip_MD5Final((unsigned char *) HA1, &Md5Ctx);
146        if ((pszAlg != NULL) && osip_strcasecmp(pszAlg, "md5-sess") == 0) {
147                osip_MD5Init(&Md5Ctx);
148                osip_MD5Update(&Md5Ctx, (unsigned char *) HA1, HASHLEN);
149                osip_MD5Update(&Md5Ctx, (unsigned char *) ":", 1);
150                osip_MD5Update(&Md5Ctx, (unsigned char *) pszNonce, strlen(pszNonce));
151                osip_MD5Update(&Md5Ctx, (unsigned char *) ":", 1);
152                osip_MD5Update(&Md5Ctx, (unsigned char *) pszCNonce, strlen(pszCNonce));
153                osip_MD5Final((unsigned char *) HA1, &Md5Ctx);
154        }
155        CvtHex(HA1, SessionKey);
156}
157
158/* calculate request-digest/response-digest as per HTTP Digest spec */
159static void DigestCalcResponse(IN HASHHEX HA1,  /* H(A1) */
160                                                           IN const char *pszNonce,     /* nonce from server */
161                                                           IN const char *pszNonceCount,        /* 8 hex digits */
162                                                           IN const char *pszCNonce,    /* client nonce */
163                                                           IN const char *pszQop,       /* qop-value: "", "auth", "auth-int" */
164                                                           IN int Aka,  /* Calculating AKAv1-MD5 response */
165                                                           IN const char *pszMethod,    /* method from the request */
166                                                           IN const char *pszDigestUri, /* requested URL */
167                                                           IN HASHHEX HEntity,  /* H(entity body) if qop="auth-int" */
168                                                           OUT HASHHEX Response
169                                                           /* request-digest or response-digest */ )
170{
171        osip_MD5_CTX Md5Ctx;
172        HASH HA2;
173        HASH RespHash;
174        HASHHEX HA2Hex;
175
176        /* calculate H(A2) */
177        osip_MD5Init(&Md5Ctx);
178        osip_MD5Update(&Md5Ctx, (unsigned char *) pszMethod, strlen(pszMethod));
179        osip_MD5Update(&Md5Ctx, (unsigned char *) ":", 1);
180        osip_MD5Update(&Md5Ctx, (unsigned char *) pszDigestUri, strlen(pszDigestUri));
181
182        if (pszQop == NULL) {
183                goto auth_withoutqop;
184        } else if (0 == osip_strcasecmp(pszQop, "auth-int")) {
185                goto auth_withauth_int;
186        } else if (0 == osip_strcasecmp(pszQop, "auth")) {
187                goto auth_withauth;
188        }
189
190  auth_withoutqop:
191        osip_MD5Final((unsigned char *) HA2, &Md5Ctx);
192        CvtHex(HA2, HA2Hex);
193
194        /* calculate response */
195        osip_MD5Init(&Md5Ctx);
196        osip_MD5Update(&Md5Ctx, (unsigned char *) HA1, HASHHEXLEN);
197        osip_MD5Update(&Md5Ctx, (unsigned char *) ":", 1);
198        osip_MD5Update(&Md5Ctx, (unsigned char *) pszNonce, strlen(pszNonce));
199        osip_MD5Update(&Md5Ctx, (unsigned char *) ":", 1);
200
201        goto end;
202
203  auth_withauth_int:
204
205        osip_MD5Update(&Md5Ctx, (unsigned char *) ":", 1);
206        osip_MD5Update(&Md5Ctx, (unsigned char *) HEntity, HASHHEXLEN);
207
208  auth_withauth:
209        osip_MD5Final((unsigned char *) HA2, &Md5Ctx);
210        CvtHex(HA2, HA2Hex);
211
212        /* calculate response */
213        osip_MD5Init(&Md5Ctx);
214        osip_MD5Update(&Md5Ctx, (unsigned char *) HA1, HASHHEXLEN);
215        osip_MD5Update(&Md5Ctx, (unsigned char *) ":", 1);
216        osip_MD5Update(&Md5Ctx, (unsigned char *) pszNonce, strlen(pszNonce));
217        osip_MD5Update(&Md5Ctx, (unsigned char *) ":", 1);
218        if (Aka == 0) {
219                osip_MD5Update(&Md5Ctx, (unsigned char *) pszNonceCount,
220                                           strlen(pszNonceCount));
221                osip_MD5Update(&Md5Ctx, (unsigned char *) ":", 1);
222                osip_MD5Update(&Md5Ctx, (unsigned char *) pszCNonce, strlen(pszCNonce));
223                osip_MD5Update(&Md5Ctx, (unsigned char *) ":", 1);
224                osip_MD5Update(&Md5Ctx, (unsigned char *) pszQop, strlen(pszQop));
225                osip_MD5Update(&Md5Ctx, (unsigned char *) ":", 1);
226        }
227  end:
228        osip_MD5Update(&Md5Ctx, (unsigned char *) HA2Hex, HASHHEXLEN);
229        osip_MD5Final((unsigned char *) RespHash, &Md5Ctx);
230        CvtHex(RespHash, Response);
231}
232
233/*"
234ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";*/
235static int base64_val(char x)
236{
237        switch (x) {
238        case '=':
239                return -1;
240        case 'A':
241                return OSIP_SUCCESS;
242        case 'B':
243                return 1;
244        case 'C':
245                return 2;
246        case 'D':
247                return 3;
248        case 'E':
249                return 4;
250        case 'F':
251                return 5;
252        case 'G':
253                return 6;
254        case 'H':
255                return 7;
256        case 'I':
257                return 8;
258        case 'J':
259                return 9;
260        case 'K':
261                return 10;
262        case 'L':
263                return 11;
264        case 'M':
265                return 12;
266        case 'N':
267                return 13;
268        case 'O':
269                return 14;
270        case 'P':
271                return 15;
272        case 'Q':
273                return 16;
274        case 'R':
275                return 17;
276        case 'S':
277                return 18;
278        case 'T':
279                return 19;
280        case 'U':
281                return 20;
282        case 'V':
283                return 21;
284        case 'W':
285                return 22;
286        case 'X':
287                return 23;
288        case 'Y':
289                return 24;
290        case 'Z':
291                return 25;
292        case 'a':
293                return 26;
294        case 'b':
295                return 27;
296        case 'c':
297                return 28;
298        case 'd':
299                return 29;
300        case 'e':
301                return 30;
302        case 'f':
303                return 31;
304        case 'g':
305                return 32;
306        case 'h':
307                return 33;
308        case 'i':
309                return 34;
310        case 'j':
311                return 35;
312        case 'k':
313                return 36;
314        case 'l':
315                return 37;
316        case 'm':
317                return 38;
318        case 'n':
319                return 39;
320        case 'o':
321                return 40;
322        case 'p':
323                return 41;
324        case 'q':
325                return 42;
326        case 'r':
327                return 43;
328        case 's':
329                return 44;
330        case 't':
331                return 45;
332        case 'u':
333                return 46;
334        case 'v':
335                return 47;
336        case 'w':
337                return 48;
338        case 'x':
339                return 49;
340        case 'y':
341                return 50;
342        case 'z':
343                return 51;
344        case '0':
345                return 52;
346        case '1':
347                return 53;
348        case '2':
349                return 54;
350        case '3':
351                return 55;
352        case '4':
353                return 56;
354        case '5':
355                return 57;
356        case '6':
357                return 58;
358        case '7':
359                return 59;
360        case '8':
361                return 60;
362        case '9':
363                return 61;
364        case '+':
365                return 62;
366        case '/':
367                return 63;
368        }
369        return OSIP_SUCCESS;
370}
371
372
373static char *base64_decode_string(const char *buf, unsigned int len, int *newlen)
374{
375        int i, j, x1, x2, x3, x4;
376        char *out;
377        out = (char *) osip_malloc((len * 3 / 4) + 8);
378        if (out == NULL)
379                return NULL;
380        for (i = 0, j = 0; i + 3 < len; i += 4) {
381                x1 = base64_val(buf[i]);
382                x2 = base64_val(buf[i + 1]);
383                x3 = base64_val(buf[i + 2]);
384                x4 = base64_val(buf[i + 3]);
385                out[j++] = (x1 << 2) | ((x2 & 0x30) >> 4);
386                out[j++] = ((x2 & 0x0F) << 4) | ((x3 & 0x3C) >> 2);
387                out[j++] = ((x3 & 0x03) << 6) | (x4 & 0x3F);
388        }
389        if (i < len) {
390                x1 = base64_val(buf[i]);
391                if (i + 1 < len)
392                        x2 = base64_val(buf[i + 1]);
393                else
394                        x2 = -1;
395                if (i + 2 < len)
396                        x3 = base64_val(buf[i + 2]);
397                else
398                        x3 = -1;
399                if (i + 3 < len)
400                        x4 = base64_val(buf[i + 3]);
401                else
402                        x4 = -1;
403                if (x2 != -1) {
404                        out[j++] = (x1 << 2) | ((x2 & 0x30) >> 4);
405                        if (x3 == -1) {
406                                out[j++] = ((x2 & 0x0F) << 4) | ((x3 & 0x3C) >> 2);
407                                if (x4 == -1) {
408                                        out[j++] = ((x3 & 0x03) << 6) | (x4 & 0x3F);
409                                }
410                        }
411                }
412
413        }
414
415        out[j++] = 0;
416        *newlen = j;
417        return out;
418}
419
420char base64[64] =
421        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
422static char *base64_encode_string(const char *buf, unsigned int len, int *newlen)
423{
424        int i, k;
425        int triplets, rest;
426        char *out, *ptr;
427
428        triplets = len / 3;
429        rest = len % 3;
430        out = (char *) osip_malloc((triplets * 4) + 8);
431        if (out == NULL)
432                return NULL;
433
434        ptr = out;
435        for (i = 0; i < triplets * 3; i += 3) {
436                k = (((unsigned char) buf[i]) & 0xFC) >> 2;
437                *ptr = base64[k];
438                ptr++;
439
440                k = (((unsigned char) buf[i]) & 0x03) << 4;
441                k |= (((unsigned char) buf[i + 1]) & 0xF0) >> 4;
442                *ptr = base64[k];
443                ptr++;
444
445                k = (((unsigned char) buf[i + 1]) & 0x0F) << 2;
446                k |= (((unsigned char) buf[i + 2]) & 0xC0) >> 6;
447                *ptr = base64[k];
448                ptr++;
449
450                k = (((unsigned char) buf[i + 2]) & 0x3F);
451                *ptr = base64[k];
452                ptr++;
453        }
454        i = triplets * 3;
455        switch (rest) {
456        case 0:
457                break;
458        case 1:
459                k = (((unsigned char) buf[i]) & 0xFC) >> 2;
460                *ptr = base64[k];
461                ptr++;
462
463                k = (((unsigned char) buf[i]) & 0x03) << 4;
464                *ptr = base64[k];
465                ptr++;
466
467                *ptr = '=';
468                ptr++;
469
470                *ptr = '=';
471                ptr++;
472                break;
473        case 2:
474                k = (((unsigned char) buf[i]) & 0xFC) >> 2;
475                *ptr = base64[k];
476                ptr++;
477
478                k = (((unsigned char) buf[i]) & 0x03) << 4;
479                k |= (((unsigned char) buf[i + 1]) & 0xF0) >> 4;
480                *ptr = base64[k];
481                ptr++;
482
483                k = (((unsigned char) buf[i + 1]) & 0x0F) << 2;
484                *ptr = base64[k];
485                ptr++;
486
487                *ptr = '=';
488                ptr++;
489                break;
490        }
491
492        *newlen = ptr - out;
493        return out;
494}
495
496
497
498char hexa[16] = "0123456789abcdef";
499/* calculate AKA request-digest/response-digest as per HTTP Digest spec */
500void DigestCalcResponseAka(IN const char *pszPassword, IN const char *pszNonce, /* nonce from server */
501                                                   IN const char *pszCNonce,    /* client nonce */
502                                                   IN const char *pszQop,       /* qop-value: "", "auth", "auth-int" */
503                                                   IN const char *pszMethod,    /* method from the request */
504                                                   IN const char *pszDigestUri, /* requested URL */
505                                                   IN int version,      /* AKA version */
506                                                   OUT RESHEXAKA2 resp_hex
507                                                   /* request-digest or response-digest */ )
508{
509
510        char tmp[MAX_HEADER_LEN];
511        /* static unsigned int mync = 1; */
512        /* int has_opaque = 0; */
513        char *nonce64, *nonce;
514        int noncelen;
515        RAND rnd;
516        MAC mac, xmac;
517        SQN sqn_he;
518        K k;
519        RES res;
520        CK ck;
521        IK ik;
522        AK ak;
523        int i, j;
524
525
526        /* Compute the AKA response */
527        resp_hex[0] = 0;
528        snprintf(tmp, MAX_HEADER_LEN-1,  "%s", pszNonce);
529        tmp[MAX_HEADER_LEN-1] = 0;
530        nonce64 = tmp;
531        nonce = base64_decode_string(nonce64, strlen(tmp), &noncelen);
532        if (nonce == NULL)
533                return;
534
535        if (noncelen < RANDLEN + AUTNLEN) {
536                /* Nonce is too short */
537                osip_free(nonce); goto done;
538        }
539        memcpy(rnd, nonce, RANDLEN);
540        /* memcpy(autn,nonce+RANDLEN,AUTNLEN); */
541        memcpy(sqn_he, nonce + RANDLEN, SQNLEN);
542        memcpy(mac, nonce + RANDLEN + SQNLEN + AMFLEN, MACLEN);
543
544        osip_free(nonce);
545
546        j = strlen(pszPassword);
547        memcpy(k, pszPassword, j);
548        memset(k + j, 0, KLEN - j);
549
550        /* compute XMAC */
551        f1(k, rnd, sqn_he, amf, xmac);
552        if (memcmp(mac, xmac, MACLEN) != 0) {
553                /*
554                   createAuthHeaderAKAv1MD5 : MAC != eXpectedMAC
555                   -> Server might not know the secret (man-in-the-middle attack?)
556                   return OSIP_SUCCESS;
557                 */
558        }
559
560        /* compute the response and keys */
561        f2345(k, rnd, res, ck, ik, ak);
562        /* no check for sqn is performed, so no AUTS synchronization performed */
563
564        /* Format data for output in the SIP message */
565        for (i = 0; i < RESLEN; i++) {
566                resp_hex[2 * i] = hexa[(res[i] & 0xF0) >> 4];
567                resp_hex[2 * i + 1] = hexa[res[i] & 0x0F];
568        }
569        resp_hex[RESHEXLEN - 1] = 0;
570
571  done:
572        switch (version) {
573        case 1:
574                /* AKA v1 */
575                /* Nothing to do */
576                break;
577        case 2:
578                /* AKA v2 */
579                resp_hex[RESHEXLEN + IKLEN * 2 + CKLEN * 2 - 1] = 0;
580                for (i = 0; i < IKLEN; i++) {
581                        resp_hex[RESLEN * 2 + 2 * i] = hexa[(ik[i] & 0xF0) >> 4];
582                        resp_hex[RESLEN * 2 + 2 * i + 1] = hexa[ik[i] & 0x0F];
583                }
584                for (i = 0; i < CKLEN; i++) {
585                        resp_hex[RESLEN * 2 + IKLEN * 2 + 2 * i] = hexa[(ck[i] & 0xF0) >> 4];
586                        resp_hex[RESLEN * 2 + IKLEN * 2 + 2 * i + 1] = hexa[ck[i] & 0x0F];
587                }
588                break;
589        }
590}
591
592int
593__eXosip_create_authorization_header(osip_www_authenticate_t * wa,
594                                                                         const char *rquri, const char *username,
595                                                                         const char *passwd, const char *ha1,
596                                                                         osip_authorization_t ** auth,
597                                                                         const char *method,
598                                                                         const char *pCNonce, int iNonceCount)
599{
600        osip_authorization_t *aut;
601
602        char *qop = NULL;
603        char *Alg = "MD5";
604        int version = 0;
605        int i;
606    static const char nullstr[] = "";
607
608        /* make some test */
609        if (passwd == NULL)
610                return OSIP_BADPARAMETER;
611        if (wa == NULL)
612                return OSIP_BADPARAMETER;
613
614        if (wa->auth_type == NULL || (wa->nonce == NULL)) {
615                OSIP_TRACE(osip_trace
616                                   (__FILE__, __LINE__, OSIP_ERROR, NULL,
617                                        "www_authenticate header is not acceptable.\n"));
618                return OSIP_SYNTAXERROR;
619        }
620
621        if (wa->realm == NULL) {
622                OSIP_TRACE(osip_trace
623                                   (__FILE__, __LINE__, OSIP_ERROR, NULL,
624                                        "www_authenticate header contains an empty realm: contact your admin!\n"));
625        }
626
627        if (0 != osip_strcasecmp("Digest", wa->auth_type)) {
628                OSIP_TRACE(osip_trace
629                                   (__FILE__, __LINE__, OSIP_ERROR, NULL,
630                                        "Authentication method not supported. (Digest only).\n"));
631                return OSIP_UNDEFINED_ERROR;
632        }
633        /* "MD5" is invalid, but some servers use it. */
634        if (wa->algorithm != NULL) {
635                if (0 == osip_strcasecmp("MD5", wa->algorithm)
636                        || 0 == osip_strcasecmp("\"MD5\"", wa->algorithm)) {
637                } else if (0 == osip_strcasecmp("AKAv1-MD5", wa->algorithm)
638                                   || 0 == osip_strcasecmp("\"AKAv1-MD5\"", wa->algorithm)) {
639                        Alg = "AKAv1-MD5";
640                } else if (0 == osip_strcasecmp("AKAv2-MD5", wa->algorithm)
641                                   || 0 == osip_strcasecmp("\"AKAv2-MD5\"", wa->algorithm)) {
642                        Alg = "AKAv2-MD5";
643                } else {
644                        OSIP_TRACE(osip_trace
645                                           (__FILE__, __LINE__, OSIP_ERROR, NULL,
646                                                "Authentication method not supported. (MD5, AKAv1-MD5, AKAv2-MD5)\n"));
647                        return OSIP_UNDEFINED_ERROR;
648                }
649        }
650
651        i = osip_authorization_init(&aut);
652        if (i != 0) {
653                OSIP_TRACE(osip_trace
654                                   (__FILE__, __LINE__, OSIP_ERROR, NULL,
655                                        "allocation with authorization_init failed.\n"));
656                return i;
657        }
658
659        /* just copy some feilds from response to new request */
660        osip_authorization_set_auth_type(aut, osip_strdup("Digest"));
661        osip_authorization_set_realm(aut,
662                                                                 osip_strdup(osip_www_authenticate_get_realm(wa)));
663        if (aut->realm == NULL) {
664                aut->realm = (char *) osip_malloc(3);
665                aut->realm[0] = '"';
666                aut->realm[1] = '"';
667                aut->realm[2] = '\0';
668        }
669        osip_authorization_set_nonce(aut,
670                                                                 osip_strdup(osip_www_authenticate_get_nonce(wa)));
671        if (osip_www_authenticate_get_opaque(wa) != NULL)
672                osip_authorization_set_opaque(aut,
673                                                                          osip_strdup
674                                                                          (osip_www_authenticate_get_opaque(wa)));
675        /* copy the username field in new request */
676        aut->username = osip_malloc(strlen(username) + 3);
677        if (aut->username == NULL) {
678                osip_authorization_free(aut);
679                return OSIP_NOMEM;
680        }
681        sprintf(aut->username, "\"%s\"", username);
682
683        {
684                char *tmp = osip_malloc(strlen(rquri) + 3);
685                if (tmp == NULL) {
686                        osip_authorization_free(aut);
687                        return OSIP_NOMEM;
688                }
689                sprintf(tmp, "\"%s\"", rquri);
690                osip_authorization_set_uri(aut, tmp);
691        }
692
693        osip_authorization_set_algorithm(aut, osip_strdup(Alg));
694
695        qop = osip_www_authenticate_get_qop_options(wa);
696        if (qop == NULL || qop[0] == '\0' || strlen(qop) < 4)
697                qop = NULL;
698
699
700        {
701                char *pszNonce =
702                        osip_strdup_without_quote(osip_www_authenticate_get_nonce(wa));
703                char *pszCNonce = nullstr;
704                const char *pszUser = username;
705                char *pszRealm = NULL;
706                const char *pszPass = NULL;
707                char *szNonceCount = NULL;
708                const char *pszMethod = method; /* previous_answer->cseq->method; */
709                char *pszQop = NULL;
710                const char *pszURI = rquri;
711
712                HASHHEX HA1;
713                HASHHEX HA2 = "";
714                HASHHEX Response;
715                RESHEXAKA2 Response2;
716                const char *pha1 = NULL;
717
718                if (osip_authorization_get_realm(aut) == NULL) {
719                        pszRealm = osip_strdup("");
720                } else {
721                        pszRealm =
722                                osip_strdup_without_quote(osip_authorization_get_realm(aut));
723                }
724
725                if (qop != NULL) {
726                        /* only accept qop="auth" */
727                        pszQop = osip_strdup("auth");
728                        if (pszQop == NULL) {
729                                osip_authorization_free(aut);
730                                osip_free(pszNonce);
731                                osip_free(pszRealm);
732                                return OSIP_NOMEM;
733                        }
734
735                        szNonceCount = osip_malloc(10);
736                        if (szNonceCount == NULL) {
737                                osip_authorization_free(aut);
738                                osip_free(pszNonce);
739                                osip_free(pszRealm);
740                                osip_free(pszQop);
741                                return OSIP_NOMEM;
742                        }
743                        snprintf(szNonceCount, 9, "%.8i", iNonceCount);
744
745                        pszCNonce = osip_strdup(pCNonce);
746                        if (pszCNonce == NULL) {
747                                osip_authorization_free(aut);
748                                osip_free(pszNonce);
749                                osip_free(pszRealm);
750                                osip_free(pszQop);
751                                osip_free(szNonceCount);
752                                return OSIP_NOMEM;
753                        }
754
755                        osip_authorization_set_message_qop(aut, osip_strdup("auth"));
756                        osip_authorization_set_nonce_count(aut, osip_strdup(szNonceCount));
757
758                        {
759                                char *tmp = osip_malloc(strlen(pszCNonce) + 3);
760                                if (tmp == NULL) {
761                                        osip_authorization_free(aut);
762                                        osip_free(pszNonce);
763                                        osip_free(pszCNonce);
764                                        osip_free(pszRealm);
765                                        osip_free(pszQop);
766                                        osip_free(szNonceCount);
767                                        return OSIP_NOMEM;
768                                }
769                                sprintf(tmp, "\"%s\"", pszCNonce);
770                                osip_authorization_set_cnonce(aut, tmp);
771                        }
772                }
773
774                pszPass = passwd;
775
776                /* Depending on which algorithm the response will be calculated, MD5 or AKAv1-MD5 */
777                if (0 == osip_strcasecmp(Alg, "MD5")) {
778                        if (ha1 && ha1[0]) {
779                                /* Depending on algorithm=md5 */
780                                pha1 = ha1;
781                        } else {
782                                DigestCalcHA1("MD5", pszUser, pszRealm, pszPass, pszNonce,
783                                                          pszCNonce, HA1);
784                                pha1 = HA1;
785                        }
786
787                        version = 0;
788                        DigestCalcResponse((char *) pha1, pszNonce, szNonceCount, pszCNonce,
789                                                           pszQop, version, pszMethod, pszURI, HA2, Response);
790                } else {
791                        if (0 == osip_strcasecmp(Alg, "AKAv1-MD5"))
792                                version = 1;
793                        else
794                                version = 2;
795
796                        DigestCalcResponseAka(pszPass, pszNonce, pszCNonce,
797                                                                  pszQop, pszMethod, pszURI, version, Response2);
798                        if (ha1 && ha1[0]) {
799                                /* Depending on algorithm=md5 */
800                                pha1 = ha1;
801                        } else {
802                                DigestCalcHA1("MD5", pszUser, pszRealm, Response2, pszNonce,
803                                                          pszCNonce, HA1);
804                                pha1 = HA1;
805                        }
806
807                        DigestCalcResponse((char *) pha1, pszNonce, szNonceCount, pszCNonce,
808                                                           pszQop, version, pszMethod, pszURI, HA2, Response);
809
810                }
811
812                OSIP_TRACE(osip_trace
813                                   (__FILE__, __LINE__, OSIP_INFO4, NULL,
814                                        "Response in authorization |%s|\n", Response));
815                {
816                        char *resp = osip_malloc(35);
817                        if (resp == NULL) {
818                                osip_authorization_free(aut);
819                                osip_free(pszNonce);
820                                osip_free(pszCNonce);
821                                osip_free(pszRealm);
822                                osip_free(pszQop);
823                                osip_free(szNonceCount);
824                                return OSIP_NOMEM;
825                        }
826
827                        snprintf(resp, 35, "\"%s\"", Response);
828                        resp[34] = 0;
829                        osip_authorization_set_response(aut, resp);
830                }
831                osip_free(pszNonce);
832                if (pszCNonce != nullstr)
833                        osip_free(pszCNonce);
834                osip_free(pszRealm);
835                osip_free(pszQop);
836                osip_free(szNonceCount);
837        }
838
839        *auth = aut;
840        return OSIP_SUCCESS;
841}
842
843int
844__eXosip_create_proxy_authorization_header(osip_proxy_authenticate_t * wa,
845                                                                                   const char *rquri,
846                                                                                   const char *username,
847                                                                                   const char *passwd,
848                                                                                   const char *ha1,
849                                                                                   osip_proxy_authorization_t **
850                                                                                   auth, const char *method,
851                                                                                   const char *pCNonce, int iNonceCount)
852{
853        osip_proxy_authorization_t *aut;
854
855        char *qop = NULL;
856        char *Alg = "MD5";
857        int version = 0;
858        int i;
859        static const char nullstr[] = "";
860
861        /* make some test */
862        if (passwd == NULL)
863                return OSIP_BADPARAMETER;
864        if (wa == NULL)
865                return OSIP_BADPARAMETER;
866
867        if (wa->auth_type == NULL || (wa->nonce == NULL)) {
868                OSIP_TRACE(osip_trace
869                                   (__FILE__, __LINE__, OSIP_ERROR, NULL,
870                                        "www_authenticate header is not acceptable.\n"));
871                return OSIP_SYNTAXERROR;
872        }
873
874        if (wa->realm == NULL) {
875                OSIP_TRACE(osip_trace
876                                   (__FILE__, __LINE__, OSIP_ERROR, NULL,
877                                        "www_authenticate header contains an empty realm: contact your admin!\n"));
878        }
879
880        if (0 != osip_strcasecmp("Digest", wa->auth_type)) {
881                OSIP_TRACE(osip_trace
882                                   (__FILE__, __LINE__, OSIP_ERROR, NULL,
883                                        "Authentication method not supported. (Digest only).\n"));
884                return OSIP_UNDEFINED_ERROR;
885        }
886
887        /* "MD5" is invalid, but some servers use it. */
888        if (wa->algorithm != NULL) {
889                if (0 == osip_strcasecmp("MD5", wa->algorithm)
890                        || 0 == osip_strcasecmp("\"MD5\"", wa->algorithm)) {
891                } else if (0 == osip_strcasecmp("AKAv1-MD5", wa->algorithm)
892                                   || 0 == osip_strcasecmp("\"AKAv1-MD5\"", wa->algorithm)) {
893                        Alg = "AKAv1-MD5";
894                } else if (0 == osip_strcasecmp("AKAv2-MD5", wa->algorithm)
895                                   || 0 == osip_strcasecmp("\"AKAv2-MD5\"", wa->algorithm)) {
896                        Alg = "AKAv2-MD5";
897                } else {
898                        OSIP_TRACE(osip_trace
899                                           (__FILE__, __LINE__, OSIP_ERROR, NULL,
900                                                "Authentication method not supported. (MD5, AKAv1-MD5, AKAv2-MD5)\n"));
901                        return OSIP_UNDEFINED_ERROR;
902                }
903        }
904
905        i = osip_proxy_authorization_init(&aut);
906        if (i != 0) {
907                OSIP_TRACE(osip_trace
908                                   (__FILE__, __LINE__, OSIP_ERROR, NULL,
909                                        "allocation with authorization_init failed.\n"));
910                return i;
911        }
912
913        /* just copy some feilds from response to new request */
914        osip_proxy_authorization_set_auth_type(aut, osip_strdup("Digest"));
915        osip_proxy_authorization_set_realm(aut,
916                                                                           osip_strdup
917                                                                           (osip_proxy_authenticate_get_realm(wa)));
918        if (aut->realm == NULL) {
919                aut->realm = (char *) osip_malloc(3);
920                aut->realm[0] = '"';
921                aut->realm[1] = '"';
922                aut->realm[2] = '\0';
923        }
924        osip_proxy_authorization_set_nonce(aut,
925                                                                           osip_strdup
926                                                                           (osip_proxy_authenticate_get_nonce(wa)));
927        if (osip_proxy_authenticate_get_opaque(wa) != NULL)
928                osip_proxy_authorization_set_opaque(aut,
929                                                                                        osip_strdup
930                                                                                        (osip_proxy_authenticate_get_opaque
931                                                                                         (wa)));
932        /* copy the username field in new request */
933        aut->username = osip_malloc(strlen(username) + 3);
934        if (aut->username == NULL) {
935                osip_authorization_free(aut);
936                return OSIP_NOMEM;
937        }
938        sprintf(aut->username, "\"%s\"", username);
939
940        {
941                char *tmp = osip_malloc(strlen(rquri) + 3);
942                if (tmp == NULL) {
943                        osip_authorization_free(aut);
944                        return OSIP_NOMEM;
945                }
946
947                sprintf(tmp, "\"%s\"", rquri);
948                osip_proxy_authorization_set_uri(aut, tmp);
949        }
950        osip_proxy_authorization_set_algorithm(aut, osip_strdup(Alg));
951
952        qop = osip_www_authenticate_get_qop_options(wa);
953        if (qop == NULL || qop[0] == '\0' || strlen(qop) < 4)
954                qop = NULL;
955
956        {
957                char *pszNonce = NULL;
958                char *pszCNonce = nullstr;
959                const char *pszUser = username;
960                char *pszRealm = NULL;
961                const char *pszPass = NULL;
962                char *szNonceCount = NULL;
963                char *pszMethod = (char *) method;      /* previous_answer->cseq->method; */
964                char *pszQop = NULL;
965                const char *pszURI = rquri;
966
967                HASHHEX HA1;
968                HASHHEX HA2 = "";
969                HASHHEX Response;
970                RESHEXAKA2 Response2;
971                const char *pha1 = NULL;
972
973                if (osip_proxy_authorization_get_realm(aut) == NULL) {
974                        pszRealm = osip_strdup("");
975                } else {
976                        pszRealm =
977                                osip_strdup_without_quote(osip_proxy_authorization_get_realm(aut));
978                }
979
980                pszPass = passwd;
981
982                if (osip_www_authenticate_get_nonce(wa) == NULL) {
983                        osip_authorization_free(aut);
984                        osip_free(pszRealm);
985                        return OSIP_SYNTAXERROR;
986                }
987                pszNonce = osip_strdup_without_quote(osip_www_authenticate_get_nonce(wa));
988
989                if (qop != NULL) {
990                        /* only accept qop="auth" */
991                        pszQop = osip_strdup("auth");
992                        if (pszQop == NULL) {
993                                return OSIP_NOMEM;
994                        }
995
996                        szNonceCount = osip_malloc(10);
997                        if (szNonceCount == NULL) {
998                                osip_authorization_free(aut);
999                                osip_free(pszNonce);
1000                                osip_free(pszRealm);
1001                                osip_free(pszQop);
1002                                return OSIP_NOMEM;
1003                        }
1004                        snprintf(szNonceCount, 9, "%.8i", iNonceCount);
1005
1006                        pszCNonce = osip_strdup(pCNonce);
1007                        if (pszCNonce == NULL) {
1008                                osip_authorization_free(aut);
1009                                osip_free(pszNonce);
1010                                osip_free(pszRealm);
1011                                osip_free(pszQop);
1012                                osip_free(szNonceCount);
1013                                return OSIP_NOMEM;
1014                        }
1015
1016                        osip_proxy_authorization_set_message_qop(aut, osip_strdup("auth"));
1017                        osip_proxy_authorization_set_nonce_count(aut,
1018                                                                                                         osip_strdup(szNonceCount));
1019
1020                        {
1021                                char *tmp = osip_malloc(strlen(pszCNonce) + 3);
1022                                if (tmp == NULL) {
1023                                        osip_authorization_free(aut);
1024                                        osip_free(pszNonce);
1025                                        osip_free(pszCNonce);
1026                                        osip_free(pszRealm);
1027                                        osip_free(pszQop);
1028                                        osip_free(szNonceCount);
1029                                        return OSIP_NOMEM;
1030                                }
1031                                sprintf(tmp, "\"%s\"", pszCNonce);
1032                                osip_proxy_authorization_set_cnonce(aut, tmp);
1033                        }
1034                }
1035
1036                if (0 == osip_strcasecmp(Alg, "MD5")) {
1037                        if (ha1 && ha1[0]) {
1038                                /* Depending on algorithm=md5 */
1039                                pha1 = ha1;
1040                        } else {
1041                                DigestCalcHA1("MD5", pszUser, pszRealm, pszPass, pszNonce,
1042                                                          pszCNonce, HA1);
1043                                pha1 = HA1;
1044                        }
1045                        version = 0;
1046                        DigestCalcResponse((char *) pha1, pszNonce, szNonceCount, pszCNonce,
1047                                                           pszQop, version, pszMethod, pszURI, HA2, Response);
1048                } else {
1049                        if (0 == osip_strcasecmp(Alg, "AKAv1-MD5"))
1050                                version = 1;
1051                        else
1052                                version = 2;
1053
1054                        DigestCalcResponseAka(pszPass, pszNonce, pszCNonce, pszQop, pszMethod,
1055                                                                  pszURI, version, Response2);
1056                        if (ha1 && ha1[0]) {
1057                                /* Depending on algorithm=md5 */
1058                                pha1 = ha1;
1059                        } else {
1060                                DigestCalcHA1("MD5", pszUser, pszRealm, Response2, pszNonce,
1061                                                          pszCNonce, HA1);
1062                                pha1 = HA1;
1063                        }
1064
1065                        DigestCalcResponse((char *) pha1, pszNonce, szNonceCount, pszCNonce,
1066                                                           pszQop, version, pszMethod, pszURI, HA2, Response);
1067                }
1068
1069                OSIP_TRACE(osip_trace
1070                                   (__FILE__, __LINE__, OSIP_INFO4, NULL,
1071                                        "Response in proxy_authorization |%s|\n", Response));
1072                {
1073                        char *resp = osip_malloc(35);
1074                        if (resp == NULL) {
1075                                osip_authorization_free(aut);
1076                                osip_free(pszNonce);
1077                                osip_free(pszCNonce);
1078                                osip_free(pszRealm);
1079                                osip_free(pszQop);
1080                                osip_free(szNonceCount);
1081                                return OSIP_NOMEM;
1082                        }
1083
1084                        snprintf(resp, 35, "\"%s\"", Response);
1085                        osip_proxy_authorization_set_response(aut, resp);
1086                }
1087                osip_free(pszNonce);
1088                if (pszCNonce != nullstr)
1089                        osip_free(pszCNonce);
1090                osip_free(pszRealm);
1091                osip_free(pszQop);
1092                osip_free(szNonceCount);
1093        }
1094
1095        *auth = aut;
1096        return OSIP_SUCCESS;
1097}
1098
1099int
1100_eXosip_store_nonce(const char *call_id, osip_proxy_authenticate_t * wa,
1101                                        int answer_code)
1102{
1103        struct eXosip_http_auth *http_auth;
1104        int pos;
1105
1106        /* update entries with same call_id */
1107        for (pos = 0; pos < MAX_EXOSIP_HTTP_AUTH; pos++) {
1108                http_auth = &eXosip.http_auths[pos];
1109                if (http_auth->pszCallId[0] == '\0')
1110                        continue;
1111                if (osip_strcasecmp(http_auth->pszCallId, call_id) == 0
1112                        && ((http_auth->wa->realm == NULL && wa->realm == NULL)
1113                                || (http_auth->wa->realm != NULL
1114                                        && wa->realm != NULL
1115                                        && osip_strcasecmp(http_auth->wa->realm, wa->realm) == 0))) {
1116                        osip_proxy_authenticate_free(http_auth->wa);
1117                        http_auth->wa = NULL;
1118                        osip_proxy_authenticate_clone(wa, &(http_auth->wa));
1119                        http_auth->iNonceCount = 1;
1120                        if (http_auth->wa == NULL)
1121                                memset(http_auth, 0, sizeof(struct eXosip_http_auth));
1122                        return OSIP_SUCCESS;
1123                }
1124        }
1125
1126        /* not found */
1127        for (pos = 0; pos < MAX_EXOSIP_HTTP_AUTH; pos++) {
1128                http_auth = &eXosip.http_auths[pos];
1129                if (http_auth->pszCallId[0] == '\0') {
1130                        snprintf(http_auth->pszCallId, sizeof(http_auth->pszCallId), "%s", call_id);
1131                        snprintf(http_auth->pszCNonce, sizeof(http_auth->pszCNonce),
1132                                         "0a4f113b");
1133                        http_auth->iNonceCount = 1;
1134                        osip_proxy_authenticate_clone(wa, &(http_auth->wa));
1135                        http_auth->answer_code = answer_code;
1136                        if (http_auth->wa == NULL)
1137                                memset(http_auth, 0, sizeof(struct eXosip_http_auth));
1138                        return OSIP_SUCCESS;
1139                }
1140        }
1141
1142        OSIP_TRACE(osip_trace
1143                           (__FILE__, __LINE__, OSIP_ERROR, NULL,
1144                                "Compile with higher MAX_EXOSIP_HTTP_AUTH value (current=%i)\n",
1145                                MAX_EXOSIP_HTTP_AUTH));
1146        return OSIP_UNDEFINED_ERROR;
1147}
1148
1149int _eXosip_delete_nonce(const char *call_id)
1150{
1151        struct eXosip_http_auth *http_auth;
1152        int pos;
1153
1154        /* update entries with same call_id */
1155        for (pos = 0; pos < MAX_EXOSIP_HTTP_AUTH; pos++) {
1156                http_auth = &eXosip.http_auths[pos];
1157                if (http_auth->pszCallId[0] == '\0')
1158                        continue;
1159                if (osip_strcasecmp(http_auth->pszCallId, call_id) == 0) {
1160                        osip_proxy_authenticate_free(http_auth->wa);
1161                        memset(http_auth, 0, sizeof(struct eXosip_http_auth));
1162                        return OSIP_SUCCESS;
1163                }
1164        }
1165        return OSIP_NOTFOUND;
1166}
Note: See TracBrowser for help on using the repository browser.