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