0425561fe24addea0dc910569f1bf443162e97f7
[sip-router] / src / modules / uac / auth_alg.c
1 /*
2  * Copyright (C) 2005 Voice Sistem SRL
3  *
4  * This file is part of Kamailio, a free SIP server.
5  *
6  * Kamailio is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * Kamailio is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19  *
20  */
21
22 /*!
23  * \file
24  * \brief Kamailio uac :: Authentication
25  * \ingroup uac
26  * Module: \ref uac
27  */
28
29
30 #include "../../core/md5.h"
31
32 #include "auth_alg.h"
33
34
35 static inline void cvt_hex(HASH bin, HASHHEX hex)
36 {
37         unsigned short i;
38         unsigned char j;
39
40         for (i = 0; i<HASHLEN; i++)
41         {
42                 j = (bin[i] >> 4) & 0xf;
43                 if (j <= 9)
44                 {
45                         hex[i * 2] = (j + '0');
46                 } else {
47                         hex[i * 2] = (j + 'a' - 10);
48                 }
49
50                 j = bin[i] & 0xf;
51
52                 if (j <= 9)
53                 {
54                         hex[i * 2 + 1] = (j + '0');
55                 } else {
56                         hex[i * 2 + 1] = (j + 'a' - 10);
57                 }
58         };
59
60         hex[HASHHEXLEN] = '\0';
61 }
62
63
64
65 /* 
66  * calculate H(A1)
67  */
68 void uac_calc_HA1( struct uac_credential *crd,
69                 struct authenticate_body *auth,
70                 str* cnonce,
71                 HASHHEX sess_key)
72 {
73         MD5_CTX Md5Ctx;
74         HASH HA1;
75
76         MD5Init(&Md5Ctx);
77         MD5Update(&Md5Ctx, crd->user.s, crd->user.len);
78         MD5Update(&Md5Ctx, ":", 1);
79         MD5Update(&Md5Ctx, crd->realm.s, crd->realm.len);
80         MD5Update(&Md5Ctx, ":", 1);
81         MD5Update(&Md5Ctx, crd->passwd.s, crd->passwd.len);
82         MD5Final(HA1, &Md5Ctx);
83
84         if ( auth->flags& AUTHENTICATE_MD5SESS )
85         {
86                 MD5Init(&Md5Ctx);
87                 MD5Update(&Md5Ctx, HA1, HASHLEN);
88                 MD5Update(&Md5Ctx, ":", 1);
89                 MD5Update(&Md5Ctx, auth->nonce.s, auth->nonce.len);
90                 MD5Update(&Md5Ctx, ":", 1);
91                 MD5Update(&Md5Ctx, cnonce->s, cnonce->len);
92                 MD5Final(HA1, &Md5Ctx);
93         };
94
95         cvt_hex(HA1, sess_key);
96 }
97
98
99
100 /* 
101  * calculate H(A2)
102  */
103 void uac_calc_HA2( str *method, str *uri,
104                 struct authenticate_body *auth,
105                 HASHHEX hentity,
106                 HASHHEX HA2Hex )
107 {
108         MD5_CTX Md5Ctx;
109         HASH HA2;
110
111         MD5Init(&Md5Ctx);
112         MD5Update(&Md5Ctx, method->s, method->len);
113         MD5Update(&Md5Ctx, ":", 1);
114         MD5Update(&Md5Ctx, uri->s, uri->len);
115
116         if ( auth->flags&QOP_AUTH_INT)
117         {
118                 MD5Update(&Md5Ctx, ":", 1);
119                 MD5Update(&Md5Ctx, hentity, HASHHEXLEN);
120         };
121
122         MD5Final(HA2, &Md5Ctx);
123         cvt_hex(HA2, HA2Hex);
124 }
125
126
127
128 /* 
129  * calculate request-digest/response-digest as per HTTP Digest spec 
130  */
131 void uac_calc_response( HASHHEX ha1, HASHHEX ha2,
132                 struct authenticate_body *auth,
133                 str* nc, str* cnonce,
134                 HASHHEX response)
135 {
136         MD5_CTX Md5Ctx;
137         HASH RespHash;
138         char *p;
139
140         MD5Init(&Md5Ctx);
141         MD5Update(&Md5Ctx, ha1, HASHHEXLEN);
142         MD5Update(&Md5Ctx, ":", 1);
143         MD5Update(&Md5Ctx, auth->nonce.s, auth->nonce.len);
144         MD5Update(&Md5Ctx, ":", 1);
145
146         if ( auth->qop.len)
147         {
148                 MD5Update(&Md5Ctx, nc->s, nc->len);
149                 MD5Update(&Md5Ctx, ":", 1);
150                 MD5Update(&Md5Ctx, cnonce->s, cnonce->len);
151                 MD5Update(&Md5Ctx, ":", 1);
152                 p = memchr(auth->qop.s, ',', auth->qop.len);
153                 if(p) {
154                         MD5Update(&Md5Ctx, auth->qop.s, (size_t)(p - auth->qop.s));
155                 } else {
156                         MD5Update(&Md5Ctx, auth->qop.s, auth->qop.len);
157                 }
158                 MD5Update(&Md5Ctx, ":", 1);
159         };
160         MD5Update(&Md5Ctx, ha2, HASHHEXLEN);
161         MD5Final(RespHash, &Md5Ctx);
162         cvt_hex(RespHash, response);
163 }