Subversion Repositories oidplus

Rev

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

  1. <?php
  2. /**
  3.  * SBrook\JWS\JwsRsa
  4.  */
  5.  
  6. namespace SBrook\JWS;
  7.  
  8. use SBrook\JWS\Exception\JwsException;
  9.  
  10. /**
  11.  * Class JwsRsa
  12.  * @package SBrook\JWS
  13.  * @throws JwsException:
  14.  *  40. Private key is not set
  15.  *  41. Public key is not set
  16.  *  49. Forwarded openssl error(s)
  17.  */
  18. class JwsRsa extends Jws implements Asymmetric
  19. {
  20.         /**
  21.          * JWS signature private key.
  22.          * @var resource
  23.          */
  24.         protected $privateKey = false;
  25.  
  26.         /**
  27.          * JWS signature public key.
  28.          * @var resource
  29.          */
  30.         protected $publicKey = false;
  31.  
  32.         /**
  33.          * Default signature algorithm.
  34.          * @var string
  35.          */
  36.         protected $defaultAlgo = "RS256";
  37.  
  38.         /**
  39.          * Signature algorithms map JWS => openssl_sign() / openssl_verify().
  40.          *
  41.          * JWS signature algorithms (RFC 7518, Section 3.3) - "alg":
  42.          *  RS256: RSASSA-PKCS1-v1_5 using SHA-256
  43.          *  RS384: RSASSA-PKCS1-v1_5 using SHA-384
  44.          *  RS512: RSASSA-PKCS1-v1_5 using SHA-512
  45.          *
  46.          * @var array
  47.          */
  48.         protected $algos = [
  49.                 "RS256" => OPENSSL_ALGO_SHA256,
  50.                 "RS384" => OPENSSL_ALGO_SHA384,
  51.                 "RS512" => OPENSSL_ALGO_SHA512
  52.         ];
  53.  
  54.         /**
  55.          * JwsRsa destructor.
  56.          */
  57.         public function __destruct()
  58.         {
  59.                 if ($this->privateKey) {
  60.                         openssl_pkey_free($this->privateKey);
  61.                 }
  62.  
  63.                 if ($this->publicKey) {
  64.                         openssl_pkey_free($this->publicKey);
  65.                 }
  66.  
  67.                 unset(
  68.                         $this->defaultAlgo,
  69.                         $this->algos
  70.                 );
  71.         }
  72.  
  73.         /**
  74.          * Set private key - overwrites previously set key.
  75.          * @param string $key - Private key. Same as openssl_pkey_get_private "key" parameter (http://php.net/manual/en/function.openssl-pkey-get-private.php).
  76.          * @param string $pass - (Optional) Private key password. Same as openssl_pkey_get_private "passphrase" parameter (http://php.net/manual/en/function.openssl-pkey-get-private.php).
  77.          * @throws JwsException
  78.          */
  79.         public function setPrivateKey($key, $pass = "") {
  80.                 if ($this->privateKey) {
  81.                         openssl_pkey_free($this->privateKey);
  82.                 }
  83.  
  84.                 $this->privateKey = openssl_pkey_get_private($key, $pass);
  85.                 if (!$this->privateKey) {
  86.                         throw new JwsException($this->getOpensslErrors(), 49);
  87.                 }
  88.         }
  89.  
  90.         /**
  91.          * Set public key - overwrites previously set key.
  92.          * @param string $key - Public key. Same as openssl_pkey_get_public "certificate" parameter (http://php.net/manual/en/function.openssl-pkey-get-public.php).
  93.          * @throws JwsException
  94.          */
  95.         public function setPublicKey($key) {
  96.                 if ($this->publicKey) {
  97.                         openssl_pkey_free($this->publicKey);
  98.                 }
  99.  
  100.                 $this->publicKey = openssl_pkey_get_public($key);
  101.                 if (!$this->publicKey) {
  102.                         throw new JwsException($this->getOpensslErrors(), 49);
  103.                 }
  104.         }
  105.  
  106.         /**
  107.          * Create JWS from payload and optional header and sign it.
  108.          * @param string $payload - Payload.
  109.          * @param array $header - (Optional) Header data.
  110.          * @return string - JWS.
  111.          * @throws JwsException
  112.          */
  113.         public function sign($payload, $header = []) {
  114.                 if ($this->privateKey) {
  115.                         $d = $this->prepareSign($this->defaultAlgo, $payload, $header);
  116.  
  117.                         $signature = null;
  118.                         $v = openssl_sign($d["h"] . "." . $d["p"], $signature, $this->privateKey, $this->algos[$d["alg"]]);
  119.                         if ($v) {
  120.                                 return $d["h"] . "." . $d["p"] . "." . base64_encode($signature);
  121.                         } else {
  122.                                 throw new JwsException($this->getOpensslErrors(), 49);
  123.                         }
  124.                 } else {
  125.                         throw new JwsException("Private key is not set", 40);
  126.                 }
  127.         }
  128.  
  129.         /**
  130.          * Verify JWS signature.
  131.          * @param string $jws - JWS.
  132.          * @return bool - TRUE on valid signature, FALSE on invalid.
  133.          * @throws JwsException
  134.          */
  135.         public function verify($jws) {
  136.                 if ($this->publicKey) {
  137.                         $d = $this->prepareVerify($jws);
  138.  
  139.                         $v = openssl_verify($d["h"] . "." . $d["p"], $d["sig"], $this->publicKey, $this->algos[$d["alg"]]);
  140.                         if ($v == 1) {
  141.                                 return true;
  142.                         } else if ($v == 0) {
  143.                                 return false;
  144.                         } else {
  145.                                 throw new JwsException($this->getOpensslErrors(), 49);
  146.                         }
  147.                 } else {
  148.                         throw new JwsException("Public key is not set", 41);
  149.                 }
  150.         }
  151.  
  152.         /**
  153.          * Check validity of signature algorithm.
  154.          * @param string $algorithm - Algorithm name.
  155.          * @return bool - TRUE on valid algorithm, FALSE on invalid.
  156.          */
  157.         protected function isValidAlgorithm(string $algorithm): bool {
  158.                 return array_key_exists(strtoupper($algorithm), $this->algos);
  159.         }
  160.  
  161.         /**
  162.          * Get openssl error queue.
  163.          * @return string - Openssl error message(s).
  164.          */
  165.         protected function getOpensslErrors() {
  166.                 $message = "OpenSSL Error(s):";
  167.  
  168.                 while ($m = openssl_error_string()) {
  169.                         $message .= " " . $m;
  170.                 }
  171.  
  172.                 return $message;
  173.         }
  174. }
  175.