/** * @param PaymentRequestBuf $request * @return bool */ public function checkAgainstRequest(PaymentRequestBuf $request) { $details = new PaymentDetailsBuf(); $details->parse($request->getSerializedPaymentDetails()); $outputs = $details->getOutputsList(); $requirements = []; foreach ($outputs as $out) { if (array_key_exists($out->getScript(), $requirements)) { $requirements[$out->getScript()] += $out->getAmount(); } else { $requirements[$out->getScript()] = $out->getAmount(); } } $parsed = []; // Check that regardless of the other outputs, that each specific output was paid. foreach ($this->getTransactions() as $tx) { foreach ($tx->getOutputs() as $output) { $scriptBin = $output->getScript()->getBinary(); if (array_key_exists($scriptBin, $parsed)) { $parsed[$scriptBin] += $output->getValue(); } else { $parsed[$scriptBin] = $output->getValue(); } } } foreach ($requirements as $script => $value) { if (!array_key_exists($script, $parsed)) { return false; } if ($parsed[$script] < $value) { return false; } } return true; }
/** * @return PaymentRequestBuf * @throws \Exception */ public function getPaymentRequest() { // Serialize the payment details, and apply a signature based on instance of PaymentRequestSigner $this->request->setSerializedPaymentDetails($this->details->serialize()); if (!$this->request->hasSignature()) { $this->request = $this->signer->apply($this->request); } return $this->request; }
/** * @return bool */ public function verifySignature() { if ($this->request->getPkiType() === 'none') { return true; } $algorithm = $this->request->getPkiType() === 'x509+sha256' ? OPENSSL_ALGO_SHA256 : OPENSSL_ALGO_SHA1; $signature = $this->request->getSignature(); $clone = clone $this->request; $clone->setSignature(''); $data = $clone->serialize(); // Parse the public key $certificates = new X509CertificatesBuf(); $certificates->parse($clone->getPkiData()); $certificate = $this->der2pem($certificates->getCertificate(0)); $pubkeyid = openssl_pkey_get_public($certificate); return 1 === openssl_verify($data, $signature, $pubkeyid, $algorithm); }
/** * @param PaymentRequestBuf $request * @return bool */ public function checkAgainstRequest(PaymentRequestBuf $request) { $details = new PaymentDetailsBuf(); $details->parse($request->getSerializedPaymentDetails()); $outputs = $details->getOutputsList(); $nOutputs = count($outputs); $found = 0; // Check that regardless of the other outputs, that each specific output was paid. foreach ($this->getTransactions()->getTransactions() as $tx) { foreach ($tx->getOutputs()->getOutputs() as $txOut) { foreach (array_keys($outputs) as $index) { // Check the scripts/amounts match if ($txOut->getScript()->getBinary() == $outputs[$index]->getScript() && $txOut->getValue() == $outputs[$index]->getAmount()) { unset($outputs[$index]); if (++$found == $nOutputs) { return true; } } } } } return false; }
/** * @param PaymentRequestBuf $request * @return PaymentRequestBuf * @throws \Exception */ public function apply(PaymentRequestBuf $request) { $request->setPkiType($this->type); $request->setSignature(''); if ($this->type !== 'none') { $request->setPkiData($this->certificates->serialize()); $data = $request->serialize(); $signature = ''; $result = openssl_sign($data, $signature, $this->privateKey, $this->algoConst); if ($signature === false || $result === false) { throw new \Exception('Error during signing: Unable to create signature'); } $request->setSignature($signature); } return $request; }
/** * Applies the configured signature algorithm, adding values to * the protobuf: 'pkiType', 'signature', 'pkiData' * * @param PaymentRequestBuf $request * @return PaymentRequestBuf * @throws \Exception */ public function apply(PaymentRequestBuf $request) { $request->setPkiType($this->type); $request->setSignature(''); if ($this->type !== 'none') { // PkiData must be captured in signature, and signature must be empty! $request->setPkiData($this->certificates->serialize()); $signature = $this->signData($request->serialize()); $request->setSignature($signature); } return $request; }
<?php require_once "../vendor/autoload.php"; use BitWasp\Bitcoin\PaymentProtocol\PaymentHandler; use BitWasp\Bitcoin\PaymentProtocol\Protobufs\PaymentRequest; $time = $_GET['time']; $input = file_get_contents("php://input"); $request = new PaymentRequest(); $request->parse(file_get_contents('/tmp/.abc' . $time)); $handler = new PaymentHandler($input); if ($handler->checkAgainstRequest($request)) { $handler->sendAck('Thanks!'); }