~chroot64bit/zivios/gentoo-experimental

« back to all changes in this revision

Viewing changes to application/library/Zend/InfoCard/Xml/Security.php

  • Committer: Mustafa A. Hashmi
  • Date: 2008-12-04 13:32:21 UTC
  • Revision ID: mhashmi@zivios.org-20081204133221-0nd1trunwevijj38
Inclusion of new installation framework with ties to zend layout and dojo layout

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<?php
 
2
/**
 
3
 * Zend Framework
 
4
 *
 
5
 * LICENSE
 
6
 *
 
7
 * This source file is subject to the new BSD license that is bundled
 
8
 * with this package in the file LICENSE.txt.
 
9
 * It is also available through the world-wide-web at this URL:
 
10
 * http://framework.zend.com/license/new-bsd
 
11
 * If you did not receive a copy of the license and are unable to
 
12
 * obtain it through the world-wide-web, please send an email
 
13
 * to license@zend.com so we can send you a copy immediately.
 
14
 *
 
15
 * @category   Zend
 
16
 * @package    Zend_InfoCard
 
17
 * @subpackage Zend_InfoCard_Xml_Security
 
18
 * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
 
19
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 
20
 * @version    $Id: Security.php 9094 2008-03-30 18:36:55Z thomas $
 
21
 */
 
22
 
 
23
/**
 
24
 * Zend_InfoCard_Xml_Security_Exception
 
25
 */
 
26
require_once 'Zend/InfoCard/Xml/Security/Exception.php';
 
27
 
 
28
/**
 
29
 * Zend_InfoCard_Xml_Security_Transform
 
30
 */
 
31
require_once 'Zend/InfoCard/Xml/Security/Transform.php';
 
32
 
 
33
/**
 
34
 *
 
35
 * @category   Zend
 
36
 * @package    Zend_InfoCard
 
37
 * @subpackage Zend_InfoCard_Xml_Security
 
38
 * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
 
39
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 
40
 */
 
41
class Zend_InfoCard_Xml_Security
 
