Signer.php 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. <?php
  2. namespace Aws\CloudFront;
  3. /**
  4. * @internal
  5. */
  6. class Signer
  7. {
  8. private $keyPairId;
  9. private $pk;
  10. /**
  11. * A signer for creating the signature values used in CloudFront signed URLs
  12. * and signed cookies.
  13. *
  14. * @param $keyPairId string ID of the key pair
  15. * @param $privateKey string Path to the private key used for signing
  16. *
  17. * @throws \RuntimeException if the openssl extension is missing
  18. * @throws \InvalidArgumentException if the private key cannot be found.
  19. */
  20. public function __construct($keyPairId, $privateKey)
  21. {
  22. if (!extension_loaded('openssl')) {
  23. //@codeCoverageIgnoreStart
  24. throw new \RuntimeException('The openssl extension is required to '
  25. . 'sign CloudFront urls.');
  26. //@codeCoverageIgnoreEnd
  27. }
  28. $this->keyPairId = $keyPairId;
  29. if (!file_exists($privateKey)) {
  30. throw new \InvalidArgumentException("PK file not found: $privateKey");
  31. }
  32. $this->pk = file_get_contents($privateKey);
  33. }
  34. /**
  35. * Create the values used to construct signed URLs and cookies.
  36. *
  37. * @param string $resource The CloudFront resource to which
  38. * this signature will grant access.
  39. * Not used when a custom policy is
  40. * provided.
  41. * @param string|integer|null $expires UTC Unix timestamp used when
  42. * signing with a canned policy.
  43. * Not required when passing a
  44. * custom $policy.
  45. * @param string $policy JSON policy. Use this option when
  46. * creating a signature for a custom
  47. * policy.
  48. *
  49. * @return array The values needed to construct a signed URL or cookie
  50. * @throws \InvalidArgumentException when not provided either a policy or a
  51. * resource and a expires
  52. *
  53. * @link http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-signed-cookies.html
  54. */
  55. public function getSignature($resource = null, $expires = null, $policy = null)
  56. {
  57. $signatureHash = [];
  58. if ($policy) {
  59. $policy = preg_replace('/\s/s', '', $policy);
  60. $signatureHash['Policy'] = $this->encode($policy);
  61. } elseif ($resource && $expires) {
  62. $policy = $this->createCannedPolicy($resource, $expires);
  63. $signatureHash['Expires'] = $expires;
  64. } else {
  65. throw new \InvalidArgumentException('Either a policy or a resource'
  66. . ' and an expiration time must be provided.');
  67. }
  68. $signatureHash['Signature'] = $this->encode($this->sign($policy));
  69. $signatureHash['Key-Pair-Id'] = $this->keyPairId;
  70. return $signatureHash;
  71. }
  72. private function createCannedPolicy($resource, $expiration)
  73. {
  74. return json_encode([
  75. 'Statement' => [
  76. [
  77. 'Resource' => $resource,
  78. 'Condition' => [
  79. 'DateLessThan' => ['AWS:EpochTime' => $expiration],
  80. ],
  81. ],
  82. ],
  83. ], JSON_UNESCAPED_SLASHES);
  84. }
  85. private function sign($policy)
  86. {
  87. $signature = '';
  88. openssl_sign($policy, $signature, $this->pk);
  89. return $signature;
  90. }
  91. private function encode($policy)
  92. {
  93. return strtr(base64_encode($policy), '+=/', '-_~');
  94. }
  95. }