[ Index ]

MailPress 7.2

[ Index ]     [ Classes ]     [ Functions ]     [ Variables ]     [ Constants ]     [ Statistics ]    

title

Body

[close]

/mp-includes/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/ -> DomainKeySigner.php (source)

   1  <?php
   2  
   3  /*
   4   * This file is part of SwiftMailer.
   5   * (c) 2004-2009 Chris Corbyn
   6   *
   7   * For the full copyright and license information, please view the LICENSE
   8   * file that was distributed with this source code.
   9   */
  10  
  11  /**
  12   * DomainKey Signer used to apply DomainKeys Signature to a message.
  13   *
  14   * @author     Xavier De Cock <xdecock@gmail.com>
  15   */
  16  class Swift_Signers_DomainKeySigner implements Swift_Signers_HeaderSigner
  17  {
  18      /**
  19       * PrivateKey.
  20       *
  21       * @var string
  22       */
  23      protected $privateKey;
  24  
  25      /**
  26       * DomainName.
  27       *
  28       * @var string
  29       */
  30      protected $domainName;
  31  
  32      /**
  33       * Selector.
  34       *
  35       * @var string
  36       */
  37      protected $selector;
  38  
  39      /**
  40       * Hash algorithm used.
  41       *
  42       * @var string
  43       */
  44      protected $hashAlgorithm = 'rsa-sha1';
  45  
  46      /**
  47       * Canonisation method.
  48       *
  49       * @var string
  50       */
  51      protected $canon = 'simple';
  52  
  53      /**
  54       * Headers not being signed.
  55       *
  56       * @var array
  57       */
  58      protected $ignoredHeaders = [];
  59  
  60      /**
  61       * Signer identity.
  62       *
  63       * @var string
  64       */
  65      protected $signerIdentity;
  66  
  67      /**
  68       * Must we embed signed headers?
  69       *
  70       * @var bool
  71       */
  72      protected $debugHeaders = false;
  73  
  74      // work variables
  75      /**
  76       * Headers used to generate hash.
  77       *
  78       * @var array
  79       */
  80      private $signedHeaders = [];
  81  
  82      /**
  83       * Stores the signature header.
  84       *
  85       * @var Swift_Mime_Headers_ParameterizedHeader
  86       */
  87      protected $domainKeyHeader;
  88  
  89      /**
  90       * Hash Handler.
  91       *
  92       * @var resource|null
  93       */
  94      private $hashHandler;
  95  
  96      private $canonData = '';
  97  
  98      private $bodyCanonEmptyCounter = 0;
  99  
 100      private $bodyCanonIgnoreStart = 2;
 101  
 102      private $bodyCanonSpace = false;
 103  
 104      private $bodyCanonLastChar = null;
 105  
 106      private $bodyCanonLine = '';
 107  
 108      private $bound = [];
 109  
 110      /**
 111       * Constructor.
 112       *
 113       * @param string $privateKey
 114       * @param string $domainName
 115       * @param string $selector
 116       */
 117      public function __construct($privateKey, $domainName, $selector)
 118      {
 119          $this->privateKey = $privateKey;
 120          $this->domainName = $domainName;
 121          $this->signerIdentity = '@'.$domainName;
 122          $this->selector = $selector;
 123      }
 124  
 125      /**
 126       * Resets internal states.
 127       *
 128       * @return $this
 129       */
 130      public function reset()
 131      {
 132          $this->hashHandler = null;
 133          $this->bodyCanonIgnoreStart = 2;
 134          $this->bodyCanonEmptyCounter = 0;
 135          $this->bodyCanonLastChar = null;
 136          $this->bodyCanonSpace = false;
 137  
 138          return $this;
 139      }
 140  
 141      /**
 142       * Writes $bytes to the end of the stream.
 143       *
 144       * Writing may not happen immediately if the stream chooses to buffer.  If
 145       * you want to write these bytes with immediate effect, call {@link commit()}
 146       * after calling write().
 147       *
 148       * This method returns the sequence ID of the write (i.e. 1 for first, 2 for
 149       * second, etc etc).
 150       *
 151       * @param string $bytes
 152       *
 153       * @return int
 154       *
 155       * @throws Swift_IoException
 156       *
 157       * @return $this
 158       */
 159      public function write($bytes)
 160      {
 161          $this->canonicalizeBody($bytes);
 162          foreach ($this->bound as $is) {
 163              $is->write($bytes);
 164          }
 165  
 166          return $this;
 167      }
 168  
 169      /**
 170       * For any bytes that are currently buffered inside the stream, force them
 171       * off the buffer.
 172       *
 173       * @throws Swift_IoException
 174       *
 175       * @return $this
 176       */
 177      public function commit()
 178      {
 179          // Nothing to do
 180          return $this;
 181      }
 182  
 183      /**
 184       * Attach $is to this stream.
 185       *
 186       * The stream acts as an observer, receiving all data that is written.
 187       * All {@link write()} and {@link flushBuffers()} operations will be mirrored.
 188       *
 189       * @return $this
 190       */
 191      public function bind(Swift_InputByteStream $is)
 192      {
 193          // Don't have to mirror anything
 194          $this->bound[] = $is;
 195  
 196          return $this;
 197      }
 198  
 199      /**
 200       * Remove an already bound stream.
 201       *
 202       * If $is is not bound, no errors will be raised.
 203       * If the stream currently has any buffered data it will be written to $is
 204       * before unbinding occurs.
 205       *
 206       * @return $this
 207       */
 208      public function unbind(Swift_InputByteStream $is)
 209      {
 210          // Don't have to mirror anything
 211          foreach ($this->bound as $k => $stream) {
 212              if ($stream === $is) {
 213                  unset($this->bound[$k]);
 214  
 215                  break;
 216              }
 217          }
 218  
 219          return $this;
 220      }
 221  
 222      /**
 223       * Flush the contents of the stream (empty it) and set the internal pointer
 224       * to the beginning.
 225       *
 226       * @throws Swift_IoException
 227       *
 228       * @return $this
 229       */
 230      public function flushBuffers()
 231      {
 232          $this->reset();
 233  
 234          return $this;
 235      }
 236  
 237      /**
 238       * Set hash_algorithm, must be one of rsa-sha256 | rsa-sha1 defaults to rsa-sha256.
 239       *
 240       * @param string $hash
 241       *
 242       * @return $this
 243       */
 244      public function setHashAlgorithm($hash)
 245      {
 246          $this->hashAlgorithm = 'rsa-sha1';
 247  
 248          return $this;
 249      }
 250  
 251      /**
 252       * Set the canonicalization algorithm.
 253       *
 254       * @param string $canon simple | nofws defaults to simple
 255       *
 256       * @return $this
 257       */
 258      public function setCanon($canon)
 259      {
 260          if ('nofws' == $canon) {
 261              $this->canon = 'nofws';
 262          } else {
 263              $this->canon = 'simple';
 264          }
 265  
 266          return $this;
 267      }
 268  
 269      /**
 270       * Set the signer identity.
 271       *
 272       * @param string $identity
 273       *
 274       * @return $this
 275       */
 276      public function setSignerIdentity($identity)
 277      {
 278          $this->signerIdentity = $identity;
 279  
 280          return $this;
 281      }
 282  
 283      /**
 284       * Enable / disable the DebugHeaders.
 285       *
 286       * @param bool $debug
 287       *
 288       * @return $this
 289       */
 290      public function setDebugHeaders($debug)
 291      {
 292          $this->debugHeaders = (bool) $debug;
 293  
 294          return $this;
 295      }
 296  
 297      /**
 298       * Start Body.
 299       */
 300      public function startBody()
 301      {
 302      }
 303  
 304      /**
 305       * End Body.
 306       */
 307      public function endBody()
 308      {
 309          $this->endOfBody();
 310      }
 311  
 312      /**
 313       * Returns the list of Headers Tampered by this plugin.
 314       *
 315       * @return array
 316       */
 317      public function getAlteredHeaders()
 318      {
 319          if ($this->debugHeaders) {
 320              return ['DomainKey-Signature', 'X-DebugHash'];
 321          }
 322  
 323          return ['DomainKey-Signature'];
 324      }
 325  
 326      /**
 327       * Adds an ignored Header.
 328       *
 329       * @param string $header_name
 330       *
 331       * @return $this
 332       */
 333      public function ignoreHeader($header_name)
 334      {
 335          $this->ignoredHeaders[strtolower($header_name)] = true;
 336  
 337          return $this;
 338      }
 339  
 340      /**
 341       * Set the headers to sign.
 342       *
 343       * @return $this
 344       */
 345      public function setHeaders(Swift_Mime_SimpleHeaderSet $headers)
 346      {
 347          $this->startHash();
 348          $this->canonData = '';
 349          // Loop through Headers
 350          $listHeaders = $headers->listAll();
 351          foreach ($listHeaders as $hName) {
 352              // Check if we need to ignore Header
 353              if (!isset($this->ignoredHeaders[strtolower($hName)])) {
 354                  if ($headers->has($hName)) {
 355                      $tmp = $headers->getAll($hName);
 356                      foreach ($tmp as $header) {
 357                          if ('' != $header->getFieldBody()) {
 358                              $this->addHeader($header->toString());
 359                              $this->signedHeaders[] = $header->getFieldName();
 360                          }
 361                      }
 362                  }
 363              }
 364          }
 365          $this->endOfHeaders();
 366  
 367          return $this;
 368      }
 369  
 370      /**
 371       * Add the signature to the given Headers.
 372       *
 373       * @return $this
 374       */
 375      public function addSignature(Swift_Mime_SimpleHeaderSet $headers)
 376      {
 377          // Prepare the DomainKey-Signature Header
 378          $params = ['a' => $this->hashAlgorithm, 'b' => chunk_split(base64_encode($this->getEncryptedHash()), 73, ' '), 'c' => $this->canon, 'd' => $this->domainName, 'h' => implode(': ', $this->signedHeaders), 'q' => 'dns', 's' => $this->selector];
 379          $string = '';
 380          foreach ($params as $k => $v) {
 381              $string .= $k.'='.$v.'; ';
 382          }
 383          $string = trim($string);
 384          $headers->addTextHeader('DomainKey-Signature', $string);
 385  
 386          return $this;
 387      }
 388  
 389      /* Private helpers */
 390  
 391      protected function addHeader($header)
 392      {
 393          switch ($this->canon) {
 394              case 'nofws':
 395                  // Prepare Header and cascade
 396                  $exploded = explode(':', $header, 2);
 397                  $name = strtolower(trim($exploded[0]));
 398                  $value = str_replace("\r\n", '', $exploded[1]);
 399                  $value = preg_replace("/[ \t][ \t]+/", ' ', $value);
 400                  $header = $name.':'.trim($value)."\r\n";
 401                  // no break
 402              case 'simple':
 403                  // Nothing to do
 404          }
 405          $this->addToHash($header);
 406      }
 407  
 408      protected function endOfHeaders()
 409      {
 410          $this->bodyCanonEmptyCounter = 1;
 411      }
 412  
 413      protected function canonicalizeBody($string)
 414      {
 415          $len = strlen($string);
 416          $canon = '';
 417          $nofws = ('nofws' == $this->canon);
 418          for ($i = 0; $i < $len; ++$i) {
 419              if ($this->bodyCanonIgnoreStart > 0) {
 420                  --$this->bodyCanonIgnoreStart;
 421                  continue;
 422              }
 423              switch ($string[$i]) {
 424                  case "\r":
 425                      $this->bodyCanonLastChar = "\r";
 426                      break;
 427                  case "\n":
 428                      if ("\r" == $this->bodyCanonLastChar) {
 429                          if ($nofws) {
 430                              $this->bodyCanonSpace = false;
 431                          }
 432                          if ('' == $this->bodyCanonLine) {
 433                              ++$this->bodyCanonEmptyCounter;
 434                          } else {
 435                              $this->bodyCanonLine = '';
 436                              $canon .= "\r\n";
 437                          }
 438                      } else {
 439                          // Wooops Error
 440                          throw new Swift_SwiftException('Invalid new line sequence in mail found \n without preceding \r');
 441                      }
 442                      break;
 443                  case ' ':
 444                  case "\t":
 445                  case "\x09": //HTAB
 446                      if ($nofws) {
 447                          $this->bodyCanonSpace = true;
 448                          break;
 449                      }
 450                      // no break
 451                  default:
 452                      if ($this->bodyCanonEmptyCounter > 0) {
 453                          $canon .= str_repeat("\r\n", $this->bodyCanonEmptyCounter);
 454                          $this->bodyCanonEmptyCounter = 0;
 455                      }
 456                      $this->bodyCanonLine .= $string[$i];
 457                      $canon .= $string[$i];
 458              }
 459          }
 460          $this->addToHash($canon);
 461      }
 462  
 463      protected function endOfBody()
 464      {
 465          if (strlen($this->bodyCanonLine) > 0) {
 466              $this->addToHash("\r\n");
 467          }
 468      }
 469  
 470      private function addToHash($string)
 471      {
 472          $this->canonData .= $string;
 473          hash_update($this->hashHandler, $string);
 474      }
 475  
 476      private function startHash()
 477      {
 478          // Init
 479          switch ($this->hashAlgorithm) {
 480              case 'rsa-sha1':
 481                  $this->hashHandler = hash_init('sha1');
 482                  break;
 483          }
 484          $this->bodyCanonLine = '';
 485      }
 486  
 487      /**
 488       * @throws Swift_SwiftException
 489       *
 490       * @return string
 491       */
 492      private function getEncryptedHash()
 493      {
 494          $signature = '';
 495          $pkeyId = openssl_get_privatekey($this->privateKey);
 496          if (!$pkeyId) {
 497              throw new Swift_SwiftException('Unable to load DomainKey Private Key ['.openssl_error_string().']');
 498          }
 499          if (openssl_sign($this->canonData, $signature, $pkeyId, OPENSSL_ALGO_SHA1)) {
 500              return $signature;
 501          }
 502          throw new Swift_SwiftException('Unable to sign DomainKey Hash  ['.openssl_error_string().']');
 503      }
 504  }


Generated: Tue May 19 15:55:14 2020 Cross-referenced by PHPXref 0.7.1