diff options
author | Christian Grothoff <christian@grothoff.org> | 2018-12-08 17:35:37 +0100 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2018-12-08 17:35:37 +0100 |
commit | bcba3f58c5fc9b4a3776494d3edddceb244ab110 (patch) | |
tree | dca7d5d47d8f6bbfb0558c53fec91e51b38d5f41 | |
parent | 6bb3796f50f31bf6381c0ff0f082503597b1640f (diff) | |
download | libmicrohttpd-bcba3f58c5fc9b4a3776494d3edddceb244ab110.tar.gz libmicrohttpd-bcba3f58c5fc9b4a3776494d3edddceb244ab110.zip |
preliminary implementation for RFC 7616 support
-rw-r--r-- | ChangeLog | 4 | ||||
-rw-r--r-- | src/include/microhttpd.h | 114 | ||||
-rw-r--r-- | src/microhttpd/Makefile.am | 9 | ||||
-rw-r--r-- | src/microhttpd/digestauth.c | 779 | ||||
-rw-r--r-- | src/microhttpd/md5.c | 130 | ||||
-rw-r--r-- | src/microhttpd/md5.h | 37 | ||||
-rw-r--r-- | src/microhttpd/sha256.c | 88 | ||||
-rw-r--r-- | src/microhttpd/sha256.h | 45 |
8 files changed, 805 insertions, 401 deletions
@@ -1,3 +1,7 @@ | |||
1 | Sat Dec 8 17:34:58 CET 2018 | ||
2 | Adding support for RFC 7616, experimental, needs | ||
3 | testing and documentation still! -CG | ||
4 | |||
1 | Fri Dec 7 12:37:17 CET 2018 | 5 | Fri Dec 7 12:37:17 CET 2018 |
2 | Add option to build MHD without any threads | 6 | Add option to build MHD without any threads |
3 | and MHD_FEATURE_THREADS to test for it. -CG | 7 | and MHD_FEATURE_THREADS to test for it. -CG |
diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h index b9a9bcf9..7591bdc4 100644 --- a/src/include/microhttpd.h +++ b/src/include/microhttpd.h | |||
@@ -3192,7 +3192,30 @@ MHD_free (void *ptr); | |||
3192 | 3192 | ||
3193 | 3193 | ||
3194 | /** | 3194 | /** |
3195 | * Authenticates the authorization header sent by the client | 3195 | * Which digest algorithm should MHD use for HTTP digest authentication? |
3196 | */ | ||
3197 | enum MHD_DigestAuthAlgorithm { | ||
3198 | |||
3199 | /** | ||
3200 | * MHD should pick (currently defaults to SHA-256). | ||
3201 | */ | ||
3202 | MHD_DIGEST_ALG_AUTO = 0, | ||
3203 | |||
3204 | /** | ||
3205 | * Force use of MD5. | ||
3206 | */ | ||
3207 | MHD_DIGEST_ALG_MD5, | ||
3208 | |||
3209 | /** | ||
3210 | * Force use of SHA-256. | ||
3211 | */ | ||
3212 | MHD_DIGEST_ALG_SHA256 | ||
3213 | |||
3214 | }; | ||
3215 | |||
3216 | |||
3217 | /** | ||
3218 | * Authenticates the authorization header sent by the client. | ||
3196 | * | 3219 | * |
3197 | * @param connection The MHD connection structure | 3220 | * @param connection The MHD connection structure |
3198 | * @param realm The realm presented to the client | 3221 | * @param realm The realm presented to the client |
@@ -3200,11 +3223,39 @@ MHD_free (void *ptr); | |||
3200 | * @param password The password used in the authentication | 3223 | * @param password The password used in the authentication |
3201 | * @param nonce_timeout The amount of time for a nonce to be | 3224 | * @param nonce_timeout The amount of time for a nonce to be |
3202 | * invalid in seconds | 3225 | * invalid in seconds |
3226 | * @param algo digest algorithms allowed for verification | ||
3203 | * @return #MHD_YES if authenticated, #MHD_NO if not, | 3227 | * @return #MHD_YES if authenticated, #MHD_NO if not, |
3204 | * #MHD_INVALID_NONCE if nonce is invalid | 3228 | * #MHD_INVALID_NONCE if nonce is invalid |
3205 | * @ingroup authentication | 3229 | * @ingroup authentication |
3206 | */ | 3230 | */ |
3207 | _MHD_EXTERN int | 3231 | _MHD_EXTERN int |
3232 | MHD_digest_auth_check2 (struct MHD_Connection *connection, | ||
3233 | const char *realm, | ||
3234 | const char *username, | ||
3235 | const char *password, | ||
3236 | unsigned int nonce_timeout, | ||
3237 | enum MHD_DigestAuthAlgorithm algo); | ||
3238 | |||
3239 | |||
3240 | /** | ||
3241 | * Authenticates the authorization header sent by the client. | ||
3242 | * Uses #MHD_DIGEST_ALG_MD5 (for now, for backwards-compatibility). | ||
3243 | * Note that this MAY change to #MHD_DIGEST_ALG_AUTO in the future. | ||
3244 | * If you want to be sure you get MD5, use #MHD_digest_auth_check2() | ||
3245 | * and specifiy MD5 explicitly. | ||
3246 | * | ||
3247 | * @param connection The MHD connection structure | ||
3248 | * @param realm The realm presented to the client | ||
3249 | * @param username The username needs to be authenticated | ||
3250 | * @param password The password used in the authentication | ||
3251 | * @param nonce_timeout The amount of time for a nonce to be | ||
3252 | * invalid in seconds | ||
3253 | * @return #MHD_YES if authenticated, #MHD_NO if not, | ||
3254 | * #MHD_INVALID_NONCE if nonce is invalid | ||
3255 | * @ingroup authentication | ||
3256 | * @deprecated use MHD_digest_auth_check2() | ||
3257 | */ | ||
3258 | _MHD_EXTERN int | ||
3208 | MHD_digest_auth_check (struct MHD_Connection *connection, | 3259 | MHD_digest_auth_check (struct MHD_Connection *connection, |
3209 | const char *realm, | 3260 | const char *realm, |
3210 | const char *username, | 3261 | const char *username, |
@@ -3213,21 +3264,51 @@ MHD_digest_auth_check (struct MHD_Connection *connection, | |||
3213 | 3264 | ||
3214 | 3265 | ||
3215 | /** | 3266 | /** |
3216 | * Authenticates the authorization header sent by the client | 3267 | * Authenticates the authorization header sent by the client. |
3217 | * | 3268 | * |
3218 | * @param connection The MHD connection structure | 3269 | * @param connection The MHD connection structure |
3219 | * @param realm The realm presented to the client | 3270 | * @param realm The realm presented to the client |
3220 | * @param username The username needs to be authenticated | 3271 | * @param username The username needs to be authenticated |
3221 | * @param digest An `unsigned char *' pointer to the binary MD5 sum | 3272 | * @param digest An `unsigned char *' pointer to the binary MD5 sum |
3222 | * for the precalculated hash value "username:realm:password" | 3273 | * for the precalculated hash value "username:realm:password" |
3223 | * of #MHD_MD5_DIGEST_SIZE bytes | 3274 | * of @a digest_size bytes |
3275 | * @param digest_size number of bytes in @a digest (size must match @a algo!) | ||
3224 | * @param nonce_timeout The amount of time for a nonce to be | 3276 | * @param nonce_timeout The amount of time for a nonce to be |
3225 | * invalid in seconds | 3277 | * invalid in seconds |
3278 | * @param algo digest algorithms allowed for verification | ||
3226 | * @return #MHD_YES if authenticated, #MHD_NO if not, | 3279 | * @return #MHD_YES if authenticated, #MHD_NO if not, |
3227 | * #MHD_INVALID_NONCE if nonce is invalid | 3280 | * #MHD_INVALID_NONCE if nonce is invalid |
3228 | * @ingroup authentication | 3281 | * @ingroup authentication |
3229 | */ | 3282 | */ |
3230 | _MHD_EXTERN int | 3283 | _MHD_EXTERN int |
3284 | MHD_digest_auth_check_digest2 (struct MHD_Connection *connection, | ||
3285 | const char *realm, | ||
3286 | const char *username, | ||
3287 | const uint8_t *digest, | ||
3288 | size_t digest_size, | ||
3289 | unsigned int nonce_timeout, | ||
3290 | enum MHD_DigestAuthAlgorithm algo); | ||
3291 | |||
3292 | |||
3293 | /** | ||
3294 | * Authenticates the authorization header sent by the client | ||
3295 | * Uses #MHD_DIGEST_ALG_MD5 (required, as @a digest is of fixed | ||
3296 | * size). | ||
3297 | * | ||
3298 | * @param connection The MHD connection structure | ||
3299 | * @param realm The realm presented to the client | ||
3300 | * @param username The username needs to be authenticated | ||
3301 | * @param digest An `unsigned char *' pointer to the binary hash | ||
3302 | * for the precalculated hash value "username:realm:password"; | ||
3303 | * length must be #MHD_MD5_DIGEST_SIZE bytes | ||
3304 | * @param nonce_timeout The amount of time for a nonce to be | ||
3305 | * invalid in seconds | ||
3306 | * @return #MHD_YES if authenticated, #MHD_NO if not, | ||
3307 | * #MHD_INVALID_NONCE if nonce is invalid | ||
3308 | * @ingroup authentication | ||
3309 | * @deprecated use #MHD_digest_auth_check_digest2() | ||
3310 | */ | ||
3311 | _MHD_EXTERN int | ||
3231 | MHD_digest_auth_check_digest (struct MHD_Connection *connection, | 3312 | MHD_digest_auth_check_digest (struct MHD_Connection *connection, |
3232 | const char *realm, | 3313 | const char *realm, |
3233 | const char *username, | 3314 | const char *username, |
@@ -3239,6 +3320,32 @@ MHD_digest_auth_check_digest (struct MHD_Connection *connection, | |||
3239 | * Queues a response to request authentication from the client | 3320 | * Queues a response to request authentication from the client |
3240 | * | 3321 | * |
3241 | * @param connection The MHD connection structure | 3322 | * @param connection The MHD connection structure |
3323 | * @param realm the realm presented to the client | ||
3324 | * @param opaque string to user for opaque value | ||
3325 | * @param response reply to send; should contain the "access denied" | ||
3326 | * body; note that this function will set the "WWW Authenticate" | ||
3327 | * header and that the caller should not do this | ||
3328 | * @param signal_stale #MHD_YES if the nonce is invalid to add | ||
3329 | * 'stale=true' to the authentication header | ||
3330 | * @param algo digest algorithm to use | ||
3331 | * @return #MHD_YES on success, #MHD_NO otherwise | ||
3332 | * @ingroup authentication | ||
3333 | */ | ||
3334 | int | ||
3335 | MHD_queue_auth_fail_response2 (struct MHD_Connection *connection, | ||
3336 | const char *realm, | ||
3337 | const char *opaque, | ||
3338 | struct MHD_Response *response, | ||
3339 | int signal_stale, | ||
3340 | enum MHD_DigestAuthAlgorithm algo); | ||
3341 | |||
3342 | |||
3343 | /** | ||
3344 | * Queues a response to request authentication from the client | ||
3345 | * For now uses MD5 (for backwards-compatibility). Still, if you | ||
3346 | * need to be sure, use #MHD_queue_fail_auth_response2(). | ||
3347 | * | ||
3348 | * @param connection The MHD connection structure | ||
3242 | * @param realm The realm presented to the client | 3349 | * @param realm The realm presented to the client |
3243 | * @param opaque string to user for opaque value | 3350 | * @param opaque string to user for opaque value |
3244 | * @param response reply to send; should contain the "access denied" | 3351 | * @param response reply to send; should contain the "access denied" |
@@ -3248,6 +3355,7 @@ MHD_digest_auth_check_digest (struct MHD_Connection *connection, | |||
3248 | * 'stale=true' to the authentication header | 3355 | * 'stale=true' to the authentication header |
3249 | * @return #MHD_YES on success, #MHD_NO otherwise | 3356 | * @return #MHD_YES on success, #MHD_NO otherwise |
3250 | * @ingroup authentication | 3357 | * @ingroup authentication |
3358 | * @deprecated use MHD_queue_auth_fail_response2() | ||
3251 | */ | 3359 | */ |
3252 | _MHD_EXTERN int | 3360 | _MHD_EXTERN int |
3253 | MHD_queue_auth_fail_response (struct MHD_Connection *connection, | 3361 | MHD_queue_auth_fail_response (struct MHD_Connection *connection, |
diff --git a/src/microhttpd/Makefile.am b/src/microhttpd/Makefile.am index 2c59876a..22b6100d 100644 --- a/src/microhttpd/Makefile.am +++ b/src/microhttpd/Makefile.am | |||
@@ -133,7 +133,8 @@ endif | |||
133 | if ENABLE_DAUTH | 133 | if ENABLE_DAUTH |
134 | libmicrohttpd_la_SOURCES += \ | 134 | libmicrohttpd_la_SOURCES += \ |
135 | digestauth.c \ | 135 | digestauth.c \ |
136 | md5.c md5.h | 136 | md5.c md5.h \ |
137 | sha256.c sha256.h | ||
137 | endif | 138 | endif |
138 | 139 | ||
139 | if ENABLE_BAUTH | 140 | if ENABLE_BAUTH |
@@ -160,18 +161,18 @@ check_PROGRAMS = \ | |||
160 | 161 | ||
161 | if HAVE_POSIX_THREADS | 162 | if HAVE_POSIX_THREADS |
162 | if ENABLE_UPGRADE | 163 | if ENABLE_UPGRADE |
163 | if USE_POSIX_THREADS | 164 | if USE_POSIX_THREADS |
164 | check_PROGRAMS += test_upgrade | 165 | check_PROGRAMS += test_upgrade |
165 | endif | 166 | endif |
166 | if USE_W32_THREADS | 167 | if USE_W32_THREADS |
167 | check_PROGRAMS += test_upgrade | 168 | check_PROGRAMS += test_upgrade |
168 | endif | 169 | endif |
169 | if ENABLE_HTTPS | 170 | if ENABLE_HTTPS |
170 | if USE_POSIX_THREADS | 171 | if USE_POSIX_THREADS |
171 | check_PROGRAMS += test_upgrade_tls | 172 | check_PROGRAMS += test_upgrade_tls |
172 | endif | 173 | endif |
173 | if USE_W32_THREADS | 174 | if USE_W32_THREADS |
174 | check_PROGRAMS += test_upgrade_tls | 175 | check_PROGRAMS += test_upgrade_tls |
175 | endif | 176 | endif |
176 | endif | 177 | endif |
177 | endif | 178 | endif |
diff --git a/src/microhttpd/digestauth.c b/src/microhttpd/digestauth.c index 80cba836..424c3761 100644 --- a/src/microhttpd/digestauth.c +++ b/src/microhttpd/digestauth.c | |||
@@ -21,11 +21,13 @@ | |||
21 | * @brief Implements HTTP digest authentication | 21 | * @brief Implements HTTP digest authentication |
22 | * @author Amr Ali | 22 | * @author Amr Ali |
23 | * @author Matthieu Speder | 23 | * @author Matthieu Speder |
24 | * @author Christian Grothoff (RFC 7616 support) | ||
24 | */ | 25 | */ |
25 | #include "platform.h" | 26 | #include "platform.h" |
26 | #include "mhd_limits.h" | 27 | #include "mhd_limits.h" |
27 | #include "internal.h" | 28 | #include "internal.h" |
28 | #include "md5.h" | 29 | #include "md5.h" |
30 | #include "sha256.h" | ||
29 | #include "mhd_mono_clock.h" | 31 | #include "mhd_mono_clock.h" |
30 | #include "mhd_str.h" | 32 | #include "mhd_str.h" |
31 | #include "mhd_compat.h" | 33 | #include "mhd_compat.h" |
@@ -37,13 +39,18 @@ | |||
37 | #include <windows.h> | 39 | #include <windows.h> |
38 | #endif /* MHD_W32_MUTEX_ */ | 40 | #endif /* MHD_W32_MUTEX_ */ |
39 | 41 | ||
40 | #define HASH_MD5_HEX_LEN (2 * MHD_MD5_DIGEST_SIZE) | 42 | /** |
41 | /* 32 bit value is 4 bytes */ | 43 | * 32 bit value is 4 bytes |
44 | */ | ||
42 | #define TIMESTAMP_BIN_SIZE 4 | 45 | #define TIMESTAMP_BIN_SIZE 4 |
43 | #define TIMESTAMP_HEX_LEN (2 * TIMESTAMP_BIN_SIZE) | ||
44 | 46 | ||
45 | /* Standard server nonce length, not including terminating null */ | 47 | /** |
46 | #define NONCE_STD_LEN (HASH_MD5_HEX_LEN + TIMESTAMP_HEX_LEN) | 48 | * Standard server nonce length, not including terminating null, |
49 | * | ||
50 | * @param digest_size digest size | ||
51 | */ | ||
52 | #define NONCE_STD_LEN(digest_size) \ | ||
53 | ((digest_size) * 2 + TIMESTAMP_BIN_SIZE * 2) | ||
47 | 54 | ||
48 | /** | 55 | /** |
49 | * Beginning string for any valid Digest authentication header. | 56 | * Beginning string for any valid Digest authentication header. |
@@ -63,7 +70,66 @@ | |||
63 | /** | 70 | /** |
64 | * Maximum length of the response in digest authentication. | 71 | * Maximum length of the response in digest authentication. |
65 | */ | 72 | */ |
66 | #define MAX_AUTH_RESPONSE_LENGTH 128 | 73 | #define MAX_AUTH_RESPONSE_LENGTH 256 |
74 | |||
75 | |||
76 | /** | ||
77 | * Context passed to functions that need to calculate | ||
78 | * a digest but are orthogonal to the specific | ||
79 | * algorithm. | ||
80 | */ | ||
81 | struct DigestAlgorithm | ||
82 | { | ||
83 | /** | ||
84 | * Size of the final digest returned by @e digest. | ||
85 | */ | ||
86 | unsigned int digest_size; | ||
87 | |||
88 | /** | ||
89 | * A context for the digest algorithm, already initialized to be | ||
90 | * useful for @e init, @e update and @e digest. | ||
91 | */ | ||
92 | void *ctx; | ||
93 | |||
94 | /** | ||
95 | * Name of the algorithm, "md5" or "sha-256" | ||
96 | */ | ||
97 | const char *alg; | ||
98 | |||
99 | /** | ||
100 | * Buffer of @e digest_size * 2 + 1 bytes. | ||
101 | */ | ||
102 | char *sessionkey; | ||
103 | |||
104 | /** | ||
105 | * Call to initialize @e ctx. | ||
106 | */ | ||
107 | void | ||
108 | (*init)(void *ctx); | ||
109 | |||
110 | /** | ||
111 | * Feed more data into the digest function. | ||
112 | * | ||
113 | * @param ctx context to feed | ||
114 | * @param length number of bytes in @a data | ||
115 | * @param data data to add | ||
116 | */ | ||
117 | void | ||
118 | (*update)(void *ctx, | ||
119 | const uint8_t *data, | ||
120 | size_t length); | ||
121 | |||
122 | /** | ||
123 | * Compute final @a digest. | ||
124 | * | ||
125 | * @param ctx context to use | ||
126 | * @param digest[out] where to write the result, | ||
127 | * must be @e digest_length bytes long | ||
128 | */ | ||
129 | void | ||
130 | (*digest)(void *ctx, | ||
131 | uint8_t *digest); | ||
132 | }; | ||
67 | 133 | ||
68 | 134 | ||
69 | /** | 135 | /** |
@@ -97,54 +163,57 @@ cvthex (const unsigned char *bin, | |||
97 | * and store the * result in 'sessionkey'. | 163 | * and store the * result in 'sessionkey'. |
98 | * | 164 | * |
99 | * @param alg The hash algorithm used, can be "md5" or "md5-sess" | 165 | * @param alg The hash algorithm used, can be "md5" or "md5-sess" |
166 | * or "sha-256" or "sha-256-sess" | ||
167 | * Note that the rest of the code does not support the the "-sess" variants! | ||
168 | * @param da[in,out] digest implementation, must match @a alg; the | ||
169 | * da->sessionkey will be initialized to the digest in HEX | ||
100 | * @param digest An `unsigned char *' pointer to the binary MD5 sum | 170 | * @param digest An `unsigned char *' pointer to the binary MD5 sum |
101 | * for the precalculated hash value "username:realm:password" | 171 | * for the precalculated hash value "username:realm:password" |
102 | * of #MHD_MD5_DIGEST_SIZE bytes | 172 | * of #MHD_MD5_DIGEST_SIZE or #MHD_SHA256_DIGEST_SIZE bytes |
103 | * @param nonce A `char *' pointer to the nonce value | 173 | * @param nonce A `char *' pointer to the nonce value |
104 | * @param cnonce A `char *' pointer to the cnonce value | 174 | * @param cnonce A `char *' pointer to the cnonce value |
105 | * @param sessionkey pointer to buffer of HASH_MD5_HEX_LEN+1 bytes | ||
106 | */ | 175 | */ |
107 | static void | 176 | static void |
108 | digest_calc_ha1_from_digest (const char *alg, | 177 | digest_calc_ha1_from_digest (const char *alg, |
109 | const uint8_t digest[MHD_MD5_DIGEST_SIZE], | 178 | struct DigestAlgorithm *da, |
179 | const uint8_t *digest, | ||
110 | const char *nonce, | 180 | const char *nonce, |
111 | const char *cnonce, | 181 | const char *cnonce) |
112 | char sessionkey[HASH_MD5_HEX_LEN + 1]) | ||
113 | { | 182 | { |
114 | struct MD5Context md5; | 183 | if ( (MHD_str_equal_caseless_(alg, |
115 | 184 | "md5-sess")) || | |
116 | if (MHD_str_equal_caseless_(alg, | 185 | (MHD_str_equal_caseless_(alg, |
117 | "md5-sess")) | 186 | "sha-256-sess")) ) |
118 | { | 187 | { |
119 | unsigned char ha1[MHD_MD5_DIGEST_SIZE]; | 188 | uint8_t dig[da->digest_size]; |
120 | 189 | ||
121 | MD5Init (&md5); | 190 | da->init (da->ctx); |
122 | MD5Update (&md5, | 191 | da->update (da->ctx, |
123 | digest, | 192 | digest, |
124 | MHD_MD5_DIGEST_SIZE); | 193 | MHD_MD5_DIGEST_SIZE); |
125 | MD5Update (&md5, | 194 | da->update (da->ctx, |
195 | (const unsigned char *) ":", | ||
196 | 1); | ||
197 | da->update (da->ctx, | ||
198 | (const unsigned char *) nonce, | ||
199 | strlen (nonce)); | ||
200 | da->update (da->ctx, | ||
126 | (const unsigned char *) ":", | 201 | (const unsigned char *) ":", |
127 | 1); | 202 | 1); |
128 | MD5Update (&md5, | 203 | da->update (da->ctx, |
129 | (const unsigned char *) nonce, | 204 | (const unsigned char *) cnonce, |
130 | strlen (nonce)); | 205 | strlen (cnonce)); |
131 | MD5Update (&md5, | 206 | da->digest (da->ctx, |
132 | (const unsigned char *) ":", | 207 | dig); |
133 | 1); | 208 | cvthex (dig, |
134 | MD5Update (&md5, | 209 | sizeof (dig), |
135 | (const unsigned char *) cnonce, | 210 | da->sessionkey); |
136 | strlen (cnonce)); | ||
137 | MD5Final (ha1, | ||
138 | &md5); | ||
139 | cvthex (ha1, | ||
140 | sizeof (ha1), | ||
141 | sessionkey); | ||
142 | } | 211 | } |
143 | else | 212 | else |
144 | { | 213 | { |
145 | cvthex (digest, | 214 | cvthex (digest, |
146 | MHD_MD5_DIGEST_SIZE, | 215 | da->digest_size, |
147 | sessionkey); | 216 | da->sessionkey); |
148 | } | 217 | } |
149 | } | 218 | } |
150 | 219 | ||
@@ -154,12 +223,14 @@ digest_calc_ha1_from_digest (const char *alg, | |||
154 | * and store the result in 'sessionkey'. | 223 | * and store the result in 'sessionkey'. |
155 | * | 224 | * |
156 | * @param alg The hash algorithm used, can be "md5" or "md5-sess" | 225 | * @param alg The hash algorithm used, can be "md5" or "md5-sess" |
226 | * or "sha-256" or "sha-256-sess" | ||
157 | * @param username A `char *' pointer to the username value | 227 | * @param username A `char *' pointer to the username value |
158 | * @param realm A `char *' pointer to the realm value | 228 | * @param realm A `char *' pointer to the realm value |
159 | * @param password A `char *' pointer to the password value | 229 | * @param password A `char *' pointer to the password value |
160 | * @param nonce A `char *' pointer to the nonce value | 230 | * @param nonce A `char *' pointer to the nonce value |
161 | * @param cnonce A `char *' pointer to the cnonce value | 231 | * @param cnonce A `char *' pointer to the cnonce value |
162 | * @param sessionkey pointer to buffer of HASH_MD5_HEX_LEN+1 bytes | 232 | * @param da[in,out] digest algorithm to use, and where to write |
233 | * the sessionkey to | ||
163 | */ | 234 | */ |
164 | static void | 235 | static void |
165 | digest_calc_ha1_from_user (const char *alg, | 236 | digest_calc_ha1_from_user (const char *alg, |
@@ -168,52 +239,54 @@ digest_calc_ha1_from_user (const char *alg, | |||
168 | const char *password, | 239 | const char *password, |
169 | const char *nonce, | 240 | const char *nonce, |
170 | const char *cnonce, | 241 | const char *cnonce, |
171 | char sessionkey[HASH_MD5_HEX_LEN + 1]) | 242 | struct DigestAlgorithm *da) |
172 | { | 243 | { |
173 | struct MD5Context md5; | 244 | unsigned char ha1[da->digest_size]; |
174 | unsigned char ha1[MHD_MD5_DIGEST_SIZE]; | ||
175 | 245 | ||
176 | MD5Init (&md5); | 246 | da->init (da->ctx); |
177 | MD5Update (&md5, | 247 | da->update (da->ctx, |
178 | (const unsigned char *) username, | 248 | (const unsigned char *) username, |
179 | strlen (username)); | 249 | strlen (username)); |
180 | MD5Update (&md5, | 250 | da->update (da->ctx, |
181 | (const unsigned char *) ":", | 251 | (const unsigned char *) ":", |
182 | 1); | 252 | 1); |
183 | MD5Update (&md5, | 253 | da->update (da->ctx, |
184 | (const unsigned char *) realm, | 254 | (const unsigned char *) realm, |
185 | strlen (realm)); | 255 | strlen (realm)); |
186 | MD5Update (&md5, | 256 | da->update (da->ctx, |
187 | (const unsigned char *) ":", | 257 | (const unsigned char *) ":", |
188 | 1); | 258 | 1); |
189 | MD5Update (&md5, | 259 | da->update (da->ctx, |
190 | (const unsigned char *) password, | 260 | (const unsigned char *) password, |
191 | strlen (password)); | 261 | strlen (password)); |
192 | MD5Final (ha1, | 262 | da->digest (da->ctx, |
193 | &md5); | 263 | ha1); |
194 | digest_calc_ha1_from_digest(alg, | 264 | digest_calc_ha1_from_digest (alg, |
195 | ha1, | 265 | da, |
196 | nonce, | 266 | ha1, |
197 | cnonce, | 267 | nonce, |
198 | sessionkey); | 268 | cnonce); |
199 | } | 269 | } |
200 | 270 | ||
201 | 271 | ||
202 | /** | 272 | /** |
203 | * Calculate request-digest/response-digest as per RFC2617 spec | 273 | * Calculate request-digest/response-digest as per RFC2617 / RFC7616 |
274 | * spec. | ||
204 | * | 275 | * |
205 | * @param ha1 H(A1) | 276 | * @param ha1 H(A1), twice the @a da->digest_size + 1 bytes (0-terminated), |
277 | * MUST NOT be aliased with `da->sessionkey`! | ||
206 | * @param nonce nonce from server | 278 | * @param nonce nonce from server |
207 | * @param noncecount 8 hex digits | 279 | * @param noncecount 8 hex digits |
208 | * @param cnonce client nonce | 280 | * @param cnonce client nonce |
209 | * @param qop qop-value: "", "auth" or "auth-int" | 281 | * @param qop qop-value: "", "auth" or "auth-int" (NOTE: only 'auth' is supported today.) |
210 | * @param method method from request | 282 | * @param method method from request |
211 | * @param uri requested URL | 283 | * @param uri requested URL |
212 | * @param hentity H(entity body) if qop="auth-int" | 284 | * @param hentity H(entity body) if qop="auth-int" |
213 | * @param response request-digest or response-digest | 285 | * @param da[in,out] digest algorithm to use, also |
286 | * we write da->sessionkey (set to response request-digest or response-digest) | ||
214 | */ | 287 | */ |
215 | static void | 288 | static void |
216 | digest_calc_response (const char ha1[HASH_MD5_HEX_LEN + 1], | 289 | digest_calc_response (const char *ha1, |
217 | const char *nonce, | 290 | const char *nonce, |
218 | const char *noncecount, | 291 | const char *noncecount, |
219 | const char *cnonce, | 292 | const char *cnonce, |
@@ -221,87 +294,85 @@ digest_calc_response (const char ha1[HASH_MD5_HEX_LEN + 1], | |||
221 | const char *method, | 294 | const char *method, |
222 | const char *uri, | 295 | const char *uri, |
223 | const char *hentity, | 296 | const char *hentity, |
224 | char response[HASH_MD5_HEX_LEN + 1]) | 297 | struct DigestAlgorithm *da) |
225 | { | 298 | { |
226 | struct MD5Context md5; | 299 | unsigned char ha2[da->digest_size]; |
227 | unsigned char ha2[MHD_MD5_DIGEST_SIZE]; | 300 | unsigned char resphash[da->digest_size]; |
228 | unsigned char resphash[MHD_MD5_DIGEST_SIZE]; | 301 | (void)hentity; /* Unused. Silence compiler warning. */ |
229 | char ha2hex[HASH_MD5_HEX_LEN + 1]; | 302 | |
230 | (void)hentity; /* Unused. Silent compiler warning. */ | 303 | da->init (da->ctx); |
231 | 304 | da->update (da->ctx, | |
232 | MD5Init (&md5); | 305 | (const unsigned char *) method, |
233 | MD5Update (&md5, | 306 | strlen (method)); |
234 | (const unsigned char *) method, | 307 | da->update (da->ctx, |
235 | strlen (method)); | 308 | (const unsigned char *) ":", |
236 | MD5Update (&md5, | 309 | 1); |
237 | (const unsigned char *) ":", | 310 | da->update (da->ctx, |
238 | 1); | ||
239 | MD5Update (&md5, | ||
240 | (const unsigned char *) uri, | 311 | (const unsigned char *) uri, |
241 | strlen (uri)); | 312 | strlen (uri)); |
242 | #if 0 | 313 | #if 0 |
243 | if (0 == strcasecmp(qop, | 314 | if (0 == strcasecmp (qop, |
244 | "auth-int")) | 315 | "auth-int")) |
245 | { | 316 | { |
246 | /* This is dead code since the rest of this module does | 317 | /* This is dead code since the rest of this module does |
247 | not support auth-int. */ | 318 | not support auth-int. */ |
248 | MD5Update (&md5, | 319 | da->update (da->ctx, |
249 | ":", | 320 | ":", |
250 | 1); | 321 | 1); |
251 | if (NULL != hentity) | 322 | if (NULL != hentity) |
252 | MD5Update (&md5, | 323 | da->update (da->ctx, |
253 | hentity, | 324 | hentity, |
254 | strlen (hentity)); | 325 | strlen (hentity)); |
255 | } | 326 | } |
256 | #endif | 327 | #endif |
257 | MD5Final (ha2, | 328 | da->digest (da->ctx, |
258 | &md5); | 329 | ha2); |
259 | cvthex (ha2, | 330 | cvthex (ha2, |
260 | MHD_MD5_DIGEST_SIZE, | 331 | da->digest_size, |
261 | ha2hex); | 332 | da->sessionkey); |
262 | MD5Init (&md5); | 333 | da->init (da->ctx); |
263 | /* calculate response */ | 334 | /* calculate response */ |
264 | MD5Update (&md5, | 335 | da->update (da->ctx, |
265 | (const unsigned char *) ha1, | 336 | (const unsigned char *) ha1, |
266 | HASH_MD5_HEX_LEN); | 337 | da->digest_size * 2); |
267 | MD5Update (&md5, | 338 | da->update (da->ctx, |
268 | (const unsigned char *) ":", | 339 | (const unsigned char *) ":", |
269 | 1); | 340 | 1); |
270 | MD5Update (&md5, | 341 | da->update (da->ctx, |
271 | (const unsigned char *) nonce, | 342 | (const unsigned char *) nonce, |
272 | strlen (nonce)); | 343 | strlen (nonce)); |
273 | MD5Update (&md5, | 344 | da->update (da->ctx, |
274 | (const unsigned char*) ":", | 345 | (const unsigned char*) ":", |
275 | 1); | 346 | 1); |
276 | if ('\0' != *qop) | 347 | if ('\0' != *qop) |
277 | { | 348 | { |
278 | MD5Update (&md5, | 349 | da->update (da->ctx, |
279 | (const unsigned char *) noncecount, | 350 | (const unsigned char *) noncecount, |
280 | strlen (noncecount)); | 351 | strlen (noncecount)); |
281 | MD5Update (&md5, | 352 | da->update (da->ctx, |
282 | (const unsigned char *) ":", | 353 | (const unsigned char *) ":", |
283 | 1); | 354 | 1); |
284 | MD5Update (&md5, | 355 | da->update (da->ctx, |
285 | (const unsigned char *) cnonce, | 356 | (const unsigned char *) cnonce, |
286 | strlen (cnonce)); | 357 | strlen (cnonce)); |
287 | MD5Update (&md5, | 358 | da->update (da->ctx, |
288 | (const unsigned char *) ":", | 359 | (const unsigned char *) ":", |
289 | 1); | 360 | 1); |
290 | MD5Update (&md5, | 361 | da->update (da->ctx, |
291 | (const unsigned char *) qop, | 362 | (const unsigned char *) qop, |
292 | strlen (qop)); | 363 | strlen (qop)); |
293 | MD5Update (&md5, | 364 | da->update (da->ctx, |
294 | (const unsigned char *) ":", | 365 | (const unsigned char *) ":", |
295 | 1); | 366 | 1); |
296 | } | 367 | } |
297 | MD5Update (&md5, | 368 | da->update (da->ctx, |
298 | (const unsigned char *) ha2hex, | 369 | (const unsigned char *) da->sessionkey, |
299 | HASH_MD5_HEX_LEN); | 370 | da->digest_size * 2); |
300 | MD5Final (resphash, | 371 | da->digest (da->ctx, |
301 | &md5); | 372 | resphash); |
302 | cvthex (resphash, | 373 | cvthex (resphash, |
303 | sizeof(resphash), | 374 | sizeof(resphash), |
304 | response); | 375 | da->sessionkey); |
305 | } | 376 | } |
306 | 377 | ||
307 | 378 | ||
@@ -552,7 +623,9 @@ MHD_digest_auth_get_username(struct MHD_Connection *connection) | |||
552 | * @param rnd_size The size of the random seed array @a rnd | 623 | * @param rnd_size The size of the random seed array @a rnd |
553 | * @param uri HTTP URI (in MHD, without the arguments ("?k=v") | 624 | * @param uri HTTP URI (in MHD, without the arguments ("?k=v") |
554 | * @param realm A string of characters that describes the realm of auth. | 625 | * @param realm A string of characters that describes the realm of auth. |
555 | * @param nonce A pointer to a character array for the nonce to put in | 626 | * @param da digest algorithm to use |
627 | * @param nonce A pointer to a character array for the nonce to put in, | ||
628 | * must provide NONCE_STD_LEN(da->digest_size)+1 bytes | ||
556 | */ | 629 | */ |
557 | static void | 630 | static void |
558 | calculate_nonce (uint32_t nonce_time, | 631 | calculate_nonce (uint32_t nonce_time, |
@@ -561,48 +634,48 @@ calculate_nonce (uint32_t nonce_time, | |||
561 | size_t rnd_size, | 634 | size_t rnd_size, |
562 | const char *uri, | 635 | const char *uri, |
563 | const char *realm, | 636 | const char *realm, |
564 | char nonce[NONCE_STD_LEN + 1]) | 637 | struct DigestAlgorithm *da, |
638 | char *nonce) | ||
565 | { | 639 | { |
566 | struct MD5Context md5; | ||
567 | unsigned char timestamp[TIMESTAMP_BIN_SIZE]; | 640 | unsigned char timestamp[TIMESTAMP_BIN_SIZE]; |
568 | unsigned char tmpnonce[MHD_MD5_DIGEST_SIZE]; | 641 | unsigned char tmpnonce[da->digest_size]; |
569 | char timestamphex[TIMESTAMP_HEX_LEN + 1]; | 642 | char timestamphex[TIMESTAMP_BIN_SIZE * 2 + 1]; |
570 | 643 | ||
571 | MD5Init (&md5); | 644 | da->init (da->ctx); |
572 | timestamp[0] = (unsigned char)((nonce_time & 0xff000000) >> 0x18); | 645 | timestamp[0] = (unsigned char)((nonce_time & 0xff000000) >> 0x18); |
573 | timestamp[1] = (unsigned char)((nonce_time & 0x00ff0000) >> 0x10); | 646 | timestamp[1] = (unsigned char)((nonce_time & 0x00ff0000) >> 0x10); |
574 | timestamp[2] = (unsigned char)((nonce_time & 0x0000ff00) >> 0x08); | 647 | timestamp[2] = (unsigned char)((nonce_time & 0x0000ff00) >> 0x08); |
575 | timestamp[3] = (unsigned char)((nonce_time & 0x000000ff)); | 648 | timestamp[3] = (unsigned char)((nonce_time & 0x000000ff)); |
576 | MD5Update (&md5, | 649 | da->update (da->ctx, |
577 | timestamp, | 650 | timestamp, |
578 | sizeof (timestamp)); | 651 | sizeof (timestamp)); |
579 | MD5Update (&md5, | 652 | da->update (da->ctx, |
580 | (const unsigned char *) ":", | 653 | (const unsigned char *) ":", |
581 | 1); | 654 | 1); |
582 | MD5Update (&md5, | 655 | da->update (da->ctx, |
583 | (const unsigned char *) method, | 656 | (const unsigned char *) method, |
584 | strlen (method)); | 657 | strlen (method)); |
585 | MD5Update (&md5, | 658 | da->update (da->ctx, |
586 | (const unsigned char *) ":", | 659 | (const unsigned char *) ":", |
587 | 1); | 660 | 1); |
588 | if (rnd_size > 0) | 661 | if (rnd_size > 0) |
589 | MD5Update (&md5, | 662 | da->update (da->ctx, |
590 | (const unsigned char *) rnd, | 663 | (const unsigned char *) rnd, |
591 | rnd_size); | 664 | rnd_size); |
592 | MD5Update (&md5, | 665 | da->update (da->ctx, |
593 | (const unsigned char *) ":", | 666 | (const unsigned char *) ":", |
594 | 1); | 667 | 1); |
595 | MD5Update (&md5, | 668 | da->update (da->ctx, |
596 | (const unsigned char *) uri, | 669 | (const unsigned char *) uri, |
597 | strlen (uri)); | 670 | strlen (uri)); |
598 | MD5Update (&md5, | 671 | da->update (da->ctx, |
599 | (const unsigned char *) ":", | 672 | (const unsigned char *) ":", |
600 | 1); | 673 | 1); |
601 | MD5Update (&md5, | 674 | da->update (da->ctx, |
602 | (const unsigned char *) realm, | 675 | (const unsigned char *) realm, |
603 | strlen (realm)); | 676 | strlen (realm)); |
604 | MD5Final (tmpnonce, | 677 | da->digest (da->ctx, |
605 | &md5); | 678 | tmpnonce); |
606 | cvthex (tmpnonce, | 679 | cvthex (tmpnonce, |
607 | sizeof (tmpnonce), | 680 | sizeof (tmpnonce), |
608 | nonce); | 681 | nonce); |
@@ -713,12 +786,15 @@ check_argument_match (struct MHD_Connection *connection, | |||
713 | * Authenticates the authorization header sent by the client | 786 | * Authenticates the authorization header sent by the client |
714 | * | 787 | * |
715 | * @param connection The MHD connection structure | 788 | * @param connection The MHD connection structure |
789 | * @param da[in,out] digest algorithm to use for checking (written to as | ||
790 | * part of the calculations, but the values left in the struct | ||
791 | * are not actually expected to be useful for the caller) | ||
716 | * @param realm The realm presented to the client | 792 | * @param realm The realm presented to the client |
717 | * @param username The username needs to be authenticated | 793 | * @param username The username needs to be authenticated |
718 | * @param password The password used in the authentication | 794 | * @param password The password used in the authentication |
719 | * @param digest An optional `unsigned char *' pointer to the binary MD5 sum | 795 | * @param digest An optional binary hash |
720 | * for the precalculated hash value "username:realm:password" | 796 | * of the precalculated hash value "username:realm:password" |
721 | * of #MHD_MD5_DIGEST_SIZE bytes | 797 | * (must contain "da->digest_size" bytes or be NULL) |
722 | * @param nonce_timeout The amount of time for a nonce to be | 798 | * @param nonce_timeout The amount of time for a nonce to be |
723 | * invalid in seconds | 799 | * invalid in seconds |
724 | * @return #MHD_YES if authenticated, #MHD_NO if not, | 800 | * @return #MHD_YES if authenticated, #MHD_NO if not, |
@@ -727,10 +803,11 @@ check_argument_match (struct MHD_Connection *connection, | |||
727 | */ | 803 | */ |
728 | static int | 804 | static int |
729 | digest_auth_check_all (struct MHD_Connection *connection, | 805 | digest_auth_check_all (struct MHD_Connection *connection, |
806 | struct DigestAlgorithm *da, | ||
730 | const char *realm, | 807 | const char *realm, |
731 | const char *username, | 808 | const char *username, |
732 | const char *password, | 809 | const char *password, |
733 | const uint8_t digest[MHD_MD5_DIGEST_SIZE], | 810 | const uint8_t *digest, |
734 | unsigned int nonce_timeout) | 811 | unsigned int nonce_timeout) |
735 | { | 812 | { |
736 | struct MHD_Daemon *daemon = connection->daemon; | 813 | struct MHD_Daemon *daemon = connection->daemon; |
@@ -738,13 +815,12 @@ digest_auth_check_all (struct MHD_Connection *connection, | |||
738 | const char *header; | 815 | const char *header; |
739 | char nonce[MAX_NONCE_LENGTH]; | 816 | char nonce[MAX_NONCE_LENGTH]; |
740 | char cnonce[MAX_NONCE_LENGTH]; | 817 | char cnonce[MAX_NONCE_LENGTH]; |
818 | char ha1[da->digest_size * 2 + 1]; | ||
741 | char qop[15]; /* auth,auth-int */ | 819 | char qop[15]; /* auth,auth-int */ |
742 | char nc[20]; | 820 | char nc[20]; |
743 | char response[MAX_AUTH_RESPONSE_LENGTH]; | 821 | char response[MAX_AUTH_RESPONSE_LENGTH]; |
744 | const char *hentity = NULL; /* "auth-int" is not supported */ | 822 | const char *hentity = NULL; /* "auth-int" is not supported */ |
745 | char ha1[HASH_MD5_HEX_LEN + 1]; | 823 | char noncehashexp[NONCE_STD_LEN(da->digest_size) + 1]; |
746 | char respexp[HASH_MD5_HEX_LEN + 1]; | ||
747 | char noncehashexp[NONCE_STD_LEN + 1]; | ||
748 | uint32_t nonce_time; | 824 | uint32_t nonce_time; |
749 | uint32_t t; | 825 | uint32_t t; |
750 | size_t left; /* number of characters left in 'header' for 'uri' */ | 826 | size_t left; /* number of characters left in 'header' for 'uri' */ |
@@ -807,9 +883,9 @@ digest_auth_check_all (struct MHD_Connection *connection, | |||
807 | header value. */ | 883 | header value. */ |
808 | return MHD_NO; | 884 | return MHD_NO; |
809 | } | 885 | } |
810 | if (TIMESTAMP_HEX_LEN != | 886 | if (TIMESTAMP_BIN_SIZE * 2 != |
811 | MHD_strx_to_uint32_n_ (nonce + len - TIMESTAMP_HEX_LEN, | 887 | MHD_strx_to_uint32_n_ (nonce + len - TIMESTAMP_BIN_SIZE * 2, |
812 | TIMESTAMP_HEX_LEN, | 888 | TIMESTAMP_BIN_SIZE * 2, |
813 | &nonce_time)) | 889 | &nonce_time)) |
814 | { | 890 | { |
815 | #ifdef HAVE_MESSAGES | 891 | #ifdef HAVE_MESSAGES |
@@ -837,6 +913,7 @@ digest_auth_check_all (struct MHD_Connection *connection, | |||
837 | daemon->digest_auth_rand_size, | 913 | daemon->digest_auth_rand_size, |
838 | connection->url, | 914 | connection->url, |
839 | realm, | 915 | realm, |
916 | da, | ||
840 | noncehashexp); | 917 | noncehashexp); |
841 | /* | 918 | /* |
842 | * Second level vetting for the nonce validity | 919 | * Second level vetting for the nonce validity |
@@ -848,7 +925,8 @@ digest_auth_check_all (struct MHD_Connection *connection, | |||
848 | * very hard to achieve. | 925 | * very hard to achieve. |
849 | */ | 926 | */ |
850 | 927 | ||
851 | if (0 != strcmp (nonce, noncehashexp)) | 928 | if (0 != strcmp (nonce, |
929 | noncehashexp)) | ||
852 | { | 930 | { |
853 | return MHD_INVALID_NONCE; | 931 | return MHD_INVALID_NONCE; |
854 | } | 932 | } |
@@ -908,40 +986,45 @@ digest_auth_check_all (struct MHD_Connection *connection, | |||
908 | 986 | ||
909 | uri = malloc (left + 1); | 987 | uri = malloc (left + 1); |
910 | if (NULL == uri) | 988 | if (NULL == uri) |
911 | { | 989 | { |
912 | #ifdef HAVE_MESSAGES | 990 | #ifdef HAVE_MESSAGES |
913 | MHD_DLOG(daemon, | 991 | MHD_DLOG(daemon, |
914 | _("Failed to allocate memory for auth header processing\n")); | 992 | _("Failed to allocate memory for auth header processing\n")); |
915 | #endif /* HAVE_MESSAGES */ | 993 | #endif /* HAVE_MESSAGES */ |
916 | return MHD_NO; | 994 | return MHD_NO; |
917 | } | 995 | } |
918 | if (0 == lookup_sub_value (uri, | 996 | if (0 == lookup_sub_value (uri, |
919 | left + 1, | 997 | left + 1, |
920 | header, | 998 | header, |
921 | "uri")) | 999 | "uri")) |
922 | { | 1000 | { |
923 | free (uri); | 1001 | free (uri); |
924 | return MHD_NO; | 1002 | return MHD_NO; |
925 | } | 1003 | } |
926 | |||
927 | if (NULL != digest) | 1004 | if (NULL != digest) |
928 | { | 1005 | { |
929 | digest_calc_ha1_from_digest ("md5", | 1006 | /* This will initialize da->sessionkey (ha1) */ |
1007 | digest_calc_ha1_from_digest (da->alg, | ||
1008 | da, | ||
930 | digest, | 1009 | digest, |
931 | nonce, | 1010 | nonce, |
932 | cnonce, | 1011 | cnonce); |
933 | ha1); | ||
934 | } | 1012 | } |
935 | else | 1013 | else |
936 | { | 1014 | { |
937 | digest_calc_ha1_from_user ("md5", | 1015 | /* This will initialize da->sessionkey (ha1) */ |
1016 | digest_calc_ha1_from_user (da->alg, | ||
938 | username, | 1017 | username, |
939 | realm, | 1018 | realm, |
940 | password, | 1019 | password, |
941 | nonce, | 1020 | nonce, |
942 | cnonce, | 1021 | cnonce, |
943 | ha1); | 1022 | da); |
944 | } | 1023 | } |
1024 | memcpy (ha1, | ||
1025 | da->sessionkey, | ||
1026 | sizeof (ha1)); | ||
1027 | /* This will initialize da->sessionkey (respexp) */ | ||
945 | digest_calc_response (ha1, | 1028 | digest_calc_response (ha1, |
946 | nonce, | 1029 | nonce, |
947 | nc, | 1030 | nc, |
@@ -950,7 +1033,7 @@ digest_auth_check_all (struct MHD_Connection *connection, | |||
950 | connection->method, | 1033 | connection->method, |
951 | uri, | 1034 | uri, |
952 | hentity, | 1035 | hentity, |
953 | respexp); | 1036 | da); |
954 | 1037 | ||
955 | 1038 | ||
956 | /* Need to unescape URI before comparing with connection->url */ | 1039 | /* Need to unescape URI before comparing with connection->url */ |
@@ -991,7 +1074,7 @@ digest_auth_check_all (struct MHD_Connection *connection, | |||
991 | } | 1074 | } |
992 | free (uri); | 1075 | free (uri); |
993 | return (0 == strcmp (response, | 1076 | return (0 == strcmp (response, |
994 | respexp)) | 1077 | da->sessionkey)) |
995 | ? MHD_YES | 1078 | ? MHD_YES |
996 | : MHD_NO; | 1079 | : MHD_NO; |
997 | } | 1080 | } |
@@ -999,7 +1082,11 @@ digest_auth_check_all (struct MHD_Connection *connection, | |||
999 | 1082 | ||
1000 | 1083 | ||
1001 | /** | 1084 | /** |
1002 | * Authenticates the authorization header sent by the client | 1085 | * Authenticates the authorization header sent by the client. |
1086 | * Uses #MHD_DIGEST_ALG_MD5 (for now, for backwards-compatibility). | ||
1087 | * Note that this MAY change to #MHD_DIGEST_ALG_AUTO in the future. | ||
1088 | * If you want to be sure you get MD5, use #MHD_digest_auth_check2 | ||
1089 | * and specifiy MD5 explicitly. | ||
1003 | * | 1090 | * |
1004 | * @param connection The MHD connection structure | 1091 | * @param connection The MHD connection structure |
1005 | * @param realm The realm presented to the client | 1092 | * @param realm The realm presented to the client |
@@ -1018,7 +1105,85 @@ MHD_digest_auth_check (struct MHD_Connection *connection, | |||
1018 | const char *password, | 1105 | const char *password, |
1019 | unsigned int nonce_timeout) | 1106 | unsigned int nonce_timeout) |
1020 | { | 1107 | { |
1108 | return MHD_digest_auth_check2 (connection, | ||
1109 | realm, | ||
1110 | username, | ||
1111 | password, | ||
1112 | nonce_timeout, | ||
1113 | MHD_DIGEST_ALG_MD5); | ||
1114 | } | ||
1115 | |||
1116 | |||
1117 | /** | ||
1118 | * Setup digest authentication data structures (on the | ||
1119 | * stack, hence must be done inline!). Initializes a | ||
1120 | * "struct DigestAlgorithm da" for algorithm @a algo. | ||
1121 | * | ||
1122 | * @param algo digest algorithm to provide | ||
1123 | * @param da data structure to setup | ||
1124 | */ | ||
1125 | #define SETUP_DA(algo,da) \ | ||
1126 | union { \ | ||
1127 | struct MD5Context md5; \ | ||
1128 | struct sha256_ctx sha256; \ | ||
1129 | } ctx; \ | ||
1130 | union { \ | ||
1131 | char md5[MD5_DIGEST_SIZE * 2 + 1]; \ | ||
1132 | char sha256[SHA256_DIGEST_SIZE * 2 + 1]; \ | ||
1133 | } skey; \ | ||
1134 | struct DigestAlgorithm da; \ | ||
1135 | \ | ||
1136 | switch (algo) { \ | ||
1137 | case MHD_DIGEST_ALG_MD5: \ | ||
1138 | da.digest_size = MD5_DIGEST_SIZE; \ | ||
1139 | da.ctx = &ctx.md5; \ | ||
1140 | da.alg = "md5"; \ | ||
1141 | da.sessionkey = skey.md5; \ | ||
1142 | da.init = &MD5Init; \ | ||
1143 | da.update = &MD5Update; \ | ||
1144 | da.digest = &MD5Final; \ | ||
1145 | break; \ | ||
1146 | case MHD_DIGEST_ALG_AUTO: \ | ||
1147 | /* auto == SHA256, fall-though thus intentional! */ \ | ||
1148 | case MHD_DIGEST_ALG_SHA256: \ | ||
1149 | da.digest_size = SHA256_DIGEST_SIZE; \ | ||
1150 | da.ctx = &ctx.sha256; \ | ||
1151 | da.alg = "sha-256"; \ | ||
1152 | da.sessionkey = skey.sha256; \ | ||
1153 | da.init = &sha256_init; \ | ||
1154 | da.update = &sha256_update; \ | ||
1155 | da.digest = &sha256_digest; \ | ||
1156 | break; \ | ||
1157 | } | ||
1158 | |||
1159 | |||
1160 | |||
1161 | /** | ||
1162 | * Authenticates the authorization header sent by the client. | ||
1163 | * | ||
1164 | * @param connection The MHD connection structure | ||
1165 | * @param realm The realm presented to the client | ||
1166 | * @param username The username needs to be authenticated | ||
1167 | * @param password The password used in the authentication | ||
1168 | * @param nonce_timeout The amount of time for a nonce to be | ||
1169 | * invalid in seconds | ||
1170 | * @param algo digest algorithms allowed for verification | ||
1171 | * @return #MHD_YES if authenticated, #MHD_NO if not, | ||
1172 | * #MHD_INVALID_NONCE if nonce is invalid | ||
1173 | * @ingroup authentication | ||
1174 | */ | ||
1175 | _MHD_EXTERN int | ||
1176 | MHD_digest_auth_check2 (struct MHD_Connection *connection, | ||
1177 | const char *realm, | ||
1178 | const char *username, | ||
1179 | const char *password, | ||
1180 | unsigned int nonce_timeout, | ||
1181 | enum MHD_DigestAuthAlgorithm algo) | ||
1182 | { | ||
1183 | SETUP_DA (algo, da); | ||
1184 | |||
1021 | return digest_auth_check_all (connection, | 1185 | return digest_auth_check_all (connection, |
1186 | &da, | ||
1022 | realm, | 1187 | realm, |
1023 | username, | 1188 | username, |
1024 | password, | 1189 | password, |
@@ -1028,7 +1193,7 @@ MHD_digest_auth_check (struct MHD_Connection *connection, | |||
1028 | 1193 | ||
1029 | 1194 | ||
1030 | /** | 1195 | /** |
1031 | * Authenticates the authorization header sent by the client | 1196 | * Authenticates the authorization header sent by the client. |
1032 | * | 1197 | * |
1033 | * @param connection The MHD connection structure | 1198 | * @param connection The MHD connection structure |
1034 | * @param realm The realm presented to the client | 1199 | * @param realm The realm presented to the client |
@@ -1036,20 +1201,29 @@ MHD_digest_auth_check (struct MHD_Connection *connection, | |||
1036 | * @param digest An `unsigned char *' pointer to the binary MD5 sum | 1201 | * @param digest An `unsigned char *' pointer to the binary MD5 sum |
1037 | * for the precalculated hash value "username:realm:password" | 1202 | * for the precalculated hash value "username:realm:password" |
1038 | * of #MHD_MD5_DIGEST_SIZE bytes | 1203 | * of #MHD_MD5_DIGEST_SIZE bytes |
1204 | * @param digest_size number of bytes in @a digest | ||
1039 | * @param nonce_timeout The amount of time for a nonce to be | 1205 | * @param nonce_timeout The amount of time for a nonce to be |
1040 | * invalid in seconds | 1206 | * invalid in seconds |
1207 | * @param algo digest algorithms allowed for verification | ||
1041 | * @return #MHD_YES if authenticated, #MHD_NO if not, | 1208 | * @return #MHD_YES if authenticated, #MHD_NO if not, |
1042 | * #MHD_INVALID_NONCE if nonce is invalid | 1209 | * #MHD_INVALID_NONCE if nonce is invalid |
1043 | * @ingroup authentication | 1210 | * @ingroup authentication |
1044 | */ | 1211 | */ |
1045 | _MHD_EXTERN int | 1212 | _MHD_EXTERN int |
1046 | MHD_digest_auth_check_digest (struct MHD_Connection *connection, | 1213 | MHD_digest_auth_check_digest2 (struct MHD_Connection *connection, |
1047 | const char *realm, | 1214 | const char *realm, |
1048 | const char *username, | 1215 | const char *username, |
1049 | const uint8_t digest[MD5_DIGEST_SIZE], | 1216 | const uint8_t *digest, |
1050 | unsigned int nonce_timeout) | 1217 | size_t digest_size, |
1218 | unsigned int nonce_timeout, | ||
1219 | enum MHD_DigestAuthAlgorithm algo) | ||
1051 | { | 1220 | { |
1221 | SETUP_DA (algo, da); | ||
1222 | |||
1223 | if (da.digest_size != digest_size) | ||
1224 | MHD_PANIC (_("digest size missmatch")); /* API violation! */ | ||
1052 | return digest_auth_check_all (connection, | 1225 | return digest_auth_check_all (connection, |
1226 | &da, | ||
1053 | realm, | 1227 | realm, |
1054 | username, | 1228 | username, |
1055 | NULL, | 1229 | NULL, |
@@ -1059,6 +1233,40 @@ MHD_digest_auth_check_digest (struct MHD_Connection *connection, | |||
1059 | 1233 | ||
1060 | 1234 | ||
1061 | /** | 1235 | /** |
1236 | * Authenticates the authorization header sent by the client. | ||
1237 | * Uses #MHD_DIGEST_ALG_MD5 (required, as @a digest is of fixed | ||
1238 | * size). | ||
1239 | * | ||
1240 | * @param connection The MHD connection structure | ||
1241 | * @param realm The realm presented to the client | ||
1242 | * @param username The username needs to be authenticated | ||
1243 | * @param digest An `unsigned char *' pointer to the binary digest | ||
1244 | * for the precalculated hash value "username:realm:password" | ||
1245 | * of @a digest_size bytes | ||
1246 | * @param nonce_timeout The amount of time for a nonce to be | ||
1247 | * invalid in seconds | ||
1248 | * @return #MHD_YES if authenticated, #MHD_NO if not, | ||
1249 | * #MHD_INVALID_NONCE if nonce is invalid | ||
1250 | * @ingroup authentication | ||
1251 | */ | ||
1252 | _MHD_EXTERN int | ||
1253 | MHD_digest_auth_check_digest (struct MHD_Connection *connection, | ||
1254 | const char *realm, | ||
1255 | const char *username, | ||
1256 | const uint8_t digest[MHD_MD5_DIGEST_SIZE], | ||
1257 | unsigned int nonce_timeout) | ||
1258 | { | ||
1259 | return MHD_digest_auth_check_digest2 (connection, | ||
1260 | realm, | ||
1261 | username, | ||
1262 | digest, | ||
1263 | MHD_MD5_DIGEST_SIZE, | ||
1264 | nonce_timeout, | ||
1265 | MHD_DIGEST_ALG_MD5); | ||
1266 | } | ||
1267 | |||
1268 | |||
1269 | /** | ||
1062 | * Queues a response to request authentication from the client | 1270 | * Queues a response to request authentication from the client |
1063 | * | 1271 | * |
1064 | * @param connection The MHD connection structure | 1272 | * @param connection The MHD connection structure |
@@ -1069,81 +1277,90 @@ MHD_digest_auth_check_digest (struct MHD_Connection *connection, | |||
1069 | * header and that the caller should not do this | 1277 | * header and that the caller should not do this |
1070 | * @param signal_stale #MHD_YES if the nonce is invalid to add | 1278 | * @param signal_stale #MHD_YES if the nonce is invalid to add |
1071 | * 'stale=true' to the authentication header | 1279 | * 'stale=true' to the authentication header |
1280 | * @param algo digest algorithm to use | ||
1072 | * @return #MHD_YES on success, #MHD_NO otherwise | 1281 | * @return #MHD_YES on success, #MHD_NO otherwise |
1073 | * @ingroup authentication | 1282 | * @ingroup authentication |
1074 | */ | 1283 | */ |
1075 | int | 1284 | int |
1076 | MHD_queue_auth_fail_response (struct MHD_Connection *connection, | 1285 | MHD_queue_auth_fail_response2 (struct MHD_Connection *connection, |
1077 | const char *realm, | 1286 | const char *realm, |
1078 | const char *opaque, | 1287 | const char *opaque, |
1079 | struct MHD_Response *response, | 1288 | struct MHD_Response *response, |
1080 | int signal_stale) | 1289 | int signal_stale, |
1290 | enum MHD_DigestAuthAlgorithm algo) | ||
1081 | { | 1291 | { |
1082 | int ret; | 1292 | int ret; |
1083 | int hlen; | 1293 | int hlen; |
1084 | char nonce[NONCE_STD_LEN + 1]; | 1294 | SETUP_DA (algo, da); |
1085 | 1295 | ||
1086 | /* Generating the server nonce */ | 1296 | { |
1087 | calculate_nonce ((uint32_t) MHD_monotonic_sec_counter(), | 1297 | char nonce[NONCE_STD_LEN(da.digest_size) + 1]; |
1088 | connection->method, | 1298 | /* Generating the server nonce */ |
1089 | connection->daemon->digest_auth_random, | 1299 | calculate_nonce ((uint32_t) MHD_monotonic_sec_counter(), |
1090 | connection->daemon->digest_auth_rand_size, | 1300 | connection->method, |
1091 | connection->url, | 1301 | connection->daemon->digest_auth_random, |
1092 | realm, | 1302 | connection->daemon->digest_auth_rand_size, |
1093 | nonce); | 1303 | connection->url, |
1094 | if (MHD_YES != | 1304 | realm, |
1095 | check_nonce_nc (connection, | 1305 | &da, |
1096 | nonce, | 1306 | nonce); |
1097 | 0)) | 1307 | if (MHD_YES != |
1098 | { | 1308 | check_nonce_nc (connection, |
1309 | nonce, | ||
1310 | 0)) | ||
1311 | { | ||
1099 | #ifdef HAVE_MESSAGES | 1312 | #ifdef HAVE_MESSAGES |
1100 | MHD_DLOG (connection->daemon, | 1313 | MHD_DLOG (connection->daemon, |
1101 | _("Could not register nonce (is the nonce array size zero?).\n")); | 1314 | _("Could not register nonce (is the nonce array size zero?).\n")); |
1102 | #endif | 1315 | #endif |
1103 | return MHD_NO; | 1316 | return MHD_NO; |
1104 | } | 1317 | } |
1105 | /* Building the authentication header */ | 1318 | /* Building the authentication header */ |
1106 | hlen = MHD_snprintf_ (NULL, | 1319 | hlen = MHD_snprintf_ (NULL, |
1107 | 0, | 1320 | 0, |
1108 | "Digest realm=\"%s\",qop=\"auth\",nonce=\"%s\",opaque=\"%s\"%s", | 1321 | "Digest realm=\"%s\",qop=\"auth\",nonce=\"%s\",opaque=\"%s\",algorithm=%s%s", |
1109 | realm, | 1322 | realm, |
1110 | nonce, | 1323 | nonce, |
1111 | opaque, | 1324 | opaque, |
1112 | signal_stale | 1325 | da.alg, |
1113 | ? ",stale=\"true\"" | 1326 | signal_stale |
1114 | : ""); | 1327 | ? ",stale=\"true\"" |
1115 | if (hlen > 0) | 1328 | : ""); |
1116 | { | 1329 | if (hlen > 0) |
1117 | char *header; | 1330 | { |
1331 | char *header; | ||
1118 | 1332 | ||
1119 | header = MHD_calloc_ (1, hlen + 1); | 1333 | header = MHD_calloc_ (1, |
1120 | if (NULL == header) | 1334 | hlen + 1); |
1121 | { | 1335 | if (NULL == header) |
1336 | { | ||
1122 | #ifdef HAVE_MESSAGES | 1337 | #ifdef HAVE_MESSAGES |
1123 | MHD_DLOG(connection->daemon, | 1338 | MHD_DLOG(connection->daemon, |
1124 | _("Failed to allocate memory for auth response header\n")); | 1339 | _("Failed to allocate memory for auth response header\n")); |
1125 | #endif /* HAVE_MESSAGES */ | 1340 | #endif /* HAVE_MESSAGES */ |
1126 | return MHD_NO; | 1341 | return MHD_NO; |
1127 | } | 1342 | } |
1128 | 1343 | ||
1129 | if (MHD_snprintf_ (header, | 1344 | if (MHD_snprintf_ (header, |
1130 | hlen + 1, | 1345 | hlen + 1, |
1131 | "Digest realm=\"%s\",qop=\"auth\",nonce=\"%s\",opaque=\"%s\"%s", | 1346 | "Digest realm=\"%s\",qop=\"auth\",nonce=\"%s\",opaque=\"%s\",algorithm=%s%s", |
1132 | realm, | 1347 | realm, |
1133 | nonce, | 1348 | nonce, |
1134 | opaque, | 1349 | opaque, |
1135 | signal_stale | 1350 | da.alg, |
1136 | ? ",stale=\"true\"" | 1351 | signal_stale |
1137 | : "") == hlen) | 1352 | ? ",stale=\"true\"" |
1138 | ret = MHD_add_response_header(response, | 1353 | : "") == hlen) |
1139 | MHD_HTTP_HEADER_WWW_AUTHENTICATE, | 1354 | ret = MHD_add_response_header(response, |
1140 | header); | 1355 | MHD_HTTP_HEADER_WWW_AUTHENTICATE, |
1141 | else | 1356 | header); |
1142 | ret = MHD_NO; | 1357 | else |
1143 | free (header); | 1358 | ret = MHD_NO; |
1144 | } | 1359 | free (header); |
1145 | else | 1360 | } |
1146 | ret = MHD_NO; | 1361 | else |
1362 | ret = MHD_NO; | ||
1363 | } | ||
1147 | 1364 | ||
1148 | if (MHD_YES == ret) | 1365 | if (MHD_YES == ret) |
1149 | { | 1366 | { |
@@ -1162,4 +1379,36 @@ MHD_queue_auth_fail_response (struct MHD_Connection *connection, | |||
1162 | } | 1379 | } |
1163 | 1380 | ||
1164 | 1381 | ||
1382 | /** | ||
1383 | * Queues a response to request authentication from the client. | ||
1384 | * For now uses MD5 (for backwards-compatibility). Still, if you | ||
1385 | * need to be sure, use #MHD_queue_fail_auth_response2(). | ||
1386 | * | ||
1387 | * @param connection The MHD connection structure | ||
1388 | * @param realm the realm presented to the client | ||
1389 | * @param opaque string to user for opaque value | ||
1390 | * @param response reply to send; should contain the "access denied" | ||
1391 | * body; note that this function will set the "WWW Authenticate" | ||
1392 | * header and that the caller should not do this | ||
1393 | * @param signal_stale #MHD_YES if the nonce is invalid to add | ||
1394 | * 'stale=true' to the authentication header | ||
1395 | * @return #MHD_YES on success, #MHD_NO otherwise | ||
1396 | * @ingroup authentication | ||
1397 | */ | ||
1398 | int | ||
1399 | MHD_queue_auth_fail_response (struct MHD_Connection *connection, | ||
1400 | const char *realm, | ||
1401 | const char *opaque, | ||
1402 | struct MHD_Response *response, | ||
1403 | int signal_stale) | ||
1404 | { | ||
1405 | return MHD_queue_auth_fail_response2 (connection, | ||
1406 | realm, | ||
1407 | opaque, | ||
1408 | response, | ||
1409 | signal_stale, | ||
1410 | MHD_DIGEST_ALG_MD5); | ||
1411 | } | ||
1412 | |||
1413 | |||
1165 | /* end of digestauth.c */ | 1414 | /* end of digestauth.c */ |
diff --git a/src/microhttpd/md5.c b/src/microhttpd/md5.c index d92a42ee..6a8819c9 100644 --- a/src/microhttpd/md5.c +++ b/src/microhttpd/md5.c | |||
@@ -42,16 +42,20 @@ static uint8_t PADDING[MD5_BLOCK_SIZE] = { | |||
42 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | 42 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 |
43 | }; | 43 | }; |
44 | 44 | ||
45 | /* | 45 | |
46 | /** | ||
46 | * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious | 47 | * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious |
47 | * initialization constants. | 48 | * initialization constants. |
49 | * | ||
50 | * @param ctx must be a `struct MD5Context *` | ||
48 | */ | 51 | */ |
49 | void | 52 | void |
50 | MD5Init(struct MD5Context *ctx) | 53 | MD5Init (void *ctx_) |
51 | { | 54 | { |
55 | struct MD5Context *ctx = ctx_; | ||
56 | |||
52 | if (!ctx) | 57 | if (!ctx) |
53 | return; | 58 | return; |
54 | |||
55 | ctx->count = 0; | 59 | ctx->count = 0; |
56 | ctx->state[0] = 0x67452301; | 60 | ctx->state[0] = 0x67452301; |
57 | ctx->state[1] = 0xefcdab89; | 61 | ctx->state[1] = 0xefcdab89; |
@@ -59,56 +63,13 @@ MD5Init(struct MD5Context *ctx) | |||
59 | ctx->state[3] = 0x10325476; | 63 | ctx->state[3] = 0x10325476; |
60 | } | 64 | } |
61 | 65 | ||
62 | /* | ||
63 | * Update context to reflect the concatenation of another buffer full | ||
64 | * of bytes. | ||
65 | */ | ||
66 | void | ||
67 | MD5Update(struct MD5Context *ctx, const unsigned char *input, size_t len) | ||
68 | { | ||
69 | size_t have, need; | ||
70 | |||
71 | if (!ctx || !input) | ||
72 | return; | ||
73 | |||
74 | /* Check how many bytes we already have and how many more we need. */ | ||
75 | have = (size_t)((ctx->count >> 3) & (MD5_BLOCK_SIZE - 1)); | ||
76 | need = MD5_BLOCK_SIZE - have; | ||
77 | |||
78 | /* Update bitcount */ | ||
79 | ctx->count += (uint64_t)len << 3; | ||
80 | |||
81 | if (len >= need) | ||
82 | { | ||
83 | if (have != 0) | ||
84 | { | ||
85 | memcpy(ctx->buffer + have, input, need); | ||
86 | MD5Transform(ctx->state, ctx->buffer); | ||
87 | input += need; | ||
88 | len -= need; | ||
89 | have = 0; | ||
90 | } | ||
91 | 66 | ||
92 | /* Process data in MD5_BLOCK_SIZE-byte chunks. */ | 67 | /** |
93 | while (len >= MD5_BLOCK_SIZE) | ||
94 | { | ||
95 | MD5Transform(ctx->state, input); | ||
96 | input += MD5_BLOCK_SIZE; | ||
97 | len -= MD5_BLOCK_SIZE; | ||
98 | } | ||
99 | } | ||
100 | |||
101 | /* Handle any remaining bytes of data. */ | ||
102 | if (len != 0) | ||
103 | memcpy(ctx->buffer + have, input, len); | ||
104 | } | ||
105 | |||
106 | /* | ||
107 | * Pad pad to 64-byte boundary with the bit pattern | 68 | * Pad pad to 64-byte boundary with the bit pattern |
108 | * 1 0* (64-bit count of bits processed, MSB-first) | 69 | * 1 0* (64-bit count of bits processed, MSB-first) |
109 | */ | 70 | */ |
110 | void | 71 | static void |
111 | MD5Pad(struct MD5Context *ctx) | 72 | MD5Pad (struct MD5Context *ctx) |
112 | { | 73 | { |
113 | uint8_t count[8]; | 74 | uint8_t count[8]; |
114 | size_t padlen; | 75 | size_t padlen; |
@@ -128,12 +89,17 @@ MD5Pad(struct MD5Context *ctx) | |||
128 | MD5Update(ctx, count, 8); | 89 | MD5Update(ctx, count, 8); |
129 | } | 90 | } |
130 | 91 | ||
131 | /* | 92 | |
93 | /** | ||
132 | * Final wrapup--call MD5Pad, fill in digest and zero out ctx. | 94 | * Final wrapup--call MD5Pad, fill in digest and zero out ctx. |
95 | * | ||
96 | * @param ctx must be a `struct MD5Context *` | ||
133 | */ | 97 | */ |
134 | void | 98 | void |
135 | MD5Final(unsigned char digest[MD5_DIGEST_SIZE], struct MD5Context *ctx) | 99 | MD5Final (void *ctx_, |
100 | unsigned char digest[MD5_DIGEST_SIZE]) | ||
136 | { | 101 | { |
102 | struct MD5Context *ctx = ctx_; | ||
137 | int i; | 103 | int i; |
138 | 104 | ||
139 | if (!ctx || !digest) | 105 | if (!ctx || !digest) |
@@ -159,13 +125,14 @@ MD5Final(unsigned char digest[MD5_DIGEST_SIZE], struct MD5Context *ctx) | |||
159 | #define MD5STEP(f, w, x, y, z, data, s) \ | 125 | #define MD5STEP(f, w, x, y, z, data, s) \ |
160 | ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x ) | 126 | ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x ) |
161 | 127 | ||
162 | /* | 128 | /** |
163 | * The core of the MD5 algorithm, this alters an existing MD5 hash to | 129 | * The core of the MD5 algorithm, this alters an existing MD5 hash to |
164 | * reflect the addition of 16 longwords of new data. MD5Update blocks | 130 | * reflect the addition of 16 longwords of new data. MD5Update blocks |
165 | * the data and converts bytes into longwords for this routine. | 131 | * the data and converts bytes into longwords for this routine. |
166 | */ | 132 | */ |
167 | void | 133 | static void |
168 | MD5Transform(uint32_t state[4], const uint8_t block[MD5_BLOCK_SIZE]) | 134 | MD5Transform (uint32_t state[4], |
135 | const uint8_t block[MD5_BLOCK_SIZE]) | ||
169 | { | 136 | { |
170 | uint32_t a, b, c, d, in[MD5_BLOCK_SIZE / 4]; | 137 | uint32_t a, b, c, d, in[MD5_BLOCK_SIZE / 4]; |
171 | 138 | ||
@@ -261,4 +228,59 @@ MD5Transform(uint32_t state[4], const uint8_t block[MD5_BLOCK_SIZE]) | |||
261 | state[3] += d; | 228 | state[3] += d; |
262 | } | 229 | } |
263 | 230 | ||
231 | |||
232 | /** | ||
233 | * Update context to reflect the concatenation of another buffer full | ||
234 | * of bytes. | ||
235 | */ | ||
236 | void | ||
237 | MD5Update (void *ctx_, | ||
238 | const uint8_t *input, | ||
239 | size_t len) | ||
240 | { | ||
241 | struct MD5Context *ctx = ctx_; | ||
242 | size_t have, need; | ||
243 | |||
244 | if (!ctx || !input) | ||
245 | return; | ||
246 | |||
247 | /* Check how many bytes we already have and how many more we need. */ | ||
248 | have = (size_t)((ctx->count >> 3) & (MD5_BLOCK_SIZE - 1)); | ||
249 | need = MD5_BLOCK_SIZE - have; | ||
250 | |||
251 | /* Update bitcount */ | ||
252 | ctx->count += (uint64_t)len << 3; | ||
253 | |||
254 | if (len >= need) | ||
255 | { | ||
256 | if (have != 0) | ||
257 | { | ||
258 | memcpy (ctx->buffer + have, | ||
259 | input, | ||
260 | need); | ||
261 | MD5Transform(ctx->state, ctx->buffer); | ||
262 | input += need; | ||
263 | len -= need; | ||
264 | have = 0; | ||
265 | } | ||
266 | |||
267 | /* Process data in MD5_BLOCK_SIZE-byte chunks. */ | ||
268 | while (len >= MD5_BLOCK_SIZE) | ||
269 | { | ||
270 | MD5Transform (ctx->state, | ||
271 | (const unsigned char *) input); | ||
272 | input += MD5_BLOCK_SIZE; | ||
273 | len -= MD5_BLOCK_SIZE; | ||
274 | } | ||
275 | } | ||
276 | |||
277 | /* Handle any remaining bytes of data. */ | ||
278 | if (0 != len) | ||
279 | memcpy (ctx->buffer + have, | ||
280 | input, | ||
281 | len); | ||
282 | } | ||
283 | |||
284 | |||
285 | |||
264 | /* end of md5.c */ | 286 | /* end of md5.c */ |
diff --git a/src/microhttpd/md5.h b/src/microhttpd/md5.h index ad1151e9..3bbfd79e 100644 --- a/src/microhttpd/md5.h +++ b/src/microhttpd/md5.h | |||
@@ -31,34 +31,37 @@ struct MD5Context | |||
31 | uint8_t buffer[MD5_BLOCK_SIZE]; /* input buffer */ | 31 | uint8_t buffer[MD5_BLOCK_SIZE]; /* input buffer */ |
32 | }; | 32 | }; |
33 | 33 | ||
34 | /* | 34 | |
35 | /** | ||
35 | * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious | 36 | * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious |
36 | * initialization constants. | 37 | * initialization constants. |
38 | * | ||
39 | * @param ctx_ must be a `struct MD5Context *` | ||
37 | */ | 40 | */ |
38 | void MD5Init(struct MD5Context *ctx); | 41 | void |
42 | MD5Init (void *ctx_); | ||
39 | 43 | ||
40 | /* | 44 | |
45 | /** | ||
41 | * Update context to reflect the concatenation of another buffer full | 46 | * Update context to reflect the concatenation of another buffer full |
42 | * of bytes. | 47 | * of bytes. |
48 | * | ||
49 | * @param ctx_ must be a `struct MD5Context *` | ||
43 | */ | 50 | */ |
44 | void MD5Update(struct MD5Context *ctx, const unsigned char *input, size_t len); | 51 | void |
52 | MD5Update (void *ctx_, | ||
53 | const uint8_t *input, | ||
54 | size_t len); | ||
45 | 55 | ||
46 | /* | ||
47 | * Pad pad to 64-byte boundary with the bit pattern | ||
48 | * 1 0* (64-bit count of bits processed, MSB-first) | ||
49 | */ | ||
50 | void MD5Pad(struct MD5Context *ctx); | ||
51 | 56 | ||
52 | /* | 57 | /** |
53 | * Final wrapup--call MD5Pad, fill in digest and zero out ctx. | 58 | * Final wrapup--call MD5Pad, fill in digest and zero out ctx. |
59 | * | ||
60 | * @param ctx_ must be a `struct MD5Context *` | ||
54 | */ | 61 | */ |
55 | void MD5Final(unsigned char digest[MD5_DIGEST_SIZE], struct MD5Context *ctx); | 62 | void |
63 | MD5Final (void *ctx_, | ||
64 | unsigned char digest[MD5_DIGEST_SIZE]); | ||
56 | 65 | ||
57 | /* | ||
58 | * The core of the MD5 algorithm, this alters an existing MD5 hash to | ||
59 | * reflect the addition of 16 longwords of new data. MD5Update blocks | ||
60 | * the data and converts bytes into longwords for this routine. | ||
61 | */ | ||
62 | void MD5Transform(uint32_t state[4], const uint8_t block[MD5_BLOCK_SIZE]); | ||
63 | 66 | ||
64 | #endif /* !MHD_MD5_H */ | 67 | #endif /* !MHD_MD5_H */ |
diff --git a/src/microhttpd/sha256.c b/src/microhttpd/sha256.c index 12675a73..977296f9 100644 --- a/src/microhttpd/sha256.c +++ b/src/microhttpd/sha256.c | |||
@@ -48,22 +48,22 @@ | |||
48 | static const uint32_t | 48 | static const uint32_t |
49 | K[64] = | 49 | K[64] = |
50 | { | 50 | { |
51 | 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, | 51 | 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, |
52 | 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, | 52 | 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, |
53 | 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, | 53 | 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, |
54 | 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, | 54 | 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, |
55 | 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, | 55 | 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, |
56 | 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, | 56 | 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, |
57 | 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, | 57 | 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, |
58 | 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, | 58 | 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, |
59 | 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, | 59 | 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, |
60 | 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, | 60 | 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, |
61 | 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, | 61 | 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, |
62 | 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, | 62 | 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, |
63 | 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, | 63 | 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, |
64 | 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, | 64 | 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, |
65 | 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, | 65 | 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, |
66 | 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL, | 66 | 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL, |
67 | }; | 67 | }; |
68 | 68 | ||
69 | 69 | ||
@@ -77,11 +77,11 @@ K[64] = | |||
77 | this */ | 77 | this */ |
78 | 78 | ||
79 | /* #define Choice(x,y,z) ( ( (x) & (y) ) | ( ~(x) & (z) ) ) */ | 79 | /* #define Choice(x,y,z) ( ( (x) & (y) ) | ( ~(x) & (z) ) ) */ |
80 | #define Choice(x,y,z) ( (z) ^ ( (x) & ( (y) ^ (z) ) ) ) | 80 | #define Choice(x,y,z) ( (z) ^ ( (x) & ( (y) ^ (z) ) ) ) |
81 | /* #define Majority(x,y,z) ( ((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)) ) */ | 81 | /* #define Majority(x,y,z) ( ((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)) ) */ |
82 | #define Majority(x,y,z) ( ((x) & (y)) ^ ((z) & ((x) ^ (y))) ) | 82 | #define Majority(x,y,z) ( ((x) & (y)) ^ ((z) & ((x) ^ (y))) ) |
83 | 83 | ||
84 | #define S0(x) (ROTL32(30,(x)) ^ ROTL32(19,(x)) ^ ROTL32(10,(x))) | 84 | #define S0(x) (ROTL32(30,(x)) ^ ROTL32(19,(x)) ^ ROTL32(10,(x))) |
85 | #define S1(x) (ROTL32(26,(x)) ^ ROTL32(21,(x)) ^ ROTL32(7,(x))) | 85 | #define S1(x) (ROTL32(26,(x)) ^ ROTL32(21,(x)) ^ ROTL32(7,(x))) |
86 | 86 | ||
87 | #define s0(x) (ROTL32(25,(x)) ^ ROTL32(14,(x)) ^ ((x) >> 3)) | 87 | #define s0(x) (ROTL32(25,(x)) ^ ROTL32(14,(x)) ^ ((x) >> 3)) |
@@ -182,22 +182,22 @@ _nettle_sha256_compress(uint32_t *state, const uint8_t *input, const uint32_t *k | |||
182 | F = state[5]; | 182 | F = state[5]; |
183 | G = state[6]; | 183 | G = state[6]; |
184 | H = state[7]; | 184 | H = state[7]; |
185 | 185 | ||
186 | /* Heavy mangling */ | 186 | /* Heavy mangling */ |
187 | /* First 16 subrounds that act on the original data */ | 187 | /* First 16 subrounds that act on the original data */ |
188 | 188 | ||
189 | for (i = 0, d = data; i<16; i+=8, k += 8, d+= 8) | 189 | for (i = 0, d = data; i<16; i+=8, k += 8, d+= 8) |
190 | { | 190 | { |
191 | ROUND(A, B, C, D, E, F, G, H, k[0], d[0]); | 191 | ROUND(A, B, C, D, E, F, G, H, k[0], d[0]); |
192 | ROUND(H, A, B, C, D, E, F, G, k[1], d[1]); | 192 | ROUND(H, A, B, C, D, E, F, G, k[1], d[1]); |
193 | ROUND(G, H, A, B, C, D, E, F, k[2], d[2]); | 193 | ROUND(G, H, A, B, C, D, E, F, k[2], d[2]); |
194 | ROUND(F, G, H, A, B, C, D, E, k[3], d[3]); | 194 | ROUND(F, G, H, A, B, C, D, E, k[3], d[3]); |
195 | ROUND(E, F, G, H, A, B, C, D, k[4], d[4]); | 195 | ROUND(E, F, G, H, A, B, C, D, k[4], d[4]); |
196 | ROUND(D, E, F, G, H, A, B, C, k[5], d[5]); | 196 | ROUND(D, E, F, G, H, A, B, C, k[5], d[5]); |
197 | ROUND(C, D, E, F, G, H, A, B, k[6], d[6]); | 197 | ROUND(C, D, E, F, G, H, A, B, k[6], d[6]); |
198 | ROUND(B, C, D, E, F, G, H, A, k[7], d[7]); | 198 | ROUND(B, C, D, E, F, G, H, A, k[7], d[7]); |
199 | } | 199 | } |
200 | 200 | ||
201 | for (; i<64; i += 16, k+= 16) | 201 | for (; i<64; i += 16, k+= 16) |
202 | { | 202 | { |
203 | ROUND(A, B, C, D, E, F, G, H, k[ 0], EXPAND(data, 0)); | 203 | ROUND(A, B, C, D, E, F, G, H, k[ 0], EXPAND(data, 0)); |
@@ -235,20 +235,21 @@ _nettle_sha256_compress(uint32_t *state, const uint8_t *input, const uint32_t *k | |||
235 | /* Initialize the SHA values */ | 235 | /* Initialize the SHA values */ |
236 | 236 | ||
237 | void | 237 | void |
238 | sha256_init(struct sha256_ctx *ctx) | 238 | sha256_init (void *ctx_) |
239 | { | 239 | { |
240 | /* Initial values, also generated by the shadata program. */ | 240 | /* Initial values, also generated by the shadata program. */ |
241 | static const uint32_t H0[_SHA256_DIGEST_LENGTH] = | 241 | static const uint32_t H0[_SHA256_DIGEST_LENGTH] = |
242 | { | 242 | { |
243 | 0x6a09e667UL, 0xbb67ae85UL, 0x3c6ef372UL, 0xa54ff53aUL, | 243 | 0x6a09e667UL, 0xbb67ae85UL, 0x3c6ef372UL, 0xa54ff53aUL, |
244 | 0x510e527fUL, 0x9b05688cUL, 0x1f83d9abUL, 0x5be0cd19UL, | 244 | 0x510e527fUL, 0x9b05688cUL, 0x1f83d9abUL, 0x5be0cd19UL, |
245 | }; | 245 | }; |
246 | struct sha256_ctx *ctx = ctx_; | ||
246 | 247 | ||
247 | memcpy(ctx->state, H0, sizeof(H0)); | 248 | memcpy(ctx->state, H0, sizeof(H0)); |
248 | 249 | ||
249 | /* Initialize bit count */ | 250 | /* Initialize bit count */ |
250 | ctx->count = 0; | 251 | ctx->count = 0; |
251 | 252 | ||
252 | /* Initialize buffer */ | 253 | /* Initialize buffer */ |
253 | ctx->index = 0; | 254 | ctx->index = 0; |
254 | } | 255 | } |
@@ -322,9 +323,11 @@ sha256_init(struct sha256_ctx *ctx) | |||
322 | 323 | ||
323 | 324 | ||
324 | void | 325 | void |
325 | sha256_update(struct sha256_ctx *ctx, | 326 | sha256_update (void *ctx_, |
326 | size_t length, const uint8_t *data) | 327 | const uint8_t *data, |
328 | size_t length) | ||
327 | { | 329 | { |
330 | struct sha256_ctx *ctx = ctx_; | ||
328 | MD_UPDATE (ctx, length, data, COMPRESS, ctx->count++); | 331 | MD_UPDATE (ctx, length, data, COMPRESS, ctx->count++); |
329 | } | 332 | } |
330 | 333 | ||
@@ -337,7 +340,7 @@ _nettle_write_be32(size_t length, uint8_t *dst, | |||
337 | size_t i; | 340 | size_t i; |
338 | size_t words; | 341 | size_t words; |
339 | unsigned leftover; | 342 | unsigned leftover; |
340 | 343 | ||
341 | words = length / 4; | 344 | words = length / 4; |
342 | leftover = length % 4; | 345 | leftover = length % 4; |
343 | 346 | ||
@@ -348,9 +351,9 @@ _nettle_write_be32(size_t length, uint8_t *dst, | |||
348 | { | 351 | { |
349 | uint32_t word; | 352 | uint32_t word; |
350 | unsigned j = leftover; | 353 | unsigned j = leftover; |
351 | 354 | ||
352 | word = src[i]; | 355 | word = src[i]; |
353 | 356 | ||
354 | switch (leftover) | 357 | switch (leftover) |
355 | { | 358 | { |
356 | default: | 359 | default: |
@@ -369,9 +372,9 @@ _nettle_write_be32(size_t length, uint8_t *dst, | |||
369 | 372 | ||
370 | 373 | ||
371 | static void | 374 | static void |
372 | sha256_write_digest(struct sha256_ctx *ctx, | 375 | sha256_write_digest (struct sha256_ctx *ctx, |
373 | size_t length, | 376 | size_t length, |
374 | uint8_t *digest) | 377 | uint8_t *digest) |
375 | { | 378 | { |
376 | uint64_t bit_count; | 379 | uint64_t bit_count; |
377 | 380 | ||
@@ -379,7 +382,7 @@ sha256_write_digest(struct sha256_ctx *ctx, | |||
379 | 382 | ||
380 | MD_PAD(ctx, 8, COMPRESS); | 383 | MD_PAD(ctx, 8, COMPRESS); |
381 | 384 | ||
382 | /* There are 512 = 2^9 bits in one block */ | 385 | /* There are 512 = 2^9 bits in one block */ |
383 | bit_count = (ctx->count << 9) | (ctx->index << 3); | 386 | bit_count = (ctx->count << 9) | (ctx->index << 3); |
384 | 387 | ||
385 | /* This is slightly inefficient, as the numbers are converted to | 388 | /* This is slightly inefficient, as the numbers are converted to |
@@ -392,10 +395,13 @@ sha256_write_digest(struct sha256_ctx *ctx, | |||
392 | } | 395 | } |
393 | 396 | ||
394 | void | 397 | void |
395 | sha256_digest(struct sha256_ctx *ctx, | 398 | sha256_digest (void *ctx_, |
396 | size_t length, | ||
397 | uint8_t *digest) | 399 | uint8_t *digest) |
398 | { | 400 | { |
399 | sha256_write_digest(ctx, length, digest); | 401 | struct sha256_ctx *ctx = ctx_; |
400 | sha256_init(ctx); | 402 | |
403 | sha256_write_digest (ctx, | ||
404 | SHA256_DIGEST_SIZE, | ||
405 | digest); | ||
406 | sha256_init (ctx); | ||
401 | } | 407 | } |
diff --git a/src/microhttpd/sha256.h b/src/microhttpd/sha256.h index 6d36ebef..5eee4a41 100644 --- a/src/microhttpd/sha256.h +++ b/src/microhttpd/sha256.h | |||
@@ -32,14 +32,10 @@ | |||
32 | the GNU Lesser General Public License along with this program. If | 32 | the GNU Lesser General Public License along with this program. If |
33 | not, see http://www.gnu.org/licenses/. | 33 | not, see http://www.gnu.org/licenses/. |
34 | */ | 34 | */ |
35 | 35 | ||
36 | #ifndef NETTLE_SHA2_H_INCLUDED | 36 | #ifndef NETTLE_SHA2_H_INCLUDED |
37 | #define NETTLE_SHA2_H_INCLUDED | 37 | #define NETTLE_SHA2_H_INCLUDED |
38 | 38 | ||
39 | #ifdef __cplusplus | ||
40 | extern "C" { | ||
41 | #endif | ||
42 | |||
43 | #define SHA256_DIGEST_SIZE 32 | 39 | #define SHA256_DIGEST_SIZE 32 |
44 | #define SHA256_BLOCK_SIZE 64 | 40 | #define SHA256_BLOCK_SIZE 64 |
45 | 41 | ||
@@ -54,21 +50,36 @@ struct sha256_ctx | |||
54 | unsigned int index; /* index into buffer */ | 50 | unsigned int index; /* index into buffer */ |
55 | }; | 51 | }; |
56 | 52 | ||
57 | void | ||
58 | sha256_init(struct sha256_ctx *ctx); | ||
59 | 53 | ||
54 | /** | ||
55 | * Start SHA256 calculation. | ||
56 | * | ||
57 | * @param ctx_ must be a `struct sha256_ctx *` | ||
58 | */ | ||
60 | void | 59 | void |
61 | sha256_update(struct sha256_ctx *ctx, | 60 | sha256_init (void *ctx_); |
62 | size_t length, | ||
63 | const uint8_t *data); | ||
64 | 61 | ||
65 | void | ||
66 | sha256_digest(struct sha256_ctx *ctx, | ||
67 | size_t length, | ||
68 | uint8_t *digest); | ||
69 | 62 | ||
70 | #ifdef __cplusplus | 63 | /** |
71 | } | 64 | * Update hash calculation. |
72 | #endif | 65 | * |
66 | * @param ctx_ must be a `struct sha256_ctx *` | ||
67 | * @param length number of bytes in @a data | ||
68 | * @param data bytes to add to hash | ||
69 | */ | ||
70 | void | ||
71 | sha256_update (void *ctx_, | ||
72 | const uint8_t *data, | ||
73 | size_t length); | ||
74 | |||
75 | /** | ||
76 | * Complete SHA256 calculation. | ||
77 | * | ||
78 | * @param ctx_ must be a `struct sha256_ctx *` | ||
79 | * @param digest[out] set to the hash, must be #SHA256_DIGEST_SIZE bytes | ||
80 | */ | ||
81 | void | ||
82 | sha256_digest (void *ctx_, | ||
83 | uint8_t digest[SHA256_DIGEST_SIZE]); | ||
73 | 84 | ||
74 | #endif /* NETTLE_SHA2_H_INCLUDED */ | 85 | #endif /* NETTLE_SHA2_H_INCLUDED */ |