Subversion Repositories oidplus

Rev

Rev 1130 | Rev 1162 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  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.  
  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) {
  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.  
  64. /**
  65.  * @param string $json_content
  66.  * @param string $privkey
  67.  * @param string $pubkey
  68.  * @return string
  69.  * @throws Exception
  70.  */
  71. function oidplus_json_sign(string $json_content, string $privkey, string $pubkey) {
  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)
  89.         // Note that the required "alg" argument will be added automatically
  90.         $header = [
  91.                 "typ" => "OID-IP", // optional (unused)
  92.                 "cty" => "text/json" // optional
  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);
  104.         if (!$json_signed) throw new Exception("JSON Encoding failed");
  105.         oidplus_json_verify($json_signed, $pubkey);
  106.         return $json_signed;
  107. }
  108.