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/crypto/md5.h"
31
32 #include "auth_alg.h"
33
34
cvt_hex(HASH bin,HASHHEX hex)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
cvt_bin(HASHHEX hex,HASH bin)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 */
uac_calc_HA1(struct uac_credential * crd,struct authenticate_body * auth,str * cnonce,HASHHEX sess_key)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(crd->aflags & 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 */
uac_calc_HA2(str * method,str * uri,struct authenticate_body * auth,HASHHEX hentity,HASHHEX HA2Hex)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 */
uac_calc_response(HASHHEX ha1,HASHHEX ha2,struct authenticate_body * auth,str * nc,str * cnonce,HASHHEX response)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 }
196