I’m integrating phase 2 in Laravel 11. To create an invoice step-by-step process:
- At the initial state, when the seller creates an invoice, it will first check for CSR, PEM, and the conf file. If not found, then it will create all the files csr, pem, and conf.
- Then I found this error (from the laravel log):
{“error”:“{\“errorCode\”:\“400\”,\“errorCategory\”:\“Invalid-CSR\”,\“errorMessage\”:\“The provided Certificate Signing Request (CSR) is invalid.\”}”} - So, my process wast, If my csr as valid, then instant it will move forward for another process to create ‘csid’ and ‘secret’. Though I’m using the seperate service function for it. but my error is showing that, ‘csr is invalid’ that’s why it’s moving forward for next steps.
Here is my code how I’m generating the keys (laravel):
private static function generateKeysAndCsr(ZatcaSetting $settings, string $environment = 'simulation' ): void
{
$certsDir = storage_path('app/certs');
if (!is_dir($certsDir)) {
mkdir($certsDir, 0755, true);
}
$configPath = $certsDir . '/zatca_openssl.cnf';
// ✅ Correct OID-based template for simulation
$templateLine = '';
if ($environment === 'simulation') {
$templateLine = "1.3.6.1.4.1.311.20.2 = ASN1:PRINTABLESTRING:PREZATCA-Code-Signing";
}
$config = <<<CFG
[ req ]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = dn
req_extensions = v3_req
[ dn ]
C = {$settings->country_code}
ST = {$settings->state}
L = {$settings->city}
O = {$settings->seller_name}
OU = {$settings->organizational_unit_name}
CN = {$settings->vat_number}
[ v3_req ]
keyUsage = digitalSignature
extendedKeyUsage = clientAuth
$templateLine
subjectAltName = @alt_names
[ alt_names ]
DNS.1 = zatca.gov.sa
CFG;
file_put_contents($configPath, $config);
$privateKeyPath = $certsDir . "/{$settings->vat_number}_private.pem";
$csrPath = $certsDir . "/{$settings->vat_number}.csr";
exec("openssl genrsa -out {$privateKeyPath} 2048", $o1, $r1);
if ($r1 !== 0) {
throw new \Exception('Private key generation failed');
}
// ⚠️ IMPORTANT: explicitly apply extensions
exec(
"openssl req -new -key {$privateKeyPath} -out {$csrPath} -config {$configPath} -reqexts v3_req",
$o2,
$r2
);
if ($r2 !== 0) {
throw new \Exception('CSR generation failed');
}
$csrPem = file_get_contents($csrPath);
$settings->update([
'private_key_path' => $privateKeyPath,
'csr_content' => $csrPem,
'csr_base64' => base64_encode($csrPem),
]);
}
From the expertise, I want to know the process about it is a perfect way to generate the keys, csid, and secret? And how can I fix this problem as a laravel developer?
Currently, I’m stuck on these steps and still not moving forward for api submission.
Need urgent help!!