Skip to content

Commit

Permalink
SCRAM-SHA-1(-PLUS) + SCRAM-SHA-256(-PLUS) + SCRAM-SHA-512(-PLUS) supp…
Browse files Browse the repository at this point in the history
…orts pear#57
  • Loading branch information
schengawegga committed Apr 1, 2023
1 parent cfd963d commit 1939d4d
Showing 1 changed file with 168 additions and 1 deletion.
169 changes: 168 additions & 1 deletion Net/SMTP.php
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,13 @@ class Net_SMTP
*/
protected $gssapi_cname = null;

/**
* SCRAM SHA-Hash algorithm.
*
* @var string
*/
protected $scram_sha_hash_algorithm = null;

/**
* Instantiates a new Net_SMTP object, overriding any defaults
* with parameters that are passed in.
Expand Down Expand Up @@ -215,6 +222,11 @@ public function __construct($host = null, $port = null, $localhost = null,
if (@include_once 'Auth/SASL.php') {
$this->setAuthMethod('CRAM-MD5', array($this, 'authCramMD5'));
$this->setAuthMethod('DIGEST-MD5', array($this, 'authDigestMD5'));
$this->setAuthMethod('SCRAM-SHA-1', array($this, 'authScramSHA1'));
$this->setAuthMethod('SCRAM-SHA-224', array($this, 'authScramSHA224'));
$this->setAuthMethod('SCRAM-SHA-256', array($this, 'authScramSHA256'));
$this->setAuthMethod('SCRAM-SHA-384', array($this, 'authScramSHA384'));
$this->setAuthMethod('SCRAM-SHA-512', array($this, 'authScramSHA512'));
}

/* These standard authentication methods are always available. */
Expand Down Expand Up @@ -426,7 +438,7 @@ public function command($command, $valid)
*/
public function getResponse()
{
return array($this->code, join("\n", $this->arguments));
return array($this->code, implode("\n", $this->arguments));
}

/**
Expand Down Expand Up @@ -1021,6 +1033,7 @@ protected function authGSSAPI($uid, $pwd, $authz = '')
* @param string $uid The userid to authenticate as.
* @param string $token The access token to authenticate with.
* @param string $authz The optional authorization proxy identifier.
* @param object $conn The current object
*
* @return mixed Returns a PEAR_Error with an error message on any
* kind of failure, or true on success.
Expand Down Expand Up @@ -1075,6 +1088,160 @@ public function authXOAuth2($uid, $token, $authz, $conn)
return true;
}

/**
* Authenticates the user using the SCRAM-SHA-1 method.
*
* @param string $uid The userid to authenticate as.
* @param string $pwd The password to authenticate with.
* @param string $authz The optional authorization proxy identifier.
*
* @return mixed Returns a PEAR_Error with an error message on any
* kind of failure, or true on success.
* @since 1.11.0
*/
protected function authScramSHA1($uid, $pwd, $authz = '')
{
$this->scram_sha_hash_algorithm = 'SCRAM-SHA-1';
return $this->authScramSHA($uid, $pwd, $authz);
}

/**
* Authenticates the user using the SCRAM-SHA-224 method.
*
* @param string $uid The userid to authenticate as.
* @param string $pwd The password to authenticate with.
* @param string $authz The optional authorization proxy identifier.
*
* @return mixed Returns a PEAR_Error with an error message on any
* kind of failure, or true on success.
* @since 1.11.0
*/
protected function authScramSHA224($uid, $pwd, $authz = '')
{
$this->scram_sha_hash_algorithm = 'SCRAM-SHA-224';
return $this->authScramSHA($uid, $pwd, $authz);
}

/**
* Authenticates the user using the SCRAM-SHA-256 method.
*
* @param string $uid The userid to authenticate as.
* @param string $pwd The password to authenticate with.
* @param string $authz The optional authorization proxy identifier.
*
* @return mixed Returns a PEAR_Error with an error message on any
* kind of failure, or true on success.
* @since 1.11.0
*/
protected function authScramSHA256($uid, $pwd, $authz = '')
{
$this->scram_sha_hash_algorithm = 'SCRAM-SHA-256';
return $this->authScramSHA($uid, $pwd, $authz);
}

/**
* Authenticates the user using the SCRAM-SHA-384 method.
*
* @param string $uid The userid to authenticate as.
* @param string $pwd The password to authenticate with.
* @param string $authz The optional authorization proxy identifier.
*
* @return mixed Returns a PEAR_Error with an error message on any
* kind of failure, or true on success.
* @since 1.11.0
*/
protected function authScramSHA384($uid, $pwd, $authz = '')
{
$this->scram_sha_hash_algorithm = 'SCRAM-SHA-384';
return $this->authScramSHA($uid, $pwd, $authz);
}

/**
* Authenticates the user using the SCRAM-SHA-512 method.
*
* @param string $uid The userid to authenticate as.
* @param string $pwd The password to authenticate with.
* @param string $authz The optional authorization proxy identifier.
*
* @return mixed Returns a PEAR_Error with an error message on any
* kind of failure, or true on success.
* @since 1.11.0
*/
protected function authScramSHA512($uid, $pwd, $authz = '')
{
$this->scram_sha_hash_algorithm = 'SCRAM-SHA-512';
return $this->authScramSHA($uid, $pwd, $authz);
}

/**
* Authenticates the user using the SCRAM-SHA method.
*
* @param string $uid The userid to authenticate as.
* @param string $pwd The password to authenticate with.
* @param string $authz The optional authorization proxy identifier.
*
* @return mixed Returns a PEAR_Error with an error message on any
* kind of failure, or true on success.
* @since 1.11.0
*/
protected function authScramSHA($uid, $pwd, $authz = '')
{
if (PEAR::isError($error = $this->put('AUTH', $this->scram_sha_hash_algorithm))) {
return $error;
}
/* 334: Continue authentication request */
if (PEAR::isError($error = $this->parseResponse(334))) {
/* 503: Error: already authenticated */
if ($this->code === 503) {
return true;
}
return $error;
}

$auth_sasl = new Auth_SASL;
$cram = $auth_sasl->factory($this->scram_sha_hash_algorithm);
$auth_str = base64_encode($cram->getResponse($uid, $pwd));

/* Step 1: Send first authentication request */
if (PEAR::isError($error = $this->put($auth_str))) {
return $error;
}

/* 334: Continue authentication request with password salt */
if (PEAR::isError($error = $this->parseResponse(334))) {
return $error;
}

$challenge = base64_decode($this->arguments[0]);
$auth_str = base64_encode($cram->getResponse($uid, $pwd, $challenge));

/* Step 2: Send salted authentication request */
if (PEAR::isError($error = $this->put($auth_str))) {
return $error;
}

/* 334: Continue authentication request with password salt */
if (PEAR::isError($error = $this->parseResponse(334))) {
return $error;
}

/* Verify server signature */
$verification = $cram->processOutcome(base64_decode($this->arguments[0]));
if ($verification == false) {
return PEAR::raiseError("SCRAM Server verification on step 3 not successful");
}

/* Step 3: Send a request to acknowledge verification */
if (PEAR::isError($error = $this->put("NOOP"))) {
return $error;
}

/* 235: Authentication successful */
if (PEAR::isError($error = $this->parseResponse(235))) {
return $error;
}
}

/**
* Send the HELO command.
*
Expand Down

0 comments on commit 1939d4d

Please sign in to comment.