~drizzle-trunk/drizzle/development

1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
1
/* Copyright (c) 2008 PrimeBase Technologies GmbH, Germany
2
 *
3
 * PrimeBase S3Daemon
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * 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
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
1802.10.2 by Monty Taylor
Update all of the copyright headers to include the correct address.
17
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
18
 *
19
 *  Created by Barry Leslie on 10/21/08.
20
 *
21
 */
22
 
23
#include "CSConfig.h"
24
#include <ctype.h>
25
26
#include "CSGlobal.h"
27
#include "CSString.h"
28
29
#include "CSEncode.h"
30
1841.1.3 by Barry.Leslie at PrimeBase
Merged changes from lp:pbms. These changes should remove any danger
31
static const u_char base64URLMap[64] = {
32
	'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 
33
	'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 
34
	'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 
35
	'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 
36
	'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 
37
	'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 
38
	'w', 'x', 'y', 'z', '0', '1', '2', '3', 
39
	'4', '5', '6', '7', '8', '9', '-', '_'
40
};
41
static const u_char base64STDMap[64] = {
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
42
	'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 
43
	'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 
44
	'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 
45
	'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 
46
	'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 
47
	'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 
48
	'w', 'x', 'y', 'z', '0', '1', '2', '3', 
49
	'4', '5', '6', '7', '8', '9', '+', '/'
50
};
51
 
