Skip to content

Commit 1939d4d

Browse files
committed
SCRAM-SHA-1(-PLUS) + SCRAM-SHA-256(-PLUS) + SCRAM-SHA-512(-PLUS) supports pear#57
1 parent cfd963d commit 1939d4d

File tree

1 file changed

+168
-1
lines changed

1 file changed

+168
-1
lines changed

Net/SMTP.php

+168-1
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,13 @@ class Net_SMTP
162162
*/
163163
protected $gssapi_cname = null;
164164

165+
/**
166+
* SCRAM SHA-Hash algorithm.
167+
*
168+
* @var string
169+
*/
170+
protected $scram_sha_hash_algorithm = null;
171+
165172
/**
166173
* Instantiates a new Net_SMTP object, overriding any defaults
167174
* with parameters that are passed in.
@@ -215,6 +222,11 @@ public function __construct($host = null, $port = null, $localhost = null,
215222
if (@include_once 'Auth/SASL.php') {
216223
$this->setAuthMethod('CRAM-MD5', array($this, 'authCramMD5'));
217224
$this->setAuthMethod('DIGEST-MD5', array($this, 'authDigestMD5'));
225+
$this->setAuthMethod('SCRAM-SHA-1', array($this, 'authScramSHA1'));
226+
$this->setAuthMethod('SCRAM-SHA-224', array($this, 'authScramSHA224'));
227+
$this->setAuthMethod('SCRAM-SHA-256', array($this, 'authScramSHA256'));
228+
$this->setAuthMethod('SCRAM-SHA-384', array($this, 'authScramSHA384'));
229+
$this->setAuthMethod('SCRAM-SHA-512', array($this, 'authScramSHA512'));
218230
}
219231

220232
/* These standard authentication methods are always available. */
@@ -426,7 +438,7 @@ public function command($command, $valid)
426438
*/
427439
public function getResponse()
428440
{
429-
return array($this->code, join("\n", $this->arguments));
441+
return array($this->code, implode("\n", $this->arguments));
430442
}
431443

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

