15 #include "httpDigestAuthorization.h" 19 #include "httpChannel.h" 20 #include "openSSLWrapper.h" 21 #include "openssl/ssl.h" 22 #include "openssl/md5.h" 25 const string HTTPDigestAuthorization::_mechanism =
"digest";
32 HTTPDigestAuthorization::
33 HTTPDigestAuthorization(
const HTTPAuthorization::Tokens &tokens,
34 const URLSpec &url,
bool is_proxy) :
35 HTTPAuthorization(tokens, url, is_proxy)
37 Tokens::const_iterator ti;
38 ti = tokens.find(
"nonce");
39 if (ti != tokens.end()) {
40 _nonce = (*ti).second;
44 ti = tokens.find(
"opaque");
45 if (ti != tokens.end()) {
46 _opaque = (*ti).second;
50 ti = tokens.find(
"algorithm");
51 if (ti != tokens.end()) {
52 string algo_str = HTTPChannel::downcase((*ti).second);
53 if (algo_str ==
"md5") {
55 }
else if (algo_str ==
"md5-sess") {
56 _algorithm = A_md5_sess;
58 _algorithm = A_unknown;
63 ti = tokens.find(
"qop");
64 if (ti != tokens.end()) {
65 string qop_str = HTTPChannel::downcase((*ti).second);
69 while (p < qop_str.length()) {
70 while (p < qop_str.length() && isspace(qop_str[p])) {
75 while (q < qop_str.length() && qop_str[q] !=
',') {
76 if (!isspace(qop_str[q])) {
77 qop_str[q] = tolower(qop_str[q]);
84 _qop |= match_qop_token(qop_str.substr(p, last_char - p + 1));
92 strm << time(NULL) <<
":" << clock() <<
":" 95 _cnonce = calc_md5(strm.str());
103 HTTPDigestAuthorization::
104 ~HTTPDigestAuthorization() {
115 bool HTTPDigestAuthorization::
117 return (_algorithm != A_unknown);
126 const string &HTTPDigestAuthorization::
127 get_mechanism()
const {
139 string HTTPDigestAuthorization::
140 generate(HTTPEnum::Method method,
const string &request_path,
141 const string &username,
const string &body) {
144 size_t colon = username.find(
':');
145 string username_only = username.substr(0, colon);
146 string password_only = username.substr(colon + 1);
148 string digest = calc_request_digest(username_only, password_only,
149 method, request_path, body);
152 strm <<
"Digest username=\"" << username.substr(0, colon) <<
"\"" 153 <<
", realm=\"" << get_realm() <<
"\"" 154 <<
", nonce=\"" << _nonce <<
"\"" 155 <<
", uri=" << request_path
156 <<
", response=\"" << digest <<
"\"" 157 <<
", algorithm=" << _algorithm;
159 if (!_opaque.empty()) {
160 strm <<
", opaque=\"" << _opaque <<
"\"";
163 if (_chosen_qop != Q_unused) {
164 strm <<
", qop=" << _chosen_qop
165 <<
", cnonce=\"" << _cnonce <<
"\"" 166 <<
", nc=" << get_hex_nonce_count();
179 int HTTPDigestAuthorization::
180 match_qop_token(
const string &token) {
181 if (token ==
"auth") {
183 }
else if (token ==
"auth-int") {
195 string HTTPDigestAuthorization::
196 calc_request_digest(
const string &username,
const string &password,
197 HTTPEnum::Method method,
const string &request_path,
198 const string &body) {
199 _chosen_qop = Q_unused;
200 string h_a1 = calc_h(get_a1(username, password));
201 string h_a2 = calc_h(get_a2(method, request_path, body));
206 _chosen_qop = Q_unused;
207 strm << _nonce <<
":" << h_a2;
210 strm << _nonce <<
":" << get_hex_nonce_count() <<
":" 211 << _cnonce <<
":" << _chosen_qop <<
":" 215 return calc_kd(h_a1, strm.str());
224 string HTTPDigestAuthorization::
225 calc_h(
const string &data)
const {
226 switch (_algorithm) {
230 return calc_md5(data);
243 string HTTPDigestAuthorization::
244 calc_kd(
const string &secret,
const string &data)
const {
245 switch (_algorithm) {
249 return calc_h(secret +
":" + data);
260 string HTTPDigestAuthorization::
261 get_a1(
const string &username,
const string &password) {
262 switch (_algorithm) {
265 return username +
":" + get_realm() +
":" + password;
269 _a1 = calc_h(username +
":" + get_realm() +
":" + password) +
270 ":" + _nonce +
":" + _cnonce;
283 string HTTPDigestAuthorization::
284 get_a2(HTTPEnum::Method method,
const string &request_path,
285 const string &body) {
288 if ((_qop & Q_auth_int) != 0 && !body.empty()) {
289 _chosen_qop = Q_auth_int;
290 strm << method <<
":" << request_path <<
":" << calc_h(body);
293 _chosen_qop = Q_auth;
294 strm << method <<
":" << request_path;
307 string HTTPDigestAuthorization::
308 get_hex_nonce_count()
const {
310 strm << hex << setfill(
'0') << setw(8) << _nonce_count;
321 string HTTPDigestAuthorization::
322 calc_md5(
const string &source) {
323 unsigned char binary[MD5_DIGEST_LENGTH];
325 MD5((
const unsigned char *)source.data(), source.length(), binary);
328 result.reserve(MD5_DIGEST_LENGTH * 2);
330 for (
int i = 0; i < MD5_DIGEST_LENGTH; i++) {
331 result += hexdigit((binary[i] >> 4) & 0xf);
332 result += hexdigit(binary[i] & 0xf);
339 operator << (ostream &out, HTTPDigestAuthorization::Algorithm algorithm) {
341 case HTTPDigestAuthorization::A_md5:
344 case HTTPDigestAuthorization::A_md5_sess:
347 case HTTPDigestAuthorization::A_unknown:
356 operator << (ostream &out, HTTPDigestAuthorization::Qop qop) {
358 case HTTPDigestAuthorization::Q_auth:
361 case HTTPDigestAuthorization::Q_auth_int:
364 case HTTPDigestAuthorization::Q_unused:
372 #endif // HAVE_OPENSSL A container for a URL, e.g.
const string & get_url() const
Returns the complete URL specification.