php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Return to Bug #55677
Patch digest.patch revision 2011-09-13 08:57 UTC by kolya at telepark dot ua

Patch digest.patch for SOAP related Bug #55677

Patch version 2011-09-13 08:57 UTC

Return to Bug #55677 | Download this patch
Patch Revisions:

Developer: kolya@telepark.ua

diff -U 3 -H -b -B -d -r -N ./php-5.3.8.old/ext/soap/php_http.c ./php-5.3.8.new/ext/soap/php_http.c
--- ./php-5.3.8.old/ext/soap/php_http.c	2011-01-01 04:19:59.000000000 +0200
+++ ./php-5.3.8.new/ext/soap/php_http.c	2011-09-13 11:22:53.768255853 +0300
@@ -24,6 +24,18 @@
 #include "ext/standard/md5.h"
 #include "ext/standard/php_rand.h"
 
+#define HASHLEN                               16
+typedef unsigned char HASH[HASHLEN];
+#define HASHHEXLEN                            32
+typedef unsigned char HASHHEX[HASHHEXLEN];
+#define u_char                                unsigned char
+#define PARAM_LENGTH                          255
+
+static void bin2Hex(HASH Bin, HASHHEX Hex);
+static void digest_calc_ha1(u_char* alg, u_char *login, u_char *realm, u_char *password, u_char *nonce, u_char *cnonce, HASHHEX session_key);
+static void digest_calc_pesponse(HASHHEX HA1, u_char *nonce, u_char *nc, u_char *cnonce, u_char *qop, u_char *method, u_char *uri, HASHHEX hentity, HASHHEX response);
+
+
 static char *get_http_header_value(char *headers, char *type);
 static int get_http_body(php_stream *socketd, int close, char *headers,  char **response, int *out_size TSRMLS_DC);
 static int get_http_headers(php_stream *socketd,char **response, int *out_size TSRMLS_DC);
