1<?php 2/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ 3 4/** 5 * DNS Library for handling lookups and updates. 6 * 7 * PHP Version 5 8 * 9 * Copyright (c) 2010, Mike Pultz <mike@mikepultz.com>. 10 * All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 16 * * Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 19 * * Redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in 21 * the documentation and/or other materials provided with the 22 * distribution. 23 * 24 * * Neither the name of Mike Pultz nor the names of his contributors 25 * may be used to endorse or promote products derived from this 26 * software without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 31 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 32 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 33 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 34 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 35 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 36 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC 37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 38 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 39 * POSSIBILITY OF SUCH DAMAGE. 40 * 41 * @category Networking 42 * @package Net_DNS2 43 * @author Mike Pultz <mike@mikepultz.com> 44 * @copyright 2010 Mike Pultz <mike@mikepultz.com> 45 * @license http://www.opensource.org/licenses/bsd-license.php BSD License 46 * @version SVN: $Id$ 47 * @link http://pear.php.net/package/Net_DNS2 48 * @since File available since Release 0.6.0 49 * 50 * This file contains code based off the Net::DNS::SEC Perl module by 51 * Olaf M. Kolkman 52 * 53 * This is the copyright notice from the PERL Net::DNS::SEC module: 54 * 55 * Copyright (c) 2001 - 2005 RIPE NCC. Author Olaf M. Kolkman 56 * Copyright (c) 2007 - 2008 NLnet Labs. Author Olaf M. Kolkman 57 * <olaf@net-dns.org> 58 * 59 * All Rights Reserved 60 * 61 * Permission to use, copy, modify, and distribute this software and its 62 * documentation for any purpose and without fee is hereby granted, 63 * provided that the above copyright notice appear in all copies and that 64 * both that copyright notice and this permission notice appear in 65 * supporting documentation, and that the name of the author not be 66 * used in advertising or publicity pertaining to distribution of the 67 * software without specific, written prior permission. 68 * 69 * THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 70 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL 71 * AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY 72 * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 73 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 74 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 75 * 76 */ 77 78/** 79 * SIG Resource Record - RFC2535 section 4.1 80 * 81 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 82 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 83 * | Type Covered | Algorithm | Labels | 84 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 85 * | Original TTL | 86 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 87 * | Signature Expiration | 88 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 89 * | Signature Inception | 90 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 91 * | Key Tag | / 92 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Signer's Name / 93 * / / 94 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 95 * / / 96 * / Signature / 97 * / / 98 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 99 * 100 * @category Networking 101 * @package Net_DNS2 102 * @author Mike Pultz <mike@mikepultz.com> 103 * @license http://www.opensource.org/licenses/bsd-license.php BSD License 104 * @link http://pear.php.net/package/Net_DNS2 105 * @see Net_DNS2_RR 106 * 107 */ 108class Net_DNS2_RR_SIG extends Net_DNS2_RR 109{ 110 /* 111 * and instance of a Net_DNS2_PrivateKey object 112 */ 113 public $private_key = null; 114 115 /* 116 * the RR type covered by this signature 117 */ 118 public $typecovered; 119 120 /* 121 * the algorithm used for the signature 122 */ 123 public $algorithm; 124 125 /* 126 * the number of labels in the name 127 */ 128 public $labels; 129 130 /* 131 * the original TTL 132 */ 133 public $origttl; 134 135 /* 136 * the signature expiration 137 */ 138 public $sigexp; 139 140 /* 141 * the inception of the signature 142 */ 143 public $sigincep; 144 145 /* 146 * the keytag used 147 */ 148 public $keytag; 149 150 /* 151 * the signer's name 152 */ 153 public $signname; 154 155 /* 156 * the signature 157 */ 158 public $signature; 159 160 /** 161 * method to return the rdata portion of the packet as a string 162 * 163 * @return string 164 * @access protected 165 * 166 */ 167 protected function rrToString() 168 { 169 return $this->typecovered . ' ' . $this->algorithm . ' ' . 170 $this->labels . ' ' . $this->origttl . ' ' . 171 $this->sigexp . ' ' . $this->sigincep . ' ' . 172 $this->keytag . ' ' . $this->cleanString($this->signname) . '. ' . 173 $this->signature; 174 } 175 176 /** 177 * parses the rdata portion from a standard DNS config line 178 * 179 * @param array $rdata a string split line of values for the rdata 180 * 181 * @return boolean 182 * @access protected 183 * 184 */ 185 protected function rrFromString(array $rdata) 186 { 187 $this->typecovered = strtoupper(array_shift($rdata)); 188 $this->algorithm = array_shift($rdata); 189 $this->labels = array_shift($rdata); 190 $this->origttl = array_shift($rdata); 191 $this->sigexp = array_shift($rdata); 192 $this->sigincep = array_shift($rdata); 193 $this->keytag = array_shift($rdata); 194 $this->signname = $this->cleanString(array_shift($rdata)); 195 196 foreach ($rdata as $line) { 197 198 $this->signature .= $line; 199 } 200 201 $this->signature = trim($this->signature); 202 203 return true; 204 } 205 206 /** 207 * parses the rdata of the Net_DNS2_Packet object 208 * 209 * @param Net_DNS2_Packet &$packet a Net_DNS2_Packet packet to parse the RR from 210 * 211 * @return boolean 212 * @access protected 213 * 214 */ 215 protected function rrSet(Net_DNS2_Packet &$packet) 216 { 217 if ($this->rdlength > 0) { 218 219 // 220 // unpack 221 // 222 $x = unpack( 223 'ntc/Calgorithm/Clabels/Norigttl/Nsigexp/Nsigincep/nkeytag', 224 $this->rdata 225 ); 226 227 $this->typecovered = Net_DNS2_Lookups::$rr_types_by_id[$x['tc']]; 228 $this->algorithm = $x['algorithm']; 229 $this->labels = $x['labels']; 230 $this->origttl = Net_DNS2::expandUint32($x['origttl']); 231 232 // 233 // the dates are in GM time 234 // 235 $this->sigexp = gmdate('YmdHis', $x['sigexp']); 236 $this->sigincep = gmdate('YmdHis', $x['sigincep']); 237 238 // 239 // get the keytag 240 // 241 $this->keytag = $x['keytag']; 242 243 // 244 // get teh signers name and signature 245 // 246 $offset = $packet->offset + 18; 247 $sigoffset = $offset; 248 249 $this->signname = strtolower( 250 Net_DNS2_Packet::expand($packet, $sigoffset) 251 ); 252 $this->signature = base64_encode( 253 substr($this->rdata, 18 + ($sigoffset - $offset)) 254 ); 255 256 return true; 257 } 258 259 return false; 260 } 261 262 /** 263 * returns the rdata portion of the DNS packet 264 * 265 * @param Net_DNS2_Packet &$packet a Net_DNS2_Packet packet use for 266 * compressed names 267 * 268 * @return mixed either returns a binary packed 269 * string or null on failure 270 * @access protected 271 * 272 */ 273 protected function rrGet(Net_DNS2_Packet &$packet) 274 { 275 // 276 // parse the values out of the dates 277 // 278 preg_match( 279 '/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/', $this->sigexp, $e 280 ); 281 preg_match( 282 '/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/', $this->sigincep, $i 283 ); 284 285 // 286 // pack the value 287 // 288 $data = pack( 289 'nCCNNNn', 290 Net_DNS2_Lookups::$rr_types_by_name[$this->typecovered], 291 $this->algorithm, 292 $this->labels, 293 $this->origttl, 294 gmmktime($e[4], $e[5], $e[6], $e[2], $e[3], $e[1]), 295 gmmktime($i[4], $i[5], $i[6], $i[2], $i[3], $i[1]), 296 $this->keytag 297 ); 298 299 // 300 // the signer name is special; it's not allowed to be compressed 301 // (see section 3.1.7) 302 // 303 $names = explode('.', strtolower($this->signname)); 304 foreach ($names as $name) { 305 306 $data .= chr(strlen($name)); 307 $data .= $name; 308 } 309 310 $data .= chr('0'); 311 312 // 313 // if the signature is empty, and $this->private_key is an instance of a 314 // private key object, and we have access to openssl, then assume this 315 // is a SIG(0), and generate a new signature 316 // 317 if ( (strlen($this->signature) == 0) 318 && ($this->private_key instanceof Net_DNS2_PrivateKey) 319 && (extension_loaded('openssl') === true) 320 ) { 321 322 // 323 // create a new packet for the signature- 324 // 325 $new_packet = new Net_DNS2_Packet_Request('example.com', 'SOA', 'IN'); 326 327 // 328 // copy the packet data over 329 // 330 $new_packet->copy($packet); 331 332 // 333 // remove the SIG object from the additional list 334 // 335 array_pop($new_packet->additional); 336 $new_packet->header->arcount = count($new_packet->additional); 337 338 // 339 // copy out the data 340 // 341 $sigdata = $data . $new_packet->get(); 342 343 // 344 // based on the algorithm 345 // 346 $algorithm = 0; 347 348 switch($this->algorithm) { 349 350 // 351 // MD5 352 // 353 case Net_DNS2_Lookups::DNSSEC_ALGORITHM_RSAMD5: 354 355 $algorithm = OPENSSL_ALGO_MD5; 356 break; 357 358 // 359 // SHA1 360 // 361 case Net_DNS2_Lookups::DNSSEC_ALGORITHM_RSASHA1: 362 363 $algorithm = OPENSSL_ALGO_SHA1; 364 break; 365 366 // 367 // SHA256 (PHP 5.4.8 or higher) 368 // 369 case Net_DNS2_Lookups::DNSSEC_ALGORITHM_RSASHA256: 370 371 if (version_compare(PHP_VERSION, '5.4.8', '<') == true) { 372 373 throw new Net_DNS2_Exception( 374 'SHA256 support is only available in PHP >= 5.4.8', 375 Net_DNS2_Lookups::E_OPENSSL_INV_ALGO 376 ); 377 } 378 379 $algorithm = OPENSSL_ALGO_SHA256; 380 break; 381 382 // 383 // SHA512 (PHP 5.4.8 or higher) 384 // 385 case Net_DNS2_Lookups::DNSSEC_ALGORITHM_RSASHA512: 386 387 if (version_compare(PHP_VERSION, '5.4.8', '<') == true) { 388 389 throw new Net_DNS2_Exception( 390 'SHA512 support is only available in PHP >= 5.4.8', 391 Net_DNS2_Lookups::E_OPENSSL_INV_ALGO 392 ); 393 } 394 395 $algorithm = OPENSSL_ALGO_SHA512; 396 break; 397 398 // 399 // unsupported at the moment 400 // 401 case Net_DNS2_Lookups::DNSSEC_ALGORITHM_DSA: 402 case Net_DNS2_Lookups::DSNSEC_ALGORITHM_RSASHA1NSEC3SHA1: 403 case Net_DNS2_Lookups::DNSSEC_ALGORITHM_DSANSEC3SHA1: 404 default: 405 throw new Net_DNS2_Exception( 406 'invalid or unsupported algorithm', 407 Net_DNS2_Lookups::E_OPENSSL_INV_ALGO 408 ); 409 break; 410 } 411 412 // 413 // sign the data 414 // 415 if (openssl_sign($sigdata, $this->signature, $this->private_key->instance, $algorithm) == false) { 416 417 throw new Net_DNS2_Exception( 418 openssl_error_string(), 419 Net_DNS2_Lookups::E_OPENSSL_ERROR 420 ); 421 } 422 423 // 424 // build the signature value based 425 // 426 switch($this->algorithm) { 427 428 // 429 // RSA- add it directly 430 // 431 case Net_DNS2_Lookups::DNSSEC_ALGORITHM_RSAMD5: 432 case Net_DNS2_Lookups::DNSSEC_ALGORITHM_RSASHA1: 433 case Net_DNS2_Lookups::DNSSEC_ALGORITHM_RSASHA256: 434 case Net_DNS2_Lookups::DNSSEC_ALGORITHM_RSASHA512: 435 436 $this->signature = base64_encode($this->signature); 437 break; 438 } 439 } 440 441 // 442 // add the signature 443 // 444 $data .= base64_decode($this->signature); 445 446 $packet->offset += strlen($data); 447 448 return $data; 449 } 450} 451 452/* 453 * Local variables: 454 * tab-width: 4 455 * c-basic-offset: 4 456 * c-hanging-comment-ender-p: nil 457 * End: 458 */ 459?> 460