http_digest.cpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. #include "http_digest.h"
  2. #include <library/cpp/digest/md5/md5.h>
  3. #include <util/stream/output.h>
  4. #include <util/stream/str.h>
  5. /************************************************************/
  6. /************************************************************/
  7. static const char* WWW_PREFIX = "Authorization: Digest ";
  8. /************************************************************/
  9. httpDigestHandler::httpDigestHandler()
  10. : User_(nullptr)
  11. , Password_(nullptr)
  12. , Nonce_(nullptr)
  13. , NonceCount_(0)
  14. , HeaderInstruction_(nullptr)
  15. {
  16. }
  17. /************************************************************/
  18. httpDigestHandler::~httpDigestHandler() {
  19. clear();
  20. }
  21. /************************************************************/
  22. void httpDigestHandler::clear() {
  23. free(Nonce_);
  24. free(HeaderInstruction_);
  25. User_ = Password_ = nullptr;
  26. Nonce_ = HeaderInstruction_ = nullptr;
  27. NonceCount_ = 0;
  28. }
  29. /************************************************************/
  30. void httpDigestHandler::setAuthorization(const char* user, const char* password) {
  31. clear();
  32. if (user && password) {
  33. User_ = user;
  34. Password_ = password;
  35. }
  36. }
  37. /************************************************************/
  38. const char* httpDigestHandler::getHeaderInstruction() const {
  39. return HeaderInstruction_;
  40. }
  41. /************************************************************/
  42. Y_FORCE_INLINE void addMD5(MD5& ctx, const char* value) {
  43. ctx.Update((const unsigned char*)(value), strlen(value));
  44. }
  45. Y_FORCE_INLINE void addMD5(MD5& ctx, const char* value, int len) {
  46. ctx.Update((const unsigned char*)(value), len);
  47. }
  48. Y_FORCE_INLINE void addMD5(MD5& ctx, std::string_view str) {
  49. ctx.Update(str);
  50. }
  51. Y_FORCE_INLINE void addMD5Sep(MD5& ctx) {
  52. addMD5(ctx, ":", 1);
  53. }
  54. /************************************************************/
  55. /* calculate H(A1) as per spec */
  56. void httpDigestHandler::digestCalcHA1(const THttpAuthHeader& hd,
  57. char* outSessionKey,
  58. const std::string& outCNonce) {
  59. MD5 ctx;
  60. ctx.Init();
  61. addMD5(ctx, User_);
  62. addMD5Sep(ctx);
  63. addMD5(ctx, hd.realm);
  64. addMD5Sep(ctx);
  65. addMD5(ctx, Password_);
  66. if (hd.algorithm == 1) { //MD5-sess
  67. unsigned char digest[16];
  68. ctx.Final(digest);
  69. ctx.Init();
  70. ctx.Update(digest, 16);
  71. addMD5Sep(ctx);
  72. addMD5(ctx, hd.nonce);
  73. addMD5Sep(ctx);
  74. addMD5(ctx, outCNonce);
  75. ctx.End(outSessionKey);
  76. }
  77. ctx.End(outSessionKey);
  78. }
  79. /************************************************************/
  80. /* calculate request-digest/response-digest as per HTTP Digest spec */
  81. void httpDigestHandler::digestCalcResponse(const THttpAuthHeader& hd,
  82. const char* path,
  83. const char* method,
  84. const char* nonceCount,
  85. char* outResponse,
  86. const std::string& outCNonce) {
  87. char HA1[33];
  88. digestCalcHA1(hd, HA1, outCNonce);
  89. char HA2[33];
  90. MD5 ctx;
  91. ctx.Init();
  92. addMD5(ctx, method);
  93. addMD5Sep(ctx);
  94. addMD5(ctx, path);
  95. //ignore auth-int
  96. ctx.End(HA2);
  97. ctx.Init();
  98. addMD5(ctx, HA1, 32);
  99. addMD5Sep(ctx);
  100. addMD5(ctx, Nonce_);
  101. addMD5Sep(ctx);
  102. if (hd.qop_auth) {
  103. addMD5(ctx, nonceCount, 8);
  104. addMD5Sep(ctx);
  105. addMD5(ctx, outCNonce);
  106. addMD5Sep(ctx);
  107. addMD5(ctx, "auth", 4);
  108. addMD5Sep(ctx);
  109. }
  110. addMD5(ctx, HA2, 32);
  111. ctx.End(outResponse);
  112. }
  113. /************************************************************/
  114. bool httpDigestHandler::processHeader(const THttpAuthHeader* header,
  115. const char* path,
  116. const char* method,
  117. const char* cnonceIn) {
  118. if (!User_ || !header || !header->use_auth || !header->realm || !header->nonce)
  119. return false;
  120. if (Nonce_) {
  121. if (strcmp(Nonce_, header->nonce)) {
  122. free(Nonce_);
  123. Nonce_ = nullptr;
  124. NonceCount_ = 0;
  125. }
  126. }
  127. if (!Nonce_) {
  128. Nonce_ = strdup(header->nonce);
  129. NonceCount_ = 0;
  130. }
  131. free(HeaderInstruction_);
  132. HeaderInstruction_ = nullptr;
  133. NonceCount_++;
  134. char nonceCount[20];
  135. snprintf(nonceCount, sizeof(nonceCount), "%08d", NonceCount_);
  136. std::string cNonce = cnonceIn ? std::string(cnonceIn) : std::to_string(time(nullptr));
  137. char response[33];
  138. digestCalcResponse(*header, path, method, nonceCount, response, cNonce);
  139. //digest-response = 1#( username | realm | nonce | digest-uri
  140. // | response | [ algorithm ] | [cnonce] |
  141. // [opaque] | [message-qop] |
  142. // [nonce-count] | [auth-param] )
  143. TStringStream out;
  144. out << WWW_PREFIX << "username=\"" << User_ << "\"";
  145. out << ", realm=\"" << header->realm << "\"";
  146. out << ", nonce=\"" << header->nonce << "\"";
  147. out << ", uri=\"" << path << "\"";
  148. if (header->algorithm == 1)
  149. out << ", algorithm=MD5-sess";
  150. else
  151. out << ", algorithm=MD5";
  152. if (header->qop_auth)
  153. out << ", qop=auth";
  154. out << ", nc=" << nonceCount;
  155. if (!cNonce.empty())
  156. out << ", cnonce=\"" << cNonce << "\"";
  157. out << ", response=\"" << response << "\"";
  158. if (header->opaque)
  159. out << ", opaque=\"" << header->opaque << "\"";
  160. out << "\r\n";
  161. TString s_out = out.Str();
  162. HeaderInstruction_ = strdup(s_out.c_str());
  163. return true;
  164. }
  165. /************************************************************/
  166. /************************************************************/