| /********** |
| This library is free software; you can redistribute it and/or modify it under |
| the terms of the GNU Lesser General Public License as published by the |
| Free Software Foundation; either version 3 of the License, or (at your |
| option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.) |
| |
| This library is distributed in the hope that it will be useful, but WITHOUT |
| ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
| FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for |
| more details. |
| |
| You should have received a copy of the GNU Lesser General Public License |
| along with this library; if not, write to the Free Software Foundation, Inc., |
| 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| **********/ |
| // "liveMedia" |
| // Copyright (c) 1996-2020 Live Networks, Inc. All rights reserved. |
| // A class used for digest authentication. |
| // Implementation |
| |
| #include "DigestAuthentication.hh" |
| #include "ourMD5.hh" |
| #include <strDup.hh> |
| #include <GroupsockHelper.hh> // for gettimeofday() |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| Authenticator::Authenticator() { |
| assign(NULL, NULL, NULL, NULL, False); |
| } |
| |
| Authenticator::Authenticator(char const* username, char const* password, Boolean passwordIsMD5) { |
| assign(NULL, NULL, username, password, passwordIsMD5); |
| } |
| |
| Authenticator::Authenticator(const Authenticator& orig) { |
| assign(orig.realm(), orig.nonce(), orig.username(), orig.password(), orig.fPasswordIsMD5); |
| } |
| |
| Authenticator& Authenticator::operator=(const Authenticator& rightSide) { |
| if (&rightSide != this) { |
| reset(); |
| assign(rightSide.realm(), rightSide.nonce(), |
| rightSide.username(), rightSide.password(), rightSide.fPasswordIsMD5); |
| } |
| |
| return *this; |
| } |
| |
| Boolean Authenticator::operator<(const Authenticator* rightSide) { |
| // Returns True if "rightSide" is 'newer' than us: |
| if (rightSide != NULL && rightSide != this && |
| (rightSide->realm() != NULL || rightSide->nonce() != NULL || |
| username() == NULL || password() == NULL || |
| strcmp(rightSide->username(), username()) != 0 || |
| strcmp(rightSide->password(), password()) != 0)) { |
| return True; |
| } |
| |
| return False; |
| } |
| |
| Authenticator::~Authenticator() { |
| reset(); |
| } |
| |
| void Authenticator::reset() { |
| resetRealmAndNonce(); |
| resetUsernameAndPassword(); |
| } |
| |
| void Authenticator::setRealmAndNonce(char const* realm, char const* nonce) { |
| resetRealmAndNonce(); |
| assignRealmAndNonce(realm, nonce); |
| } |
| |
| void Authenticator::setRealmAndRandomNonce(char const* realm) { |
| resetRealmAndNonce(); |
| |
| // Construct data to seed the random nonce: |
| struct { |
| struct timeval timestamp; |
| unsigned counter; |
| } seedData; |
| gettimeofday(&seedData.timestamp, NULL); |
| static unsigned counter = 0; |
| seedData.counter = ++counter; |
| |
| // Use MD5 to compute a 'random' nonce from this seed data: |
| char nonceBuf[33]; |
| our_MD5Data((unsigned char*)(&seedData), sizeof seedData, nonceBuf); |
| |
| assignRealmAndNonce(realm, nonceBuf); |
| } |
| |
| void Authenticator::setUsernameAndPassword(char const* username, |
| char const* password, |
| Boolean passwordIsMD5) { |
| resetUsernameAndPassword(); |
| assignUsernameAndPassword(username, password, passwordIsMD5); |
| } |
| |
| char const* Authenticator::computeDigestResponse(char const* cmd, |
| char const* url) const { |
| // The "response" field is computed as: |
| // md5(md5(<username>:<realm>:<password>):<nonce>:md5(<cmd>:<url>)) |
| // or, if "fPasswordIsMD5" is True: |
| // md5(<password>:<nonce>:md5(<cmd>:<url>)) |
| char ha1Buf[33]; |
| if (fPasswordIsMD5) { |
| strncpy(ha1Buf, password(), 32); |
| ha1Buf[32] = '\0'; // just in case |
| } else { |
| unsigned const ha1DataLen = strlen(username()) + 1 |
| + strlen(realm()) + 1 + strlen(password()); |
| unsigned char* ha1Data = new unsigned char[ha1DataLen+1]; |
| sprintf((char*)ha1Data, "%s:%s:%s", username(), realm(), password()); |
| our_MD5Data(ha1Data, ha1DataLen, ha1Buf); |
| delete[] ha1Data; |
| } |
| |
| unsigned const ha2DataLen = strlen(cmd) + 1 + strlen(url); |
| unsigned char* ha2Data = new unsigned char[ha2DataLen+1]; |
| sprintf((char*)ha2Data, "%s:%s", cmd, url); |
| char ha2Buf[33]; |
| our_MD5Data(ha2Data, ha2DataLen, ha2Buf); |
| delete[] ha2Data; |
| |
| unsigned const digestDataLen |
| = 32 + 1 + strlen(nonce()) + 1 + 32; |
| unsigned char* digestData = new unsigned char[digestDataLen+1]; |
| sprintf((char*)digestData, "%s:%s:%s", |
| ha1Buf, nonce(), ha2Buf); |
| char const* result = our_MD5Data(digestData, digestDataLen, NULL); |
| delete[] digestData; |
| return result; |
| } |
| |
| void Authenticator::reclaimDigestResponse(char const* responseStr) const { |
| delete[](char*)responseStr; |
| } |
| |
| void Authenticator::resetRealmAndNonce() { |
| delete[] fRealm; fRealm = NULL; |
| delete[] fNonce; fNonce = NULL; |
| } |
| |
| void Authenticator::resetUsernameAndPassword() { |
| delete[] fUsername; fUsername = NULL; |
| delete[] fPassword; fPassword = NULL; |
| fPasswordIsMD5 = False; |
| } |
| |
| void Authenticator::assignRealmAndNonce(char const* realm, char const* nonce) { |
| fRealm = strDup(realm); |
| fNonce = strDup(nonce); |
| } |
| |
| void Authenticator::assignUsernameAndPassword(char const* username, char const* password, Boolean passwordIsMD5) { |
| if (username == NULL) username = ""; |
| if (password == NULL) password = ""; |
| |
| fUsername = strDup(username); |
| fPassword = strDup(password); |
| fPasswordIsMD5 = passwordIsMD5; |
| } |
| |
| void Authenticator::assign(char const* realm, char const* nonce, |
| char const* username, char const* password, Boolean passwordIsMD5) { |
| assignRealmAndNonce(realm, nonce); |
| assignUsernameAndPassword(username, password, passwordIsMD5); |
| } |