1091+
/**
1092+
* Authenticates the user using the SCRAM-SHA-1 method.
1093+
*
1094+
* @param string $uid The userid to authenticate as.
1095+
* @param string $pwd The password to authenticate with.
1096+
* @param string $authz The optional authorization proxy identifier.
1097+
*
1098+
* @return mixed Returns a PEAR_Error with an error message on any
1099+
* kind of failure, or true on success.
1100+
* @since 1.11.0
1101+
*/
1102+
protected function authScramSHA1($uid, $pwd, $authz = '')
1103+
{
1104+
$this->scram_sha_hash_algorithm = 'SCRAM-SHA-1';
1105+
return $this->authScramSHA($uid, $pwd, $authz);
1106+
}
1107+
1108+
/**
1109+
* Authenticates the user using the SCRAM-SHA-224 method.
1110+
*
1111+
* @param string $uid The userid to authenticate as.
1112+
* @param string $pwd The password to authenticate with.
1113+
* @param string $authz The optional authorization proxy identifier.
1114+
*
1115+
* @return mixed Returns a PEAR_Error with an error message on any
1116+
* kind of failure, or true on success.
1117+
* @since 1.11.0
1118+
*/
1119+
protected function authScramSHA224($uid, $pwd, $authz = '')
1120+
{
1121+
$this->scram_sha_hash_algorithm = 'SCRAM-SHA-224';
1122+
return $this->authScramSHA($uid, $pwd, $authz);
1123+
}
1124+
1125+
/**
1126+
* Authenticates the user using the SCRAM-SHA-256 method.
1127+
*
1128+
* @param string $uid The userid to authenticate as.
1129+
* @param string $pwd The password to authenticate with.
1130+
* @param string $authz The optional authorization proxy identifier.
1131+
*
1132+
* @return mixed Returns a PEAR_Error with an error message on any
1133+
* kind of failure, or true on success.
1134+
* @since 1.11.0
1135+
*/
1136+
protected function authScramSHA256($uid, $pwd, $authz = '')
1137+
{
1138+
$this->scram_sha_hash_algorithm = 'SCRAM-SHA-256';
1139+
return $this->authScramSHA($uid, $pwd, $authz);
1140+
}
1141+
1142+
/**
1143+
* Authenticates the user using the SCRAM-SHA-384 method.
1144+
*
1145+
* @param string $uid The userid to authenticate as.
1146+
* @param string $pwd The password to authenticate with.
1147+
* @param string $authz The optional authorization proxy identifier.
1148+
*
1149+
* @return mixed Returns a PEAR_Error with an error message on any
1150+
* kind of failure, or true on success.
1151+
* @since 1.11.0
1152+
*/
1153+
protected function authScramSHA384($uid, $pwd, $authz = '')
1154+
{
1155+
$this->scram_sha_hash_algorithm = 'SCRAM-SHA-384';
1156+
return $this->authScramSHA($uid, $pwd, $authz);
1157+
}
1158+
1159+
/**
1160+
* Authenticates the user using the SCRAM-SHA-512 method.
1161+
*
1162+
* @param string $uid The userid to authenticate as.
1163+
* @param string $pwd The password to authenticate with.
1164+
* @param string $authz The optional authorization proxy identifier.
1165+
*
1166+
* @return mixed Returns a PEAR_Error with an error message on any
1167+
* kind of failure, or true on success.
1168+
* @since 1.11.0
1169+
*/
1170+
protected function authScramSHA512($uid, $pwd, $authz = '')
1171+
{
1172+
$this->scram_sha_hash_algorithm = 'SCRAM-SHA-512';
1173+
return $this->authScramSHA($uid, $pwd, $authz);
1174+
}
1175+
1176+
/**
1177+
* Authenticates the user using the SCRAM-SHA method.
1178+
*
1179+
* @param string $uid The userid to authenticate as.
1180+
* @param string $pwd The password to authenticate with.
1181+
* @param string $authz The optional authorization proxy identifier.
1182+
*
1183+
* @return mixed Returns a PEAR_Error with an error message on any
1184+
* kind of failure, or true on success.
1185+
* @since 1.11.0
1186+
*/
1187+
protected function authScramSHA($uid, $pwd, $authz = '')
1188+
{
1189+
if (PEAR::isError($error = $this->put('AUTH', $this->scram_sha_hash_algorithm))) {
1190+
return $error;
1191+
}
1192+
/* 334: Continue authentication request */
1193+
if (PEAR::isError($error = $this->parseResponse(334))) {
1194+
/* 503: Error: already authenticated */
1195+
if ($this->code === 503) {
1196+
return true;
1197+
}
1198+
return $error;
1199+
}
1200+
1201+
$auth_sasl = new Auth_SASL;
1202+
$cram = $auth_sasl->factory($this->scram_sha_hash_algorithm);
1203+
$auth_str = base64_encode($cram->getResponse($uid, $pwd));
1204+
1205+
/* Step 1: Send first authentication request */
1206+
if (PEAR::isError($error = $this->put($auth_str))) {
1207+
return $error;
1208+
}
1209+
1210+
/* 334: Continue authentication request with password salt */
1211+
if (PEAR::isError($error = $this->parseResponse(334))) {
1212+
return $error;
1213+
}
1214+
1215+
$challenge = base64_decode($this->arguments[0]);
1216+
$auth_str = base64_encode($cram->getResponse($uid, $pwd, $challenge));
1217+
1218+
/* Step 2: Send salted authentication request */
1219+
if (PEAR::isError($error = $this->put($auth_str))) {
1220+
return $error;
1221+
}
1222+
1223+
/* 334: Continue authentication request with password salt */
1224+
if (PEAR::isError($error = $this->parseResponse(334))) {
1225+
return $error;
1226+
}
1227+
1228+
/* Verify server signature */
1229+
$verification = $cram->processOutcome(base64_decode($this->arguments[0]));
1230+
if ($verification == false) {
1231+
return PEAR::raiseError("SCRAM Server verification on step 3 not successful");
1232+
}
1233+
1234+
/* Step 3: Send a request to acknowledge verification */
1235+
if (PEAR::isError($error = $this->put("NOOP"))) {
1236+
return $error;
1237+
}
1238+
1239+
/* 235: Authentication successful */
1240+
if (PEAR::isError($error = $this->parseResponse(235))) {
1241+
return $error;
1242+
}
1243+
}
1244+
10781245
/**
10791246
* Send the HELO command.
10801247
*

0 commit comments

Comments
 (0)