Subversion Repositories oidplus

Rev

Rev 868 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
868 daniel-mar 1
<?php
2
 
3
/*
4
 * OIDplus 2.0
5
 * Copyright 2019 - 2022 Daniel Marschall, ViaThinkSoft
6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 */
19
 
20
// Works with composer.json
21
// "robrichards/xmlseclibs": "^3.1"
22
// or
23
// "selective/xmldsig": "^2.4"
24
 
1130 daniel-mar 25
/**
26
 * @param string $xml_content
27
 * @param string $pubkey
28
 * @return void
29
 * @throws Exception
30
 */
31
function oidplus_xml_verify(string $xml_content, string $pubkey) {
868 daniel-mar 32
        require_once __DIR__.'/vendor/autoload.php';
33
 
34
        $sig_ok = false;
35
        if (class_exists('\RobRichards\XMLSecLibs\XMLSecurityDSig')) {
36
                // Template: https://github.com/robrichards/xmlseclibs/blob/master/tests/xmlsec-verify.phpt
37
 
38
                $doc = new DOMDocument();
39
                $doc->loadXML($xml_content);
40
 
41
                $objXMLSecDSig = new \RobRichards\XMLSecLibs\XMLSecurityDSig();
42
 
43
                $objDSig = $objXMLSecDSig->locateSignature($doc);
44
                if (! $objDSig) {
45
                        throw new Exception("Cannot locate Signature Node");
46
                }
47
                $objXMLSecDSig->canonicalizeSignedInfo();
48
                $objXMLSecDSig->idKeys = array('wsu:Id');
49
                $objXMLSecDSig->idNS = array('wsu'=>'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd');
50
 
51
                $retVal = $objXMLSecDSig->validateReference();
52
                if (! $retVal) {
53
                        throw new Exception("Reference Validation Failed");
54
                }
55
 
56
                $objKey = $objXMLSecDSig->locateKey();
57
                if (! $objKey ) {
58
                        throw new Exception("We have no idea about the key");
59
                }
60
                /*
61
                $key = NULL;
62
 
63
                $objKeyInfo = \RobRichards\XMLSecLibs\XMLSecEnc::staticLocateKeyInfo($objKey, $objDSig);
64
                if (! $objKeyInfo->key && empty($key)) {
65
                        $objKey->loadKey($pubkey, false);
66
                }
67
                */
68
                $objKey->loadKey($pubkey, /*isfile*/false);
69
 
70
                $sig_ok = $objXMLSecDSig->verify($objKey) === 1;
71
        } else if (class_exists("\Selective\XmlDSig\XmlSignatureValidator")) {
72
                $signatureValidator = new \Selective\XmlDSig\XmlSignatureValidator();
73
                $signatureValidator->loadPublicKey($pubkey);
74
                $sig_ok = $signatureValidator->verifyXml($xml_content);
75
        } else {
76
                assert(false);
77
        }
78
 
79
        if (!$sig_ok) {
80
                throw new Exception("Signature verification failed!");
81
        }
82
}
83
 
1130 daniel-mar 84
/**
85
 * @param string $xml_content
86
 * @param string $privkey
87
 * @param string $pubkey
88
 * @return false|string|void
89
 * @throws Exception
90
 */
91
function oidplus_xml_sign(string $xml_content, string $privkey, string $pubkey) {
868 daniel-mar 92
        require_once __DIR__.'/vendor/autoload.php';
93
 
94
        if (class_exists('\RobRichards\XMLSecLibs\XMLSecurityDSig')) {
95
                // Template: https://github.com/robrichards/xmlseclibs/blob/master/README.md
96
 
97
                // Load the XML to be signed
98
                $doc = new DOMDocument();
99
                $doc->loadXML($xml_content);
100
 
101
                // Create a new Security object
102
                $objDSig = new \RobRichards\XMLSecLibs\XMLSecurityDSig();
103
                // Use the c14n exclusive canonicalization
104
                $objDSig->setCanonicalMethod(\RobRichards\XMLSecLibs\XMLSecurityDSig::EXC_C14N);
105
                // Sign using SHA-512
106
                $objDSig->addReference(
107
                    $doc,
108
                    \RobRichards\XMLSecLibs\XMLSecurityDSig::SHA512,
109
                    array('http://www.w3.org/2000/09/xmldsig#enveloped-signature')
110
                );
111
 
112
                // Create a new (private) Security key
113
                $objKey = new \RobRichards\XMLSecLibs\XMLSecurityKey(\RobRichards\XMLSecLibs\XMLSecurityKey::RSA_SHA512, array('type'=>'private'));
114
                /*
115
                If key has a passphrase, set it using
116
                $objKey->passphrase = '<passphrase>';
117
                */
118
                // Load the private key
119
                $objKey->loadKey($privkey, /*isfile*/false);
120
 
121
                // Sign the XML file
122
                $objDSig->sign($objKey);
123
 
124
                // TODO: Selective\XmlDSig has "KeyInfo" with RSAKeyValue (showing Modulus and Exponent)
125
                //       while RobRichards\XMLSecLibs has no "KeyInfo".
126
                //       We can't use $objDSig->add509Cert, because we have no X.509 certificate, just pubkey and privkey...
127
 
128
                // Append the signature to the XML
129
                $objDSig->appendSignature($doc->documentElement);
130
 
131
                // Save the signed XML
132
                $xml_signed = $doc->saveXML();
133
        } else if (class_exists("\Selective\XmlDSig\XmlSigner")) {
134
                $xmlSigner = new \Selective\XmlDSig\XmlSigner();
135
                $xmlSigner->loadPrivateKey($privkey, '');
136
                $xmlSigner->setReferenceUri(''); // Optional: Set reference URI (TODO?)
137
 
138
                /* @phpstan-ignore-next-line */
139
                $xml_signed = $xmlSigner->signXml($xml_content, \Selective\XmlDSig\DigestAlgorithmType::SHA512);
140
        } else {
141
                assert(false);
142
                return false;
143
        }
144
 
145
        oidplus_xml_verify($xml_signed, $pubkey);
146
        return $xml_signed;
147
}