]> git.sur5r.net Git - openldap/blob - contrib/slapd-modules/passwd/apr1.c
Merge remote-tracking branch 'origin/mdb.master'
[openldap] / contrib / slapd-modules / passwd / apr1.c
1 /* $OpenLDAP$ */\r
2 /*\r
3  * This file is derived from OpenLDAP Software. All of the modifications to\r
4  * OpenLDAP Software represented in the following file were developed by\r
5  * Devin J. Pohly <djpohly@gmail.com>. I have not assigned rights and/or\r
6  * interest in this work to any party. \r
7  *\r
8  * The extensions to OpenLDAP Software herein are subject to the following\r
9  * notice:\r
10  *\r
11  * Copyright 2011 Devin J. Pohly\r
12  * Portions Copyright 2011 Howard Chu\r
13  * Redistribution and use in source and binary forms, with or without\r
14  * modification, are permitted only as authorized by the OpenLDAP Public\r
15  * License. \r
16  *\r
17  * A portion of this code is used in accordance with the Beer-ware License,\r
18  * revision 42, as noted.\r
19  *\r
20  */\r
21 #include <lber.h>\r
22 #include <lber_pvt.h>\r
23 #include "lutil.h"\r
24 #include "lutil_md5.h"\r
25 #include <ac/string.h>\r
26 \r
27 #include <assert.h>\r
28 \r
29 /* the only difference between this and straight PHK is the magic */\r
30 static LUTIL_PASSWD_CHK_FUNC chk_apr1;\r
31 static LUTIL_PASSWD_HASH_FUNC hash_apr1;\r
32 static const struct berval scheme_apr1 = BER_BVC("{APR1}");\r
33 static const struct berval magic_apr1 = BER_BVC("$apr1$");\r
34 \r
35 static LUTIL_PASSWD_CHK_FUNC chk_bsdmd5;\r
36 static LUTIL_PASSWD_HASH_FUNC hash_bsdmd5;\r
37 static const struct berval scheme_bsdmd5 = BER_BVC("{BSDMD5}");\r
38 static const struct berval magic_bsdmd5 = BER_BVC("$1$");\r
39 \r
40 static const unsigned char apr64[] =\r
41         "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";\r
42 \r
43 #define APR_SALT_SIZE   8\r
44 \r
45 /* The algorithm implemented in this function was created by Poul-Henning\r
46  * Kamp and released under the following license:\r
47  * ----------------------------------------------------------------------------\r
48  * "THE BEER-WARE LICENSE" (Revision 42):\r
49  * <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you\r
50  * can do whatever you want with this stuff. If we meet some day, and you think\r
51  * this stuff is worth it, you can buy me a beer in return Poul-Henning Kamp\r
52  * ----------------------------------------------------------------------------\r
53  */\r
54 static void do_phk_hash(\r
55         const struct berval *passwd,\r
56         const struct berval *salt,\r
57         const struct berval *magic,\r
58         unsigned char *digest)\r
59 {\r
60         lutil_MD5_CTX ctx, ctx1;\r
61         int n;\r
62 \r
63         /* Start hashing */\r
64         lutil_MD5Init(&ctx);\r
65         lutil_MD5Update(&ctx, (const unsigned char *) passwd->bv_val, passwd->bv_len);\r
66         lutil_MD5Update(&ctx, (const unsigned char *) magic->bv_val, magic->bv_len);\r
67         lutil_MD5Update(&ctx, (const unsigned char *) salt->bv_val, salt->bv_len);\r
68         /* Inner hash */\r
69         lutil_MD5Init(&ctx1);\r
70         lutil_MD5Update(&ctx1, (const unsigned char *) passwd->bv_val, passwd->bv_len);\r
71         lutil_MD5Update(&ctx1, (const unsigned char *) salt->bv_val, salt->bv_len);\r
72         lutil_MD5Update(&ctx1, (const unsigned char *) passwd->bv_val, passwd->bv_len);\r
73         lutil_MD5Final(digest, &ctx1);\r
74         /* Nom start mixing things up */\r
75         for (n = passwd->bv_len; n > 0; n -= LUTIL_MD5_BYTES)\r
76                 lutil_MD5Update(&ctx, digest,\r
77                                 (n > LUTIL_MD5_BYTES ? LUTIL_MD5_BYTES : n));\r
78         memset(digest, 0, LUTIL_MD5_BYTES);\r
79         /* Curiouser and curiouser... */\r
80         for (n = passwd->bv_len; n; n >>= 1)\r
81                 if (n & 1)\r
82                         lutil_MD5Update(&ctx, digest, 1);\r
83                 else\r
84                         lutil_MD5Update(&ctx, (const unsigned char *) passwd->bv_val, 1);\r
85         lutil_MD5Final(digest, &ctx);\r
86         /*\r
87          * Repeatedly hash things into the final value. This was originally\r
88          * intended to slow the algorithm down.\r
89          */\r
90         for (n = 0; n < 1000; n++) {\r
91                 lutil_MD5Init(&ctx1);\r
92                 if (n & 1)\r
93                         lutil_MD5Update(&ctx1,\r
94                                 (const unsigned char *) passwd->bv_val, passwd->bv_len);\r
95                 else\r
96                         lutil_MD5Update(&ctx1, digest, LUTIL_MD5_BYTES);\r
97 \r
98                 if (n % 3)\r
99                         lutil_MD5Update(&ctx1,\r
100                                 (const unsigned char *) salt->bv_val, salt->bv_len);\r
101                 if (n % 7)\r
102                         lutil_MD5Update(&ctx1,\r
103                                 (const unsigned char *) passwd->bv_val, passwd->bv_len);\r
104 \r
105                 if (n & 1)\r
106                         lutil_MD5Update(&ctx1, digest, LUTIL_MD5_BYTES);\r
107                 else\r
108                         lutil_MD5Update(&ctx1,\r
109                                 (const unsigned char *) passwd->bv_val, passwd->bv_len);\r
110                 lutil_MD5Final(digest, &ctx1);\r
111         }\r
112 }\r
113 \r
114 static int chk_phk(\r
115         const struct berval *magic,\r
116         const struct berval *passwd,\r
117         const struct berval *cred,\r
118         const char **text)\r
119 {\r
120         unsigned char digest[LUTIL_MD5_BYTES];\r
121         unsigned char *orig_pass;\r
122         int rc, n;\r
123         struct berval salt;\r
124 \r
125         /* safety check */\r
126         n = LUTIL_BASE64_DECODE_LEN(passwd->bv_len);\r
127         if (n <= sizeof(digest))\r
128                 return LUTIL_PASSWD_ERR;\r
129 \r
130         /* base64 un-encode password hash */\r
131         orig_pass = (unsigned char *) ber_memalloc((size_t) (n + 1));\r
132 \r
133         if (orig_pass == NULL)\r
134                 return LUTIL_PASSWD_ERR;\r
135 \r
136         rc = lutil_b64_pton(passwd->bv_val, orig_pass, passwd->bv_len);\r
137 \r
138         if (rc <= (int) sizeof(digest)) {\r
139                 ber_memfree(orig_pass);\r
140                 return LUTIL_PASSWD_ERR;\r
141         }\r
142 \r
143         salt.bv_val = (char *) &orig_pass[sizeof(digest)];\r
144         salt.bv_len = rc - sizeof(digest);\r
145 \r
146         do_phk_hash(cred, magic, &salt, digest);\r
147 \r
148         if (text)\r
149                 *text = NULL;\r
150 \r
151         /* compare */\r
152         rc = memcmp((char *) orig_pass, (char *) digest, sizeof(digest));\r
153         ber_memfree(orig_pass);\r
154         return rc ?  LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK;\r
155 }\r
156 \r
157 static int chk_apr1(\r
158         const struct berval *scheme,\r
159         const struct berval *passwd,\r
160         const struct berval *cred,\r
161         const char **text)\r
162 {\r
163         return chk_phk(&magic_apr1, passwd, cred, text);\r
164 }\r
165 \r
166 static int chk_bsdmd5(\r
167         const struct berval *scheme,\r
168         const struct berval *passwd,\r
169         const struct berval *cred,\r
170         const char **text)\r
171 {\r
172         return chk_phk(&magic_bsdmd5, passwd, cred, text);\r
173 }\r
174 \r
175 static int hash_phk(\r
176         const struct berval *scheme,\r
177         const struct berval *magic,\r
178         const struct berval *passwd,\r
179         struct berval *hash,\r
180         const char **text)\r
181 {\r
182         unsigned char digest_buf[LUTIL_MD5_BYTES];\r
183         char salt_buf[APR_SALT_SIZE];\r
184         struct berval digest;\r
185         struct berval salt;\r
186         int n;\r
187 \r
188         digest.bv_val = (char *) digest_buf;\r
189         digest.bv_len = sizeof(digest_buf);\r
190         salt.bv_val = salt_buf;\r
191         salt.bv_len = APR_SALT_SIZE;\r
192 \r
193         /* generate random salt */\r
194         if (lutil_entropy( (unsigned char *) salt.bv_val, salt.bv_len) < 0)\r
195                 return LUTIL_PASSWD_ERR; \r
196         /* limit it to characters in the 64-char set */\r
197         for (n = 0; n < salt.bv_len; n++)\r
198                 salt.bv_val[n] = apr64[salt.bv_val[n] % (sizeof(apr64) - 1)];\r
199 \r
200         do_phk_hash(passwd, magic, &salt, digest_buf);\r
201 \r
202         if (text)\r
203                 *text = NULL;\r
204 \r
205         return lutil_passwd_string64(scheme, &digest, hash, &salt);\r
206 }\r
207 \r
208 static int hash_apr1(\r
209         const struct berval *scheme,\r
210         const struct berval *passwd,\r
211         struct berval *hash,\r
212         const char **text)\r
213 {\r
214         return hash_phk(scheme, &magic_apr1, passwd, hash, text);\r
215 }\r
216 \r
217 static int hash_bsdmd5(\r
218         const struct berval *scheme,\r
219         const struct berval *passwd,\r
220         struct berval *hash,\r
221         const char **text)\r
222 {\r
223         return hash_phk(scheme, &magic_bsdmd5, passwd, hash, text);\r
224 }\r
225 \r
226 int init_module(int argc, char *argv[]) {\r
227         int rc;\r
228         rc = lutil_passwd_add((struct berval *) &scheme_apr1, chk_apr1, hash_apr1);\r
229         if ( !rc )\r
230                 rc = lutil_passwd_add((struct berval *) &scheme_bsdmd5,\r
231                         chk_bsdmd5, hash_bsdmd5);\r
232         return rc;\r
233 }\r