[ Index ]

MailPress 544

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

title

Body

[close]

/mp-includes/Swiftmailer/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 = array();
  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 = array();
  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 $_hash;
  97  
  98      private $_canonData = '';
  99  
 100      private $_bodyCanonEmptyCounter = 0;
 101  
 102      private $_bodyCanonIgnoreStart = 2;
 103  
 104      private $_bodyCanonSpace = false;
 105  
 106      private $_bodyCanonLastChar = null;
 107  
 108      private $_bodyCanonLine = '';
 109  
 110      private $_bound = array();
 111  
 112      /**
 113       * Constructor.
 114       *
 115       * @param string $privateKey
 116       * @param string $domainName
 117       * @param string $selector
 118       */
 119      public function __construct($privateKey, $domainName, $selector)
 120      {
 121          $this->_privateKey = $privateKey;
 122          $this->_domainName = $domainName;
 123          $this->_signerIdentity = '@'.$domainName;
 124          $this->_selector = $selector;
 125      }
 126  
 127      /**
 128       * Instanciate DomainKeySigner.
 129       *
 130       * @param string $privateKey
 131       * @param string $domainName
 132       * @param string $selector
 133       *
 134       * @return Swift_Signers_DomainKeySigner
 135       */
 136      public static function newInstance($privateKey, $domainName, $selector)
 137      {
 138          return new static($privateKey, $domainName, $selector);
 139      }
 140  
 141      /**
 142       * Resets internal states.
 143       *
 144       * @return Swift_Signers_DomainKeysSigner
 145       */
 146      public function reset()
 147      {
 148          $this->_hash = null;
 149          $this->_hashHandler = null;
 150          $this->_bodyCanonIgnoreStart = 2;
 151          $this->_bodyCanonEmptyCounter = 0;
 152          $this->_bodyCanonLastChar = null;
 153          $this->_bodyCanonSpace = false;
 154  
 155          return $this;
 156      }
 157  
 158      /**
 159       * Writes $bytes to the end of the stream.
 160       *
 161       * Writing may not happen immediately if the stream chooses to buffer.  If
 162       * you want to write these bytes with immediate effect, call {@link commit()}
 163       * after calling write().
 164       *
 165       * This method returns the sequence ID of the write (i.e. 1 for first, 2 for
 166       * second, etc etc).
 167       *
 168       * @param string $bytes
 169       *
 170       * @throws Swift_IoException
 171       *
 172       * @return int
 173       * @return Swift_Signers_DomainKeysSigner
 174       */
 175      public function write($bytes)
 176      {
 177          $this->_canonicalizeBody($bytes);
 178          foreach ($this->_bound as $is) {
 179              $is->write($bytes);
 180          }
 181  
 182          return $this;
 183      }
 184  
 185      /**
 186       * For any bytes that are currently buffered inside the stream, force them
 187       * off the buffer.
 188       *
 189       * @throws Swift_IoException
 190       *
 191       * @return Swift_Signers_DomainKeysSigner
 192       */
 193      public function commit()
 194      {
 195          // Nothing to do
 196          return $this;
 197      }
 198  
 199      /**
 200       * Attach $is to this stream.
 201       * The stream acts as an observer, receiving all data that is written.
 202       * All {@link write()} and {@link flushBuffers()} operations will be mirrored.
 203       *
 204       * @param Swift_InputByteStream $is
 205       *
 206       * @return Swift_Signers_DomainKeysSigner
 207       */
 208      public function bind(Swift_InputByteStream $is)
 209      {
 210          // Don't have to mirror anything
 211          $this->_bound[] = $is;
 212  
 213          return $this;
 214      }
 215  
 216      /**
 217       * Remove an already bound stream.
 218       * If $is is not bound, no errors will be raised.
 219       * If the stream currently has any buffered data it will be written to $is
 220       * before unbinding occurs.
 221       *
 222       * @param Swift_InputByteStream $is
 223       *
 224       * @return Swift_Signers_DomainKeysSigner
 225       */
 226      public function unbind(Swift_InputByteStream $is)
 227      {
 228          // Don't have to mirror anything
 229          foreach ($this->_bound as $k => $stream) {
 230              if ($stream === $is) {
 231                  unset($this->_bound[$k]);
 232  
 233                  return;
 234              }
 235          }
 236  
 237          return $this;
 238      }
 239  
 240      /**
 241       * Flush the contents of the stream (empty it) and set the internal pointer
 242       * to the beginning.
 243       *
 244       * @throws Swift_IoException
 245       *
 246       * @return Swift_Signers_DomainKeysSigner
 247       */
 248      public function flushBuffers()
 249      {
 250          $this->reset();
 251  
 252          return $this;
 253      }
 254  
 255      /**
 256       * Set hash_algorithm, must be one of rsa-sha256 | rsa-sha1 defaults to rsa-sha256.
 257       *
 258       * @param string $hash
 259       *
 260       * @return Swift_Signers_DomainKeysSigner
 261       */
 262      public function setHashAlgorithm($hash)
 263      {
 264          $this->_hashAlgorithm = 'rsa-sha1';
 265  
 266          return $this;
 267      }
 268  
 269      /**
 270       * Set the canonicalization algorithm.
 271       *
 272       * @param string $canon simple | nofws defaults to simple
 273       *
 274       * @return Swift_Signers_DomainKeysSigner
 275       */
 276      public function setCanon($canon)
 277      {
 278          if ($canon == 'nofws') {
 279              $this->_canon = 'nofws';
 280          } else {
 281              $this->_canon = 'simple';
 282          }
 283  
 284          return $this;
 285      }
 286  
 287      /**
 288       * Set the signer identity.
 289       *
 290       * @param string $identity
 291       *
 292       * @return Swift_Signers_DomainKeySigner
 293       */
 294      public function setSignerIdentity($identity)
 295      {
 296          $this->_signerIdentity = $identity;
 297  
 298          return $this;
 299      }
 300  
 301      /**
 302       * Enable / disable the DebugHeaders.
 303       *
 304       * @param bool $debug
 305       *
 306       * @return Swift_Signers_DomainKeySigner
 307       */
 308      public function setDebugHeaders($debug)
 309      {
 310          $this->_debugHeaders = (bool) $debug;
 311  
 312          return $this;
 313      }
 314  
 315      /**
 316       * Start Body.
 317       */
 318      public function startBody()
 319      {
 320      }
 321  
 322      /**
 323       * End Body.
 324       */
 325      public function endBody()
 326      {
 327          $this->_endOfBody();
 328      }
 329  
 330      /**
 331       * Returns the list of Headers Tampered by this plugin.
 332       *
 333       * @return array
 334       */
 335      public function getAlteredHeaders()
 336      {
 337          if ($this->_debugHeaders) {
 338              return array('DomainKey-Signature', 'X-DebugHash');
 339          } else {
 340              return array('DomainKey-Signature');
 341          }
 342      }
 343  
 344      /**
 345       * Adds an ignored Header.
 346       *
 347       * @param string $header_name
 348       *
 349       * @return Swift_Signers_DomainKeySigner
 350       */
 351      public function ignoreHeader($header_name)
 352      {
 353          $this->_ignoredHeaders[strtolower($header_name)] = true;
 354  
 355          return $this;
 356      }
 357  
 358      /**
 359       * Set the headers to sign.
 360       *
 361       * @param Swift_Mime_HeaderSet $headers
 362       *
 363       * @return Swift_Signers_DomainKeySigner
 364       */
 365      public function setHeaders(Swift_Mime_HeaderSet $headers)
 366      {
 367          $this->_startHash();
 368          $this->_canonData = '';
 369          // Loop through Headers
 370          $listHeaders = $headers->listAll();
 371          foreach ($listHeaders as $hName) {
 372              // Check if we need to ignore Header
 373              if (!isset($this->_ignoredHeaders[strtolower($hName)])) {
 374                  if ($headers->has($hName)) {
 375                      $tmp = $headers->getAll($hName);
 376                      foreach ($tmp as $header) {
 377                          if ($header->getFieldBody() != '') {
 378                              $this->_addHeader($header->toString());
 379                              $this->_signedHeaders[] = $header->getFieldName();
 380                          }
 381                      }
 382                  }
 383              }
 384          }
 385          $this->_endOfHeaders();
 386  
 387          return $this;
 388      }
 389  
 390      /**
 391       * Add the signature to the given Headers.
 392       *
 393       * @param Swift_Mime_HeaderSet $headers
 394       *
 395       * @return Swift_Signers_DomainKeySigner
 396       */
 397      public function addSignature(Swift_Mime_HeaderSet $headers)
 398      {
 399          // Prepare the DomainKey-Signature Header
 400          $params = array('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);
 401          $string = '';
 402          foreach ($params as $k => $v) {
 403              $string .= $k.'='.$v.'; ';
 404          }
 405          $string = trim($string);
 406          $headers->addTextHeader('DomainKey-Signature', $string);
 407  
 408          return $this;
 409      }
 410  
 411      /* Private helpers */
 412  
 413      protected function _addHeader($header)
 414      {
 415          switch ($this->_canon) {
 416              case 'nofws' :
 417                  // Prepare Header and cascade
 418                  $exploded = explode(':', $header, 2);
 419                  $name = strtolower(trim($exploded[0]));
 420                  $value = str_replace("\r\n", '', $exploded[1]);
 421                  $value = preg_replace("/[ \t][ \t]+/", ' ', $value);
 422                  $header = $name.':'.trim($value)."\r\n";
 423              case 'simple' :
 424                  // Nothing to do
 425          }
 426          $this->_addToHash($header);
 427      }
 428  
 429      protected function _endOfHeaders()
 430      {
 431          $this->_bodyCanonEmptyCounter = 1;
 432      }
 433  
 434      protected function _canonicalizeBody($string)
 435      {
 436          $len = strlen($string);
 437          $canon = '';
 438          $nofws = ($this->_canon == 'nofws');
 439          for ($i = 0; $i < $len; ++$i) {
 440              if ($this->_bodyCanonIgnoreStart > 0) {
 441                  --$this->_bodyCanonIgnoreStart;
 442                  continue;
 443              }
 444              switch ($string[$i]) {
 445                  case "\r" :
 446                      $this->_bodyCanonLastChar = "\r";
 447                      break;
 448                  case "\n" :
 449                      if ($this->_bodyCanonLastChar == "\r") {
 450                          if ($nofws) {
 451                              $this->_bodyCanonSpace = false;
 452                          }
 453                          if ($this->_bodyCanonLine == '') {
 454                              ++$this->_bodyCanonEmptyCounter;
 455                          } else {
 456                              $this->_bodyCanonLine = '';
 457                              $canon .= "\r\n";
 458                          }
 459                      } else {
 460                          // Wooops Error
 461                          throw new Swift_SwiftException('Invalid new line sequence in mail found \n without preceding \r');
 462                      }
 463                      break;
 464                  case ' ' :
 465                  case "\t" :
 466                  case "\x09": //HTAB
 467                      if ($nofws) {
 468                          $this->_bodyCanonSpace = true;
 469                          break;
 470                      }
 471                  default :
 472                      if ($this->_bodyCanonEmptyCounter > 0) {
 473                          $canon .= str_repeat("\r\n", $this->_bodyCanonEmptyCounter);
 474                          $this->_bodyCanonEmptyCounter = 0;
 475                      }
 476                      $this->_bodyCanonLine .= $string[$i];
 477                      $canon .= $string[$i];
 478              }
 479          }
 480          $this->_addToHash($canon);
 481      }
 482  
 483      protected function _endOfBody()
 484      {
 485          if (strlen($this->_bodyCanonLine) > 0) {
 486              $this->_addToHash("\r\n");
 487          }
 488          $this->_hash = hash_final($this->_hashHandler, true);
 489      }
 490  
 491      private function _addToHash($string)
 492      {
 493          $this->_canonData .= $string;
 494          hash_update($this->_hashHandler, $string);
 495      }
 496  
 497      private function _startHash()
 498      {
 499          // Init
 500          switch ($this->_hashAlgorithm) {
 501              case 'rsa-sha1' :
 502                  $this->_hashHandler = hash_init('sha1');
 503                  break;
 504          }
 505          $this->_canonLine = '';
 506      }
 507  
 508      /**
 509       * @throws Swift_SwiftException
 510       *
 511       * @return string
 512       */
 513      private function _getEncryptedHash()
 514      {
 515          $signature = '';
 516          $pkeyId = openssl_get_privatekey($this->_privateKey);
 517          if (!$pkeyId) {
 518              throw new Swift_SwiftException('Unable to load DomainKey Private Key ['.openssl_error_string().']');
 519          }
 520          if (openssl_sign($this->_canonData, $signature, $pkeyId, OPENSSL_ALGO_SHA1)) {
 521              return $signature;
 522          }
 523          throw new Swift_SwiftException('Unable to sign DomainKey Hash  ['.openssl_error_string().']');
 524      }
 525  }


Generated: Thu Apr 28 18:38:52 2016 Cross-referenced by PHPXref 0.7.1