aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/http/fetch/http_digest.cpp
diff options
context:
space:
mode:
authorDevtools Arcadia <arcadia-devtools@yandex-team.ru>2022-02-07 18:08:42 +0300
committerDevtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net>2022-02-07 18:08:42 +0300
commit1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch)
treee26c9fed0de5d9873cce7e00bc214573dc2195b7 /library/cpp/http/fetch/http_digest.cpp
downloadydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'library/cpp/http/fetch/http_digest.cpp')
-rw-r--r--library/cpp/http/fetch/http_digest.cpp206
1 files changed, 206 insertions, 0 deletions
diff --git a/library/cpp/http/fetch/http_digest.cpp b/library/cpp/http/fetch/http_digest.cpp
new file mode 100644
index 0000000000..1eaa02b7f2
--- /dev/null
+++ b/library/cpp/http/fetch/http_digest.cpp
@@ -0,0 +1,206 @@
+#include "http_digest.h"
+
+#include <library/cpp/digest/md5/md5.h>
+#include <util/stream/output.h>
+#include <util/stream/str.h>
+
+/************************************************************/
+/************************************************************/
+static const char* WWW_PREFIX = "Authorization: Digest ";
+
+/************************************************************/
+httpDigestHandler::httpDigestHandler()
+ : User_(nullptr)
+ , Password_(nullptr)
+ , Nonce_(nullptr)
+ , NonceCount_(0)
+ , HeaderInstruction_(nullptr)
+{
+}
+
+/************************************************************/
+httpDigestHandler::~httpDigestHandler() {
+ clear();
+}
+
+/************************************************************/
+void httpDigestHandler::clear() {
+ free(Nonce_);
+ free(HeaderInstruction_);
+ User_ = Password_ = nullptr;
+ Nonce_ = HeaderInstruction_ = nullptr;
+ NonceCount_ = 0;
+}
+
+/************************************************************/
+void httpDigestHandler::setAuthorization(const char* user, const char* password) {
+ clear();
+ if (user && password) {
+ User_ = user;
+ Password_ = password;
+ }
+}
+
+/************************************************************/
+const char* httpDigestHandler::getHeaderInstruction() const {
+ return HeaderInstruction_;
+}
+
+/************************************************************/
+void httpDigestHandler::generateCNonce(char* outCNonce) {
+ if (!*outCNonce)
+ sprintf(outCNonce, "%ld", (long)time(nullptr));
+}
+
+/************************************************************/
+inline void addMD5(MD5& ctx, const char* value) {
+ ctx.Update((const unsigned char*)(value), strlen(value));
+}
+
+inline void addMD5(MD5& ctx, const char* value, int len) {
+ ctx.Update((const unsigned char*)(value), len);
+}
+
+inline void addMD5Sep(MD5& ctx) {
+ addMD5(ctx, ":", 1);
+}
+
+/************************************************************/
+/* calculate H(A1) as per spec */
+void httpDigestHandler::digestCalcHA1(const THttpAuthHeader& hd,
+ char* outSessionKey,
+ char* outCNonce) {
+ MD5 ctx;
+ ctx.Init();
+ addMD5(ctx, User_);
+ addMD5Sep(ctx);
+ addMD5(ctx, hd.realm);
+ addMD5Sep(ctx);
+ addMD5(ctx, Password_);
+
+ if (hd.algorithm == 1) { //MD5-sess
+ unsigned char digest[16];
+ ctx.Final(digest);
+
+ generateCNonce(outCNonce);
+
+ ctx.Init();
+ ctx.Update(digest, 16);
+ addMD5Sep(ctx);
+ addMD5(ctx, hd.nonce);
+ addMD5Sep(ctx);
+ addMD5(ctx, outCNonce);
+ ctx.End(outSessionKey);
+ }
+
+ ctx.End(outSessionKey);
+};
+
+/************************************************************/
+/* calculate request-digest/response-digest as per HTTP Digest spec */
+void httpDigestHandler::digestCalcResponse(const THttpAuthHeader& hd,
+ const char* path,
+ const char* method,
+ const char* nonceCount,
+ char* outResponse,
+ char* outCNonce) {
+ char HA1[33];
+ digestCalcHA1(hd, HA1, outCNonce);
+
+ char HA2[33];
+ MD5 ctx;
+ ctx.Init();
+ addMD5(ctx, method);
+ addMD5Sep(ctx);
+ addMD5(ctx, path);
+ //ignore auth-int
+ ctx.End(HA2);
+
+ ctx.Init();
+ addMD5(ctx, HA1, 32);
+ addMD5Sep(ctx);
+ addMD5(ctx, Nonce_);
+ addMD5Sep(ctx);
+
+ if (hd.qop_auth) {
+ if (!*outCNonce)
+ generateCNonce(outCNonce);
+
+ addMD5(ctx, nonceCount, 8);
+ addMD5Sep(ctx);
+ addMD5(ctx, outCNonce);
+ addMD5Sep(ctx);
+ addMD5(ctx, "auth", 4);
+ addMD5Sep(ctx);
+ }
+ addMD5(ctx, HA2, 32);
+ ctx.End(outResponse);
+}
+
+/************************************************************/
+bool httpDigestHandler::processHeader(const THttpAuthHeader* header,
+ const char* path,
+ const char* method,
+ const char* cnonce) {
+ if (!User_ || !header || !header->use_auth || !header->realm || !header->nonce)
+ return false;
+
+ if (Nonce_) {
+ if (strcmp(Nonce_, header->nonce)) {
+ free(Nonce_);
+ Nonce_ = nullptr;
+ NonceCount_ = 0;
+ }
+ }
+ if (!Nonce_) {
+ Nonce_ = strdup(header->nonce);
+ NonceCount_ = 0;
+ }
+ free(HeaderInstruction_);
+ HeaderInstruction_ = nullptr;
+ NonceCount_++;
+
+ char nonceCount[20];
+ sprintf(nonceCount, "%08d", NonceCount_);
+
+ char CNonce[50];
+ if (cnonce)
+ strcpy(CNonce, cnonce);
+ else
+ CNonce[0] = 0;
+
+ char response[33];
+ digestCalcResponse(*header, path, method, nonceCount, response, CNonce);
+
+ //digest-response = 1#( username | realm | nonce | digest-uri
+ // | response | [ algorithm ] | [cnonce] |
+ // [opaque] | [message-qop] |
+ // [nonce-count] | [auth-param] )
+
+ TStringStream out;
+ out << WWW_PREFIX << "username=\"" << User_ << "\"";
+ out << ", realm=\"" << header->realm << "\"";
+ out << ", nonce=\"" << header->nonce << "\"";
+ out << ", uri=\"" << path << "\"";
+ if (header->algorithm == 1)
+ out << ", algorithm=MD5-sess";
+ else
+ out << ", algorithm=MD5";
+ if (header->qop_auth)
+ out << ", qop=auth";
+ out << ", nc=" << nonceCount;
+ if (CNonce[0])
+ out << ", cnonce=\"" << CNonce << "\"";
+ out << ", response=\"" << response << "\"";
+ if (header->opaque)
+ out << ", opaque=\"" << header->opaque << "\"";
+ out << "\r\n";
+
+ TString s_out = out.Str();
+ HeaderInstruction_ = strdup(s_out.c_str());
+
+ return true;
+}
+
+/************************************************************/
+/************************************************************/