source: verona/libeXosip2/src/jauth.c @ 70:b5397355ceb4

Last change on this file since 70:b5397355ceb4 was 70:b5397355ceb4, checked in by vadim@…, 3 years ago

Fix incorrect snprintf usage

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