auth_helper.c 9.72 KB
Newer Older
jehan's avatar
jehan committed
1 2 3 4 5 6
/*
	auth_helper.c belle-sip - SIP (RFC3261) library.
    Copyright (C) 2010  Belledonne Communications SARL

    This program is free software: you can redistribute it and/or modify
    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
jehan's avatar
jehan committed
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/


#include "belle-sip/auth-helper.h"
#include "belle_sip_internal.h"
#include "md5.h"
#include <string.h>

jehan's avatar
jehan committed
25

jehan's avatar
jehan committed
26 27
#define CHECK_IS_PRESENT(obj,header_name,name) \
	if (!belle_sip_header_##header_name##_get_##name(obj)) {\
jehan's avatar
jehan committed
28
		 belle_sip_error("parameter ["#name"]not found for header ["#header_name"]");\
jehan's avatar
jehan committed
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
		 return-1;\
	}

static void belle_sip_auth_helper_clone_authorization(belle_sip_header_authorization_t* authorization, const belle_sip_header_www_authenticate_t* authentication) {
	CLONE_STRING_GENERIC(belle_sip_header_www_authenticate,belle_sip_header_authorization,scheme,authorization,authentication)
	CLONE_STRING_GENERIC(belle_sip_header_www_authenticate,belle_sip_header_authorization,realm,authorization,authentication)
	CLONE_STRING_GENERIC(belle_sip_header_www_authenticate,belle_sip_header_authorization,nonce,authorization,authentication)
	CLONE_STRING_GENERIC(belle_sip_header_www_authenticate,belle_sip_header_authorization,algorithm,authorization,authentication)
	CLONE_STRING_GENERIC(belle_sip_header_www_authenticate,belle_sip_header_authorization,opaque,authorization,authentication)
}
belle_sip_header_authorization_t* belle_sip_auth_helper_create_authorization(const belle_sip_header_www_authenticate_t* authentication) {
	belle_sip_header_authorization_t* authorization = belle_sip_header_authorization_new();
	belle_sip_auth_helper_clone_authorization(authorization,authentication);
	return authorization;
}
jehan's avatar
jehan committed
44 45 46 47 48 49
belle_http_header_authorization_t* belle_http_auth_helper_create_authorization(const belle_sip_header_www_authenticate_t* authentication) {
	belle_http_header_authorization_t* authorization = belle_http_header_authorization_new();
	belle_sip_auth_helper_clone_authorization(BELLE_SIP_HEADER_AUTHORIZATION(authorization),authentication);
	return authorization;
}

jehan's avatar
jehan committed
50 51 52 53 54
belle_sip_header_proxy_authorization_t* belle_sip_auth_helper_create_proxy_authorization(const belle_sip_header_proxy_authenticate_t* proxy_authentication){
	belle_sip_header_proxy_authorization_t* authorization = belle_sip_header_proxy_authorization_new();
	belle_sip_auth_helper_clone_authorization(BELLE_SIP_HEADER_AUTHORIZATION(authorization),BELLE_SIP_HEADER_WWW_AUTHENTICATE(proxy_authentication));
	return authorization;
}
jehan's avatar
jehan committed
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72

int belle_sip_auth_helper_compute_ha1(const char* userid,const char* realm,const char* password, char ha1[33]) {
	md5_byte_t out[16];
	md5_state_t state;
	int di;
	if (!userid) {
		 belle_sip_error("belle_sip_fill_authorization_header, username not found ");
		 return -1;
	}
	if (!password) {
		 belle_sip_error("belle_sip_fill_authorization_header, password not found ");
		 return -1;
	}
	if (!realm) {
		 belle_sip_error("belle_sip_fill_authorization_header, password not found ");
		 return -1;
	}

73 74 75 76 77 78 79
	belle_sip_md5_init(&state);
	belle_sip_md5_append(&state,(const md5_byte_t *)userid,strlen(userid));
	belle_sip_md5_append(&state,(const md5_byte_t *)":",1);
	belle_sip_md5_append(&state,(const md5_byte_t *)realm,strlen(realm));
	belle_sip_md5_append(&state,(const md5_byte_t *)":",1);
	belle_sip_md5_append(&state,(const md5_byte_t *)password,strlen(password));
	belle_sip_md5_finish(&state,out);
jehan's avatar
jehan committed
80 81
	for (di = 0; di < 16; ++di)
			    sprintf(ha1 + di * 2, "%02x", out[di]);
jehan's avatar
jehan committed
82 83 84 85 86 87 88 89 90 91
	ha1[32]='\0';
	return 0;
}

int belle_sip_auth_helper_compute_ha2(const char* method,const char* uri, char ha2[33]) {
	md5_byte_t out[16];
	md5_state_t state;
	int di;
	ha2[32]='\0';
	/*HA2=MD5(method:uri)*/
92 93 94 95 96
	belle_sip_md5_init(&state);
	belle_sip_md5_append(&state,(const md5_byte_t *)method,strlen(method));
	belle_sip_md5_append(&state,(const md5_byte_t *)":",1);
	belle_sip_md5_append(&state,(const md5_byte_t *)uri,strlen(uri));
	belle_sip_md5_finish(&state,out);
jehan's avatar
jehan committed
97 98 99 100 101 102 103 104 105 106
	for (di = 0; di < 16; ++di)
				    sprintf(ha2 + di * 2, "%02x", out[di]);
	return 0;
}
int belle_sip_auth_helper_compute_response(const char* ha1,const char* nonce, const char* ha2, char response[33]) {
	md5_byte_t out[16];
	md5_state_t state;
	int di;
	response[32]='\0';

107 108 109 110
	belle_sip_md5_init(&state);
	belle_sip_md5_append(&state,(const md5_byte_t *)ha1,strlen(ha1));
	belle_sip_md5_append(&state,(const md5_byte_t *)":",1);
	belle_sip_md5_append(&state
jehan's avatar
jehan committed
111 112
			,(const md5_byte_t *)nonce
			,strlen(nonce));
113 114 115
	belle_sip_md5_append(&state,(const md5_byte_t *)":",1);
	belle_sip_md5_append(&state,(const md5_byte_t *)ha2,strlen(ha2));
		belle_sip_md5_finish(&state,out);
jehan's avatar
jehan committed
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
		/*copy values*/
		for (di = 0; di < 16; ++di)
			    sprintf(response + di * 2, "%02x", out[di]);
	return 0;

}
int belle_sip_auth_helper_compute_response_qop_auth(const char* ha1
													, const char* nonce
													, unsigned int nonce_count
													, const char* cnonce
													, const char* qop
													, const char* ha2, char response[33]) {
	md5_byte_t out[16];
	md5_state_t state;
	char nounce_count_as_string[9];
	int di;
132 133 134

	response[32]='\0';

jehan's avatar
jehan committed
135 136 137
	snprintf(nounce_count_as_string,sizeof(nounce_count_as_string),"%08x",nonce_count);
	/*response=MD5(HA1:nonce:nonce_count:cnonce:qop:HA2)*/

138 139 140 141
	belle_sip_md5_init(&state);
	belle_sip_md5_append(&state,(const md5_byte_t *)ha1,strlen(ha1));
	belle_sip_md5_append(&state,(const md5_byte_t *)":",1);
	belle_sip_md5_append(&state
jehan's avatar
jehan committed
142 143
			,(const md5_byte_t *)nonce
			,strlen(nonce));
144 145
	belle_sip_md5_append(&state,(const md5_byte_t *)":",1);
	belle_sip_md5_append(&state
jehan's avatar
jehan committed
146 147
				,(const md5_byte_t *)nounce_count_as_string
				,strlen(nounce_count_as_string));
148 149
	belle_sip_md5_append(&state,(const md5_byte_t *)":",1);
	belle_sip_md5_append(&state
jehan's avatar
jehan committed
150 151
				,(const md5_byte_t *)cnonce
				,strlen(cnonce));
152 153
	belle_sip_md5_append(&state,(const md5_byte_t *)":",1);
	belle_sip_md5_append(&state
jehan's avatar
jehan committed
154 155
				,(const md5_byte_t *)qop
				,strlen(qop));
156
	belle_sip_md5_append(&state,(const md5_byte_t *)":",1);
jehan's avatar
jehan committed
157

158 159
	belle_sip_md5_append(&state,(const md5_byte_t *)ha2,strlen(ha2));
	belle_sip_md5_finish(&state,out);
jehan's avatar
jehan committed
160 161 162 163
	/*copy values*/
	for (di = 0; di < 16; ++di)
		    sprintf(response + di * 2, "%02x", out[di]);

jehan's avatar
jehan committed
164 165
	return 0;
}
jehan's avatar
jehan committed
166
int belle_sip_auth_helper_fill_authorization(belle_sip_header_authorization_t* authorization
jehan's avatar
jehan committed
167 168
											,const char* method
											,const char* ha1) {
jehan's avatar
jehan committed
169

jehan's avatar
jehan committed
170
	int auth_mode=0;
jehan's avatar
jehan committed
171 172 173
	char* uri;
	char ha2[16*2 + 1];
	char response[16*2 + 1];
jehan's avatar
jehan committed
174 175
	char cnonce[9];

176 177
	response[32]=ha2[32]='\0';

jehan's avatar
jehan committed
178 179 180 181 182 183 184
	if (belle_sip_header_authorization_get_scheme(authorization) != NULL &&
		strcmp("Digest",belle_sip_header_authorization_get_scheme(authorization))!=0) {
		belle_sip_error("belle_sip_fill_authorization_header, unsupported schema [%s]"
						,belle_sip_header_authorization_get_scheme(authorization));
		return -1;
	}
	if (belle_sip_header_authorization_get_qop(authorization)
jehan's avatar
jehan committed
185 186
		&& !(auth_mode=strcmp("auth",belle_sip_header_authorization_get_qop(authorization))==0)) {
		belle_sip_error("belle_sip_fill_authorization_header, unsupported qop [%s], use auth or nothing instead"
jehan's avatar
jehan committed
187 188 189 190 191
								,belle_sip_header_authorization_get_qop(authorization));
		return -1;
	}
	CHECK_IS_PRESENT(authorization,authorization,realm)
	CHECK_IS_PRESENT(authorization,authorization,nonce)
jehan's avatar
jehan committed
192 193 194 195 196 197 198 199 200
	if (BELLE_SIP_IS_INSTANCE_OF(authorization,belle_http_header_authorization_t)) {
		/*http case*/
		if (!belle_http_header_authorization_get_uri(BELLE_HTTP_HEADER_AUTHORIZATION(authorization))) {
			 belle_sip_error("parameter uri not found for http header authorization");
			 return-1;
		}
	} else {
		CHECK_IS_PRESENT(authorization,authorization,uri)
	}
jehan's avatar
jehan committed
201 202 203
	if (auth_mode) {
		CHECK_IS_PRESENT(authorization,authorization,nonce_count)
		if (!belle_sip_header_authorization_get_cnonce(authorization)) {
jehan's avatar
jehan committed
204
			snprintf(cnonce,sizeof(cnonce),"%08x",(short)(long)authorization^0x5555555); /*spseudo randomly genrated cnonce*/
jehan's avatar
jehan committed
205 206 207
			belle_sip_header_authorization_set_cnonce(authorization,cnonce);
		}
	}
jehan's avatar
jehan committed
208 209 210 211 212
	if (!method) {
		 belle_sip_error("belle_sip_fill_authorization_header, method not found ");
		 return -1;
	}

jehan's avatar
jehan committed
213 214 215 216 217 218
	if (BELLE_SIP_IS_INSTANCE_OF(authorization,belle_http_header_authorization_t)) {
			/*http case*/
		uri=belle_generic_uri_to_string(belle_http_header_authorization_get_uri(BELLE_HTTP_HEADER_AUTHORIZATION(authorization)));
	} else {
		uri=belle_sip_uri_to_string(belle_sip_header_authorization_get_uri(authorization));
	}
jehan's avatar
jehan committed
219

jehan's avatar
jehan committed
220
	belle_sip_auth_helper_compute_ha2(method,uri,ha2);
jehan's avatar
jehan committed
221
	belle_sip_free(uri);
jehan's avatar
jehan committed
222 223
	if (auth_mode) {
		/*response=MD5(HA1:nonce:nonce_count:cnonce:qop:HA2)*/
jehan's avatar
jehan committed
224

jehan's avatar
jehan committed
225 226 227 228 229 230 231 232 233 234 235
		belle_sip_auth_helper_compute_response_qop_auth(ha1
														,belle_sip_header_authorization_get_nonce(authorization)
														,belle_sip_header_authorization_get_nonce_count(authorization)
														,belle_sip_header_authorization_get_cnonce(authorization)
														,belle_sip_header_authorization_get_qop(authorization)
														,ha2
														,response);
	}  else {
		/*response=MD5(ha1:nonce:ha2)*/
		belle_sip_auth_helper_compute_response(ha1,belle_sip_header_authorization_get_nonce(authorization),ha2,response);
	}
jehan's avatar
jehan committed
236 237 238 239 240 241
	belle_sip_header_authorization_set_response(authorization,(const char*)response);
	return 0;
}

int belle_sip_auth_helper_fill_proxy_authorization(belle_sip_header_proxy_authorization_t* proxy_authorization
												,const char* method
jehan's avatar
jehan committed
242
												,const char* ha1) {
jehan's avatar
jehan committed
243
	return belle_sip_auth_helper_fill_authorization(BELLE_SIP_HEADER_AUTHORIZATION(proxy_authorization)
jehan's avatar
jehan committed
244
													,method, ha1);
jehan's avatar
jehan committed
245 246 247 248


}

jehan's avatar
jehan committed
249 250 251 252