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 2011 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 1.1.0
49 *
50 */
51
52/**
53 * SSL Private Key container class
54 *
55 * @category Networking
56 * @package  Net_DNS2
57 * @author   Mike Pultz <mike@mikepultz.com>
58 * @license  http://www.opensource.org/licenses/bsd-license.php  BSD License
59 * @link     http://pear.php.net/package/Net_DNS2
60 *
61 */
62class Net_DNS2_PrivateKey
63{
64    /*
65     * the filename that was loaded; stored for reference
66     */
67    public $filename;
68
69    /*
70     * the keytag for the signature
71     */
72    public $keytag;
73
74    /*
75     * the sign name for the signature
76     */
77    public $signname;
78
79    /*
80     * the algorithm used for the signature
81     */
82    public $algorithm;
83
84    /*
85     * the key format fo the signature
86     */
87    public $key_format;
88
89    /*
90     * the openssl private key id
91     */
92    public $instance;
93
94    /*
95     * RSA: modulus
96     */
97    private $_modulus;
98
99    /*
100     * RSA: public exponent
101     */
102    private $_public_exponent;
103
104    /*
105     * RSA: rivate exponent
106     */
107    private $_private_exponent;
108
109    /*
110     * RSA: prime1
111     */
112    private $_prime1;
113
114    /*
115     * RSA: prime2
116     */
117    private $_prime2;
118
119    /*
120     * RSA: exponent 1
121     */
122    private $_exponent1;
123
124    /*
125     * RSA: exponent 2
126     */
127    private $_exponent2;
128
129    /*
130     * RSA: coefficient
131     */
132    private $_coefficient;
133
134    /*
135     * DSA: prime
136     */
137    public $prime;
138
139    /*
140     * DSA: subprime
141     */
142    public $subprime;
143
144    /*
145     * DSA: base
146     */
147    public $base;
148
149    /*
150     * DSA: private value
151     */
152    public $private_value;
153
154    /*
155     * DSA: public value
156     */
157    public $public_value;
158
159    /**
160     * Constructor - base constructor the private key container class
161     *
162     * @param string $file path to a private-key file to parse and load
163     *
164     * @throws Net_DNS2_Exception
165     * @access public
166     *
167     */
168    public function __construct($file = null)
169    {
170        if (isset($file)) {
171            $this->parseFile($file);
172        }
173    }
174
175    /**
176     * parses a private key file generated by dnssec-keygen
177     *
178     * @param string $file path to a private-key file to parse and load
179     *
180     * @return boolean
181     * @throws Net_DNS2_Exception
182     * @access public
183     *
184     */
185    public function parseFile($file)
186    {
187        //
188        // check for OpenSSL
189        //
190        if (extension_loaded('openssl') === false) {
191
192            throw new Net_DNS2_Exception(
193                'the OpenSSL extension is required to use parse private key.',
194                Net_DNS2_Lookups::E_OPENSSL_UNAVAIL
195            );
196        }
197
198        //
199        // check to make sure the file exists
200        //
201        if (is_readable($file) == false) {
202
203            throw new Net_DNS2_Exception(
204                'invalid private key file: ' . $file,
205                Net_DNS2_Lookups::E_OPENSSL_INV_PKEY
206            );
207        }
208
209        //
210        // get the base filename, and parse it for the local value
211        //
212        $keyname = basename($file);
213        if (strlen($keyname) == 0) {
214
215            throw new Net_DNS2_Exception(
216                'failed to get basename() for: ' . $file,
217                Net_DNS2_Lookups::E_OPENSSL_INV_PKEY
218            );
219        }
220
221        //
222        // parse the keyname
223        //
224        if (preg_match("/K(.*)\.\+(\d{3})\+(\d*)\.private/", $keyname, $matches)) {
225
226            $this->signname    = $matches[1];
227            $this->algorithm   = intval($matches[2]);
228            $this->keytag      = intval($matches[3]);
229
230        } else {
231
232            throw new Net_DNS2_Exception(
233                'file ' . $keyname . ' does not look like a private key file!',
234                Net_DNS2_Lookups::E_OPENSSL_INV_PKEY
235            );
236        }
237
238        //
239        // read all the data from the
240        //
241        $data = file($file, FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES);
242        if (count($data) == 0) {
243
244            throw new Net_DNS2_Exception(
245                'file ' . $keyname . ' is empty!',
246                Net_DNS2_Lookups::E_OPENSSL_INV_PKEY
247            );
248        }
249
250        foreach ($data as $line) {
251
252            list($key, $value) = explode(':', $line);
253
254            $key    = trim($key);
255            $value  = trim($value);
256
257            switch(strtolower($key)) {
258
259            case 'private-key-format':
260                $this->_key_format = $value;
261                break;
262
263            case 'algorithm':
264                if ($this->algorithm != $value) {
265                    throw new Net_DNS2_Exception(
266                        'Algorithm mis-match! filename is ' . $this->algorithm .
267                        ', contents say ' . $value,
268                        Net_DNS2_Lookups::E_OPENSSL_INV_ALGO
269                    );
270                }
271                break;
272
273            //
274            // RSA
275            //
276            case 'modulus':
277                $this->_modulus = $value;
278                break;
279
280            case 'publicexponent':
281                $this->_public_exponent = $value;
282                break;
283
284            case 'privateexponent':
285                $this->_private_exponent = $value;
286                break;
287
288            case 'prime1':
289                $this->_prime1 = $value;
290                break;
291
292            case 'prime2':
293                $this->_prime2 = $value;
294                break;
295
296            case 'exponent1':
297                $this->_exponent1 = $value;
298                break;
299
300            case 'exponent2':
301                $this->_exponent2 = $value;
302                break;
303
304            case 'coefficient':
305                $this->_coefficient = $value;
306                break;
307
308            //
309            // DSA - this won't work in PHP until the OpenSSL extension is better
310            //
311            case 'prime(p)':
312                $this->prime = $value;
313                break;
314
315            case 'subprime(q)':
316                $this->subprime = $value;
317                break;
318
319            case 'base(g)':
320                $this->base = $value;
321                break;
322
323            case 'private_value(x)':
324                $this->private_value = $value;
325                break;
326
327            case 'public_value(y)':
328                $this->public_value = $value;
329                break;
330
331            default:
332                throw new Net_DNS2_Exception(
333                    'unknown private key data: ' . $key . ': ' . $value,
334                    Net_DNS2_Lookups::E_OPENSSL_INV_PKEY
335                );
336            }
337        }
338
339        //
340        // generate the private key
341        //
342        $args = array();
343
344        switch($this->algorithm) {
345
346        //
347        // RSA
348        //
349        case Net_DNS2_Lookups::DNSSEC_ALGORITHM_RSAMD5:
350        case Net_DNS2_Lookups::DNSSEC_ALGORITHM_RSASHA1:
351        case Net_DNS2_Lookups::DNSSEC_ALGORITHM_RSASHA256:
352        case Net_DNS2_Lookups::DNSSEC_ALGORITHM_RSASHA512:
353
354            $args = array(
355
356                'rsa' => array(
357
358                    'n'                 => base64_decode($this->_modulus),
359                    'e'                 => base64_decode($this->_public_exponent),
360                    'd'                 => base64_decode($this->_private_exponent),
361                    'p'                 => base64_decode($this->_prime1),
362                    'q'                 => base64_decode($this->_prime2),
363                    'dmp1'              => base64_decode($this->_exponent1),
364                    'dmq1'              => base64_decode($this->_exponent2),
365                    'iqmp'              => base64_decode($this->_coefficient)
366                )
367            );
368
369            break;
370
371        //
372        // DSA - this won't work in PHP until the OpenSSL extension is better
373        //
374        case Net_DNS2_Lookups::DNSSEC_ALGORITHM_DSA:
375
376            $args = array(
377
378                'dsa' => array(
379
380                    'p'                 => base64_decode($this->prime),
381                    'q'                 => base64_decode($this->subprime),
382                    'g'                 => base64_decode($this->base),
383                    'priv_key'          => base64_decode($this->private_value),
384                    'pub_key'           => base64_decode($this->public_value)
385                )
386            );
387
388            break;
389
390        default:
391            throw new Net_DNS2_Exception(
392                'we only currently support RSAMD5 and RSASHA1 encryption.',
393                Net_DNS2_Lookups::E_OPENSSL_INV_PKEY
394            );
395        }
396
397        //
398        // generate and store the key
399        //
400        $this->instance = openssl_pkey_new($args);
401        if ($this->instance === false) {
402            throw new Net_DNS2_Exception(
403                openssl_error_string(),
404                Net_DNS2_Lookups::E_OPENSSL_ERROR
405            );
406        }
407
408        //
409        // store the filename incase we need it for something
410        //
411        $this->filename = $file;
412
413        return true;
414    }
415}
416
417/*
418 * Local variables:
419 * tab-width: 4
420 * c-basic-offset: 4
421 * c-hanging-comment-ender-p: nil
422 * End:
423 */
424?>
425