52
static const u_char decodeBase64Map[128] = {
1841.1.3 by Barry.Leslie at PrimeBase
Merged changes from lp:pbms. These changes should remove any danger
53
	0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 
54
	0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 
55
	0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 
56
	0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 
57
	0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 
58
	0XFF, 0XFF, 0XFF, 0X3E, 0XFF, 0X3E, 0XFF, 0X3F, 
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
59
	0X34, 0X35, 0X36, 0X37, 0X38, 0X39, 0X3A, 0X3B, 
1841.1.3 by Barry.Leslie at PrimeBase
Merged changes from lp:pbms. These changes should remove any danger
60
	0X3C, 0X3D, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 
61
	0XFF, 0X00, 0X01, 0X02, 0X03, 0X04, 0X05, 0X06, 
62
	0X07, 0X08, 0X09, 0X0A, 0X0B, 0X0C, 0X0D, 0X0E, 
63
	0X0F, 0X10, 0X11, 0X12, 0X13, 0X14, 0X15, 0X16, 
64
	0X17, 0X18, 0X19, 0XFF, 0XFF, 0XFF, 0XFF, 0X3F, 
65
	0XFF, 0X1A, 0X1B, 0X1C, 0X1D, 0X1E, 0X1F, 0X20, 
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
66
	0X21, 0X22, 0X23, 0X24, 0X25, 0X26, 0X27, 0X28, 
67
	0X29, 0X2A, 0X2B, 0X2C, 0X2D, 0X2E, 0X2F, 0X30, 
1841.1.3 by Barry.Leslie at PrimeBase
Merged changes from lp:pbms. These changes should remove any danger
68
	0X31, 0X32, 0X33, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
69
};
70
1841.1.3 by Barry.Leslie at PrimeBase
Merged changes from lp:pbms. These changes should remove any danger
71
//------------------
72
static bool base64Encoded(const u_char *data, size_t len, const u_char *vc)
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
73
{
74
	if (len % 4)
75
		return false;
76
		
77
	size_t i = len;
78
	
79
	while ( i && data[i-1] == '=') i--;
80
	
81
	if ( (len - i) > 2)
82
		return false;
83
		
84
	for (; i ; i--, data++) {
1841.1.3 by Barry.Leslie at PrimeBase
Merged changes from lp:pbms. These changes should remove any danger
85
		if (((*data < 'A') || (*data > 'Z')) &&
86
			((*data < 'a') || (*data > 'z')) &&
87
			((*data < '0') || (*data > '9')) &&
88
			((*data != vc[0]) && (*data != vc[1])))
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
89
			return false;
90
	}
91
	
92
	return true; // Actually this isn't so much 'true' as 'maybe'
93
}
94
1841.1.3 by Barry.Leslie at PrimeBase
Merged changes from lp:pbms. These changes should remove any danger
95
//------------------
96
static char *genericBase64Encode(const void *data, size_t len, char *encode_buffer, size_t encode_buffer_len, const u_char base64Map[])
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
97
{
98
	u_char *wptr, *rptr, *encoding;
99
	size_t size;
100
	enter_();
101
1841.1.3 by Barry.Leslie at PrimeBase
Merged changes from lp:pbms. These changes should remove any danger
102
	size = ((len + 2) / 3) * 4 +1;
103
	if ((encode_buffer != NULL) && (encode_buffer_len < size)) 
104
		CSException::throwException(CS_CONTEXT, CS_ERR_GENERIC_ERROR, "Base64 encode buffer is too small.");
105
	
106
	if (encode_buffer)
107
		encoding = (u_char *) encode_buffer;
108
	else
109
		encoding = (u_char *) cs_malloc(size);
110
		
111
	size--;
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
112
	encoding[size] = 0;
113
	
114
	wptr= encoding;
115
	rptr = (u_char *) data;
116
	
117
	while (len/3) {		
118
		wptr[0] = base64Map[rptr[0] >>2];
119
		wptr[1] = base64Map[((rptr[0] & 0X03) <<4) + (rptr[1] >> 4)];
120
		wptr[2] = base64Map[((rptr[1] & 0X0F) <<2) + (rptr[2] >> 6)];
121
		wptr[3] = base64Map[(rptr[2] & 0X3F)];
122
		rptr += 3;
123
		wptr += 4;
124
		len -=3;
125
	}
126
	
127
	if (len) {
128
		wptr[0] = base64Map[rptr[0] >>2];
129
130
		if (len == 1) {
131
			wptr[1] = base64Map[(rptr[0] & 0x03) << 4]; 
132
			wptr[2] = wptr[3] = '=';
133
		} else {
134
			wptr[1] = base64Map[((rptr[0] & 0X03) <<4) + (rptr[1] >> 4)];
135
			wptr[2] = base64Map[(rptr[1] & 0X0F) <<2];
136
			wptr[3] = '=';
137
		}
138
		
139
	}
140
	
141
	return_((char*)encoding);
142
}
143
1841.1.3 by Barry.Leslie at PrimeBase
Merged changes from lp:pbms. These changes should remove any danger
144
//------------------
145
static void *genericBase64Decode(const char *data, size_t len, void *decode_buffer, size_t decode_buffer_len, const u_char base64Map[])
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
146
{
147
	u_char *wptr, *rptr, *decoding;
148
	enter_();
149
150
	rptr = (u_char *) data;
151
1841.1.3 by Barry.Leslie at PrimeBase
Merged changes from lp:pbms. These changes should remove any danger
152
	if (!base64Encoded(rptr, len, base64Map +62)) 
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
153
		CSException::throwException(CS_CONTEXT, CS_ERR_GENERIC_ERROR, "String was not Base64 encoded.");
154
	
1841.1.3 by Barry.Leslie at PrimeBase
Merged changes from lp:pbms. These changes should remove any danger
155
	if ((decode_buffer != NULL) && (decode_buffer_len < ((len/ 4) * 3))) 
156
		CSException::throwException(CS_CONTEXT, CS_ERR_GENERIC_ERROR, "Base64 decoded buffer is too small.");
157
	
158
	if (decode_buffer)
159
		decoding = (u_char *) decode_buffer;
160
	else
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
161
	decoding = (u_char *) cs_malloc((len/ 4) * 3);
162
	
163
	wptr= decoding;
164
	
1841.1.3 by Barry.Leslie at PrimeBase
Merged changes from lp:pbms. These changes should remove any danger
165
	while (rptr[len-1] == '=') 
166
		len--; 
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
167
168
	while (len/4) {		
169
		wptr[0] = ( ((decodeBase64Map[rptr[0]] << 2) & 0xFF) | ((decodeBase64Map[rptr[1]] >> 4) & 0x03) ); 
170
		wptr[1] = ( ((decodeBase64Map[rptr[1]] << 4) & 0xFF) | ((decodeBase64Map[rptr[2]] >> 2) & 0x0F) ); 
171
		wptr[2] = ( ((decodeBase64Map[rptr[2]] << 6) & 0xFF) | (decodeBase64Map[rptr[3]] & 0x3F) ); 
172
173
		rptr += 4;
174
		wptr += 3;
175
		len -=4;
176
	}
177
	
178
	if (len) {
179
		wptr[0] = ( ((decodeBase64Map[rptr[0]] << 2) & 0xFF) |  ((decodeBase64Map[rptr[1]] >> 4) & 0x03) ); 
180
		if (len == 2) 
181
			wptr[1] = ( ((decodeBase64Map[rptr[1]] << 4) & 0xFF) | ((decodeBase64Map[rptr[2]] >> 2) & 0x0F) ); 
182
	}
183
	
184
	return_(decoding);
185
}
186
1841.1.3 by Barry.Leslie at PrimeBase
Merged changes from lp:pbms. These changes should remove any danger
187
//------------------
188
char *base64Encode(const void *data, size_t len, char *encode_buffer, size_t encode_buffer_len)
189
{
190
	return genericBase64Encode(data, len, encode_buffer, encode_buffer_len, base64STDMap);
191
}
192
193
//------------------
194
void *base64Decode(const char *data, size_t len, void *decode_buffer, size_t decode_buffer_len)
195
{
196
	return genericBase64Decode(data, len, decode_buffer, decode_buffer_len, base64STDMap);
197
}
198
199
//------------------
200
char *base64UrlEncode(const void *data, size_t len, char *encode_buffer, size_t encode_buffer_len)
201
{
202
	return genericBase64Encode(data, len, encode_buffer, encode_buffer_len, base64URLMap);
203
}
204
205
//------------------
206
void *base64UrlDecode(const char *data, size_t len, void *decode_buffer, size_t decode_buffer_len)
207
{
208
	return genericBase64Decode(data, len, decode_buffer, decode_buffer_len, base64URLMap);
209
}
210
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
211
#ifdef NOT_USED
212
//-----------------------------------------------------
213
void  hmac_md5(u_char *text, size_t text_len, u_char *key, size_t key_len, Md5Digest *digest)
214
{
215
	CSMd5 md5;
216
	unsigned char k_ipad[65];    /* inner padding -
217
								  * key XORd with ipad
218
								  */
219
	unsigned char k_opad[65];    /* outer padding -
220
								  * key XORd with opad
221
								  */
222
	unsigned char tk[16];
223
	int i;
224
	
225
	/* if key is longer than 64 bytes reset it to key=MD5(key) */
226
	if (key_len > 64) {
227
		CSMd5 tmd5;
228
229
		md5.md5_init();
230
		md5.md5_append(key, key_len);
231
		md5.md5_digest(digest);
232
233
		key = digest->val;
234
		key_len = 16;
235
	}
236
237
	/* start out by storing key in pads */
238
	memset(k_ipad, 0, sizeof(k_ipad));
239
	memset(k_opad, 0, sizeof(k_opad));
240
241
	memcpy(k_ipad, key, key_len);
242
	memcpy(k_opad, key, key_len);
243
244
	/* XOR key with ipad and opad values */
245
	for (i=0; i<64; i++) {
246
		k_ipad[i] ^= 0x36;
247
		k_opad[i] ^= 0x5c;
248
	}
249
	/*
250
	 * perform inner encoding
251
	 */
252
	md5.md5_init();
253
	md5.md5_append(k_ipad, 64);
254
	md5.md5_append(text, strlen(text));
255
	md5.md5_digest(digest);
256
257
	/*
258
	 * perform outer encoding
259
	 */
260
	md5.md5_init();
261
	md5.md5_append(k_opad, 64);
262
	md5.md5_append((u_char*)digest, 16);
263
	md5.md5_digest(digest);
264
	
265
}
266
267
#endif // NOT_USED
268
269
//-----------------------------------------------------
270
void  hmac_sha1(const char *text, const char *key, Sha1Digest *digest)
271
{
272
	CSSha1 sha1;
273
	size_t key_len = strlen(key);
274
	unsigned char k_ipad[65];    /* inner padding -
275
								  * key XORd with ipad
276
								  */
277
	unsigned char k_opad[65];    /* outer padding -
278
								  * key XORd with opad
279
								  */
280
	int i;
281
	
282
	/* if key is longer than 64 bytes reset it to key=MD5(key) */
283
	if (key_len > 64) {
284
		CSMd5 tmd5;
285
286
		sha1.sha1_reset();
287
		sha1.sha1_input(key, key_len);
288
		sha1.sha1_digest(digest);
289
290
		key = (char *) digest->val;
291
		key_len = 16;
292
	}
293
294
	/* start out by storing key in pads */
295
	memset(k_ipad, 0, sizeof(k_ipad));
296
	memset(k_opad, 0, sizeof(k_opad));
297
298
	memcpy(k_ipad, key, key_len);
299
	memcpy(k_opad, key, key_len);
300
301
	/* XOR key with ipad and opad values */
302
	for (i=0; i<64; i++) {
303
		k_ipad[i] ^= 0x36;
304
		k_opad[i] ^= 0x5c;
305
	}
306
307
	/*
308
	 * perform inner encoding
309
	 */
310
	sha1.sha1_reset();
311
	sha1.sha1_input(k_ipad, 64);
312
	sha1.sha1_input(text, strlen(text));
313
	sha1.sha1_digest(digest);
314
315
316
	/*
317
	 * perform outer encoding
318
	 */
319
	sha1.sha1_reset();
320
	sha1.sha1_input(k_opad, 64);
321
	sha1.sha1_input(digest, 20);
322
	sha1.sha1_digest(digest);
323
}
324
325
326
//-----------------------------------------------------
327
CSString *signature(const char *text, const char *key)
328
{
329
	Sha1Digest digest;
330
	char *encoding;
331
	CSString *signed_str;
332
	
333
	memset(&digest, 0, sizeof(digest));
334
	hmac_sha1(text, key, &digest);
335
336
	encoding = base64Encode(digest.val, SHA1_HASH_SIZE);
337
	signed_str = CSString::newString(encoding);
338
	cs_free(encoding);
339
	return signed_str;
340
}
341
342
343
//-----------------------------------------------------
344
// Encode url unsafe characters
345
CSString *urlEncode(CSString *src)
346
{
347
	const char *hex = "0123456789ABCDEF", *start, *ptr;
348
	char encoded[3];
349
	CSStringBuffer *url;
350
	
351
	enter_();
352
	push_(src);
353
	
354
	new_(url, CSStringBuffer(10));
355
	push_(url);
356
	
357
	start = ptr = src->getCString();
358
	encoded[0] = '%';
359
	
360
	while(*ptr) {
361
		if (!isalnum(*ptr)) {
362
			switch (*ptr) {
363
				case '.':
364
				case '!':
365
				case '*':
366
				case '~':
367
				case '\'':
368
				case '(':
369
				case ')':
370
				case '_':
371
				case '-':
372
				case '/':
373
					break;
374
				default:
375
					url->append(start, ptr-start);
376
					start = ptr +1;
377
					encoded[1] = hex[*ptr/16];
378
					encoded[2] = hex[*ptr%16];				
379
					url->append(encoded, 3);
380
			}
381
		}
382
		ptr++;		
383
	}
384
	url->append(start, ptr-start);	
385
	
386
	CSString *safe_str = CSString::newString(url->getCString());
387
	
388
	release_(url);
389
	release_(src);
390
	return_(safe_str);
391
}