http_digest.cpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  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. void httpDigestHandler::generateCNonce(char* outCNonce) {
  43. if (!*outCNonce)
  44. sprintf(outCNonce, "%ld", (long)time(nullptr));
  45. }
  46. /************************************************************/
  47. inline void addMD5(MD5& ctx, const char* value) {
  48. ctx.Update((const unsigned char*)(value), strlen(value));
  49. }
  50. inline void addMD5(MD5& ctx, const char* value, int len) {
  51. ctx.Update((const unsigned char*)(value), len);
  52. }
  53. inline void addMD5Sep(MD5& ctx) {
  54. addMD5(ctx, ":", 1);
  55. }
  56. /************************************************************/
  57. /* calculate H(A1) as per spec */
  58. void httpDigestHandler::digestCalcHA1(const THttpAuthHeader& hd,
  59. char* outSessionKey,
  60. char* outCNonce) {
  61. MD5 ctx;
  62. ctx.Init();
  63. addMD5(ctx, User_);
  64. addMD5Sep(ctx);
  65. addMD5(ctx, hd.realm);
  66. addMD5Sep(ctx);
  67. addMD5(ctx, Password_);
  68. if (hd.algorithm == 1) { //MD5-sess
  69. unsigned char digest[16];
  70. ctx.Final(digest);
  71. generateCNonce(outCNonce);
  72. ctx.Init();
  73. ctx.Update(digest, 16);
  74. addMD5Sep(ctx);
  75. addMD5(ctx, hd.nonce);
  76. addMD5Sep(ctx);
  77. addMD5(ctx, outCNonce);
  78. ctx.End(outSessionKey);
  79. }
  80. ctx.End(outSessionKey);
  81. }
  82. /************************************************************/
  83. /* calculate request-digest/response-digest as per HTTP Digest spec */
  84. void httpDigestHandler::digestCalcResponse(const THttpAuthHeader& hd,
  85. const char* path,
  86. const char* method,
  87. const char* nonceCount,
  88. char* outResponse,
  89. char* outCNonce) {
  90. char HA1[33];
  91. digestCalcHA1(hd, HA1, outCNonce);
  92. char HA2[33];
  93. MD5 ctx;
  94. ctx.Init();
  95. addMD5(ctx, method);
  96. addMD5Sep(ctx);
  97. addMD5(ctx, path);
  98. //ignore auth-int
  99. ctx.End(HA2);
  100. ctx.Init();
  101. addMD5(ctx, HA1, 32);
  102. addMD5Sep(ctx);
  103. addMD5(ctx, Nonce_);
  104. addMD5Sep(ctx);
  105. if (hd.qop_auth) {
  106. if (!*outCNonce)
  107. generateCNonce(outCNonce);
  108. addMD5(ctx, nonceCount, 8);
  109. addMD5Sep(ctx);
  110. addMD5(ctx, outCNonce);
  111. addMD5Sep(ctx);
  112. addMD5(ctx, "auth", 4);
  113. addMD5Sep(ctx);
  114. }
  115. addMD5(ctx, HA2, 32);
  116. ctx.End(outResponse);
  117. }
  118. /************************************************************/
  119. bool httpDigestHandler::processHeader(const THttpAuthHeader* header,
  120. const char* path,
  121. const char* method,
  122. const char* cnonce) {
  123. if (!User_ || !header || !header->use_auth || !header->realm || !header->nonce)
  124. return false;
  125. if (Nonce_) {
  126. if (strcmp(Nonce_, header->nonce)) {
  127. free(Nonce_);
  128. Nonce_ = nullptr;
  129. NonceCount_ = 0;
  130. }
  131. }
  132. if (!Nonce_) {
  133. Nonce_ = strdup(header->nonce);
  134. NonceCount_ = 0;
  135. }
  136. free(HeaderInstruction_);
  137. HeaderInstruction_ = nullptr;
  138. NonceCount_++;
  139. char nonceCount[20];
  140. sprintf(nonceCount, "%08d", NonceCount_);
  141. char CNonce[50];
  142. if (cnonce)
  143. strcpy(CNonce, cnonce);
  144. else
  145. CNonce[0] = 0;
  146. char response[33];
  147. digestCalcResponse(*header, path, method, nonceCount, response, CNonce);
  148. //digest-response = 1#( username | realm | nonce | digest-uri
  149. // | response | [ algorithm ] | [cnonce] |
  150. // [opaque] | [message-qop] |
  151. // [nonce-count] | [auth-param] )
  152. TStringStream out;
  153. out << WWW_PREFIX << "username=\"" << User_ << "\"";
  154. out << ", realm=\"" << header->realm << "\"";
  155. out << ", nonce=\"" << header->nonce << "\"";
  156. out << ", uri=\"" << path << "\"";
  157. if (header->algorithm == 1)
  158. out << ", algorithm=MD5-sess";
  159. else
  160. out << ", algorithm=MD5";
  161. if (header->qop_auth)
  162. out << ", qop=auth";
  163. out << ", nc=" << nonceCount;
  164. if (CNonce[0])
  165. out << ", cnonce=\"" << CNonce << "\"";
  166. out << ", response=\"" << response << "\"";
  167. if (header->opaque)
  168. out << ", opaque=\"" << header->opaque << "\"";
  169. out << "\r\n";
  170. TString s_out = out.Str();
  171. HeaderInstruction_ = strdup(s_out.c_str());
  172. return true;
  173. }
  174. /************************************************************/
  175. /************************************************************/