ksgi

Форк
0
/
auth.c 
264 строки · 6.6 Кб
1
/*	$Id$ */
2
/*
3
 * Copyright (c) 2015--2018 Kristaps Dzonsons <kristaps@bsd.lv>
4
 * Copyright (c) 2018 Charles Collicutt <charles@collicutt.co.uk>
5
 *
6
 * Permission to use, copy, modify, and distribute this software for any
7
 * purpose with or without fee is hereby granted, provided that the above
8
 * copyright notice and this permission notice appear in all copies.
9
 *
10
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
 */
18
#include "config.h"
19

20
#include <inttypes.h>
21
#if HAVE_MD5
22
# include <sys/types.h>
23
# include <md5.h>
24
#endif
25
#include <stdarg.h>
26
#include <stdio.h>
27
#include <stdint.h>
28
#include <stdlib.h>
29
#include <string.h>
30

31
#include "kcgi.h"
32
#include "extern.h"
33

34
#define MD5Updatec(_ctx, _b, _sz) \
35
	MD5Update((_ctx), (const uint8_t *)(_b), (_sz))
36

37
static const char b64[] = 
38
	"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
39
	"abcdefghijklmnopqrstuvwxyz"
40
	"0123456789+/";
41

42
static size_t 
43
base64len(size_t len)
44
{
45

46
	return((len + 2) / 3 * 4) + 1;
47
}
48

49
static size_t 
50
base64buf(char *enc, const char *str, size_t len)
51
{
52
	size_t 	i;
53
	char 	*p;
54

55
	p = enc;
56

57
	for (i = 0; i < len - 2; i += 3) {
58
		*p++ = b64[(str[i] >> 2) & 0x3F];
59
		*p++ = b64[((str[i] & 0x3) << 4) |
60
			((int)(str[i + 1] & 0xF0) >> 4)];
61
		*p++ = b64[((str[i + 1] & 0xF) << 2) |
62
			((int)(str[i + 2] & 0xC0) >> 6)];
63
		*p++ = b64[str[i + 2] & 0x3F];
64
	}
65

66
	if (i < len) {
67
		*p++ = b64[(str[i] >> 2) & 0x3F];
68
		if (i == (len - 1)) {
69
			*p++ = b64[((str[i] & 0x3) << 4)];
70
			*p++ = '=';
71
		} else {
72
			*p++ = b64[((str[i] & 0x3) << 4) |
73
				((int)(str[i + 1] & 0xF0) >> 4)];
74
			*p++ = b64[((str[i + 1] & 0xF) << 2)];
75
		}
76
		*p++ = '=';
77
	}
78

79
	*p++ = '\0';
80
	return (p - enc);
81
}
82

83
int
84
khttpbasic_validate(const struct kreq *req, 
85
	const char *user, const char *pass)
86
{
87
	char	*buf, *enc;
88
	size_t	 sz;
89
	int	 rc;
90

91
	if (req->rawauth.type != KAUTH_BASIC &&
92
	    req->rawauth.type != KAUTH_BEARER)
93
		return (-1);
94
	else if (req->method == KMETHOD__MAX)
95
		return (-1);
96
	else if (req->rawauth.authorised == 0)
97
		return (-1);
98

99
	/* Make sure we don't bail on memory allocation. */
100

101
	sz = strlen(user) + 1 + strlen(pass) + 1;
102
	if ((buf = kxmalloc(sz)) == NULL)
103
		return (-1);
104

105
	sz = snprintf(buf, sz, "%s:%s", user, pass);
106
	if ((enc = kxmalloc(base64len(sz))) == NULL) {
107
		free(buf);
108
		return (-1);
109
	}
110

111
	base64buf(enc, buf, sz);
112
	rc = strcmp(enc, req->rawauth.d.basic.response) == 0;
113

114
	free(enc);
115
	free(buf);
116
	return rc;
117
}
118

