Subversion Repositories oidplus

Rev

Rev 1130 | Rev 1162 | 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
// "sergeybrook/php-jws": "^1.0"
22
 
1130 daniel-mar 23
/**
24
 * @param string $json_content
25
 * @param string $pubkey
26
 * @return void
27
 * @throws Exception
28
 */
29
function oidplus_json_verify(string $json_content, string $pubkey) {
868 daniel-mar 30
        require_once __DIR__.'/vendor/autoload.php';
31
 
32
        $jws = new \SBrook\JWS\JwsRsa();
33
 
34
        // Load JSON
35
        $json = json_decode($json_content);
36
 
37
        // 1. Extract the contents of the "signature" key from the JSON.
38
        $signature = $json->signature;
39
 
40
        // 2. Remove the "signature" key from the JSON
41
        unset($json->signature);
42
 
43
        // 3. Canonize the JSON contents using RFC 8785
44
        $canonicalization = \aywan\JsonCanonicalization\JsonCanonicalizationFactory::getInstance();
45
        $canonical = $canonicalization->canonicalize($json);
46
        $actual_payload = $canonical;
47
 
48
        // 4. Compare the canonized JSON to the base64-encoded payload of the JSON Web Signature.
49
        $expected_payload = $jws->getPayload($signature);
50
        if ($actual_payload != $expected_payload) {
51
                // echo "Actual:\n\n$actual_payload\n\n";
52
                // echo "Expected:\n\n$expected_payload\n\n";
53
                throw new Exception("Signature verification failed (Payload different)");
54
        }
55
 
56
        // 5. Verify the JSON Web Signature according to RFC 7515
57
        $jws->setPublicKey($pubkey);
58
        $v = $jws->verify($signature);
59
        if (!$v) {
60
                throw new Exception("Signature verification failed!");
61
        }
62
}
63
 
1130 daniel-mar 64
/**
65
 * @param string $json_content
66
 * @param string $privkey
67
 * @param string $pubkey
1143 daniel-mar 68
 * @return string
1130 daniel-mar 69
 * @throws Exception
70
 */
71
function oidplus_json_sign(string $json_content, string $privkey, string $pubkey) {
868 daniel-mar 72
        require_once __DIR__.'/vendor/autoload.php';
73
 
74
        $jws = new \SBrook\JWS\JwsRsa();
75
 
76
        // Load JSON
77
        $input = json_decode($json_content);
78
 
79
        // 1. Make sure that the JSON file has no signature (remove "signature" key if one exists).
80
        unset($input->signature);
81
 
82
        // 2. Canonize the JSON contents using RFC 8785
83
        $canonicalization = \aywan\JsonCanonicalization\JsonCanonicalizationFactory::getInstance();
84
        $canonical = $canonicalization->canonicalize($input);
85
 
86
        // 3. Sign the canonized JSON using a JSON Web Signature (JWS, RFC 7515)
87
 
88
        // For JWS registered header parameter names see (RFC 7515, Section 4.1)
871 daniel-mar 89
        // Note that the required "alg" argument will be added automatically
868 daniel-mar 90
        $header = [
871 daniel-mar 91
                "typ" => "OID-IP", // optional (unused)
92
                "cty" => "text/json" // optional
868 daniel-mar 93
        ];
94
        $payload = $canonical;
95
        $jws->setPrivateKey($privkey, '');
96
        $signature = $jws->sign($payload, $header);
97
 
98
        // 4. Add the key "signature" into the final JSON. Note that the final JSON does not need to be canonized. It can be pretty-printed.
99
        $output = $input;
100
        $output->signature = $signature;
101
 
102
        // Self-test and output
103
        $json_signed = json_encode($output);
1143 daniel-mar 104
        if (!$json_signed) throw new Exception("JSON Encoding failed");
868 daniel-mar 105
        oidplus_json_verify($json_signed, $pubkey);
106
        return $json_signed;
107
}