source: verona/libeXosip2/src/jauth.c @ 123:a7c5735df076

Last change on this file since 123:a7c5735df076 was 123:a7c5735df076, checked in by Nikita Kozlov <nikita@…>, 3 years ago

update of osip2 (2010-03-10) and eXosip2(2010-04-09) from git repositories

File size: 29.1 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        sprintf(tmp, "%s", pszNonce);
529        nonce64 = tmp;
530        nonce = base64_decode_string(nonce64, strlen(tmp), &noncelen);
531        if (nonce == NULL)
532                return;
533
534        if (noncelen < RANDLEN + AUTNLEN) {
535                /* Nonce is too short */
536                goto done;
537        }
538        memcpy(rnd, nonce, RANDLEN);
539        /* memcpy(autn,nonce+RANDLEN,AUTNLEN); */
540        memcpy(sqn_he, nonce + RANDLEN, SQNLEN);
541        memcpy(mac, nonce + RANDLEN + SQNLEN + AMFLEN, MACLEN);
542
543        osip_free(nonce);
544
545        j = strlen(pszPassword);
546        memcpy(k, pszPassword, j);
547        memset(k + j, 0, KLEN - j);
548
549        /* compute XMAC */
550        f1(k, rnd, sqn_he, amf, xmac);
551        if (memcmp(mac, xmac, MACLEN) != 0) {
552                /*
553                   createAuthHeaderAKAv1MD5 : MAC != eXpectedMAC
554                   -> Server might not know the secret (man-in-the-middle attack?)
555                   return OSIP_SUCCESS;
556                 */
557        }
558
559        /* compute the response and keys */
560        f2345(k, rnd, res, ck, ik, ak);
561        /* no check for sqn is performed, so no AUTS synchronization performed */
562
563        /* Format data for output in the SIP message */
564        for (i = 0; i < RESLEN; i++) {
565                resp_hex[2 * i] = hexa[(res[i] & 0xF0) >> 4];
566                resp_hex[2 * i + 1] = hexa[res[i] & 0x0F];
567        }
568        resp_hex[RESHEXLEN - 1] = 0;
569
570  done:
571        switch (version) {
572        case 1:
573                /* AKA v1 */
574                /* Nothing to do */
575                break;
576        case 2:
577                /* AKA v2 */
578                resp_hex[RESHEXLEN + IKLEN * 2 + CKLEN * 2 - 1] = 0;
579                for (i = 0; i < IKLEN; i++) {
580                        resp_hex[RESLEN * 2 + 2 * i] = hexa[(ik[i] & 0xF0) >> 4];
581                        resp_hex[RESLEN * 2 + 2 * i + 1] = hexa[ik[i] & 0x0F];
582                }
583                for (i = 0; i < CKLEN; i++) {
584                        resp_hex[RESLEN * 2 + IKLEN * 2 + 2 * i] = hexa[(ck[i] & 0xF0) >> 4];
585                        resp_hex[RESLEN * 2 + IKLEN * 2 + 2 * i + 1] = hexa[ck[i] & 0x0F];
586                }
587                break;
588        }
589}
590
591int
592__eXosip_create_authorization_header(osip_www_authenticate_t * wa,
593                                                                         const char *rquri, const char *username,
594                                                                         const char *passwd, const char *ha1,
595                                                                         osip_authorization_t ** auth,
596                                                                         const char *method,
597                                                                         const char *pCNonce, int iNonceCount)
598{
599        osip_authorization_t *aut;
600
601        char *qop = NULL;
602        char *Alg = "MD5";
603        int version = 0;
604        int i;
605
606        /* make some test */
607        if (passwd == NULL)
608                return OSIP_BADPARAMETER;
609        if (wa == NULL)
610                return OSIP_BADPARAMETER;
611
612        if (wa->auth_type == NULL || (wa->nonce == NULL)) {
613                OSIP_TRACE(osip_trace
614                                   (__FILE__, __LINE__, OSIP_ERROR, NULL,
615                                        "www_authenticate header is not acceptable.\n"));
616                return OSIP_SYNTAXERROR;
617        }
618
619        if (wa->realm == NULL) {
620                OSIP_TRACE(osip_trace
621                                   (__FILE__, __LINE__, OSIP_ERROR, NULL,
622                                        "www_authenticate header contains an empty realm: contact your admin!\n"));
623        }
624
625        if (0 != osip_strcasecmp("Digest", wa->auth_type)) {
626                OSIP_TRACE(osip_trace
627                                   (__FILE__, __LINE__, OSIP_ERROR, NULL,
628                                        "Authentication method not supported. (Digest only).\n"));
629                return OSIP_UNDEFINED_ERROR;
630        }
631        /* "MD5" is invalid, but some servers use it. */
632        if (wa->algorithm != NULL) {
633                if (0 == osip_strcasecmp("MD5", wa->algorithm)
634                        || 0 == osip_strcasecmp("\"MD5\"", wa->algorithm)) {
635                } else if (0 == osip_strcasecmp("AKAv1-MD5", wa->algorithm)
636                                   || 0 == osip_strcasecmp("\"AKAv1-MD5\"", wa->algorithm)) {
637                        Alg = "AKAv1-MD5";
638                } else if (0 == osip_strcasecmp("AKAv2-MD5", wa->algorithm)
639                                   || 0 == osip_strcasecmp("\"AKAv2-MD5\"", wa->algorithm)) {
640                        Alg = "AKAv2-MD5";
641                } else {
642                        OSIP_TRACE(osip_trace
643                                           (__FILE__, __LINE__, OSIP_ERROR, NULL,
644                                                "Authentication method not supported. (MD5, AKAv1-MD5, AKAv2-MD5)\n"));
645                        return OSIP_UNDEFINED_ERROR;
646                }
647        }
648
649        i = osip_authorization_init(&aut);
650        if (i != 0) {
651                OSIP_TRACE(osip_trace
652                                   (__FILE__, __LINE__, OSIP_ERROR, NULL,
653                                        "allocation with authorization_init failed.\n"));
654                return i;
655        }
656
657        /* just copy some feilds from response to new request */
658        osip_authorization_set_auth_type(aut, osip_strdup("Digest"));
659        osip_authorization_set_realm(aut,
660                                                                 osip_strdup(osip_www_authenticate_get_realm(wa)));
661        if (aut->realm == NULL) {
662                aut->realm = (char *) osip_malloc(3);
663                aut->realm[0] = '"';
664                aut->realm[1] = '"';
665                aut->realm[2] = '\0';
666        }
667        osip_authorization_set_nonce(aut,
668                                                                 osip_strdup(osip_www_authenticate_get_nonce(wa)));
669        if (osip_www_authenticate_get_opaque(wa) != NULL)
670                osip_authorization_set_opaque(aut,
671                                                                          osip_strdup
672                                                                          (osip_www_authenticate_get_opaque(wa)));
673        /* copy the username field in new request */
674        aut->username = osip_malloc(strlen(username) + 3);
675        if (aut->username == NULL) {
676                osip_authorization_free(aut);
677                return OSIP_NOMEM;
678        }
679        sprintf(aut->username, "\"%s\"", username);
680
681        {
682                char *tmp = osip_malloc(strlen(rquri) + 3);
683                if (tmp == NULL) {
684                        osip_authorization_free(aut);
685                        return OSIP_NOMEM;
686                }
687                sprintf(tmp, "\"%s\"", rquri);
688                osip_authorization_set_uri(aut, tmp);
689        }
690
691        osip_authorization_set_algorithm(aut, osip_strdup(Alg));
692
693        qop = osip_www_authenticate_get_qop_options(wa);
694        if (qop == NULL || qop[0] == '\0' || strlen(qop) < 4)
695                qop = NULL;
696
697
698        {
699                char *pszNonce =
700                        osip_strdup_without_quote(osip_www_authenticate_get_nonce(wa));
701                char *pszCNonce = NULL;
702                const char *pszUser = username;
703                char *pszRealm = NULL;
704                const char *pszPass = NULL;
705                char *szNonceCount = NULL;
706                const char *pszMethod = method; /* previous_answer->cseq->method; */
707                char *pszQop = NULL;
708                const char *pszURI = rquri;
709
710                HASHHEX HA1;
711                HASHHEX HA2 = "";
712                HASHHEX Response;
713                RESHEXAKA2 Response2;
714                const char *pha1 = NULL;
715
716                if (osip_authorization_get_realm(aut) == NULL) {
717                        pszRealm = osip_strdup("");
718                } else {
719                        pszRealm =
720                                osip_strdup_without_quote(osip_authorization_get_realm(aut));
721                }
722
723                if (qop != NULL) {
724                        /* only accept qop="auth" */
725                        pszQop = osip_strdup("auth");
726                        if (pszQop == NULL) {
727                                osip_authorization_free(aut);
728                                osip_free(pszNonce);
729                                osip_free(pszRealm);
730                                return OSIP_NOMEM;
731                        }
732
733                        szNonceCount = osip_malloc(10);
734                        if (szNonceCount == NULL) {
735                                osip_authorization_free(aut);
736                                osip_free(pszNonce);
737                                osip_free(pszRealm);
738                                osip_free(pszQop);
739                                return OSIP_NOMEM;
740                        }
741                        snprintf(szNonceCount, 9, "%.8i", iNonceCount);
742
743                        pszCNonce = osip_strdup(pCNonce);
744                        if (pszCNonce == NULL) {
745                                osip_authorization_free(aut);
746                                osip_free(pszNonce);
747                                osip_free(pszRealm);
748                                osip_free(pszQop);
749                                osip_free(szNonceCount);
750                                return OSIP_NOMEM;
751                        }
752
753                        osip_authorization_set_message_qop(aut, osip_strdup("auth"));
754                        osip_authorization_set_nonce_count(aut, osip_strdup(szNonceCount));
755
756                        {
757                                char *tmp = osip_malloc(strlen(pszCNonce) + 3);
758                                if (tmp == NULL) {
759                                        osip_authorization_free(aut);
760                                        osip_free(pszNonce);
761                                        osip_free(pszCNonce);
762                                        osip_free(pszRealm);
763                                        osip_free(pszQop);
764                                        osip_free(szNonceCount);
765                                        return OSIP_NOMEM;
766                                }
767                                sprintf(tmp, "\"%s\"", pszCNonce);
768                                osip_authorization_set_cnonce(aut, tmp);
769                        }
770                }
771
772                pszPass = passwd;
773
774                /* Depending on which algorithm the response will be calculated, MD5 or AKAv1-MD5 */
775                if (0 == osip_strcasecmp(Alg, "MD5")) {
776                        if (ha1 && ha1[0]) {
777                                /* Depending on algorithm=md5 */
778                                pha1 = ha1;
779                        } else {
780                                DigestCalcHA1("MD5", pszUser, pszRealm, pszPass, pszNonce,
781                                                          pszCNonce, HA1);
782                                pha1 = HA1;
783                        }
784
785                        version = 0;
786                        DigestCalcResponse((char *) pha1, pszNonce, szNonceCount, pszCNonce,
787                                                           pszQop, version, pszMethod, pszURI, HA2, Response);
788                } else {
789                        if (0 == osip_strcasecmp(Alg, "AKAv1-MD5"))
790                                version = 1;
791                        else
792                                version = 2;
793
794                        DigestCalcResponseAka(pszPass, pszNonce, pszCNonce,
795                                                                  pszQop, pszMethod, pszURI, version, Response2);
796                        if (ha1 && ha1[0]) {
797                                /* Depending on algorithm=md5 */
798                                pha1 = ha1;
799                        } else {
800                                DigestCalcHA1("MD5", pszUser, pszRealm, Response2, pszNonce,
801                                                          pszCNonce, HA1);
802                                pha1 = HA1;
803                        }
804
805                        DigestCalcResponse((char *) pha1, pszNonce, szNonceCount, pszCNonce,
806                                                           pszQop, version, pszMethod, pszURI, HA2, Response);
807
808                }
809
810                OSIP_TRACE(osip_trace
811                                   (__FILE__, __LINE__, OSIP_INFO4, NULL,
812                                        "Response in authorization |%s|\n", Response));
813                {
814                        char *resp = osip_malloc(35);
815                        if (resp == NULL) {
816                                osip_authorization_free(aut);
817                                osip_free(pszNonce);
818                                osip_free(pszCNonce);
819                                osip_free(pszRealm);
820                                osip_free(pszQop);
821                                osip_free(szNonceCount);
822                                return OSIP_NOMEM;
823                        }
824
825                        sprintf(resp, "\"%s\"", Response);
826                        osip_authorization_set_response(aut, resp);
827                }
828                osip_free(pszNonce);
829                osip_free(pszCNonce);
830                osip_free(pszRealm);
831                osip_free(pszQop);
832                osip_free(szNonceCount);
833        }
834
835        *auth = aut;
836        return OSIP_SUCCESS;
837}
838
839int
840__eXosip_create_proxy_authorization_header(osip_proxy_authenticate_t * wa,
841                                                                                   const char *rquri,
842                                                                                   const char *username,
843                                                                                   const char *passwd,
844                                                                                   const char *ha1,
845                                                                                   osip_proxy_authorization_t **
846                                                                                   auth, const char *method,
847                                                                                   const char *pCNonce, int iNonceCount)
848{
849        osip_proxy_authorization_t *aut;
850
851        char *qop = NULL;
852        char *Alg = "MD5";
853        int version = 0;
854        int i;
855
856        /* make some test */
857        if (passwd == NULL)
858                return OSIP_BADPARAMETER;
859        if (wa == NULL)
860                return OSIP_BADPARAMETER;
861
862        if (wa->auth_type == NULL || (wa->nonce == NULL)) {
863                OSIP_TRACE(osip_trace
864                                   (__FILE__, __LINE__, OSIP_ERROR, NULL,
865                                        "www_authenticate header is not acceptable.\n"));
866                return OSIP_SYNTAXERROR;
867        }
868
869        if (wa->realm == NULL) {
870                OSIP_TRACE(osip_trace
871                                   (__FILE__, __LINE__, OSIP_ERROR, NULL,
872                                        "www_authenticate header contains an empty realm: contact your admin!\n"));
873        }
874
875        if (0 != osip_strcasecmp("Digest", wa->auth_type)) {
876                OSIP_TRACE(osip_trace
877                                   (__FILE__, __LINE__, OSIP_ERROR, NULL,
878                                        "Authentication method not supported. (Digest only).\n"));
879                return OSIP_UNDEFINED_ERROR;
880        }
881
882        /* "MD5" is invalid, but some servers use it. */
883        if (wa->algorithm != NULL) {
884                if (0 == osip_strcasecmp("MD5", wa->algorithm)
885                        || 0 == osip_strcasecmp("\"MD5\"", wa->algorithm)) {
886                } else if (0 == osip_strcasecmp("AKAv1-MD5", wa->algorithm)
887                                   || 0 == osip_strcasecmp("\"AKAv1-MD5\"", wa->algorithm)) {
888                        Alg = "AKAv1-MD5";
889                } else if (0 == osip_strcasecmp("AKAv2-MD5", wa->algorithm)
890                                   || 0 == osip_strcasecmp("\"AKAv2-MD5\"", wa->algorithm)) {
891                        Alg = "AKAv2-MD5";
892                } else {
893                        OSIP_TRACE(osip_trace
894                                           (__FILE__, __LINE__, OSIP_ERROR, NULL,
895                                                "Authentication method not supported. (MD5, AKAv1-MD5, AKAv2-MD5)\n"));
896                        return OSIP_UNDEFINED_ERROR;
897                }
898        }
899
900        i = osip_proxy_authorization_init(&aut);
901        if (i != 0) {
902                OSIP_TRACE(osip_trace
903                                   (__FILE__, __LINE__, OSIP_ERROR, NULL,
904                                        "allocation with authorization_init failed.\n"));
905                return i;
906        }
907
908        /* just copy some feilds from response to new request */
909        osip_proxy_authorization_set_auth_type(aut, osip_strdup("Digest"));
910        osip_proxy_authorization_set_realm(aut,
911                                                                           osip_strdup
912                                                                           (osip_proxy_authenticate_get_realm(wa)));
913        if (aut->realm == NULL) {
914                aut->realm = (char *) osip_malloc(3);
915                aut->realm[0] = '"';
916                aut->realm[1] = '"';
917                aut->realm[2] = '\0';
918        }
919        osip_proxy_authorization_set_nonce(aut,
920                                                                           osip_strdup
921                                                                           (osip_proxy_authenticate_get_nonce(wa)));
922        if (osip_proxy_authenticate_get_opaque(wa) != NULL)
923                osip_proxy_authorization_set_opaque(aut,
924                                                                                        osip_strdup
925                                                                                        (osip_proxy_authenticate_get_opaque
926                                                                                         (wa)));
927        /* copy the username field in new request */
928        aut->username = osip_malloc(strlen(username) + 3);
929        if (aut->username == NULL) {
930                osip_authorization_free(aut);
931                return OSIP_NOMEM;
932        }
933        sprintf(aut->username, "\"%s\"", username);
934
935        {
936                char *tmp = osip_malloc(strlen(rquri) + 3);
937                if (tmp == NULL) {
938                        osip_authorization_free(aut);
939                        return OSIP_NOMEM;
940                }
941
942                sprintf(tmp, "\"%s\"", rquri);
943                osip_proxy_authorization_set_uri(aut, tmp);
944        }
945        osip_proxy_authorization_set_algorithm(aut, osip_strdup(Alg));
946
947        qop = osip_www_authenticate_get_qop_options(wa);
948        if (qop == NULL || qop[0] == '\0' || strlen(qop) < 4)
949                qop = NULL;
950
951        {
952                char *pszNonce = NULL;
953                char *pszCNonce = NULL;
954                const char *pszUser = username;
955                char *pszRealm = NULL;
956                const char *pszPass = NULL;
957                char *szNonceCount = NULL;
958                char *pszMethod = (char *) method;      /* previous_answer->cseq->method; */
959                char *pszQop = NULL;
960                const char *pszURI = rquri;
961
962                HASHHEX HA1;
963                HASHHEX HA2 = "";
964                HASHHEX Response;
965                RESHEXAKA2 Response2;
966                const char *pha1 = NULL;
967
968                if (osip_proxy_authorization_get_realm(aut) == NULL) {
969                        pszRealm = osip_strdup("");
970                } else {
971                        pszRealm =
972                                osip_strdup_without_quote(osip_proxy_authorization_get_realm(aut));
973                }
974
975                pszPass = passwd;
976
977                if (osip_www_authenticate_get_nonce(wa) == NULL)
978                        return OSIP_SYNTAXERROR;
979                pszNonce = osip_strdup_without_quote(osip_www_authenticate_get_nonce(wa));
980
981                if (qop != NULL) {
982                        /* only accept qop="auth" */
983                        pszQop = osip_strdup("auth");
984                        if (pszQop == NULL) {
985                                osip_authorization_free(aut);
986                                osip_free(pszNonce);
987                                osip_free(pszRealm);
988                                return OSIP_NOMEM;
989                        }
990
991                        szNonceCount = osip_malloc(10);
992                        if (szNonceCount == NULL) {
993                                osip_authorization_free(aut);
994                                osip_free(pszNonce);
995                                osip_free(pszRealm);
996                                osip_free(pszQop);
997                                return OSIP_NOMEM;
998                        }
999                        snprintf(szNonceCount, 9, "%.8i", iNonceCount);
1000
1001                        pszCNonce = osip_strdup(pCNonce);
1002                        if (pszCNonce == NULL) {
1003                                osip_authorization_free(aut);
1004                                osip_free(pszNonce);
1005                                osip_free(pszRealm);
1006                                osip_free(pszQop);
1007                                osip_free(szNonceCount);
1008                                return OSIP_NOMEM;
1009                        }
1010
1011                        osip_proxy_authorization_set_message_qop(aut, osip_strdup("auth"));
1012                        osip_proxy_authorization_set_nonce_count(aut,
1013                                                                                                         osip_strdup(szNonceCount));
1014
1015                        {
1016                                char *tmp = osip_malloc(strlen(pszCNonce) + 3);
1017                                if (tmp == NULL) {
1018                                        osip_authorization_free(aut);
1019                                        osip_free(pszNonce);
1020                                        osip_free(pszCNonce);
1021                                        osip_free(pszRealm);
1022                                        osip_free(pszQop);
1023                                        osip_free(szNonceCount);
1024                                        return OSIP_NOMEM;
1025                                }
1026                                sprintf(tmp, "\"%s\"", pszCNonce);
1027                                osip_proxy_authorization_set_cnonce(aut, tmp);
1028                        }
1029                }
1030
1031                if (0 == osip_strcasecmp(Alg, "MD5")) {
1032                        if (ha1 && ha1[0]) {
1033                                /* Depending on algorithm=md5 */
1034                                pha1 = ha1;
1035                        } else {
1036                                DigestCalcHA1("MD5", pszUser, pszRealm, pszPass, pszNonce,
1037                                                          pszCNonce, HA1);
1038                                pha1 = HA1;
1039                        }
1040                        version = 0;
1041                        DigestCalcResponse((char *) pha1, pszNonce, szNonceCount, pszCNonce,
1042                                                           pszQop, version, pszMethod, pszURI, HA2, Response);
1043                } else {
1044                        if (0 == osip_strcasecmp(Alg, "AKAv1-MD5"))
1045                                version = 1;
1046                        else
1047                                version = 2;
1048
1049                        DigestCalcResponseAka(pszPass, pszNonce, pszCNonce, pszQop, pszMethod,
1050                                                                  pszURI, version, Response2);
1051                        if (ha1 && ha1[0]) {
1052                                /* Depending on algorithm=md5 */
1053                                pha1 = ha1;
1054                        } else {
1055                                DigestCalcHA1("MD5", pszUser, pszRealm, Response2, pszNonce,
1056                                                          pszCNonce, HA1);
1057                                pha1 = HA1;
1058                        }
1059
1060                        DigestCalcResponse((char *) pha1, pszNonce, szNonceCount, pszCNonce,
1061                                                           pszQop, version, pszMethod, pszURI, HA2, Response);
1062                }
1063
1064                OSIP_TRACE(osip_trace
1065                                   (__FILE__, __LINE__, OSIP_INFO4, NULL,
1066                                        "Response in proxy_authorization |%s|\n", Response));
1067                {
1068                        char *resp = osip_malloc(35);
1069                        if (resp == NULL) {
1070                                osip_authorization_free(aut);
1071                                osip_free(pszNonce);
1072                                osip_free(pszCNonce);
1073                                osip_free(pszRealm);
1074                                osip_free(pszQop);
1075                                osip_free(szNonceCount);
1076                                return OSIP_NOMEM;
1077                        }
1078
1079                        sprintf(resp, "\"%s\"", Response);
1080                        osip_proxy_authorization_set_response(aut, resp);
1081                }
1082                osip_free(pszNonce);
1083                osip_free(pszCNonce);
1084                osip_free(pszRealm);
1085                osip_free(pszQop);
1086                osip_free(szNonceCount);
1087        }
1088
1089        *auth = aut;
1090        return OSIP_SUCCESS;
1091}
1092
1093int
1094_eXosip_store_nonce(const char *call_id, osip_proxy_authenticate_t * wa,
1095                                        int answer_code)
1096{
1097        struct eXosip_http_auth *http_auth;
1098        int pos;
1099
1100        /* update entries with same call_id */
1101        for (pos = 0; pos < MAX_EXOSIP_HTTP_AUTH; pos++) {
1102                http_auth = &eXosip.http_auths[pos];
1103                if (http_auth->pszCallId[0] == '\0')
1104                        continue;
1105                if (osip_strcasecmp(http_auth->pszCallId, call_id) == 0
1106                        && ((http_auth->wa->realm == NULL && wa->realm == NULL)
1107                                || (http_auth->wa->realm != NULL
1108                                        && wa->realm != NULL
1109                                        && osip_strcasecmp(http_auth->wa->realm, wa->realm) == 0))) {
1110                        osip_proxy_authenticate_free(http_auth->wa);
1111                        http_auth->wa = NULL;
1112                        osip_proxy_authenticate_clone(wa, &(http_auth->wa));
1113                        http_auth->iNonceCount = 1;
1114                        if (http_auth->wa == NULL)
1115                                memset(http_auth, 0, sizeof(struct eXosip_http_auth));
1116                        return OSIP_SUCCESS;
1117                }
1118        }
1119
1120        /* not found */
1121        for (pos = 0; pos < MAX_EXOSIP_HTTP_AUTH; pos++) {
1122                http_auth = &eXosip.http_auths[pos];
1123                if (http_auth->pszCallId[0] == '\0') {
1124                        snprintf(http_auth->pszCallId, sizeof(http_auth->pszCallId), "%s", call_id);
1125                        snprintf(http_auth->pszCNonce, sizeof(http_auth->pszCNonce),
1126                                         "0a4f113b");
1127                        http_auth->iNonceCount = 1;
1128                        osip_proxy_authenticate_clone(wa, &(http_auth->wa));
1129                        http_auth->answer_code = answer_code;
1130                        if (http_auth->wa == NULL)
1131                                memset(http_auth, 0, sizeof(struct eXosip_http_auth));
1132                        return OSIP_SUCCESS;
1133                }
1134        }
1135
1136        OSIP_TRACE(osip_trace
1137                           (__FILE__, __LINE__, OSIP_ERROR, NULL,
1138                                "Compile with higher MAX_EXOSIP_HTTP_AUTH value (current=%i)\n",
1139                                MAX_EXOSIP_HTTP_AUTH));
1140        return OSIP_UNDEFINED_ERROR;
1141}
1142
1143int _eXosip_delete_nonce(const char *call_id)
1144{
1145        struct eXosip_http_auth *http_auth;
1146        int pos;
1147
1148        /* update entries with same call_id */
1149        for (pos = 0; pos < MAX_EXOSIP_HTTP_AUTH; pos++) {
1150                http_auth = &eXosip.http_auths[pos];
1151                if (http_auth->pszCallId[0] == '\0')
1152                        continue;
1153                if (osip_strcasecmp(http_auth->pszCallId, call_id) == 0) {
1154                        osip_proxy_authenticate_free(http_auth->wa);
1155                        memset(http_auth, 0, sizeof(struct eXosip_http_auth));
1156                        return OSIP_SUCCESS;
1157                }
1158        }
1159        return OSIP_NOTFOUND;
1160}
Note: See TracBrowser for help on using the repository browser.