public function testGenerationOfTheSigninInput() { $payload = array('a' => 'b'); $header = array('a' => 'b'); $jwt = new JWT($payload, $header); $encoder = new Base64UrlSafeEncoder(); $this->assertEquals(sprintf("%s.%s", $encoder->encode(json_encode($payload)), $encoder->encode(json_encode($header))), $jwt->generateSigninInput()); }
public function testGenerationOfTheSigninInputCanHandleSlashes() { $encoder = new Base64UrlSafeEncoder(); $json_string = '{"a":"/b/"}'; $encoded_json_string = $encoder->encode($json_string); $jwt = new JWT(json_decode($json_string, true), json_decode($json_string, true)); $this->assertEquals(sprintf('%s.%s', $encoded_json_string, $encoded_json_string), $jwt->generateSigninInput()); }
/** * Generates the payload which must be provided in challenges, e.g. HTTP-01 and DNS-01. * * @api * @param KeyPair $accountKeyPair account key pair * @param string $token challenge token * @return string payload to be provided at /.well-known/acme-challenge/$token for HTTP-01 and _acme-challenge.example.com for DNS-01 * @throws AcmeException If something went wrong. * @see https://github.com/ietf-wg-acme/acme/blob/master/draft-ietf-acme-acme.md#key-authorizations */ function generateKeyAuthorization(KeyPair $accountKeyPair, $token) { if (!is_string($token)) { throw new InvalidArgumentException(sprintf("\$token must be of type string, %s given.", gettype($token))); } if (!($privateKey = openssl_pkey_get_private($accountKeyPair->getPrivate()))) { throw new AcmeException("Couldn't read private key."); } if (!($details = openssl_pkey_get_details($privateKey))) { throw new AcmeException("Couldn't get private key details."); } if ($details["type"] !== OPENSSL_KEYTYPE_RSA) { throw new AcmeException("Key type not supported, only RSA supported currently."); } $enc = new Base64UrlSafeEncoder(); $payload = ["e" => $enc->encode($details["rsa"]["e"]), "kty" => "RSA", "n" => $enc->encode($details["rsa"]["n"])]; return $token . "." . $enc->encode(hash("sha256", json_encode($payload), true)); }
private function doPost(string $resource, array $payload) : Generator { $privateKey = openssl_pkey_get_private($this->keyPair->getPrivate()); $details = openssl_pkey_get_details($privateKey); if ($details["type"] !== OPENSSL_KEYTYPE_RSA) { throw new \RuntimeException("Only RSA keys are supported right now."); } $uri = (yield $this->getResourceUri($resource)); $enc = new Base64UrlSafeEncoder(); $jws = new SimpleJWS(["alg" => "RS256", "jwk" => ["kty" => "RSA", "n" => $enc->encode($details["rsa"]["n"]), "e" => $enc->encode($details["rsa"]["e"])], "nonce" => (yield $this->getNonce($uri))]); $payload["resource"] = $payload["resource"] ?? $resource; $jws->setPayload($payload); $jws->sign($privateKey); $request = (new Request())->setMethod("POST")->setUri($uri)->setBody($jws->getTokenString()); $response = (yield $this->http->request($request)); $this->saveNonce($response); return $response; }
public function generateHttp01Payload(string $token) : string { if (!($privateKey = openssl_pkey_get_private($this->accountKeyPair->getPrivate()))) { throw new AcmeException("Couldn't read private key"); } if (!($details = openssl_pkey_get_details($privateKey))) { throw new AcmeException("Couldn't get private key details"); } if ($details["type"] !== OPENSSL_KEYTYPE_RSA) { throw new AcmeException("Key type not supported, only RSA supported currently"); } $enc = new Base64UrlSafeEncoder(); $payload = ["e" => $enc->encode($details["rsa"]["e"]), "kty" => "RSA", "n" => $enc->encode($details["rsa"]["n"])]; return $token . "." . $enc->encode(hash("sha256", json_encode($payload), true)); }
/** * Encodes a key authorization for use in the DNS-01 challenge as TXT payload. * * @api * @param string $keyAuthorization key authorization generated using `generateKeyAuthorization` * @return string Base64Url-encoded SHA256 digest of the `$keyAuthorization` * @see https://tools.ietf.org/html/draft-ietf-acme-acme-01#section-7.5 */ function generateDns01Payload($keyAuthorization) { $encoder = new Base64UrlSafeEncoder(); return $encoder->encode(hash("sha256", $keyAuthorization, true)); }
private function doPost($resource, array $payload) { if (!is_string($resource)) { throw new InvalidArgumentException(sprintf("\$resource must be of type string, %s given.", gettype($resource))); } $privateKey = openssl_pkey_get_private($this->keyPair->getPrivate()); $details = openssl_pkey_get_details($privateKey); if ($details["type"] !== OPENSSL_KEYTYPE_RSA) { throw new \RuntimeException("Only RSA keys are supported right now."); } $uri = (yield $this->getResourceUri($resource)); $atempt = 0; do { $attempt++; if ($attempt > 3) { throw new AcmeException("POST request to {$uri} failed, received too many badNonce errors."); } $enc = new Base64UrlSafeEncoder(); $jws = new SimpleJWS(["alg" => "RS256", "jwk" => ["kty" => "RSA", "n" => $enc->encode($details["rsa"]["n"]), "e" => $enc->encode($details["rsa"]["e"])], "nonce" => (yield $this->getNonce($uri))]); $payload["resource"] = isset($payload["resource"]) ? $payload["resource"] : $resource; $jws->setPayload($payload); $jws->sign($privateKey); $request = (new Request())->setMethod("POST")->setUri($uri)->setBody($jws->getTokenString()); try { $response = (yield $this->http->request($request)); $this->saveNonce($response); if ($response->getStatus() === 400) { $info = json_decode($response->getBody()); if ($info && isset($info->type) && $info->type === "urn:acme:badNonce") { continue; } } } catch (Exception $e) { throw new AcmeException("POST request to {$uri} failed.", null, $e); } catch (Throwable $e) { throw new AcmeException("POST request to {$uri} failed.", null, $e); } (yield new CoroutineResult($response)); return; } while (true); }
/** * Revokes a certificate. * * @param string $pem PEM encoded certificate * @return \Generator coroutine resolved by Amp returning true * @throws AcmeException If something went wrong. */ private function doRevokeCertificate($pem) { if (!is_string($pem)) { throw new InvalidArgumentException(sprintf("\$pem must be of type string, %s given.", gettype($pem))); } $begin = "CERTIFICATE-----"; $end = "----END"; $pem = substr($pem, strpos($pem, $begin) + strlen($begin)); $pem = substr($pem, 0, strpos($pem, $end)); $enc = new Base64UrlSafeEncoder(); /** @var Response $response */ $response = (yield $this->acmeClient->post(AcmeResource::REVOKE_CERTIFICATE, ["certificate" => $enc->encode(base64_decode($pem))])); if ($response->getStatus() === 200) { (yield new CoroutineResult(true)); return; } throw $this->generateException($response); }