From: Michael R Sweet Date: Fri, 14 Sep 2018 18:58:35 +0000 (-0400) Subject: More Digest changes. X-Git-Tag: v2.3b6~96 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5737d5eba4ed4b376555b8c8de0c58ed8f598bb7;p=thirdparty%2Fcups.git More Digest changes. --- diff --git a/cups/auth.c b/cups/auth.c index a2651527ba..47e14168e4 100644 --- a/cups/auth.c +++ b/cups/auth.c @@ -266,15 +266,7 @@ cupsDoAuthentication( cups_auth_param(schemedata, "nonce", nonce, sizeof(nonce)); cups_auth_param(schemedata, "realm", http->realm, sizeof(http->realm)); - if (strcmp(nonce, http->nonce)) - { - strlcpy(http->nonce, nonce, sizeof(http->nonce)); - http->nonce_count = 1; - } - else - http->nonce_count ++; - - if (_httpSetDigestAuthString(http, method, resource)) + if (_httpSetDigestAuthString(http, nonce, method, resource)) break; } } diff --git a/cups/getputfile.c b/cups/getputfile.c index ba88973c00..2cdb9cb099 100644 --- a/cups/getputfile.c +++ b/cups/getputfile.c @@ -92,16 +92,7 @@ cupsGetFd(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFA * Update the Digest authentication string... */ - if (http->nextnonce[0]) - { - strlcpy(http->nonce, http->nextnonce, sizeof(http->nonce)); - http->nonce_count = 1; - http->nextnonce[0] = '\0'; - } - else - http->nonce_count ++; - - _httpSetDigestAuthString(http, "GET", resource); + _httpSetDigestAuthString(http, http->nextnonce, "GET", resource); } #ifdef HAVE_GSSAPI @@ -356,16 +347,7 @@ cupsPutFd(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFA * Update the Digest authentication string... */ - if (http->nextnonce[0]) - { - strlcpy(http->nonce, http->nextnonce, sizeof(http->nonce)); - http->nonce_count = 1; - http->nextnonce[0] = '\0'; - } - else - http->nonce_count ++; - - _httpSetDigestAuthString(http, "PUT", resource); + _httpSetDigestAuthString(http, http->nextnonce, "PUT", resource); } #ifdef HAVE_GSSAPI diff --git a/cups/http-private.h b/cups/http-private.h index db71ede28c..e7f7e445fe 100644 --- a/cups/http-private.h +++ b/cups/http-private.h @@ -440,7 +440,7 @@ extern const char *_httpResolveURI(const char *uri, char *resolved_uri, size_t resolved_size, int options, int (*cb)(void *context), void *context); -extern int _httpSetDigestAuthString(http_t *http, const char *method, const char *resource); +extern int _httpSetDigestAuthString(http_t *http, const char *nonce, const char *method, const char *resource); extern const char *_httpStatus(cups_lang_t *lang, http_status_t status); extern void _httpTLSInitialize(void); extern size_t _httpTLSPending(http_t *http); diff --git a/cups/http-support.c b/cups/http-support.c index cd423aefd9..3834dbef84 100644 --- a/cups/http-support.c +++ b/cups/http-support.c @@ -661,139 +661,6 @@ httpDecode64_2(char *out, /* I - String to write to */ } -/* - * '_httpSetDigestAuthString()' - Calculate a Digest authentication response - * using the appropriate RFC 2068/2617/7616 - * algorithm. - */ - -int /* O - 1 on success, 0 on failure */ -_httpSetDigestAuthString( - http_t *http, /* I - HTTP connection */ - const char *method, /* I - HTTP method */ - const char *resource) /* I - HTTP resource path */ -{ - char kd[65], /* Final MD5/SHA-256 digest */ - ha1[65], /* Hash of username:realm:password */ - ha2[65], /* Hash of method:request-uri */ - username[HTTP_MAX_VALUE], - /* username:password */ - *password, /* Pointer to password */ - temp[1024], /* Temporary string */ - digest[1024]; /* Digest auth data */ - unsigned char hash[32]; /* Hash buffer */ - size_t hashsize; /* Size of hash */ - - - DEBUG_printf(("2_httpSetDigestAuthString(http=%p, method=\"%s\", resource=\"%s\")", http, method, resource)); - - strlcpy(username, http->userpass, sizeof(username)); - if ((password = strchr(username, ':')) != NULL) - *password++ = '\0'; - else - return (0); - - if (http->algorithm[0]) - { - /* - * Follow RFC 2617/7616... - */ - - int i; /* Looping var */ - char cnonce[65]; /* cnonce value */ - const char *hashalg; /* Hashing algorithm */ - - for (i = 0; i < 64; i ++) - cnonce[i] = "0123456789ABCDEF"[CUPS_RAND() & 15]; - cnonce[64] = '\0'; - - if (!_cups_strcasecmp(http->algorithm, "MD5")) - { - /* - * RFC 2617 Digest with MD5 - */ - - hashalg = "md5"; - } - else if (!_cups_strcasecmp(http->algorithm, "SHA-256")) - { - /* - * RFC 7616 Digest with SHA-256 - */ - - hashalg = "sha2-256"; - } - else - { - /* - * Some other algorithm we don't support, skip this one... - */ - - return (0); - } - - /* - * Calculate digest value... - */ - - /* H(A1) = H(username:realm:password) */ - snprintf(temp, sizeof(temp), "%s:%s:%s", username, http->realm, password); - hashsize = (size_t)cupsHashData(hashalg, (unsigned char *)temp, strlen(temp), hash, sizeof(hash)); - cupsHashString(hash, hashsize, ha1, sizeof(ha1)); - - /* H(A2) = H(method:uri) */ - snprintf(temp, sizeof(temp), "%s:%s", method, resource); - hashsize = (size_t)cupsHashData(hashalg, (unsigned char *)temp, strlen(temp), hash, sizeof(hash)); - cupsHashString(hash, hashsize, ha2, sizeof(ha2)); - - /* KD = H(H(A1):nonce:nc:cnonce:qop:H(A2)) */ - snprintf(temp, sizeof(temp), "%s:%s:%08x:%s:%s:%s", ha1, http->nonce, http->nonce_count, cnonce, "auth", ha2); - hashsize = (size_t)cupsHashData(hashalg, (unsigned char *)temp, strlen(temp), hash, sizeof(hash)); - cupsHashString(hash, hashsize, kd, sizeof(kd)); - - /* - * Pass the RFC 2617/7616 WWW-Authenticate header... - */ - - if (http->opaque[0]) - snprintf(digest, sizeof(digest), "username=\"%s\", realm=\"%s\", nonce=\"%s\", algorithm=%s, qop=auth, opaque=\"%s\", cnonce=\"%s\", nc=%08x, uri=\"%s\", response=\"%s\"", cupsUser(), http->realm, http->nonce, http->algorithm, http->opaque, cnonce, http->nonce_count, resource, kd); - else - snprintf(digest, sizeof(digest), "username=\"%s\", realm=\"%s\", nonce=\"%s\", algorithm=%s, qop=auth, cnonce=\"%s\", nc=%08x, uri=\"%s\", response=\"%s\"", username, http->realm, http->nonce, http->algorithm, cnonce, http->nonce_count, resource, kd); - } - else - { - /* - * Use old RFC 2069 Digest method... - */ - - /* H(A1) = H(username:realm:password) */ - snprintf(temp, sizeof(temp), "%s:%s:%s", username, http->realm, password); - hashsize = (size_t)cupsHashData("md5", (unsigned char *)temp, strlen(temp), hash, sizeof(hash)); - cupsHashString(hash, hashsize, ha1, sizeof(ha1)); - - /* H(A2) = H(method:uri) */ - snprintf(temp, sizeof(temp), "%s:%s", method, resource); - hashsize = (size_t)cupsHashData("md5", (unsigned char *)temp, strlen(temp), hash, sizeof(hash)); - cupsHashString(hash, hashsize, ha2, sizeof(ha2)); - - /* KD = H(H(A1):nonce:H(A2)) */ - snprintf(temp, sizeof(temp), "%s:%s:%s", ha1, http->nonce, ha2); - hashsize = (size_t)cupsHashData("md5", (unsigned char *)temp, strlen(temp), hash, sizeof(hash)); - cupsHashString(hash, hashsize, kd, sizeof(kd)); - - /* - * Pass the old RFC 2069 WWW-Authenticate header... - */ - - snprintf(digest, sizeof(digest), "username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", response=\"%s\"", username, http->realm, http->nonce, resource, kd); - } - - httpSetAuthString(http, "Digest", digest); - - return (1); -} - - /* * 'httpEncode64()' - Base64-encode a string. * @@ -1430,6 +1297,152 @@ httpSeparateURI( } +/* + * '_httpSetDigestAuthString()' - Calculate a Digest authentication response + * using the appropriate RFC 2068/2617/7616 + * algorithm. + */ + +int /* O - 1 on success, 0 on failure */ +_httpSetDigestAuthString( + http_t *http, /* I - HTTP connection */ + const char *nonce, /* I - Nonce value */ + const char *method, /* I - HTTP method */ + const char *resource) /* I - HTTP resource path */ +{ + char kd[65], /* Final MD5/SHA-256 digest */ + ha1[65], /* Hash of username:realm:password */ + ha2[65], /* Hash of method:request-uri */ + username[HTTP_MAX_VALUE], + /* username:password */ + *password, /* Pointer to password */ + temp[1024], /* Temporary string */ + digest[1024]; /* Digest auth data */ + unsigned char hash[32]; /* Hash buffer */ + size_t hashsize; /* Size of hash */ + + + DEBUG_printf(("2_httpSetDigestAuthString(http=%p, nonce=\"%s\", method=\"%s\", resource=\"%s\")", http, nonce, method, resource)); + + if (nonce && *nonce && strcmp(nonce, http->nonce)) + { + strlcpy(http->nonce, nonce, sizeof(http->nonce)); + + if (nonce == http->nextnonce) + http->nextnonce[0] = '\0'; + + http->nonce_count = 1; + } + else + http->nonce_count ++; + + strlcpy(username, http->userpass, sizeof(username)); + if ((password = strchr(username, ':')) != NULL) + *password++ = '\0'; + else + return (0); + + if (http->algorithm[0]) + { + /* + * Follow RFC 2617/7616... + */ + + int i; /* Looping var */ + char cnonce[65]; /* cnonce value */ + const char *hashalg; /* Hashing algorithm */ + + for (i = 0; i < 64; i ++) + cnonce[i] = "0123456789ABCDEF"[CUPS_RAND() & 15]; + cnonce[64] = '\0'; + + if (!_cups_strcasecmp(http->algorithm, "MD5")) + { + /* + * RFC 2617 Digest with MD5 + */ + + hashalg = "md5"; + } + else if (!_cups_strcasecmp(http->algorithm, "SHA-256")) + { + /* + * RFC 7616 Digest with SHA-256 + */ + + hashalg = "sha2-256"; + } + else + { + /* + * Some other algorithm we don't support, skip this one... + */ + + return (0); + } + + /* + * Calculate digest value... + */ + + /* H(A1) = H(username:realm:password) */ + snprintf(temp, sizeof(temp), "%s:%s:%s", username, http->realm, password); + hashsize = (size_t)cupsHashData(hashalg, (unsigned char *)temp, strlen(temp), hash, sizeof(hash)); + cupsHashString(hash, hashsize, ha1, sizeof(ha1)); + + /* H(A2) = H(method:uri) */ + snprintf(temp, sizeof(temp), "%s:%s", method, resource); + hashsize = (size_t)cupsHashData(hashalg, (unsigned char *)temp, strlen(temp), hash, sizeof(hash)); + cupsHashString(hash, hashsize, ha2, sizeof(ha2)); + + /* KD = H(H(A1):nonce:nc:cnonce:qop:H(A2)) */ + snprintf(temp, sizeof(temp), "%s:%s:%08x:%s:%s:%s", ha1, http->nonce, http->nonce_count, cnonce, "auth", ha2); + hashsize = (size_t)cupsHashData(hashalg, (unsigned char *)temp, strlen(temp), hash, sizeof(hash)); + cupsHashString(hash, hashsize, kd, sizeof(kd)); + + /* + * Pass the RFC 2617/7616 WWW-Authenticate header... + */ + + if (http->opaque[0]) + snprintf(digest, sizeof(digest), "username=\"%s\", realm=\"%s\", nonce=\"%s\", algorithm=%s, qop=auth, opaque=\"%s\", cnonce=\"%s\", nc=%08x, uri=\"%s\", response=\"%s\"", cupsUser(), http->realm, http->nonce, http->algorithm, http->opaque, cnonce, http->nonce_count, resource, kd); + else + snprintf(digest, sizeof(digest), "username=\"%s\", realm=\"%s\", nonce=\"%s\", algorithm=%s, qop=auth, cnonce=\"%s\", nc=%08x, uri=\"%s\", response=\"%s\"", username, http->realm, http->nonce, http->algorithm, cnonce, http->nonce_count, resource, kd); + } + else + { + /* + * Use old RFC 2069 Digest method... + */ + + /* H(A1) = H(username:realm:password) */ + snprintf(temp, sizeof(temp), "%s:%s:%s", username, http->realm, password); + hashsize = (size_t)cupsHashData("md5", (unsigned char *)temp, strlen(temp), hash, sizeof(hash)); + cupsHashString(hash, hashsize, ha1, sizeof(ha1)); + + /* H(A2) = H(method:uri) */ + snprintf(temp, sizeof(temp), "%s:%s", method, resource); + hashsize = (size_t)cupsHashData("md5", (unsigned char *)temp, strlen(temp), hash, sizeof(hash)); + cupsHashString(hash, hashsize, ha2, sizeof(ha2)); + + /* KD = H(H(A1):nonce:H(A2)) */ + snprintf(temp, sizeof(temp), "%s:%s:%s", ha1, http->nonce, ha2); + hashsize = (size_t)cupsHashData("md5", (unsigned char *)temp, strlen(temp), hash, sizeof(hash)); + cupsHashString(hash, hashsize, kd, sizeof(kd)); + + /* + * Pass the old RFC 2069 WWW-Authenticate header... + */ + + snprintf(digest, sizeof(digest), "username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", response=\"%s\"", username, http->realm, http->nonce, resource, kd); + } + + httpSetAuthString(http, "Digest", digest); + + return (1); +} + + /* * 'httpStateString()' - Return the string describing a HTTP state value. * diff --git a/cups/request.c b/cups/request.c index 924bb6fc00..e58beceeba 100644 --- a/cups/request.c +++ b/cups/request.c @@ -686,16 +686,7 @@ cupsSendRequest(http_t *http, /* I - Connection to server or @code CUPS_HTTP * Update the Digest authentication string... */ - if (http->nextnonce[0]) - { - strlcpy(http->nonce, http->nextnonce, sizeof(http->nonce)); - http->nonce_count = 1; - http->nextnonce[0] = '\0'; - } - else - http->nonce_count ++; - - _httpSetDigestAuthString(http, "POST", resource); + _httpSetDigestAuthString(http, http->nextnonce, "POST", resource); } #ifdef HAVE_GSSAPI diff --git a/cups/testhttp.c b/cups/testhttp.c index 1480d04b5b..dfb767c89e 100644 --- a/cups/testhttp.c +++ b/cups/testhttp.c @@ -628,6 +628,8 @@ main(int argc, /* I - Number of command-line arguments */ for (i = 1; i < argc; i ++) { + int new_auth; + if (!strcmp(argv[i], "-o")) { i ++; @@ -711,6 +713,8 @@ main(int argc, /* I - Number of command-line arguments */ printf("Checking file \"%s\"...\n", resource); + new_auth = 0; + do { if (!_cups_strcasecmp(httpGetField(http, HTTP_FIELD_CONNECTION), "close")) @@ -723,9 +727,13 @@ main(int argc, /* I - Number of command-line arguments */ } } + if (http->authstring && !strncmp(http->authstring, "Digest ", 7) && !new_auth) + _httpSetDigestAuthString(http, http->nextnonce, "HEAD", resource); + httpClearFields(http); httpSetField(http, HTTP_FIELD_AUTHORIZATION, httpGetAuthString(http)); httpSetField(http, HTTP_FIELD_ACCEPT_LANGUAGE, "en"); + if (httpHead(http, resource)) { if (httpReconnect2(http, 30000, NULL)) @@ -742,6 +750,8 @@ main(int argc, /* I - Number of command-line arguments */ while ((status = httpUpdate(http)) == HTTP_STATUS_CONTINUE); + new_auth = 0; + if (status == HTTP_STATUS_UNAUTHORIZED) { /* @@ -754,6 +764,8 @@ main(int argc, /* I - Number of command-line arguments */ * See if we can do authentication... */ + new_auth = 1; + if (cupsDoAuthentication(http, "HEAD", resource)) { status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED; @@ -802,6 +814,8 @@ main(int argc, /* I - Number of command-line arguments */ printf("Requesting file \"%s\" (Accept-Encoding: %s)...\n", resource, encoding ? encoding : "identity"); + new_auth = 0; + do { if (!_cups_strcasecmp(httpGetField(http, HTTP_FIELD_CONNECTION), "close")) @@ -814,6 +828,9 @@ main(int argc, /* I - Number of command-line arguments */ } } + if (http->authstring && !strncmp(http->authstring, "Digest ", 7) && !new_auth) + _httpSetDigestAuthString(http, http->nextnonce, "GET", resource); + httpClearFields(http); httpSetField(http, HTTP_FIELD_AUTHORIZATION, httpGetAuthString(http)); httpSetField(http, HTTP_FIELD_ACCEPT_LANGUAGE, "en"); @@ -835,6 +852,8 @@ main(int argc, /* I - Number of command-line arguments */ while ((status = httpUpdate(http)) == HTTP_STATUS_CONTINUE); + new_auth = 0; + if (status == HTTP_STATUS_UNAUTHORIZED) { /* @@ -847,6 +866,8 @@ main(int argc, /* I - Number of command-line arguments */ * See if we can do authentication... */ + new_auth = 1; + if (cupsDoAuthentication(http, "GET", resource)) { status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED;