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
|