corona-warn-app / cwa-quicktest-onboarding

This repository contains the informations about onboarding procedure for rapid antigen test partners of the Corona-Warn-App. Please use our Wiki page for further details (german language only).
22 stars 52 forks source link

PHP DCC Implementierung #88

Closed ukadmin closed 2 years ago

ukadmin commented 2 years ago

Hallo zusammen,

ich versuche DCC zu implementieren und benutze den unten genannten Code. CWA Funktioniert ohne Probleme. als Fehler erhalte ich:

{"timestamp":"2022-02-10T14:53:15.658+00:00","status":500,"error":"Internal Server Error","path":"/version/v1/test//dcc"}

Was mache ich falsch? zum Verständnis, ich erstelle einen CWA QR Code mit dcc -> true, anschließend wird der QR Code gescannt, erst dann darf DCC angefragt werden?

Wir habt ihr das gelöst?

`<?php if(!function_exists("readline")) { function readline($prompt = null){ if($prompt){ echo $prompt; } $fp = fopen("php://stdin","r"); $line = rtrim(fgets($fp, 1024)); return $line; } } / CBOREncode-master Library / use CBOR\Decoder; use CBOR\ListObject; use CBOR\MapObject; use CBOR\ByteStringObject; use CBOR\TextStringObject;

/ connectivity credentials - please enter your files and password / $certfile="../wru.schnelltestportal.de.cer"; $keyfile="../wru.key"; $pwd="xxx";

/ e.g. ö --> Ö / setlocale (LC_ALL, 'de_DE@euro', 'de_DE', 'de', 'ge');

// Some constants $validity = 60 60 24 * 2;

$fn = "Max"; $ln = "Mustermann"; $rand_number = "825031231"; $dob = date("Y-m-d",$rand_number); $testid = uniqid(); $timestamp = time(); $salt = strtoupper( bin2hex( random_bytes(16) ) ); $data = $dob . "#" . $fn . "#" . $ln . "#" . $timestamp . "#" . $testid . "#" . $salt; $hash = hash( 'sha256', $data ); $labid = 'mdf00004';

$data_arr = array( 'fn' => $fn, 'ln' => $ln, 'dob' => $dob, 'timestamp' => $timestamp, 'testid' => $testid, 'salt' => $salt, 'hash' => $hash, 'dgc' => true

);

print("
");print_r($data_arr);print("
");

$data_json = json_encode( $data_arr ); print("
");print_r($data_json);print("
"); $url1 = 'https://s.coronawarn.app?v=1#' . base64url_encode( $data_json ); print("
");print_r($url1);print("
");

$ergebnis="6"; $test_results = array( 'testResults' => array( array( 'id' => $hash, 'result' => $ergebnis ) ), 'labId' => $labid );

$test_results = json_encode( $test_results );

print("
");print_r($test_results);print("
");

$url = 'https://quicktest-result-cff4f7147260.coronawarn.app/api/v1/quicktest/results';

$ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2); curl_setopt($ch, CURLOPT_SSLCERT, $certfile); curl_setopt($ch, CURLOPT_SSLKEY, $keyfile); curl_setopt($ch, CURLOPT_SSLKEYPASSWD, $pwd); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt( $ch, CURLOPT_POSTFIELDS, $test_results ); curl_setopt( $ch, CURLOPT_HTTPHEADER, array('Content-Type:application/json')); curl_setopt( $ch, CURLOPT_VERBOSE, 1);

print("
");

$result = curl_exec($ch); $error = curl_error($ch);

print("
");print_r($result);print("
"); print("
");print_r($error);print("
");

// Start DCC Part here print("
Processing DCC
");

// get Public Key -- polling $url = 'https://dcc-proxy-cff4f7147260.coronawarn.app/version/v1/publicKey/search/' . $labid;

print("
");print_r($labid);print("
");

$ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2); curl_setopt($ch, CURLOPT_SSLCERT, $certfile); curl_setopt($ch, CURLOPT_SSLKEY, $keyfile); curl_setopt($ch, CURLOPT_SSLKEYPASSWD, $pwd); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_VERBOSE, 1);

$result = trim(curl_exec($ch));

print("
result");print_r($result);print("
"); $jsonArrayResponse = json_decode($result, true); print("
Array");print_r($jsonArrayResponse);print("
");

$error = curl_error($ch); print("
Error: ");print_r($error);print("
");

// POST

// calculate the expected testId as hash from hash $expTestId = hash("sha256",$hash);

echo 'search for testId: ' . $expTestId . PHP_EOL;

$dcci = ""; $publicKey = ""; $testId = "";

// fetch public key and dcci from response foreach ($jsonArrayResponse as $element) {

if ($expTestId == $element["testId"])
{
    echo 'dcci:' . $element["dcci"] . ' - publicKey:' . $element["publicKey"] . ' - testId:' . $element["testId"] . PHP_EOL;
    $dcci = $element["dcci"];
    $publicKey = $element["publicKey"];
    $testId = $element["testId"];

}
//get the matching testId

}

// assemble HCERT JSON as base for encryptedDcc

// 2tvenom CBOREncode include "CBOR/CBOREncoder.php"; include "CBOR/Types/CBORByteString.php";

if($ergebnis=='6'){ $tr="260415000"; }else{ if($ergebnis=='8'){ $tr="260373001"; }else{} }

$values = array( 1 => "DE", 4 => ($timestamp + $validity), 6 => $timestamp, -260 => array( 1 => array( "t" => array( 0 => array( "ci" => (string)$dcci, "co" => "DE", "is" => "Robert Koch-Institut", "tg" => $tr, "tt" => "LP217198-3", "sc" => (string)date("c", $timestamp), "tr" => "260415000", "tc" => "MDF Testzentrum (1234)", "ma" => "2098" ) ), "dob"=>(string)$dob, "nam"=> array( "fn"=> $ln, "fnt"=> convertAccentsAndSpecialToICAONormal(mb_strtoupper($ln,"UTF-8")), "gn"=> $fn, "gnt"=> convertAccentsAndSpecialToICAONormal(mb_strtoupper($fn,"UTF-8")) ), "ver" => "1.3.0" ) ) );

// HCERT CBOR

$encoded_data = \CBOR\CBOREncoder::encode($values); $byte_arr = unpack("C*", $encoded_data); $cbor_hcert= implode("", array_map(function ($byte) { if (strlen(strtoupper(dechex($byte))) == 1) return "0" . strtoupper(dechex($byte)); return "" . strtoupper(dechex($byte));

}, $byte_arr));

echo "CBOR: ".$cbor_hcert.PHP_EOL;

// Assemble COSE structure for dccHash calculation only

// Creates CBOR for the signing object for the dccHash calculation only // Since the CBOR prefix coding is always the same, just add the CBOR of the HCERT // Attention: This just an example - has to be adapted if CBOR HEX > 255 Byte (0xFF)!

echo "
CBOR Lenght HCERT: ".dechex(strlen($cbor_hcert)/2).PHP_EOL; echo "
CBOR: ".$cbor_hcert.PHP_EOL;

$byteCount = strlen(dechex(strlen($cbor_hcert)/2)); echo "byteCount: ".$byteCount.PHP_EOL;

if ( $byteCount == 1 ) { $cbor_cose = '846A5369676E61747572653143A1012640580' . dechex(strlen($cbor_hcert)/2) . $cbor_hcert; } else if ( $byteCount == 2 ) { $cbor_cose = '846A5369676E61747572653143A101264058' . dechex(strlen($cbor_hcert)/2) . $cbor_hcert; } else if ( $byteCount == 3 ) { $cbor_cose = '846A5369676E61747572653143A1012640590' . dechex(strlen($cbor_hcert)/2) . $cbor_hcert;

} else if ( $byteCount == 4 ) { $cbor_cose = '846A5369676E61747572653143A101264059' . dechex(strlen($cbor_hcert)/2) . $cbor_hcert; } else { echo "Unexpeted Error EXITING - CBOR TOO LONG".PHP_EOL; exit; }

echo "
CBOR for Hash: ".$cbor_cose.PHP_EOL;

$dccHashHex = openssl_digest(hexToStr($cbor_cose), "sha256", false);

echo "
Hash: " . $dccHashHex . PHP_EOL;

// encypt CBOR of HCERT // generate a 32 Byte Key $dek = bin2hex(random_bytes(32)); echo "AES key: " . $dek . PHP_EOL; $iv = str_repeat("0",32); // encrypt DCC with AES256 (CBC/PKSC5Padding) $encryptedDcc = base64_encode(openssl_encrypt(hexToStr($cbor_hcert),"AES-256-CBC",hexToStr($dek),OPENSSL_RAW_DATA,hexToStr($iv))); echo "encryptedDCC = " . $encryptedDcc . PHP_EOL;

// encrypt DEK with Public Key

// PHPSecLib Version 2

include('phpseclib/Net/SSH2.php'); include('phpseclib/Net/SFTP.php'); include('phpseclib/Crypt/RSA.php'); include('phpseclib/Crypt/Random.php'); include('phpseclib/Math/BigInteger.php'); include('phpseclib/Crypt/Hash.php');

use phpseclib\Crypt\RSA; use phpseclib\Crypt\Random; use phpseclib\Crypt\Common; use phpseclib\net\SFTP;

$rsaObj = new \phpseclib\Crypt\RSA();

$rsaObj->loadKey($publicKey); $rsaObj->setMGFHash('sha256'); $rsaObj->setHash('sha256'); $rsaObj->setEncryptionMode(phpseclib\Crypt\RSA::ENCRYPTION_OAEP);

$dataEncryptionKey = base64_encode($rsaObj->encrypt(hexToStr($dek), phpseclib\Crypt\RSA::ENCRYPTION_OAEP));

echo "dataEncryptionKey: " . $dataEncryptionKey . PHP_EOL;

echo "Test: $dataEncryptionKey"; echo "dataEncryptionKey: " . $dataEncryptionKey . PHP_EOL;

// Send DCC Data to Proxy

$dcc_json = array( 'dccHash' => $dccHashHex, 'encryptedDcc' => $encryptedDcc, 'dataEncryptionKey' => $dataEncryptionKey );

$dcc_json = json_encode( $dcc_json );

print("
");print_r($dcc_json);print("
");

$url = 'https://dcc-proxy-cff4f7147260.coronawarn.app/version/v1/test/'. $testId . '/dcc';

$ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2); curl_setopt($ch, CURLOPT_SSLCERT, $certfile); curl_setopt($ch, CURLOPT_SSLKEY, $keyfile); curl_setopt($ch, CURLOPT_SSLKEYPASSWD, $pwd); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt( $ch, CURLOPT_POSTFIELDS, $dcc_json ); curl_setopt( $ch, CURLOPT_HTTPHEADER, array('Content-Type:application/json')); curl_setopt( $ch, CURLOPT_VERBOSE, 1);

print("
");

$result = curl_exec($ch); $error = curl_error($ch);

print("
");print_r($result);print("
"); print("
");print_r($error);print("
");

// FUNCTIONS

function base64url_encode($data) { return rtrim(strtr(base64encode($data), '+/', '-'), '='); }

function generateRandomString($length = 10) { $characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; $charactersLength = strlen($characters); $randomString = ''; for ($i = 0; $i < $length; $i++) { $randomString .= $characters[rand(0, $charactersLength - 1)]; } return $randomString; }

function strToHex($string) { $hex=''; for ($i=0; $i < strlen($string); $i++) { $hex .= dechex(ord($string[$i])); } return $hex; }

function hexToStr($hex) { $string=''; for ($i=0; $i < strlen($hex)-1; $i+=2) { if ( $hex[$i] == ' ') continue; $string .= chr(hexdec($hex[$i].$hex[$i+1])); } return $string; }

/**

?> `

philharmonie commented 2 years ago

Hast du eine Lösung?