static void http_da_calc_HA1(struct soap *soap, void **context, char *alg, char *userid, char *realm, char *passwd, char *nonce, char *cnonce, char HA1hex[33]) { char HA1[16]; md5_handler(soap, context, MD5_INIT, NULL, 0); md5_handler(soap, context, MD5_UPDATE, userid, strlen(userid)); md5_handler(soap, context, MD5_UPDATE, ":", 1); md5_handler(soap, context, MD5_UPDATE, realm, strlen(realm)); md5_handler(soap, context, MD5_UPDATE, ":", 1); md5_handler(soap, context, MD5_UPDATE, passwd, strlen(passwd)); md5_handler(soap, context, MD5_FINAL, HA1, 0); if (alg && !soap_tag_cmp(alg, "MD5-sess")) { md5_handler(soap, context, MD5_INIT, NULL, 0); md5_handler(soap, context, MD5_UPDATE, HA1, 16); md5_handler(soap, context, MD5_UPDATE, ":", 1); md5_handler(soap, context, MD5_UPDATE, nonce, strlen(nonce)); md5_handler(soap, context, MD5_UPDATE, ":", 1); md5_handler(soap, context, MD5_UPDATE, cnonce, strlen(cnonce)); md5_handler(soap, context, MD5_FINAL, HA1, 0); }; soap_s2hex(soap, (unsigned char*)HA1, HA1hex, 16); };
static void http_da_calc_response(struct soap *soap, void **context, char HA1hex[33], const char *nonce, const char *ncount, const char *cnonce, const char *qop, const char *method, const char *uri, char entityHAhex[33], char response[33]) { char HA2[16], HA2hex[33], responseHA[16]; md5_handler(soap, context, MD5_INIT, NULL, 0); md5_handler(soap, context, MD5_UPDATE, (char*)method, strlen(method)); md5_handler(soap, context, MD5_UPDATE, (char*)":", 1); md5_handler(soap, context, MD5_UPDATE, (char*)uri, strlen(uri)); if (qop && !soap_tag_cmp(qop, "auth-int")) { md5_handler(soap, context, MD5_UPDATE, (char*)":", 1); md5_handler(soap, context, MD5_UPDATE, entityHAhex, 32); } md5_handler(soap, context, MD5_FINAL, HA2, 0); soap_s2hex(soap, (unsigned char*)HA2, HA2hex, 16); md5_handler(soap, context, MD5_INIT, NULL, 0); md5_handler(soap, context, MD5_UPDATE, HA1hex, 32); if (nonce) { md5_handler(soap, context, MD5_UPDATE, (char*)":", 1); md5_handler(soap, context, MD5_UPDATE, (char*)nonce, strlen(nonce)); } md5_handler(soap, context, MD5_UPDATE, (char*)":", 1); if (qop && *qop) { md5_handler(soap, context, MD5_UPDATE, (char*)ncount, strlen(ncount)); md5_handler(soap, context, MD5_UPDATE, (char*)":", 1); md5_handler(soap, context, MD5_UPDATE, (char*)cnonce, strlen(cnonce)); md5_handler(soap, context, MD5_UPDATE, (char*)":", 1); md5_handler(soap, context, MD5_UPDATE, (char*)qop, strlen(qop)); md5_handler(soap, context, MD5_UPDATE, (char*)":", 1); } md5_handler(soap, context, MD5_UPDATE, HA2hex, 32); md5_handler(soap, context, MD5_FINAL, responseHA, 0); soap_s2hex(soap, (unsigned char*)responseHA, response, 16); }
static int http_da_calc_HA1(struct soap *soap, struct soap_smd_data *smd_data, const char *alg, const char *userid, const char *realm, const char *passwd, const char *nonce, const char *cnonce, char HA1hex[65]) { int smd_alg = SOAP_SMD_DGST_MD5; size_t smd_len = 16; char HA1[32]; if (alg && !soap_tag_cmp(alg, "SHA-256*")) { smd_alg = SOAP_SMD_DGST_SHA256; smd_len = 32; } if (soap_smd_init(soap, smd_data, smd_alg, NULL, 0) || soap_smd_update(soap, smd_data, userid, strlen(userid)) || soap_smd_update(soap, smd_data, ":", 1) || soap_smd_update(soap, smd_data, realm, strlen(realm)) || soap_smd_update(soap, smd_data, ":", 1) || soap_smd_update(soap, smd_data, passwd, strlen(passwd)) || soap_smd_final(soap, smd_data, HA1, NULL)) return soap->error; if (alg && !soap_tag_cmp(alg, "*-sess")) { if (soap_smd_init(soap, smd_data, smd_alg, NULL, 0) || soap_smd_update(soap, smd_data, HA1, smd_len)) return soap->error; if (nonce) { if (soap_smd_update(soap, smd_data, ":", 1) || soap_smd_update(soap, smd_data, nonce, strlen(nonce))) return soap->error; } if (soap_smd_update(soap, smd_data, ":", 1) || soap_smd_update(soap, smd_data, cnonce, strlen(cnonce)) || soap_smd_final(soap, smd_data, HA1, NULL)) return soap->error; } (void)soap_s2hex(soap, (unsigned char*)HA1, HA1hex, smd_len); return SOAP_OK; };
static int http_da_verify_method(struct soap *soap, const char *method, const char *passwd) { struct http_da_data *data = (struct http_da_data*)soap_lookup_plugin(soap, http_da_id); char HA1hex[65], entityHAhex[65], response[65], responseHA[32]; size_t smd_len = 16; if (!data) return SOAP_ERR; if (data->alg && !soap_tag_cmp(data->alg, "SHA-256*")) smd_len = 32; /* reject if none or basic authentication was used */ if (!soap->authrealm || !soap->userid || soap->passwd) /* passwd is set when basic auth is used */ return SOAP_ERR; /* require at least qop="auth" to prevent replay attacks */ if (!data->qop) return SOAP_ERR; if (http_da_session_update(soap->authrealm, data->nonce, data->opaque, data->cnonce, data->ncount)) return SOAP_ERR; if (http_da_calc_HA1(soap, &data->smd_data, data->alg, soap->userid, soap->authrealm, passwd, data->nonce, data->cnonce, HA1hex)) return soap->error; if (!soap_tag_cmp(data->qop, "auth-int")) (void)soap_s2hex(soap, (unsigned char*)data->digest, entityHAhex, smd_len); if (http_da_calc_response(soap, &data->smd_data, data->alg, HA1hex, data->nonce, data->ncount, data->cnonce, data->qop, method, soap->path, entityHAhex, response, responseHA)) return soap->error; /* check digest response values */ if (memcmp(data->response, responseHA, smd_len)) return SOAP_ERR; return SOAP_OK; }
static int http_da_verify_method(struct soap *soap, char *method, char *passwd) { struct http_da_data *data = (struct http_da_data*)soap_lookup_plugin(soap, http_da_id); char HA1[33], entityHAhex[33], response[33]; if (!data) return SOAP_ERR; /* reject if none or basic authentication was used */ if (!soap->authrealm || !soap->userid || soap->passwd) /* passwd is set when basic auth is used */ return SOAP_ERR; /* require at least qop="auth" to prevent replay attacks */ if (!data->qop) return SOAP_ERR; if (http_da_session_update(soap->authrealm, data->nonce, data->opaque, data->cnonce, data->ncount)) return SOAP_ERR; http_da_calc_HA1(soap, &data->context, NULL, soap->userid, soap->authrealm, passwd, data->nonce, data->cnonce, HA1); if (!soap_tag_cmp(data->qop, "auth-int")) soap_s2hex(soap, (unsigned char*)data->digest, entityHAhex, 16); http_da_calc_response(soap, &data->context, HA1, data->nonce, data->ncount, data->cnonce, data->qop, method, soap->path, entityHAhex, response); #ifdef SOAP_DEBUG fprintf(stderr, "Debug message: verifying client response=%s with calculated digest=%s\n", data->response, response); #endif /* check digest response values */ if (strcmp(data->response, response)) return SOAP_ERR; return SOAP_OK; }
static int http_da_post_header(struct soap *soap, const char *key, const char *val) { struct http_da_data *data = (struct http_da_data*)soap_lookup_plugin(soap, http_da_id); if (!data) return SOAP_PLUGIN_ERROR; /* client's HTTP Authorization response */ if (key && !strcmp(key, "Authorization")) { char HA1[33], entityHAhex[33], response[33]; char cnonce[HTTP_DA_NONCELEN]; char ncount[9]; char *qop, *method; md5_handler(soap, &data->context, MD5_FINAL, data->digest, 0); http_da_calc_nonce(soap, cnonce); http_da_calc_HA1(soap, &data->context, data->alg, soap->userid, soap->authrealm, soap->passwd, data->nonce, cnonce, HA1); if (data->qop && !soap_tag_cmp(data->qop, "*auth-int*")) { qop = "auth-int"; soap_s2hex(soap, (unsigned char*)data->digest, entityHAhex, 16); } else if (data->qop) qop = "auth"; else qop = NULL; if (soap->status == SOAP_GET) method = "GET"; else method = "POST"; sprintf(ncount, "%8.8lx", data->nc++); http_da_calc_response(soap, &data->context, HA1, data->nonce, ncount, cnonce, qop, method, soap->path, entityHAhex, response); sprintf(soap->tmpbuf, "Digest realm=\"%s\", username=\"%s\", nonce=\"%s\", uri=\"%s\", nc=%s, cnonce=\"%s\", response=\"%s\"", soap->authrealm, soap->userid, data->nonce, soap->path, ncount, cnonce, response); if (data->opaque) sprintf(soap->tmpbuf + strlen(soap->tmpbuf), ", opaque=\"%s\"", data->opaque); if (qop) sprintf(soap->tmpbuf + strlen(soap->tmpbuf), ", qop=\"%s\"", qop); return data->fposthdr(soap, key, soap->tmpbuf); } /* server's HTTP Authorization response */ if (key && !strcmp(key, "WWW-Authenticate")) { char nonce[HTTP_DA_NONCELEN]; char opaque[HTTP_DA_OPAQUELEN]; http_da_calc_nonce(soap, nonce); http_da_calc_opaque(soap, opaque); http_da_session_start(soap->authrealm, nonce, opaque); sprintf(soap->tmpbuf, "Digest realm=\"%s\", qop=\"auth,auth-int\", nonce=\"%s\", opaque=\"%s\"", soap->authrealm, nonce, opaque); return data->fposthdr(soap, key, soap->tmpbuf); } return data->fposthdr(soap, key, val); }
static int http_da_post_header(struct soap *soap, const char *key, const char *val) { struct http_da_data *data = (struct http_da_data*)soap_lookup_plugin(soap, http_da_id); if (!data) return SOAP_PLUGIN_ERROR; /* client's HTTP Authorization request */ if (key && (!strcmp(key, "Authorization") || !strcmp(key, "Proxy-Authorization"))) { char HA1[33], entityHAhex[33], response[33]; char cnonce[HTTP_DA_NONCELEN]; char ncount[9]; const char *qop, *method; const char *userid = (*key == 'A' ? soap->userid : soap->proxy_userid); const char *passwd = (*key == 'A' ? soap->passwd : soap->proxy_passwd); md5_handler(soap, &data->context, MD5_FINAL, data->digest, 0); if (!userid || !passwd || !soap->authrealm || !data->nonce) { #ifdef SOAP_DEBUG fprintf(stderr, "Debug message: authentication header failed, missing authentication data\n"); #endif return SOAP_OK; } http_da_calc_nonce(soap, cnonce); http_da_calc_HA1(soap, &data->context, data->alg, userid, soap->authrealm, passwd, data->nonce, cnonce, HA1); if (data->qop && !soap_tag_cmp(data->qop, "*auth-int*")) { qop = "auth-int"; soap_s2hex(soap, (unsigned char*)data->digest, entityHAhex, 16); } else if (data->qop) qop = "auth"; else qop = NULL; if (soap->status == SOAP_GET) method = "GET"; else if (soap->status == SOAP_CONNECT) method = "CONNECT"; else method = "POST"; #ifdef HAVE_SNPRINTF soap_snprintf(ncount, sizeof(ncount), "%8.8lx", data->nc++); #else sprintf(ncount, "%8.8lx", data->nc++); #endif http_da_calc_response(soap, &data->context, HA1, data->nonce, ncount, cnonce, qop, method, soap->path, entityHAhex, response); #ifdef HAVE_SNPRINTF soap_snprintf(soap->tmpbuf, sizeof(soap->tmpbuf), "Digest realm=\"%s\", username=\"%s\", nonce=\"%s\", uri=\"%s\", nc=%s, cnonce=\"%s\", response=\"%s\"", soap->authrealm, userid, data->nonce, soap->path, ncount, cnonce, response); #else sprintf(soap->tmpbuf, "Digest realm=\"%s\", username=\"%s\", nonce=\"%s\", uri=\"%s\", nc=%s, cnonce=\"%s\", response=\"%s\"", soap->authrealm, userid, data->nonce, soap->path, ncount, cnonce, response); #endif if (data->opaque) #ifdef HAVE_SNPRINTF soap_snprintf(soap->tmpbuf + strlen(soap->tmpbuf), sizeof(soap->tmpbuf) - strlen(soap->tmpbuf), ", opaque=\"%s\"", data->opaque); #else sprintf(soap->tmpbuf + strlen(soap->tmpbuf), ", opaque=\"%s\"", data->opaque); #endif if (qop) #ifdef HAVE_SNPRINTF soap_snprintf(soap->tmpbuf + strlen(soap->tmpbuf), sizeof(soap->tmpbuf) - strlen(soap->tmpbuf), ", qop=\"%s\"", qop); #else sprintf(soap->tmpbuf + strlen(soap->tmpbuf), ", qop=\"%s\"", qop); #endif return data->fposthdr(soap, key, soap->tmpbuf); } /* server's HTTP Authorization challenge/response */ if (key && (!strcmp(key, "WWW-Authenticate") || !strcmp(key, "Proxy-Authenticate"))) { char nonce[HTTP_DA_NONCELEN]; char opaque[HTTP_DA_OPAQUELEN]; http_da_calc_nonce(soap, nonce); http_da_calc_opaque(soap, opaque); http_da_session_start(soap->authrealm, nonce, opaque); #ifdef HAVE_SNPRINTF soap_snprintf(soap->tmpbuf, sizeof(soap->tmpbuf), "Digest realm=\"%s\", qop=\"auth,auth-int\", nonce=\"%s\", opaque=\"%s\"", soap->authrealm, nonce, opaque); #else sprintf(soap->tmpbuf, "Digest realm=\"%s\", qop=\"auth,auth-int\", nonce=\"%s\", opaque=\"%s\"", soap->authrealm, nonce, opaque); #endif return data->fposthdr(soap, key, soap->tmpbuf); } return data->fposthdr(soap, key, val); }
static int http_da_post_header(struct soap *soap, const char *key, const char *val) { struct http_da_data *data = (struct http_da_data*)soap_lookup_plugin(soap, http_da_id); if (!data) return SOAP_PLUGIN_ERROR; /* client's HTTP Authorization request */ if (key && (!strcmp(key, "Authorization") || !strcmp(key, "Proxy-Authorization"))) { char HA1hex[65], entityHAhex[65], response[65], responseHA[32]; char cnonce[HTTP_DA_NONCELEN]; char ncount[9]; const char *qop, *method; const char *userid = (*key == 'A' ? soap->userid : soap->proxy_userid); const char *passwd = (*key == 'A' ? soap->passwd : soap->proxy_passwd); size_t smd_len = 16; if (data->alg && !soap_tag_cmp(data->alg, "SHA-256*")) smd_len = 32; if (soap_smd_final(soap, &data->smd_data, data->digest, NULL)) return soap->error; if (!userid || !passwd || !soap->authrealm || !data->nonce) { #ifdef SOAP_DEBUG fprintf(stderr, "Debug message: authentication header construction failed, missing some of the authentication data!\n"); #endif return SOAP_OK; } http_da_calc_nonce(soap, cnonce); if (http_da_calc_HA1(soap, &data->smd_data, data->alg, userid, soap->authrealm, passwd, data->nonce, cnonce, HA1hex)) return soap->error; if (soap->status != SOAP_GET && soap->status != SOAP_CONNECT && data->qop && !soap_tag_cmp(data->qop, "*auth-int*")) { qop = "auth-int"; (void)soap_s2hex(soap, (unsigned char*)data->digest, entityHAhex, smd_len); } else if (data->qop) qop = "auth"; else qop = NULL; if (soap->status == SOAP_GET) method = "GET"; else if (soap->status == SOAP_CONNECT) method = "CONNECT"; else method = "POST"; (SOAP_SNPRINTF(ncount, sizeof(ncount), 8), "%8.8lx", data->nc++); if (http_da_calc_response(soap, &data->smd_data, data->alg, HA1hex, data->nonce, ncount, cnonce, qop, method, soap->path, entityHAhex, response, responseHA)) return soap->error; (SOAP_SNPRINTF(soap->tmpbuf, sizeof(soap->tmpbuf), strlen(soap->authrealm) + strlen(userid) + strlen(data->nonce) + strlen(soap->path) + strlen(ncount) + strlen(cnonce) + strlen(response) + 75), "Digest algorithm=%s, realm=\"%s\", username=\"%s\", nonce=\"%s\", uri=\"%s\", nc=%s, cnonce=\"%s\", response=\"%s\"", data->alg ? data->alg : "MD5", soap->authrealm, userid, data->nonce, soap->path, ncount, cnonce, response); if (data->opaque) { size_t l = strlen(soap->tmpbuf); (SOAP_SNPRINTF(soap->tmpbuf + l, sizeof(soap->tmpbuf) - l, strlen(data->opaque) + 11), ", opaque=\"%s\"", data->opaque); } if (qop) { size_t l = strlen(soap->tmpbuf); (SOAP_SNPRINTF(soap->tmpbuf + l, sizeof(soap->tmpbuf) - l, strlen(qop) + 8), ", qop=\"%s\"", qop); } return data->fposthdr(soap, key, soap->tmpbuf); } /* server's HTTP Authorization challenge/response */ if (key && (!strcmp(key, "WWW-Authenticate") || !strcmp(key, "Proxy-Authenticate"))) { static const char *algos[] = { "MD5", "MD5-sess", "SHA-256", "SHA-256-sess", "SHA-512-256", "SHA-512-256-sess" }; const char *alg = algos[data->option]; char nonce[HTTP_DA_NONCELEN]; char opaque[HTTP_DA_OPAQUELEN]; http_da_calc_nonce(soap, nonce); http_da_calc_opaque(soap, opaque); http_da_session_start(soap->authrealm, nonce, opaque); if (data->option > 0) { (SOAP_SNPRINTF(soap->tmpbuf, sizeof(soap->tmpbuf), strlen(soap->authrealm) + strlen(nonce) + strlen(opaque) + 59), "Digest algorithm=%s, realm=\"%s\", qop=\"auth,auth-int\", nonce=\"%s\", opaque=\"%s\"", alg, soap->authrealm, nonce, opaque); if (data->fposthdr(soap, key, soap->tmpbuf)) return soap->error; } (SOAP_SNPRINTF(soap->tmpbuf, sizeof(soap->tmpbuf), strlen(soap->authrealm) + strlen(nonce) + strlen(opaque) + 59), "Digest algorithm=MD5, realm=\"%s\", qop=\"auth,auth-int\", nonce=\"%s\", opaque=\"%s\"", soap->authrealm, nonce, opaque); return data->fposthdr(soap, key, soap->tmpbuf); } return data->fposthdr(soap, key, val); }
static int http_da_calc_response(struct soap *soap, struct soap_smd_data *smd_data, const char *alg, char HA1hex[65], const char *nonce, const char *ncount, const char *cnonce, const char *qop, const char *method, const char *uri, char entityHAhex[65], char response[65], char responseHA[32]) { int smd_alg = SOAP_SMD_DGST_MD5; size_t smd_len = 16; char HA2[32], HA2hex[65]; if (alg && !soap_tag_cmp(alg, "SHA-256*")) { smd_alg = SOAP_SMD_DGST_SHA256; smd_len = 32; } if (soap_smd_init(soap, smd_data, smd_alg, NULL, 0) || soap_smd_update(soap, smd_data, method, strlen(method)) || soap_smd_update(soap, smd_data, ":", 1) || soap_smd_update(soap, smd_data, uri, strlen(uri))) return soap->error; if (qop && !soap_tag_cmp(qop, "auth-int")) { if (soap_smd_update(soap, smd_data, ":", 1) || soap_smd_update(soap, smd_data, entityHAhex, 2*smd_len)) return soap->error; } if (soap_smd_final(soap, smd_data, HA2, NULL)) return soap->error; (void)soap_s2hex(soap, (unsigned char*)HA2, HA2hex, smd_len); if (soap_smd_init(soap, smd_data, smd_alg, NULL, 0) || soap_smd_update(soap, smd_data, HA1hex, 2*smd_len)) return soap->error; if (nonce) { if (soap_smd_update(soap, smd_data, ":", 1) || soap_smd_update(soap, smd_data, nonce, strlen(nonce))) return soap->error; } if (qop && *qop) { if (soap_smd_update(soap, smd_data, ":", 1) || soap_smd_update(soap, smd_data, ncount, strlen(ncount)) || soap_smd_update(soap, smd_data, ":", 1) || soap_smd_update(soap, smd_data, cnonce, strlen(cnonce)) || soap_smd_update(soap, smd_data, ":", 1) || soap_smd_update(soap, smd_data, qop, strlen(qop))) return soap->error; } if (soap_smd_update(soap, smd_data, ":", 1) || soap_smd_update(soap, smd_data, HA2hex, 2*smd_len) || soap_smd_final(soap, smd_data, responseHA, NULL)) return soap->error; (void)soap_s2hex(soap, (unsigned char*)responseHA, response, smd_len); return SOAP_OK; }