1 /**********
2 This library is free software; you can redistribute it and/or modify it under
3 the terms of the GNU Lesser General Public License as published by the
4 Free Software Foundation; either version 3 of the License, or (at your
5 option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)
6
7 This library is distributed in the hope that it will be useful, but WITHOUT
8 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
9 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
10 more details.
11
12 You should have received a copy of the GNU Lesser General Public License
13 along with this library; if not, write to the Free Software Foundation, Inc.,
14 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
15 **********/
16 // "liveMedia"
17 // Copyright (c) 1996-2020 Live Networks, Inc. All rights reserved.
18 // A class used for digest authentication.
19 // Implementation
20
21 #include "DigestAuthentication.hh"
22 #include "ourMD5.hh"
23 #include <strDup.hh>
24 #include <GroupsockHelper.hh> // for gettimeofday()
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28
Authenticator()29 Authenticator::Authenticator() {
30 assign(NULL, NULL, NULL, NULL, False);
31 }
32
Authenticator(char const * username,char const * password,Boolean passwordIsMD5)33 Authenticator::Authenticator(char const* username, char const* password, Boolean passwordIsMD5) {
34 assign(NULL, NULL, username, password, passwordIsMD5);
35 }
36
Authenticator(const Authenticator & orig)37 Authenticator::Authenticator(const Authenticator& orig) {
38 assign(orig.realm(), orig.nonce(), orig.username(), orig.password(), orig.fPasswordIsMD5);
39 }
40
operator =(const Authenticator & rightSide)41 Authenticator& Authenticator::operator=(const Authenticator& rightSide) {
42 if (&rightSide != this) {
43 reset();
44 assign(rightSide.realm(), rightSide.nonce(),
45 rightSide.username(), rightSide.password(), rightSide.fPasswordIsMD5);
46 }
47
48 return *this;
49 }
50
operator <(const Authenticator * rightSide)51 Boolean Authenticator::operator<(const Authenticator* rightSide) {
52 // Returns True if "rightSide" is 'newer' than us:
53 if (rightSide != NULL && rightSide != this &&
54 (rightSide->realm() != NULL || rightSide->nonce() != NULL ||
55 username() == NULL || password() == NULL ||
56 strcmp(rightSide->username(), username()) != 0 ||
57 strcmp(rightSide->password(), password()) != 0)) {
58 return True;
59 }
60
61 return False;
62 }
63
~Authenticator()64 Authenticator::~Authenticator() {
65 reset();
66 }
67
reset()68 void Authenticator::reset() {
69 resetRealmAndNonce();
70 resetUsernameAndPassword();
71 }
72
setRealmAndNonce(char const * realm,char const * nonce)73 void Authenticator::setRealmAndNonce(char const* realm, char const* nonce) {
74 resetRealmAndNonce();
75 assignRealmAndNonce(realm, nonce);
76 }
77
setRealmAndRandomNonce(char const * realm)78 void Authenticator::setRealmAndRandomNonce(char const* realm) {
79 resetRealmAndNonce();
80
81 // Construct data to seed the random nonce:
82 struct {
83 struct timeval timestamp;
84 unsigned counter;
85 } seedData;
86 gettimeofday(&seedData.timestamp, NULL);
87 static unsigned counter = 0;
88 seedData.counter = ++counter;
89
90 // Use MD5 to compute a 'random' nonce from this seed data:
91 char nonceBuf[33];
92 our_MD5Data((unsigned char*)(&seedData), sizeof seedData, nonceBuf);
93
94 assignRealmAndNonce(realm, nonceBuf);
95 }
96
setUsernameAndPassword(char const * username,char const * password,Boolean passwordIsMD5)97 void Authenticator::setUsernameAndPassword(char const* username,
98 char const* password,
99 Boolean passwordIsMD5) {
100 resetUsernameAndPassword();
101 assignUsernameAndPassword(username, password, passwordIsMD5);
102 }
103
computeDigestResponse(char const * cmd,char const * url) const104 char const* Authenticator::computeDigestResponse(char const* cmd,
105 char const* url) const {
106 // The "response" field is computed as:
107 // md5(md5(<username>:<realm>:<password>):<nonce>:md5(<cmd>:<url>))
108 // or, if "fPasswordIsMD5" is True:
109 // md5(<password>:<nonce>:md5(<cmd>:<url>))
110 char ha1Buf[33];
111 if (fPasswordIsMD5) {
112 strncpy(ha1Buf, password(), 32);
113 ha1Buf[32] = '\0'; // just in case
114 } else {
115 unsigned const ha1DataLen = strlen(username()) + 1
116 + strlen(realm()) + 1 + strlen(password());
117 unsigned char* ha1Data = new unsigned char[ha1DataLen+1];
118 sprintf((char*)ha1Data, "%s:%s:%s", username(), realm(), password());
119 our_MD5Data(ha1Data, ha1DataLen, ha1Buf);
120 delete[] ha1Data;
121 }
122
123 unsigned const ha2DataLen = strlen(cmd) + 1 + strlen(url);
124 unsigned char* ha2Data = new unsigned char[ha2DataLen+1];
125 sprintf((char*)ha2Data, "%s:%s", cmd, url);
126 char ha2Buf[33];
127 our_MD5Data(ha2Data, ha2DataLen, ha2Buf);
128 delete[] ha2Data;
129
130 unsigned const digestDataLen
131 = 32 + 1 + strlen(nonce()) + 1 + 32;
132 unsigned char* digestData = new unsigned char[digestDataLen+1];
133 sprintf((char*)digestData, "%s:%s:%s",
134 ha1Buf, nonce(), ha2Buf);
135 char const* result = our_MD5Data(digestData, digestDataLen, NULL);
136 delete[] digestData;
137 return result;
138 }
139
reclaimDigestResponse(char const * responseStr) const140 void Authenticator::reclaimDigestResponse(char const* responseStr) const {
141 delete[](char*)responseStr;
142 }
143
resetRealmAndNonce()144 void Authenticator::resetRealmAndNonce() {
145 delete[] fRealm; fRealm = NULL;
146 delete[] fNonce; fNonce = NULL;
147 }
148
resetUsernameAndPassword()149 void Authenticator::resetUsernameAndPassword() {
150 delete[] fUsername; fUsername = NULL;
151 delete[] fPassword; fPassword = NULL;
152 fPasswordIsMD5 = False;
153 }
154
assignRealmAndNonce(char const * realm,char const * nonce)155 void Authenticator::assignRealmAndNonce(char const* realm, char const* nonce) {
156 fRealm = strDup(realm);
157 fNonce = strDup(nonce);
158 }
159
assignUsernameAndPassword(char const * username,char const * password,Boolean passwordIsMD5)160 void Authenticator::assignUsernameAndPassword(char const* username, char const* password, Boolean passwordIsMD5) {
161 if (username == NULL) username = "";
162 if (password == NULL) password = "";
163
164 fUsername = strDup(username);
165 fPassword = strDup(password);
166 fPasswordIsMD5 = passwordIsMD5;
167 }
168
assign(char const * realm,char const * nonce,char const * username,char const * password,Boolean passwordIsMD5)169 void Authenticator::assign(char const* realm, char const* nonce,
170 char const* username, char const* password, Boolean passwordIsMD5) {
171 assignRealmAndNonce(realm, nonce);
172 assignUsernameAndPassword(username, password, passwordIsMD5);
173 }
174