uac: use auth_ha1 field if set for remote registrations
[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 static inline void cvt_bin(HASHHEX hex, HASH bin)
65 {
66         unsigned short i;
67         unsigned char j;
68         for (i = 0; i<HASHLEN; i++) {
69                 if(hex[2*i]>='0' && hex[2*i]<='9')
70                         j = (hex[2*i]-'0') << 4;
71                 else if(hex[2*i]>='a'&&hex[2*i]<='f')
72                         j = (hex[2*i]-'a'+10) << 4;
73                 else if(hex[2*i]>='A'&&hex[2*i]<='F')
74                         j = (hex[2*i]-'A'+10) << 4;
75                 else j = 0;
76
77                 if(hex[2*i+1]>='0'&&hex[2*i+1]<='9')
78                         j += hex[2*i+1]-'0';
79                 else if(hex[2*i+1]>='a'&&hex[2*i+1]<='f')
80                         j += hex[2*i+1]-'a'+10;
81                 else if(hex[2*i+1]>='A'&&hex[2*i+1]<='F')
82                         j += hex[2*i+1]-'A'+10;
83
84                 bin[i] = j;
85         }
86 }
87
88 /*
89  * calculate H(A1)
90  */
91 void uac_calc_HA1( struct uac_credential *crd,
92                 struct authenticate_body *auth,
93                 str* cnonce,
94                 HASHHEX sess_key)
95 {
96         MD5_CTX Md5Ctx;
97         HASH HA1;
98
99         if(UAC_FLCRED_HA1 & UAC_FLCRED_HA1) {
100                 memcpy(sess_key, crd->passwd.s, HASHHEXLEN);
101                 sess_key[HASHHEXLEN] = '\0';
102                 if ( auth->flags& AUTHENTICATE_MD5SESS ) {
103                         cvt_bin(sess_key, HA1);
104                 } else {
105                         return;
106                 }
107         } else {
108                 MD5Init(&Md5Ctx);
109                 MD5Update(&Md5Ctx, crd->user.s, crd->user.len);
110                 MD5Update(&Md5Ctx, ":", 1);
111                 MD5Update(&Md5Ctx, crd->realm.s, crd->realm.len);
112                 MD5Update(&Md5Ctx, ":", 1);
113                 MD5Update(&Md5Ctx, crd->passwd.s, crd->passwd.len);
114                 MD5Final(HA1, &Md5Ctx);
115         }
116
117         if ( auth->flags& AUTHENTICATE_MD5SESS ) {
118                 MD5Init(&Md5Ctx);
119                 MD5Update(&Md5Ctx, HA1, HASHLEN);
120                 MD5Update(&Md5Ctx, ":", 1);
121                 MD5Update(&Md5Ctx, auth->nonce.s, auth->nonce.len);
122                 MD5Update(&Md5Ctx, ":", 1);
123                 MD5Update(&Md5Ctx, cnonce->s, cnonce->len);
124                 MD5Final(HA1, &Md5Ctx);
125         }
126
127         cvt_hex(HA1, sess_key);
128 }
129
130
131
132 /* 
133  * calculate H(A2)
134  */
135 void uac_calc_HA2( str *method, str *uri,
136                 struct authenticate_body *auth,
137                 HASHHEX hentity,
138                 HASHHEX HA2Hex )
139 {
140         MD5_CTX Md5Ctx;
141         HASH HA2;
142
143         MD5Init(&Md5Ctx);
144         MD5Update(&Md5Ctx, method->s, method->len);
145         MD5Update(&Md5Ctx, ":", 1);
146         MD5Update(&Md5Ctx, uri->s, uri->len);
147
148         if ( auth->flags&QOP_AUTH_INT)
149         {
150                 MD5Update(&Md5Ctx, ":", 1);
151                 MD5Update(&Md5Ctx, hentity, HASHHEXLEN);
152         };
153
154         MD5Final(HA2, &Md5Ctx);
155         cvt_hex(HA2, HA2Hex);
156 }
157
158
159
160 /* 
161  * calculate request-digest/response-digest as per HTTP Digest spec 
162  */
163 void uac_calc_response( HASHHEX ha1, HASHHEX ha2,
164                 struct authenticate_body *auth,
165                 str* nc, str* cnonce,
166                 HASHHEX response)
167 {
168         MD5_CTX Md5Ctx;
169         HASH RespHash;
170         char *p;
171
172         MD5Init(&Md5Ctx);
173         MD5Update(&Md5Ctx, ha1, HASHHEXLEN);
174         MD5Update(&Md5Ctx, ":", 1);
175         MD5Update(&Md5Ctx, auth->nonce.s, auth->nonce.len);
176         MD5Update(&Md5Ctx, ":", 1);
177
178         if ( auth->qop.len)
179         {
180                 MD5Update(&Md5Ctx, nc->s, nc->len);
181                 MD5Update(&Md5Ctx, ":", 1);
182                 MD5Update(&Md5Ctx, cnonce->s, cnonce->len);
183                 MD5Update(&Md5Ctx, ":", 1);
184                 p = memchr(auth->qop.s, ',', auth->qop.len);
185                 if(p) {
186                         MD5Update(&Md5Ctx, auth->qop.s, (size_t)(p - auth->qop.s));
187                 } else {
188                         MD5Update(&Md5Ctx, auth->qop.s, auth->qop.len);
189                 }
190                 MD5Update(&Md5Ctx, ":", 1);
191         };
192         MD5Update(&Md5Ctx, ha2, HASHHEXLEN);
193         MD5Final(RespHash, &Md5Ctx);
194         cvt_hex(RespHash, response);
195 }