LDAPAccountManager/lam/lib/3rdParty/composer/pear-pear.horde.org/Horde_Imap_Client/Horde/Imap/Client/Auth/DigestMD5.php

190 lines
7.0 KiB
PHP

<?php
/**
* Copyright (c) 2002-2003 Richard Heyes
* Copyright 2011-2017 Horde LLC (http://www.horde.org/)
*
* This code is based on the original code contained in the PEAR Auth_SASL
* package (v0.5.1):
* $Id: DigestMD5.php 294702 2010-02-07 16:03:55Z cweiske $
*
* That code is covered by the BSD 3-Clause license, as set forth below:
* +-----------------------------------------------------------------------+
* | Copyright (c) 2002-2003 Richard Heyes |
* | All rights reserved. |
* | |
* | Redistribution and use in source and binary forms, with or without |
* | modification, are permitted provided that the following conditions |
* | are met: |
* | |
* | o Redistributions of source code must retain the above copyright |
* | notice, this list of conditions and the following disclaimer. |
* | o Redistributions in binary form must reproduce the above copyright |
* | notice, this list of conditions and the following disclaimer in the |
* | documentation and/or other materials provided with the distribution.|
* | o The names of the authors may not be used to endorse or promote |
* | products derived from this software without specific prior written |
* | permission. |
* | |
* | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
* | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
* | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
* | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
* | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
* | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
* | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
* +-----------------------------------------------------------------------+
*
* @category Horde
* @copyright 2002-2003 Richard Heyes
* @copyright 2011-2017 Horde LLC
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
* @package Imap_Client
*/
/**
* Provides the code needed to authenticate via the DIGEST-MD5 SASL mechanism
* (defined in RFC 2831). This method has been obsoleted by RFC 6331, but
* still is in use on legacy servers.
*
* @author Richard Heyes <richard@php.net>
* @author Michael Slusarz <slusarz@horde.org>
* @copyright 2002-2003 Richard Heyes
* @copyright 2011-2017 Horde LLC
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
* @package Imap_Client
*/
class Horde_Imap_Client_Auth_DigestMD5
{
/**
* Digest response components.
*
* @var string
*/
protected $_response;
/**
* Generate the Digest-MD5 response.
*
* @param string $id Authentication id (username).
* @param string $pass Password.
* @param string $challenge The digest challenge sent by the server.
* @param string $hostname The hostname of the machine connecting to.
* @param string $service The service name (e.g. 'imap', 'pop3').
*
* @throws Horde_Imap_Client_Exception
*/
public function __construct($id, $pass, $challenge, $hostname, $service)
{
$challenge = $this->_parseChallenge($challenge);
$cnonce = $this->_getCnonce();
$digest_uri = sprintf('%s/%s', $service, $hostname);
/* Get response value. */
$A1 = sprintf('%s:%s:%s', pack('H32', hash('md5', sprintf('%s:%s:%s', $id, $challenge['realm'], $pass))), $challenge['nonce'], $cnonce);
$A2 = 'AUTHENTICATE:' . $digest_uri;
$response_value = hash('md5', sprintf('%s:%s:00000001:%s:auth:%s', hash('md5', $A1), $challenge['nonce'], $cnonce, hash('md5', $A2)));
$this->_response = array(
'cnonce' => '"' . $cnonce . '"',
'digest-uri' => '"' . $digest_uri . '"',
'maxbuf' => $challenge['maxbuf'],
'nc' => '00000001',
'nonce' => '"' . $challenge['nonce'] . '"',
'qop' => 'auth',
'response' => $response_value,
'username' => '"' . $id . '"'
);
if (strlen($challenge['realm'])) {
$this->_response['realm'] = '"' . $challenge['realm'] . '"';
}
}
/**
* Cooerce to string.
*
* @return string The digest response (not base64 encoded).
*/
public function __toString()
{
$out = array();
foreach ($this->_response as $key => $val) {
$out[] = $key . '=' . $val;
}
return implode(',', $out);
}
/**
* Return specific digest response directive.
*
* @return mixed Requested directive, or null if it does not exist.
*/
public function __get($name)
{
return isset($this->_response[$name])
? $this->_response[$name]
: null;
}
/**
* Parses and verifies the digest challenge.
*
* @param string $challenge The digest challenge
*
* @return array The parsed challenge as an array with directives as keys.
*
* @throws Horde_Imap_Client_Exception
*/
protected function _parseChallenge($challenge)
{
$tokens = array(
'maxbuf' => 65536,
'realm' => ''
);
preg_match_all('/([a-z-]+)=("[^"]+(?<!\\\)"|[^,]+)/i', $challenge, $matches, PREG_SET_ORDER);
foreach ($matches as $val) {
$tokens[$val[1]] = trim($val[2], '"');
}
// Required directives.
if (!isset($tokens['nonce']) || !isset($tokens['algorithm'])) {
throw new Horde_Imap_Client_Exception(
Horde_Imap_Client_Translation::r("Authentication failure."),
Horde_Imap_Client_Exception::SERVER_CONNECT
);
}
return $tokens;
}
/**
* Creates the client nonce for the response
*
* @return string The cnonce value.
*/
protected function _getCnonce()
{
if ((@is_readable('/dev/urandom') &&
($fd = @fopen('/dev/urandom', 'r'))) ||
(@is_readable('/dev/random') &&
($fd = @fopen('/dev/random', 'r')))) {
$str = fread($fd, 32);
fclose($fd);
} else {
$str = '';
for ($i = 0; $i < 32; ++$i) {
$str .= chr(mt_rand(0, 255));
}
}
return base64_encode($str);
}
}