42
{
 
43
    /**
 
44
     * ASN.1 type INTEGER class
 
45
     */
 
46
    const ASN_TYPE_INTEGER = 0x02;
 
47
 
 
48
    /**
 
49
     * ASN.1 type BIT STRING class
 
50
     */
 
51
    const ASN_TYPE_BITSTRING = 0x03;
 
52
 
 
53
    /**
 
54
     * ASN.1 type SEQUENCE class
 
55
     */
 
56
    const ASN_TYPE_SEQUENCE = 0x30;
 
57
 
 
58
    /**
 
59
     * The URI for Canonical Method C14N Exclusive
 
60
     */
 
61
    const CANONICAL_METHOD_C14N_EXC = 'http://www.w3.org/2001/10/xml-exc-c14n#';
 
62
 
 
63
    /**
 
64
     * The URI for Signature Method SHA1
 
65
     */
 
66
    const SIGNATURE_METHOD_SHA1 = 'http://www.w3.org/2000/09/xmldsig#rsa-sha1';
 
67
 
 
68
    /**
 
69
     * The URI for Digest Method SHA1
 
70
     */
 
71
    const DIGEST_METHOD_SHA1 = 'http://www.w3.org/2000/09/xmldsig#sha1';
 
72
 
 
73
    /**
 
74
     * The Identifier for RSA Keys
 
75
     */
 
76
    const RSA_KEY_IDENTIFIER = '300D06092A864886F70D0101010500';
 
77
 
 
78
    /**
 
79
     * Constructor  (disabled)
 
80
     *
 
81
     * @return void
 
82
     */
 
83
    private function __construct()
 
84
    {
 
85
    }
 
86
 
 
87
    /**
 
88
     * Validates the signature of a provided XML block
 
89
     *
 
90
     * @param  string $strXMLInput An XML block containing a Signature
 
91
     * @return bool True if the signature validated, false otherwise
 
92
     * @throws Zend_InfoCard_Xml_Security_Exception
 
93
     */
 
94
    static public function validateXMLSignature($strXMLInput)
 
95
    {
 
96
        if(!extension_loaded('openssl')) {
 
97
            throw new Zend_InfoCard_Xml_Security_Exception("You must have the openssl extension installed to use this class");
 
98
        }
 
99
 
 
100
        $sxe = simplexml_load_string($strXMLInput);
 
101
 
 
102
        if(!isset($sxe->Signature)) {
 
103
            throw new Zend_InfoCard_Xml_Security_Exception("Could not identify XML Signature element");
 
104
        }
 
105
 
 
106
        if(!isset($sxe->Signature->SignedInfo)) {
 
107
            throw new Zend_InfoCard_Xml_Security_Exception("Signature is missing a SignedInfo block");
 
108
        }
 
109
 
 
110
        if(!isset($sxe->Signature->SignatureValue)) {
 
111
            throw new Zend_InfoCard_Xml_Security_Exception("Signature is missing a SignatureValue block");
 
112
        }
 
113
 
 
114
        if(!isset($sxe->Signature->KeyInfo)) {
 
115
            throw new Zend_InfoCard_Xml_Security_Exception("Signature is missing a KeyInfo block");
 
116
        }
 
117
 
 
118
        if(!isset($sxe->Signature->KeyInfo->KeyValue)) {
 
119
            throw new Zend_InfoCard_Xml_Security_Exception("Signature is missing a KeyValue block");
 
120
        }
 
121
 
 
122
        switch((string)$sxe->Signature->SignedInfo->CanonicalizationMethod['Algorithm']) {
 
123
            case self::CANONICAL_METHOD_C14N_EXC:
 
124
                $cMethod = (string)$sxe->Signature->SignedInfo->CanonicalizationMethod['Algorithm'];
 
125
                break;
 
126
            default:
 
127
                throw new Zend_InfoCard_Xml_Security_Exception("Unknown or unsupported CanonicalizationMethod Requested");
 
128
        }
 
129
 
 
130
        switch((string)$sxe->Signature->SignedInfo->SignatureMethod['Algorithm']) {
 
131
            case self::SIGNATURE_METHOD_SHA1:
 
132
                $sMethod = (string)$sxe->Signature->SignedInfo->SignatureMethod['Algorithm'];
 
133
                break;
 
134
            default:
 
135
                throw new Zend_InfoCard_Xml_Security_Exception("Unknown or unsupported SignatureMethod Requested");
 
136
        }
 
137
 
 
138
        switch((string)$sxe->Signature->SignedInfo->Reference->DigestMethod['Algorithm']) {
 
139
            case self::DIGEST_METHOD_SHA1:
 
140
                $dMethod = (string)$sxe->Signature->SignedInfo->Reference->DigestMethod['Algorithm'];
 
141
                break;
 
142
            default:
 
143
                throw new Zend_InfoCard_Xml_Security_Exception("Unknown or unsupported DigestMethod Requested");
 
144
        }
 
145
 
 
146
        $base64DecodeSupportsStrictParam = version_compare(PHP_VERSION, '5.2.0', '>=');
 
147
 
 
148
        if ($base64DecodeSupportsStrictParam) {
 
149
            $dValue = base64_decode((string)$sxe->Signature->SignedInfo->Reference->DigestValue, true);
 
150
        } else {
 
151
            $dValue = base64_decode((string)$sxe->Signature->SignedInfo->Reference->DigestValue);
 
152
        }
 
153
 
 
154
        if ($base64DecodeSupportsStrictParam) {
 
155
            $signatureValue = base64_decode((string)$sxe->Signature->SignatureValue, true);
 
156
        } else {
 
157
            $signatureValue = base64_decode((string)$sxe->Signature->SignatureValue);
 
158
        }
 
159
 
 
160
        $transformer = new Zend_InfoCard_Xml_Security_Transform();
 
161
 
 
162
        foreach($sxe->Signature->SignedInfo->Reference->Transforms->children() as $transform) {
 
163
            $transformer->addTransform((string)$transform['Algorithm']);
 
164
        }
 
165
 
 
166
        $transformed_xml = $transformer->applyTransforms($strXMLInput);
 
167
 
 
168
        $transformed_xml_binhash = pack("H*", sha1($transformed_xml));
 
169
 
 
170
        if($transformed_xml_binhash != $dValue) {
 
171
            throw new Zend_InfoCard_Xml_Security_Exception("Locally Transformed XML does not match XML Document. Cannot Verify Signature");
 
172
        }
 
173
 
 
174
        $public_key = null;
 
175
 
 
176
        switch(true) {
 
177
            case isset($sxe->Signature->KeyInfo->KeyValue->X509Certificate):
 
178
 
 
179
                $certificate = (string)$sxe->Signature->KeyInfo->KeyValue->X509Certificate;
 
180
 
 
181
 
 
182
                $pem = "-----BEGIN CERTIFICATE-----\n" .
 
183
                       wordwrap($certificate, 64, "\n", true) .
 
184
                       "\n-----END CERTIFICATE-----";
 
185
 
 
186
                $public_key = openssl_pkey_get_public($pem);
 
187
 
 
188
                if(!$public_key) {
 
189
                    throw new Zend_InfoCard_Xml_Security_Exception("Unable to extract and prcoess X509 Certificate from KeyValue");
 
190
                }
 
191
 
 
192
                break;
 
193
            case isset($sxe->Signature->KeyInfo->KeyValue->RSAKeyValue):
 
194
 
 
195
                if(!isset($sxe->Signature->KeyInfo->KeyValue->RSAKeyValue->Modulus) ||
 
196
                   !isset($sxe->Signature->KeyInfo->KeyValue->RSAKeyValue->Exponent)) {
 
197
                    throw new Zend_InfoCard_Xml_Security_Exception("RSA Key Value not in Modulus/Exponent form");
 
198
                }
 
199
 
 
200
                $modulus = base64_decode((string)$sxe->Signature->KeyInfo->KeyValue->RSAKeyValue->Modulus);
 
201
                $exponent = base64_decode((string)$sxe->Signature->KeyInfo->KeyValue->RSAKeyValue->Exponent);
 
202
 
 
203
                $pem_public_key = self::_getPublicKeyFromModExp($modulus, $exponent);
 
204
 
 
205
                $public_key = openssl_pkey_get_public ($pem_public_key);
 
206
 
 
207
                break;
 
208
            default:
 
209
                throw new Zend_InfoCard_Xml_Security_Exception("Unable to determine or unsupported representation of the KeyValue block");
 
210
        }
 
211
 
 
212
        $transformer = new Zend_InfoCard_Xml_Security_Transform();
 
213
        $transformer->addTransform((string)$sxe->Signature->SignedInfo->CanonicalizationMethod['Algorithm']);
 
214
 
 
215
        // The way we are doing our XML processing requires that we specifically add this
 
216
        // (even though it's in the <Signature> parent-block).. otherwise, our canonical form
 
217
        // fails signature verification
 
218
        $sxe->Signature->SignedInfo->addAttribute('xmlns', 'http://www.w3.org/2000/09/xmldsig#');
 
219
 
 
220
        $canonical_signedinfo = $transformer->applyTransforms($sxe->Signature->SignedInfo->asXML());
 
221
 
 
222
        if(@openssl_verify($canonical_signedinfo, $signatureValue, $public_key)) {
 
223
            return (string)$sxe->Signature->SignedInfo->Reference['URI'];
 
224
        }
 
225
 
 
226
        return false;
 
227
    }
 
228
 
 
229
    /**
 
230
     * Transform an RSA Key in Modulus/Exponent format into a PEM encoding and
 
231
     * return an openssl resource for it
 
232
     *
 
233
     * @param string $modulus The RSA Modulus in binary format
 
234
     * @param string $exponent The RSA exponent in binary format
 
235
     * @return string The PEM encoded version of the key
 
236
     */
 
237
    static protected function _getPublicKeyFromModExp($modulus, $exponent)
 
238
    {
 
239
        $modulusInteger  = self::_encodeValue($modulus, self::ASN_TYPE_INTEGER);
 
240
        $exponentInteger = self::_encodeValue($exponent, self::ASN_TYPE_INTEGER);
 
241
        $modExpSequence  = self::_encodeValue($modulusInteger . $exponentInteger, self::ASN_TYPE_SEQUENCE);
 
242
        $modExpBitString = self::_encodeValue($modExpSequence, self::ASN_TYPE_BITSTRING);
 
243
 
 
244
        $binRsaKeyIdentifier = pack( "H*", self::RSA_KEY_IDENTIFIER );
 
245
 
 
246
        $publicKeySequence = self::_encodeValue($binRsaKeyIdentifier . $modExpBitString, self::ASN_TYPE_SEQUENCE);
 
247
 
 
248
        $publicKeyInfoBase64 = base64_encode( $publicKeySequence );
 
249
 
 
250
        $publicKeyString = "-----BEGIN PUBLIC KEY-----\n";
 
251
        $publicKeyString .= wordwrap($publicKeyInfoBase64, 64, "\n", true);
 
252
        $publicKeyString .= "\n-----END PUBLIC KEY-----\n";
 
253
 
 
254
        return $publicKeyString;
 
255
    }
 
256
 
 
257
    /**
 
258
     * Encode a limited set of data types into ASN.1 encoding format
 
259
     * which is used in X.509 certificates
 
260
     *
 
261
     * @param string $data The data to encode
 
262
     * @param const $type The encoding format constant
 
263
     * @return string The encoded value
 
264
     * @throws Zend_InfoCard_Xml_Security_Exception
 
265
     */
 
266
    static protected function _encodeValue($data, $type)
 
267
    {
 
268
        // Null pad some data when we get it (integer values > 128 and bitstrings)
 
269
        if( (($type == self::ASN_TYPE_INTEGER) && (ord($data) > 0x7f)) ||
 
270
            ($type == self::ASN_TYPE_BITSTRING)) {
 
271
                $data = "\0$data";
 
272
        }
 
273
 
 
274
        $len = strlen($data);
 
275
 
 
276
        // encode the value based on length of the string
 
277
        // I'm fairly confident that this is by no means a complete implementation
 
278
        // but it is enough for our purposes
 
279
        switch(true) {
 
280
            case ($len < 128):
 
281
                return sprintf("%c%c%s", $type, $len, $data);
 
282
            case ($len < 0x0100):
 
283
                return sprintf("%c%c%c%s", $type, 0x81, $len, $data);
 
284
            case ($len < 0x010000):
 
285
                return sprintf("%c%c%c%c%s", $type, 0x82, $len / 0x0100, $len % 0x0100, $data);
 
286
            default:
 
287
                throw new Zend_InfoCard_Xml_Security_Exception("Could not encode value");
 
288
        }
 
289
 
 
290
        throw new Zend_InfoCard_Xml_Security_Exception("Invalid code path");
 
291
    }
 
292
}
 
 
b'\\ No newline at end of file'