@@ -493,149 +505,91 @@
 			has_authorization = 1;
 			if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_digest", sizeof("_digest"), (void **)&digest) == SUCCESS) {
 				if (Z_TYPE_PP(digest) == IS_ARRAY) {
-					char          HA1[33], HA2[33], response[33], cnonce[33], nc[9];
-					PHP_MD5_CTX   md5ctx;
-					unsigned char hash[16];
+					u_char dUsername[PARAM_LENGTH];
+					u_char dPassword[PARAM_LENGTH];
+					u_char dNonce[PARAM_LENGTH];
+					u_char dCNonce[HASHHEXLEN]; snprintf(dCNonce, HASHHEXLEN, "%08x", php_rand(TSRMLS_C));
+					u_char dRealm[PARAM_LENGTH];
+					u_char dAlg[PARAM_LENGTH] = "MD5";
+					u_char dNC[9] = "00000001";
+					u_char dMethod[PARAM_LENGTH] = "POST";
+					u_char dQop[PARAM_LENGTH] = "auth";
+					u_char dOpaque[PARAM_LENGTH];
+					u_char dUri[PARAM_LENGTH] = "/";
+					HASHHEX HA1;
+					HASHHEX HA2 = "";
+					HASHHEX response;
 
-					PHP_MD5Init(&md5ctx);
-					snprintf(cnonce, sizeof(cnonce), "%ld", php_rand(TSRMLS_C));
-					PHP_MD5Update(&md5ctx, (unsigned char*)cnonce, strlen(cnonce));
-					PHP_MD5Final(hash, &md5ctx);
-					make_digest(cnonce, hash);
+					dUsername[0] = dPassword[0] = dNonce[0] = dRealm[0] = dOpaque[0]  = '\0';
 
-					if (zend_hash_find(Z_ARRVAL_PP(digest), "nc", sizeof("nc"), (void **)&tmp) == SUCCESS &&
-					    Z_TYPE_PP(tmp) == IS_LONG) {
-						Z_LVAL_PP(tmp)++;
-						snprintf(nc, sizeof(nc), "%08ld", Z_LVAL_PP(tmp));
-					} else {
-						add_assoc_long(*digest, "nc", 1);
-						strcpy(nc, "00000001");
-					}
+					strncpy(dUsername, Z_STRVAL_PP(login), PARAM_LENGTH);
 
-					PHP_MD5Init(&md5ctx);
-					PHP_MD5Update(&md5ctx, (unsigned char*)Z_STRVAL_PP(login), Z_STRLEN_PP(login));
-					PHP_MD5Update(&md5ctx, (unsigned char*)":", 1);
-					if (zend_hash_find(Z_ARRVAL_PP(digest), "realm", sizeof("realm"), (void **)&tmp) == SUCCESS &&
-					    Z_TYPE_PP(tmp) == IS_STRING) {
-						PHP_MD5Update(&md5ctx, (unsigned char*)Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
-					}
-					PHP_MD5Update(&md5ctx, (unsigned char*)":", 1);
-					if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_password", sizeof("_password"), (void **)&password) == SUCCESS &&
-					    Z_TYPE_PP(password) == IS_STRING) {
-						PHP_MD5Update(&md5ctx, (unsigned char*)Z_STRVAL_PP(password), Z_STRLEN_PP(password));
+					if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_password", sizeof("_password"), (void **)&password) == SUCCESS && Z_TYPE_PP(password) == IS_STRING) {
+						strncpy(dPassword, Z_STRVAL_PP(password), PARAM_LENGTH);
 					}
-					PHP_MD5Final(hash, &md5ctx);
-					make_digest(HA1, hash);
-					if (zend_hash_find(Z_ARRVAL_PP(digest), "algorithm", sizeof("algorithm"), (void **)&tmp) == SUCCESS &&
-					    Z_TYPE_PP(tmp) == IS_STRING &&
-					    Z_STRLEN_PP(tmp) == sizeof("md5-sess")-1 &&
-					    stricmp(Z_STRVAL_PP(tmp), "md5-sess") == 0) {
-						PHP_MD5Init(&md5ctx);
-						PHP_MD5Update(&md5ctx, (unsigned char*)HA1, 32);
-						PHP_MD5Update(&md5ctx, (unsigned char*)":", 1);
-						if (zend_hash_find(Z_ARRVAL_PP(digest), "nonce", sizeof("nonce"), (void **)&tmp) == SUCCESS &&
-						    Z_TYPE_PP(tmp) == IS_STRING) {
-							PHP_MD5Update(&md5ctx, (unsigned char*)Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
+
+					if (zend_hash_find(Z_ARRVAL_PP(digest), "nonce", sizeof("nonce"), (void **)&tmp) == SUCCESS && Z_TYPE_PP(tmp) == IS_STRING) {
+						strncpy(dNonce, Z_STRVAL_PP(tmp), PARAM_LENGTH);
 						}
-						PHP_MD5Update(&md5ctx, (unsigned char*)":", 1);
-						PHP_MD5Update(&md5ctx, (unsigned char*)cnonce, 8);
-						PHP_MD5Final(hash, &md5ctx);
-						make_digest(HA1, hash);
+
+					if (zend_hash_find(Z_ARRVAL_PP(digest), "realm", sizeof("realm"), (void **)&tmp) == SUCCESS && Z_TYPE_PP(tmp) == IS_STRING) {
+						strncpy(dRealm, Z_STRVAL_PP(tmp), PARAM_LENGTH);
 					}
 
-					PHP_MD5Init(&md5ctx);
-					PHP_MD5Update(&md5ctx, (unsigned char*)"POST:", sizeof("POST:")-1);
-					if (phpurl->path) {
-						PHP_MD5Update(&md5ctx, (unsigned char*)phpurl->path, strlen(phpurl->path));
-					} else {
-						PHP_MD5Update(&md5ctx, (unsigned char*)"/", 1);
+					if (zend_hash_find(Z_ARRVAL_PP(digest), "algorithm", sizeof("algorithm"), (void **)&tmp) == SUCCESS && Z_TYPE_PP(tmp) == IS_STRING) {
+						strncpy(dAlg, Z_STRVAL_PP(tmp), PARAM_LENGTH);
 					}
-					if (phpurl->query) {
-						PHP_MD5Update(&md5ctx, (unsigned char*)"?", 1);
-						PHP_MD5Update(&md5ctx, (unsigned char*)phpurl->query, strlen(phpurl->query));
+
+					if (zend_hash_find(Z_ARRVAL_PP(digest), "qop", sizeof("qop"), (void **)&tmp) == SUCCESS && Z_TYPE_PP(tmp) == IS_STRING) {
+						strncpy(dQop, Z_STRVAL_PP(tmp), PARAM_LENGTH);
 					}
 
-					/* TODO: Support for qop="auth-int" */
-/*
-					if (zend_hash_find(Z_ARRVAL_PP(digest), "qop", sizeof("qop"), (void **)&tmp) == SUCCESS &&
-					    Z_TYPE_PP(tmp) == IS_STRING &&
-					    Z_STRLEN_PP(tmp) == sizeof("auth-int")-1 &&
-					    stricmp(Z_STRVAL_PP(tmp), "auth-int") == 0) {
-						PHP_MD5Update(&md5ctx, ":", 1);
-						PHP_MD5Update(&md5ctx, HEntity, HASHHEXLEN);
+					if (zend_hash_find(Z_ARRVAL_PP(digest), "opaque", sizeof("opaque"), (void **)&tmp) == SUCCESS && Z_TYPE_PP(tmp) == IS_STRING) {
+						strncpy(dOpaque, Z_STRVAL_PP(tmp), PARAM_LENGTH);
 					}
-*/
-					PHP_MD5Final(hash, &md5ctx);
-					make_digest(HA2, hash);
 
-					PHP_MD5Init(&md5ctx);
-					PHP_MD5Update(&md5ctx, (unsigned char*)HA1, 32);
-					PHP_MD5Update(&md5ctx, (unsigned char*)":", 1);
-					if (zend_hash_find(Z_ARRVAL_PP(digest), "nonce", sizeof("nonce"), (void **)&tmp) == SUCCESS &&
-					    Z_TYPE_PP(tmp) == IS_STRING) {
-						PHP_MD5Update(&md5ctx, (unsigned char*)Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
+					if (phpurl->path) {
+						strncpy(dUri, phpurl->path, PARAM_LENGTH);
+
+						if (phpurl->query) {
+							strncat(dUri, "/", 1);
+							strncat(dUri, phpurl->query, PARAM_LENGTH - strlen(dUri));
 					}
-					PHP_MD5Update(&md5ctx, (unsigned char*)":", 1);
-					if (zend_hash_find(Z_ARRVAL_PP(digest), "qop", sizeof("qop"), (void **)&tmp) == SUCCESS &&
-					    Z_TYPE_PP(tmp) == IS_STRING) {
-						PHP_MD5Update(&md5ctx, (unsigned char*)nc, 8);
-						PHP_MD5Update(&md5ctx, (unsigned char*)":", 1);
-						PHP_MD5Update(&md5ctx, (unsigned char*)cnonce, 8);
-						PHP_MD5Update(&md5ctx, (unsigned char*)":", 1);
-						/* TODO: Support for qop="auth-int" */
-						PHP_MD5Update(&md5ctx, (unsigned char*)"auth", sizeof("auth")-1);
-						PHP_MD5Update(&md5ctx, (unsigned char*)":", 1);
 					}
-					PHP_MD5Update(&md5ctx, (unsigned char*)HA2, 32);
-					PHP_MD5Final(hash, &md5ctx);
-					make_digest(response, hash);
+
+					digest_calc_ha1(dAlg, dUsername, dRealm, dPassword, dNonce, dCNonce, HA1);
+					digest_calc_pesponse(HA1, dNonce, dNC, dCNonce, dQop, dMethod, dUri, HA2, response);
 	
 					smart_str_append_const(&soap_headers, "Authorization: Digest username=\"");
 					smart_str_appendl(&soap_headers, Z_STRVAL_PP(login), Z_STRLEN_PP(login));
-					if (zend_hash_find(Z_ARRVAL_PP(digest), "realm", sizeof("realm"), (void **)&tmp) == SUCCESS &&
-					    Z_TYPE_PP(tmp) == IS_STRING) {
+
 						smart_str_append_const(&soap_headers, "\", realm=\"");
-						smart_str_appendl(&soap_headers, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
-					}
-					if (zend_hash_find(Z_ARRVAL_PP(digest), "nonce", sizeof("nonce"), (void **)&tmp) == SUCCESS &&
-					    Z_TYPE_PP(tmp) == IS_STRING) {
+					smart_str_appendl(&soap_headers, dRealm, strlen(dRealm));
+
 						smart_str_append_const(&soap_headers, "\", nonce=\"");
-						smart_str_appendl(&soap_headers, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
-					}
+					smart_str_appendl(&soap_headers, dNonce, strlen(dNonce));
+
 					smart_str_append_const(&soap_headers, "\", uri=\"");
-					if (phpurl->path) {
-						smart_str_appends(&soap_headers, phpurl->path);
-					} else {
-						smart_str_appendc(&soap_headers, '/');
-					} 
-					if (phpurl->query) {
-						smart_str_appendc(&soap_headers, '?');
-						smart_str_appends(&soap_headers, phpurl->query);
-					}
-					if (phpurl->fragment) {
-						smart_str_appendc(&soap_headers, '#');
-						smart_str_appends(&soap_headers, phpurl->fragment);
-					}
-					if (zend_hash_find(Z_ARRVAL_PP(digest), "qop", sizeof("qop"), (void **)&tmp) == SUCCESS &&
-					    Z_TYPE_PP(tmp) == IS_STRING) {
-					/* TODO: Support for qop="auth-int" */
-						smart_str_append_const(&soap_headers, "\", qop=\"auth");
-						smart_str_append_const(&soap_headers, "\", nc=\"");
-						smart_str_appendl(&soap_headers, nc, 8);
-						smart_str_append_const(&soap_headers, "\", cnonce=\"");
-						smart_str_appendl(&soap_headers, cnonce, 8);
-					}
+					smart_str_appendl(&soap_headers, dUri, strlen(dUri));
+
+					smart_str_append_const(&soap_headers, "\", qop=");     /* 'qop' do not use character (") */
+					smart_str_appendl(&soap_headers, dQop, strlen(dQop));
+
+					smart_str_append_const(&soap_headers, ", nc=");        /* 'nc' do not use character (") */
+					smart_str_appendl(&soap_headers, dNC, strlen(dNC));
+
+					smart_str_append_const(&soap_headers, ", cnonce=\"");
+					smart_str_appendl(&soap_headers, dCNonce, strlen(dCNonce));
+
 					smart_str_append_const(&soap_headers, "\", response=\"");
-					smart_str_appendl(&soap_headers, response, 32);
-					if (zend_hash_find(Z_ARRVAL_PP(digest), "opaque", sizeof("opaque"), (void **)&tmp) == SUCCESS &&
-					    Z_TYPE_PP(tmp) == IS_STRING) {
+					smart_str_appendl(&soap_headers, response, strlen(response));
+
 						smart_str_append_const(&soap_headers, "\", opaque=\"");
-						smart_str_appendl(&soap_headers, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
-					}
-					if (zend_hash_find(Z_ARRVAL_PP(digest), "algorithm", sizeof("algorithm"), (void **)&tmp) == SUCCESS &&
-						Z_TYPE_PP(tmp) == IS_STRING) {
+					smart_str_appendl(&soap_headers, dOpaque, strlen(dOpaque));
+
+					if (strlen(dAlg) != 3) {
 						smart_str_append_const(&soap_headers, "\", algorithm=\"");
-						smart_str_appendl(&soap_headers, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
+						smart_str_appendl(&soap_headers, dAlg, strlen(dAlg));
 					}
 					smart_str_append_const(&soap_headers, "\"\r\n");
 				}
@@ -1439,6 +1393,101 @@
 	(*out_size) = tmp_response.len;
 	return done;
 }
+
+static void bin2Hex(HASH Bin, HASHHEX Hex)
+{
+    unsigned short i;
+    unsigned char j;
+
+    for (i = 0; i < HASHLEN; i++) {
+        j = (Bin[i] >> 4) & 0xf;
+        if (j <= 9)
+            Hex[i*2] = (j + '0');
+         else
+            Hex[i*2] = (j + 'a' - 10);
+        j = Bin[i] & 0xf;
+        if (j <= 9)
+            Hex[i*2+1] = (j + '0');
+         else
+            Hex[i*2+1] = (j + 'a' - 10);
+    };
+    Hex[HASHHEXLEN] = '\0';
+};
+
+#define DELIMETER                           ":"
+#define DELIMETERLENGTH                     1
+static void digest_calc_ha1(u_char* alg, u_char *login, u_char *realm, u_char *password, u_char *nonce, u_char *cnonce, HASHHEX session_key)
+{
+#define MD5_SESS                "md5-sess"
+
+        PHP_MD5_CTX   md5ctx;
+        HASH HA1;
+
+        PHP_MD5Init(&md5ctx);
+        PHP_MD5Update(&md5ctx, login, strlen(login));
+        PHP_MD5Update(&md5ctx, (unsigned char*) DELIMETER, DELIMETERLENGTH);
+        PHP_MD5Update(&md5ctx, realm, strlen(realm));
+        PHP_MD5Update(&md5ctx, (unsigned char*) DELIMETER, DELIMETERLENGTH);
+        PHP_MD5Update(&md5ctx, password, strlen(password));
+        PHP_MD5Final(HA1, &md5ctx);
+
+        if (!strncasecmp(alg, MD5_SESS, sizeof(MD5_SESS))) {
+                PHP_MD5Init(&md5ctx);
+                PHP_MD5Update(&md5ctx, HA1, HASHLEN);
+                PHP_MD5Update(&md5ctx, (unsigned char*) DELIMETER, DELIMETERLENGTH);
+                PHP_MD5Update(&md5ctx, nonce, strlen(nonce));
+                PHP_MD5Update(&md5ctx, (unsigned char*) DELIMETER, DELIMETERLENGTH);
+                PHP_MD5Update(&md5ctx, cnonce, strlen(cnonce));
+                PHP_MD5Final(HA1, &md5ctx);
+        }
+
+        bin2Hex(HA1, session_key);
+
+#undef MD5_SESS
+}
+
+static void digest_calc_pesponse(HASHHEX HA1, u_char *nonce, u_char *nc, u_char *cnonce, u_char *qop, u_char *method, u_char *uri, HASHHEX hentity, HASHHEX response)
+{
+#define TYPE_AUTH                "auth-int"
+        PHP_MD5_CTX   md5ctx;
+        HASH HA2;
+        HASH RespHash;
+        HASHHEX HA2Hex;
+
+        // calculate H(A2)
+        PHP_MD5Init(&md5ctx);
+        PHP_MD5Update(&md5ctx, method, strlen(method));
+        PHP_MD5Update(&md5ctx, (unsigned char*) DELIMETER, DELIMETERLENGTH);
+        PHP_MD5Update(&md5ctx, uri, strlen(uri));
+        if (!strncasecmp(qop, TYPE_AUTH, sizeof(TYPE_AUTH))) {
+                PHP_MD5Update(&md5ctx, (unsigned char*) DELIMETER, DELIMETERLENGTH);
+                PHP_MD5Update(&md5ctx, hentity, HASHHEXLEN);
+        }
+        PHP_MD5Final(HA2, &md5ctx);
+        bin2Hex(HA2, HA2Hex);
+
+        // calculate response
+        PHP_MD5Init(&md5ctx);
+        PHP_MD5Update(&md5ctx, HA1, HASHHEXLEN);
+        PHP_MD5Update(&md5ctx, (unsigned char*) DELIMETER, DELIMETERLENGTH);
+        PHP_MD5Update(&md5ctx, nonce, strlen(nonce));
+        PHP_MD5Update(&md5ctx, (unsigned char*) DELIMETER, DELIMETERLENGTH);
+        if (qop[0] != '\0') {
+                PHP_MD5Update(&md5ctx, nc, strlen(nc));
+                PHP_MD5Update(&md5ctx, (unsigned char*) DELIMETER, DELIMETERLENGTH);
+                PHP_MD5Update(&md5ctx, cnonce, strlen(cnonce));
+                PHP_MD5Update(&md5ctx, (unsigned char*) DELIMETER, DELIMETERLENGTH);
+                PHP_MD5Update(&md5ctx, qop, strlen(qop));
+                PHP_MD5Update(&md5ctx, (unsigned char*) DELIMETER, DELIMETERLENGTH);
+        }
+        PHP_MD5Update(&md5ctx, HA2Hex, HASHHEXLEN);
+        PHP_MD5Final(RespHash, &md5ctx);
+        bin2Hex(RespHash, response);
+#undef TYPE_AUTH
+}
+#undef DELIMETERLENGTH
+#undef DELIMETER
+
 /*
  * Local variables:
  * tab-width: 4
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sat Apr 20 06:01:28 2024 UTC