119
int
120
khttpdigest_validatehash(const struct kreq *req, const char *skey4)
121
{
122
	MD5_CTX	 	 ctx;
123
	unsigned char	 ha1[MD5_DIGEST_LENGTH],
124
			 ha2[MD5_DIGEST_LENGTH],
125
			 ha3[MD5_DIGEST_LENGTH];
126
	char		 skey1[MD5_DIGEST_LENGTH * 2 + 1],
127
			 skey2[MD5_DIGEST_LENGTH * 2 + 1],
128
			 skey3[MD5_DIGEST_LENGTH * 2 + 1],
129
	                 skeyb[MD5_DIGEST_LENGTH * 2 + 1],
130
			 count[9];
131
	size_t		 i;
132
	const struct khttpdigest *auth;
133

134
	/*
135
	 * Make sure we're a digest with all fields intact.
136
	 */
137
	if (KAUTH_DIGEST != req->rawauth.type)
138
		return(-1);
139
	else if (KMETHOD__MAX == req->method)
140
		return(-1);
141
	else if (0 == req->rawauth.authorised)
142
		return(-1);
143

144
	auth = &req->rawauth.d.digest;
145

146
	/*
147
	 * MD5-sess hashes the nonce and client nonce as well as the
148
	 * existing hash (user/real/pass).
149
	 */
150

151
	if (KHTTPALG_MD5_SESS == auth->alg) {
152
		MD5Init(&ctx);
153
		MD5Updatec(&ctx, skey4, strlen(skey4));
154
		MD5Updatec(&ctx, ":", 1);
155
		MD5Updatec(&ctx, auth->nonce, strlen(auth->nonce));
156
		MD5Updatec(&ctx, ":", 1);
157
		MD5Updatec(&ctx, auth->cnonce, strlen(auth->cnonce));
158
		MD5Final(ha1, &ctx);
159
		for (i = 0; i < MD5_DIGEST_LENGTH; i++) 
160
			snprintf(&skey1[i * 2], 3, "%02x", ha1[i]);
161
	} else 
162
		strlcpy(skey1, skey4, sizeof(skey1));
163

164
	/* Now start the "auth" hash sequence. */
165

166
	MD5Init(&ctx);
167
	MD5Updatec(&ctx, kmethods[req->method],
168
		strlen(kmethods[req->method]));
169
	MD5Updatec(&ctx, ":", 1);
170
	MD5Updatec(&ctx, auth->uri, strlen(auth->uri));
171

172
	/*
173
	 * If we're requesting integrity authentication ("auth-int"),
174
	 * then we also bring in the hash of the message body.
175
	 */
176

177
	if (KHTTPQOP_AUTH_INT == auth->qop) {
178
		/* This shouldn't happen... */
179
		if (NULL == req->rawauth.digest)
180
			return(-1);
181

182
		for (i = 0; i < MD5_DIGEST_LENGTH; i++)
183
			snprintf(&skeyb[i * 2], 3, "%02x",
184
			    (unsigned char)req->rawauth.digest[i]);
185

186
		MD5Updatec(&ctx, ":", 1);
187
		MD5Updatec(&ctx, skeyb, MD5_DIGEST_LENGTH * 2);
188
	}
189

190
	MD5Final(ha2, &ctx);
191

192
	for (i = 0; i < MD5_DIGEST_LENGTH; i++) 
193
		snprintf(&skey2[i * 2], 3, "%02x", ha2[i]);
194

195
	if (KHTTPQOP_AUTH_INT == auth->qop || 
196
	    KHTTPQOP_AUTH == auth->qop) {
197
		snprintf(count, sizeof(count), "%08" PRIx32, auth->count);
198
		MD5Init(&ctx);
199
		MD5Updatec(&ctx, skey1, MD5_DIGEST_LENGTH * 2);
200
		MD5Updatec(&ctx, ":", 1);
201
		MD5Updatec(&ctx, auth->nonce, strlen(auth->nonce));
202
		MD5Updatec(&ctx, ":", 1);
203
		MD5Updatec(&ctx, count, strlen(count));
204
		MD5Updatec(&ctx, ":", 1);
205
		MD5Updatec(&ctx, auth->cnonce, strlen(auth->cnonce));
206
		MD5Updatec(&ctx, ":", 1);
207
		if (KHTTPQOP_AUTH_INT == auth->qop)
208
			MD5Updatec(&ctx, "auth-int", 8);
209
		else
210
			MD5Updatec(&ctx, "auth", 4);
211
		MD5Updatec(&ctx, ":", 1);
212
		MD5Updatec(&ctx, skey2, MD5_DIGEST_LENGTH * 2);
213
		MD5Final(ha3, &ctx);
214
	} else {
215
		MD5Init(&ctx);
216
		MD5Updatec(&ctx, skey1, MD5_DIGEST_LENGTH * 2);
217
		MD5Updatec(&ctx, ":", 1);
218
		MD5Updatec(&ctx, auth->nonce, strlen(auth->nonce));
219
		MD5Updatec(&ctx, ":", 1);
220
		MD5Updatec(&ctx, skey2, MD5_DIGEST_LENGTH * 2);
221
		MD5Final(ha3, &ctx);
222
	}
223

224
	for (i = 0; i < MD5_DIGEST_LENGTH; i++) 
225
		snprintf(&skey3[i * 2], 3, "%02x", ha3[i]);
226

227
	return(0 == strcmp(auth->response, skey3));
228
}
229

230
int
231
khttpdigest_validate(const struct kreq *req, const char *pass)
232
{
233
	MD5_CTX	 	 ctx;
234
	unsigned char	 ha4[MD5_DIGEST_LENGTH];
235
	char		 skey4[MD5_DIGEST_LENGTH * 2 + 1];
236
	size_t		 i;
237
	const struct khttpdigest *auth;
238

239
	/*
240
	 * Make sure we're a digest with all fields intact.
241
	 */
242

243
	if (KAUTH_DIGEST != req->rawauth.type)
244
		return(-1);
245
	else if (KMETHOD__MAX == req->method)
246
		return(-1);
247
	else if (0 == req->rawauth.authorised)
248
		return(-1);
249

250
	auth = &req->rawauth.d.digest;
251

252
	MD5Init(&ctx);
253
	MD5Updatec(&ctx, auth->user, strlen(auth->user));
254
	MD5Updatec(&ctx, ":", 1);
255
	MD5Updatec(&ctx, auth->realm, strlen(auth->realm));
256
	MD5Updatec(&ctx, ":", 1);
257
	MD5Updatec(&ctx, pass, strlen(pass));
258
	MD5Final(ha4, &ctx);
259

260
	for (i = 0; i < MD5_DIGEST_LENGTH; i++) 
261
		snprintf(&skey4[i * 2], 3, "%02x", ha4[i]);
262

263
	return(khttpdigest_validatehash(req, skey4));
264
}
265

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.