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 | |
29 | Authenticator::Authenticator() { |
30 | assign(NULL, NULL, NULL, NULL, False); |
31 | } |
32 | |
33 | Authenticator::Authenticator(char const* username, char const* password, Boolean passwordIsMD5) { |
34 | assign(NULL, NULL, username, password, passwordIsMD5); |
35 | } |
36 | |
37 | Authenticator::Authenticator(const Authenticator& orig) { |
38 | assign(orig.realm(), orig.nonce(), orig.username(), orig.password(), orig.fPasswordIsMD5); |
39 | } |
40 | |
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 | |
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 | |
64 | Authenticator::~Authenticator() { |
65 | reset(); |
66 | } |
67 | |
68 | void Authenticator::reset() { |
69 | resetRealmAndNonce(); |
70 | resetUsernameAndPassword(); |
71 | } |
72 | |
73 | void Authenticator::setRealmAndNonce(char const* realm, char const* nonce) { |
74 | resetRealmAndNonce(); |
75 | assignRealmAndNonce(realm, nonce); |
76 | } |
77 | |
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 | |
97 | void Authenticator::setUsernameAndPassword(char const* username, |
98 | char const* password, |
99 | Boolean passwordIsMD5) { |
100 | resetUsernameAndPassword(); |
101 | assignUsernameAndPassword(username, password, passwordIsMD5); |
102 | } |
103 | |
104 | 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 | |
140 | void Authenticator::reclaimDigestResponse(char const* responseStr) const { |
141 | delete[](char*)responseStr; |
142 | } |
143 | |
144 | void Authenticator::resetRealmAndNonce() { |
145 | delete[] fRealm; fRealm = NULL; |
146 | delete[] fNonce; fNonce = NULL; |
147 | } |
148 | |
149 | void Authenticator::resetUsernameAndPassword() { |
150 | delete[] fUsername; fUsername = NULL; |
151 | delete[] fPassword; fPassword = NULL; |
152 | fPasswordIsMD5 = False; |
153 | } |
154 | |
155 | void Authenticator::assignRealmAndNonce(char const* realm, char const* nonce) { |
156 | fRealm = strDup(realm); |
157 | fNonce = strDup(nonce); |
158 | } |
159 | |
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 | |
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 | |