comparison src/auth/password-scheme.c @ 2367:203938a7f45e HEAD

Added dovecotpw utility. Patch by Joshua Goodall
author Timo Sirainen <tss@iki.fi>
date Mon, 26 Jul 2004 19:21:29 +0300
parents d921b930abd7
children 8f5be0be3199
comparison
equal deleted inserted replaced
2366:33c584ef528a 2367:203938a7f45e
6 #include "hex-binary.h" 6 #include "hex-binary.h"
7 #include "md5.h" 7 #include "md5.h"
8 #include "module-dir.h" 8 #include "module-dir.h"
9 #include "mycrypt.h" 9 #include "mycrypt.h"
10 #include "randgen.h" 10 #include "randgen.h"
11 #include "sha1.h"
11 #include "str.h" 12 #include "str.h"
12 #include "password-scheme.h" 13 #include "password-scheme.h"
13
14 #ifdef HAVE_OPENSSL_SHA1
15 # include <openssl/sha.h>
16 #endif
17 14
18 static const char salt_chars[] = 15 static const char salt_chars[] =
19 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 16 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
20 17
21 static buffer_t *schemes_buf; 18 static buffer_t *schemes_buf;
36 if (strcasecmp(s->name, scheme) == 0) 33 if (strcasecmp(s->name, scheme) == 0)
37 return s->password_verify(plaintext, password, user); 34 return s->password_verify(plaintext, password, user);
38 } 35 }
39 36
40 return -1; 37 return -1;
38 }
39
40 const char *password_list_schemes(const struct password_scheme **listptr)
41 {
42 if (*listptr == NULL)
43 *listptr = schemes;
44
45 if ((*listptr)->name == NULL) {
46 *listptr = NULL;
47 return NULL;
48 }
49
50 return (*listptr)++->name;
41 } 51 }
42 52
43 const char *password_get_scheme(const char **password) 53 const char *password_get_scheme(const char **password)
44 { 54 {
45 const char *p, *scheme; 55 const char *p, *scheme;
66 if (p == NULL) 76 if (p == NULL)
67 return NULL; 77 return NULL;
68 78
69 scheme = t_strdup_until(*password + 1, p); 79 scheme = t_strdup_until(*password + 1, p);
70 *password = p + 1; 80 *password = p + 1;
81
82 /* LDAP's RFC2307 specifies the MD5 scheme for what we call PLAIN-MD5,
83 only base64-encoded rather than hex-encoded.
84 We can detect this case - base64 doesn't use '$'. */
85 if (strncasecmp(scheme, "MD5", 3) == 0 &&
86 strncmp(*password, "$1$", 3) != 0) {
87 scheme = "LDAP-MD5";
88 }
71 return scheme; 89 return scheme;
72 } 90 }
73 91
74 const char *password_generate(const char *plaintext, const char *user, 92 const char *password_generate(const char *plaintext, const char *user,
75 const char *scheme) 93 const char *scheme)
122 salt[i] = salt_chars[salt[i] % (sizeof(salt_chars)-1)]; 140 salt[i] = salt_chars[salt[i] % (sizeof(salt_chars)-1)];
123 salt[8] = '\0'; 141 salt[8] = '\0';
124 return password_generate_md5_crypt(plaintext, salt); 142 return password_generate_md5_crypt(plaintext, salt);
125 } 143 }
126 144
127 #ifdef HAVE_OPENSSL_SHA1 145 static const char *sha1_generate(const char *plaintext,
128 static int sha_verify(const char *plaintext, const char *password, 146 const char *user __attr_unused__)
147 {
148 unsigned char digest[SHA1_RESULTLEN];
149 string_t *str;
150
151 sha1_get_digest(plaintext, strlen(plaintext), digest);
152 str = t_str_new(MAX_BASE64_ENCODED_SIZE(sizeof(digest)+1));
153 base64_encode(digest, sizeof(digest), str);
154 return str_c(str);
155 }
156
157 static int sha1_verify(const char *plaintext, const char *password,
129 const char *user __attr_unused__) 158 const char *user __attr_unused__)
130 { 159 {
131 unsigned char digest[SHA_DIGEST_LENGTH]; 160 unsigned char sha1_digest[SHA1_RESULTLEN];
161 const char *data;
162 buffer_t *buf;
163 size_t size;
164
165 sha1_get_digest(plaintext, strlen(plaintext), sha1_digest);
166
167 buf = buffer_create_static(pool_datastack_create(),
168 MAX_BASE64_DECODED_SIZE(strlen(password)+1));
169
170 if (base64_decode(password, strlen(password), NULL, buf) <= 0) {
171 i_error("sha1_verify(%s): failed decoding SHA base64", user);
172 return 0;
173 }
174
175 data = buffer_get_data(buf, &size);
176 if (size < SHA1_RESULTLEN) {
177 i_error("sha1_verify(%s): invalid SHA base64 decode", user);
178 return 0;
179 }
180
181 return memcmp(sha1_digest, data, SHA1_RESULTLEN) == 0;
182 }
183
184 static const char *ssha_generate(const char *plaintext,
185 const char *user __attr_unused__)
186 {
187 unsigned char ssha_digest[SHA1_RESULTLEN+4];
188 unsigned char *salt = &ssha_digest[SHA1_RESULTLEN];
189 struct sha1_ctxt ctx;
132 string_t *str; 190 string_t *str;
133 191
134 SHA1(plaintext, strlen(plaintext), digest); 192 random_fill(salt, 4);
135 193
136 str = t_str_new(64); 194 sha1_init(&ctx);
137 base64_encode(digest, sizeof(digest), str); 195 sha1_loop(&ctx, plaintext, strlen(plaintext));
138 return strcasecmp(str_c(str), password) == 0; 196 sha1_loop(&ctx, salt, 4);
139 } 197 sha1_result(&ctx, ssha_digest);
140 #endif 198
199 str = t_str_new(MAX_BASE64_ENCODED_SIZE(sizeof(ssha_digest))+1);
200 base64_encode(ssha_digest, sizeof(ssha_digest), str);
201 return str_c(str);
202 }
203
204 static int ssha_verify(const char *plaintext, const char *password,
205 const char *user __attr_unused__)
206 {
207 unsigned char sha1_digest[SHA1_RESULTLEN];
208 buffer_t *buf;
209 const char *data;
210 size_t size;
211 struct sha1_ctxt ctx;
212
213 /* format: base64-encoded MD5 hash and salt */
214 buf = buffer_create_static(pool_datastack_create(),
215 MAX_BASE64_DECODED_SIZE(strlen(password)+1));
216
217 if (base64_decode(password, strlen(password), NULL, buf) <= 0) {
218 i_error("ssha_verify(%s): failed decoding SSHA base64", user);
219 return 0;
220 }
221
222 data = buffer_get_data(buf, &size);
223 if (size <= SHA1_RESULTLEN) {
224 i_error("ssha_verify(%s): invalid SSHA base64 decode", user);
225 return 0;
226 }
227
228 sha1_init(&ctx);
229 sha1_loop(&ctx, plaintext, strlen(plaintext));
230 sha1_loop(&ctx, &data[SHA1_RESULTLEN], size-SHA1_RESULTLEN);
231 sha1_result(&ctx, sha1_digest);
232 return memcmp(sha1_digest, data, SHA1_RESULTLEN) == 0;
233 }
234
235 static const char *smd5_generate(const char *plaintext,
236 const char *user __attr_unused__)
237 {
238 unsigned char smd5_digest[20];
239 unsigned char *salt = &smd5_digest[16];
240 struct md5_context ctx;
241 string_t *str;
242
243 random_fill(salt, 4);
244
245 md5_init(&ctx);
246 md5_update(&ctx, plaintext, strlen(plaintext));
247 md5_update(&ctx, salt, 4);
248 md5_final(&ctx, smd5_digest);
249
250 str = t_str_new(MAX_BASE64_ENCODED_SIZE(sizeof(smd5_digest))+1);
251 base64_encode(smd5_digest, sizeof(smd5_digest), str);
252 return str_c(str);
253 }
254
255 static int smd5_verify(const char *plaintext, const char *password,
256 const char *user __attr_unused__)
257 {
258 unsigned char md5_digest[16];
259 buffer_t *buf;
260 const char *data;
261 size_t size;
262 struct md5_context ctx;
263
264 /* format: base64-encoded MD5 hash and salt */
265 buf = buffer_create_static(pool_datastack_create(),
266 MAX_BASE64_DECODED_SIZE(strlen(password)+1));
267
268 if (base64_decode(password, strlen(password), NULL, buf) <= 0) {
269 i_error("smd5_verify(%s): failed decoding SMD5 base64", user);
270 return 0;
271 }
272
273 data = buffer_get_data(buf, &size);
274 if (size <= 16) {
275 i_error("smd5_verify(%s): invalid SMD5 base64 decode", user);
276 return 0;
277 }
278
279 md5_init(&ctx);
280 md5_update(&ctx, plaintext, strlen(plaintext));
281 md5_update(&ctx, &data[16], size-16);
282 md5_final(&ctx, md5_digest);
283 return memcmp(md5_digest, data, 16) == 0;
284 }
141 285
142 static int plain_verify(const char *plaintext, const char *password, 286 static int plain_verify(const char *plaintext, const char *password,
143 const char *user __attr_unused__) 287 const char *user __attr_unused__)
144 { 288 {
145 return strcmp(password, plaintext) == 0; 289 return strcmp(password, plaintext) == 0;
214 358
215 md5_get_digest(plaintext, strlen(plaintext), digest); 359 md5_get_digest(plaintext, strlen(plaintext), digest);
216 return binary_to_hex(digest, sizeof(digest)); 360 return binary_to_hex(digest, sizeof(digest));
217 } 361 }
218 362
363 static const char *ldap_md5_generate(const char *plaintext,
364 const char *user __attr_unused__)
365 {
366 unsigned char digest[16];
367 string_t *str;
368
369 md5_get_digest(plaintext, strlen(plaintext), digest);
370 str = t_str_new(MAX_BASE64_ENCODED_SIZE(sizeof(digest)+1));
371 base64_encode(digest, sizeof(digest), str);
372 return str_c(str);
373 }
374
375 static int ldap_md5_verify(const char *plaintext, const char *password,
376 const char *user __attr_unused__)
377 {
378 unsigned char md5_digest[16];
379 buffer_t *buf;
380 const char *data;
381 size_t size;
382
383 md5_get_digest(plaintext, strlen(plaintext), md5_digest);
384
385 buf = buffer_create_static(pool_datastack_create(),
386 MAX_BASE64_DECODED_SIZE(strlen(password)+1));
387
388 if (base64_decode(password, strlen(password), NULL, buf) <= 0) {
389 i_error("ldap_md5_verify(%s): failed decoding MD5 base64",
390 user);
391 return 0;
392 }
393
394 data = buffer_get_data(buf, &size);
395 if (size != 16) {
396 i_error("ldap_md5_verify(%s): invalid MD5 base64 decode", user);
397 return 0;
398 }
399
400 return memcmp(md5_digest, data, 16) == 0;
401 }
402
219 static const struct password_scheme default_schemes[] = { 403 static const struct password_scheme default_schemes[] = {
220 { "CRYPT", crypt_verify, crypt_generate }, 404 { "CRYPT", crypt_verify, crypt_generate },
221 { "MD5", md5_verify, md5_generate }, 405 { "MD5", md5_verify, md5_generate },
222 #ifdef HAVE_OPENSSL_SHA1 406 { "SHA", sha1_verify, sha1_generate },
223 { "SHA", sha_verify, NULL }, 407 { "SHA1", sha1_verify, sha1_generate },
224 { "SHA1", sha_verify, NULL }, 408 { "SMD5", smd5_verify, smd5_generate },
225 #endif 409 { "SSHA", ssha_verify, ssha_generate },
226 { "PLAIN", plain_verify, plain_generate }, 410 { "PLAIN", plain_verify, plain_generate },
411 { "CLEARTEXT", plain_verify, plain_generate },
227 { "HMAC-MD5", hmac_md5_verify, hmac_md5_generate }, 412 { "HMAC-MD5", hmac_md5_verify, hmac_md5_generate },
228 { "DIGEST-MD5", digest_md5_verify, digest_md5_generate }, 413 { "DIGEST-MD5", digest_md5_verify, digest_md5_generate },
229 { "PLAIN-MD5", plain_md5_verify, plain_md5_generate }, 414 { "PLAIN-MD5", plain_md5_verify, plain_md5_generate },
415 { "LDAP-MD5", ldap_md5_verify, ldap_md5_generate },
230 { NULL, NULL, NULL } 416 { NULL, NULL, NULL }
231 }; 417 };
232 418
233 void password_schemes_init(void) 419 void password_schemes_init(void)
234 { 420 {