|
@@ -120,8 +120,12 @@ enum http_flags {
|
120
|
120
|
HTTP_BASIC_AUTH = 0x0020,
|
121
|
121
|
/** Provide Digest authentication details */
|
122
|
122
|
HTTP_DIGEST_AUTH = 0x0040,
|
|
123
|
+ /** Include qop parameter in Digest authentication reponse */
|
|
124
|
+ HTTP_DIGEST_AUTH_QOP = 0x0080,
|
|
125
|
+ /** Use MD5-sess algorithm for Digest authentication */
|
|
126
|
+ HTTP_DIGEST_AUTH_MD5_SESS = 0x0100,
|
123
|
127
|
/** Socket must be reopened */
|
124
|
|
- HTTP_REOPEN_SOCKET = 0x0080,
|
|
128
|
+ HTTP_REOPEN_SOCKET = 0x0200,
|
125
|
129
|
};
|
126
|
130
|
|
127
|
131
|
/** HTTP receive state */
|
|
@@ -615,6 +619,18 @@ static int http_rx_digest_auth ( struct http_request *http, char *params ) {
|
615
|
619
|
/* Not an error; "opaque" is optional */
|
616
|
620
|
}
|
617
|
621
|
|
|
622
|
+ /* Check for presence of qop */
|
|
623
|
+ if ( strstr ( params, "qop=\"" ) != NULL )
|
|
624
|
+ http->flags |= HTTP_DIGEST_AUTH_QOP;
|
|
625
|
+
|
|
626
|
+ /* Check for MD5-sess. For some bizarre reason,
|
|
627
|
+ * RFC2617 requires this to be unquoted, which means
|
|
628
|
+ * that http_digest_param() cannot be used.
|
|
629
|
+ */
|
|
630
|
+ if ( strstr ( params, "algorithm=MD5-sess" ) != NULL )
|
|
631
|
+ http->flags |= HTTP_DIGEST_AUTH_MD5_SESS;
|
|
632
|
+
|
|
633
|
+ /* Retry using digest authentication */
|
618
|
634
|
http->flags |= ( HTTP_TRY_AGAIN | HTTP_DIGEST_AUTH );
|
619
|
635
|
}
|
620
|
636
|
|
|
@@ -1133,10 +1149,13 @@ static char * http_digest_auth ( struct http_request *http,
|
1133
|
1149
|
const char *realm = http->auth_realm;
|
1134
|
1150
|
const char *nonce = http->auth_nonce;
|
1135
|
1151
|
const char *opaque = http->auth_opaque;
|
|
1152
|
+ char cnonce[ 9 /* "xxxxxxxx" + NUL */ ];
|
1136
|
1153
|
struct md5_context ctx;
|
1137
|
1154
|
char ha1[ base16_encoded_len ( MD5_DIGEST_SIZE ) + 1 /* NUL */ ];
|
1138
|
1155
|
char ha2[ base16_encoded_len ( MD5_DIGEST_SIZE ) + 1 /* NUL */ ];
|
1139
|
1156
|
char response[ base16_encoded_len ( MD5_DIGEST_SIZE ) + 1 /* NUL */ ];
|
|
1157
|
+ int qop = ( http->flags & HTTP_DIGEST_AUTH_QOP );
|
|
1158
|
+ int md5sess = ( qop && ( http->flags & HTTP_DIGEST_AUTH_MD5_SESS ) );
|
1140
|
1159
|
char *auth;
|
1141
|
1160
|
int len;
|
1142
|
1161
|
|
|
@@ -1145,12 +1164,22 @@ static char * http_digest_auth ( struct http_request *http,
|
1145
|
1164
|
assert ( realm != NULL );
|
1146
|
1165
|
assert ( nonce != NULL );
|
1147
|
1166
|
|
|
1167
|
+ /* Generate a client nonce */
|
|
1168
|
+ snprintf ( cnonce, sizeof ( cnonce ), "%08lx", random() );
|
|
1169
|
+
|
1148
|
1170
|
/* Generate HA1 */
|
1149
|
1171
|
http_digest_init ( &ctx );
|
1150
|
1172
|
http_digest_update ( &ctx, user );
|
1151
|
1173
|
http_digest_update ( &ctx, realm );
|
1152
|
1174
|
http_digest_update ( &ctx, password );
|
1153
|
1175
|
http_digest_final ( &ctx, ha1 );
|
|
1176
|
+ if ( md5sess ) {
|
|
1177
|
+ http_digest_init ( &ctx );
|
|
1178
|
+ http_digest_update ( &ctx, ha1 );
|
|
1179
|
+ http_digest_update ( &ctx, nonce );
|
|
1180
|
+ http_digest_update ( &ctx, cnonce );
|
|
1181
|
+ http_digest_final ( &ctx, ha1 );
|
|
1182
|
+ }
|
1154
|
1183
|
|
1155
|
1184
|
/* Generate HA2 */
|
1156
|
1185
|
http_digest_init ( &ctx );
|
|
@@ -1162,13 +1191,24 @@ static char * http_digest_auth ( struct http_request *http,
|
1162
|
1191
|
http_digest_init ( &ctx );
|
1163
|
1192
|
http_digest_update ( &ctx, ha1 );
|
1164
|
1193
|
http_digest_update ( &ctx, nonce );
|
|
1194
|
+ if ( qop ) {
|
|
1195
|
+ http_digest_update ( &ctx, "00000001" /* nc */ );
|
|
1196
|
+ http_digest_update ( &ctx, cnonce );
|
|
1197
|
+ http_digest_update ( &ctx, "auth" /* qop */ );
|
|
1198
|
+ }
|
1165
|
1199
|
http_digest_update ( &ctx, ha2 );
|
1166
|
1200
|
http_digest_final ( &ctx, response );
|
1167
|
1201
|
|
1168
|
1202
|
/* Generate the authorisation string */
|
1169
|
1203
|
len = asprintf ( &auth, "Authorization: Digest username=\"%s\", "
|
1170
|
1204
|
"realm=\"%s\", nonce=\"%s\", uri=\"%s\", "
|
1171
|
|
- "%s%s%sresponse=\"%s\"\r\n", user, realm, nonce, uri,
|
|
1205
|
+ "%s%s%s%s%s%s%s%sresponse=\"%s\"\r\n",
|
|
1206
|
+ user, realm, nonce, uri,
|
|
1207
|
+ ( qop ? "qop=\"auth\", algorithm=" : "" ),
|
|
1208
|
+ ( qop ? ( md5sess ? "MD5-sess, " : "MD5, " ) : "" ),
|
|
1209
|
+ ( qop ? "nc=00000001, cnonce=\"" : "" ),
|
|
1210
|
+ ( qop ? cnonce : "" ),
|
|
1211
|
+ ( qop ? "\", " : "" ),
|
1172
|
1212
|
( opaque ? "opaque=\"" : "" ),
|
1173
|
1213
|
( opaque ? opaque : "" ),
|
1174
|
1214
|
( opaque ? "\", " : "" ), response );
|