aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2018-12-08 17:35:37 +0100
committerChristian Grothoff <christian@grothoff.org>2018-12-08 17:35:37 +0100
commitbcba3f58c5fc9b4a3776494d3edddceb244ab110 (patch)
treedca7d5d47d8f6bbfb0558c53fec91e51b38d5f41
parent6bb3796f50f31bf6381c0ff0f082503597b1640f (diff)
downloadlibmicrohttpd-bcba3f58c5fc9b4a3776494d3edddceb244ab110.tar.gz
libmicrohttpd-bcba3f58c5fc9b4a3776494d3edddceb244ab110.zip
preliminary implementation for RFC 7616 support
-rw-r--r--ChangeLog4
-rw-r--r--src/include/microhttpd.h114
-rw-r--r--src/microhttpd/Makefile.am9
-rw-r--r--src/microhttpd/digestauth.c779
-rw-r--r--src/microhttpd/md5.c130
-rw-r--r--src/microhttpd/md5.h37
-rw-r--r--src/microhttpd/sha256.c88
-rw-r--r--src/microhttpd/sha256.h45
8 files changed, 805 insertions, 401 deletions
diff --git a/ChangeLog b/ChangeLog
index 53a72733..352cdc8e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
1Sat Dec 8 17:34:58 CET 2018
2 Adding support for RFC 7616, experimental, needs
3 testing and documentation still! -CG
4
1Fri Dec 7 12:37:17 CET 2018 5Fri 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 */
3197enum 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
3232MHD_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
3208MHD_digest_auth_check (struct MHD_Connection *connection, 3259MHD_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
3284MHD_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
3231MHD_digest_auth_check_digest (struct MHD_Connection *connection, 3312MHD_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 */
3334int
3335MHD_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
3253MHD_queue_auth_fail_response (struct MHD_Connection *connection, 3361MHD_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
133if ENABLE_DAUTH 133if ENABLE_DAUTH
134libmicrohttpd_la_SOURCES += \ 134libmicrohttpd_la_SOURCES += \
135 digestauth.c \ 135 digestauth.c \
136 md5.c md5.h 136 md5.c md5.h \
137 sha256.c sha256.h
137endif 138endif
138 139
139if ENABLE_BAUTH 140if ENABLE_BAUTH
@@ -160,18 +161,18 @@ check_PROGRAMS = \
160 161
161if HAVE_POSIX_THREADS 162if HAVE_POSIX_THREADS
162if ENABLE_UPGRADE 163if ENABLE_UPGRADE
163if USE_POSIX_THREADS 164if USE_POSIX_THREADS
164 check_PROGRAMS += test_upgrade 165 check_PROGRAMS += test_upgrade
165endif 166endif
166if USE_W32_THREADS 167if USE_W32_THREADS
167 check_PROGRAMS += test_upgrade 168 check_PROGRAMS += test_upgrade
168endif 169endif
169if ENABLE_HTTPS 170if ENABLE_HTTPS
170if USE_POSIX_THREADS 171if USE_POSIX_THREADS
171check_PROGRAMS += test_upgrade_tls 172check_PROGRAMS += test_upgrade_tls
172endif 173endif
173if USE_W32_THREADS 174if USE_W32_THREADS
174check_PROGRAMS += test_upgrade_tls 175check_PROGRAMS += test_upgrade_tls
175endif 176endif
176endif 177endif
177endif 178endif
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 */
81struct 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 */
107static void 176static void
108digest_calc_ha1_from_digest (const char *alg, 177digest_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 */
164static void 235static void
165digest_calc_ha1_from_user (const char *alg, 236digest_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 */
215static void 288static void
216digest_calc_response (const char ha1[HASH_MD5_HEX_LEN + 1], 289digest_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 */
557static void 630static void
558calculate_nonce (uint32_t nonce_time, 631calculate_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 */
728static int 804static int
729digest_auth_check_all (struct MHD_Connection *connection, 805digest_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
1176MHD_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
1046MHD_digest_auth_check_digest (struct MHD_Connection *connection, 1213MHD_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
1253MHD_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 */
1075int 1284int
1076MHD_queue_auth_fail_response (struct MHD_Connection *connection, 1285MHD_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 */
1398int
1399MHD_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 */
49void 52void
50MD5Init(struct MD5Context *ctx) 53MD5Init (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 */
66void
67MD5Update(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 */
110void 71static void
111MD5Pad(struct MD5Context *ctx) 72MD5Pad (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 */
134void 98void
135MD5Final(unsigned char digest[MD5_DIGEST_SIZE], struct MD5Context *ctx) 99MD5Final (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 */
167void 133static void
168MD5Transform(uint32_t state[4], const uint8_t block[MD5_BLOCK_SIZE]) 134MD5Transform (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 */
236void
237MD5Update (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 */
38void MD5Init(struct MD5Context *ctx); 41void
42MD5Init (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 */
44void MD5Update(struct MD5Context *ctx, const unsigned char *input, size_t len); 51void
52MD5Update (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 */
50void 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 */
55void MD5Final(unsigned char digest[MD5_DIGEST_SIZE], struct MD5Context *ctx); 62void
63MD5Final (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 */
62void 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 @@
48static const uint32_t 48static const uint32_t
49K[64] = 49K[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
237void 237void
238sha256_init(struct sha256_ctx *ctx) 238sha256_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
324void 325void
325sha256_update(struct sha256_ctx *ctx, 326sha256_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
371static void 374static void
372sha256_write_digest(struct sha256_ctx *ctx, 375sha256_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
394void 397void
395sha256_digest(struct sha256_ctx *ctx, 398sha256_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
40extern "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
57void
58sha256_init(struct sha256_ctx *ctx);
59 53
54/**
55 * Start SHA256 calculation.
56 *
57 * @param ctx_ must be a `struct sha256_ctx *`
58 */
60void 59void
61sha256_update(struct sha256_ctx *ctx, 60sha256_init (void *ctx_);
62 size_t length,
63 const uint8_t *data);
64 61
65void
66sha256_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 */
70void
71sha256_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 */
81void
82sha256_digest (void *ctx_,
83 uint8_t digest[SHA256_DIGEST_SIZE]);
73 84
74#endif /* NETTLE_SHA2_H_INCLUDED */ 85#endif /* NETTLE_SHA2_H_INCLUDED */