Problems when signing openssl certificates using php

30 Views Asked by At

I'm trying to manage custom openssl certificates in php, using symfony framework. I have read and reviewed the php.net docs many times, and I think I'm not doing anything non-standard nor covered by the functions. I want to first create an own CA, and then, server and client certificates signed by the CA. So first, I create a private key, then a csr with by that private key and, finally, sign the csr with the generated private key. I have my CA key and certificate, this looks OK. Then, I want to create a server certificate signed with the CA certificate, and according to php docs, when creating this kind of certificate, in both csr and csr sign, you can provide options, in my case, x509_extensions, but what I've tried about custom options is totally ignored (or overriden), creating a new CA certificate (issued by the first CA, that part works). The only thing that has not been ignored is the 'v3_req' option, but I've been unable to use this to add custom extensions. I haven't tried yet to create a custom openssl conf file and pass it, but one of the things because I haven't done that yet is there is any chance that I'm doing things wrong. Here is the relevant code, called from the controller to this App\Utils\Certificate class, where the createServerCert() function gets the form data:

<?php

namespace App\Utils;

class Certificate
{

    const pkeyConfigArgs = [
        "digest_alg" => "sha512",
        "private_key_bits" => 4096,
        "private_key_type" => OPENSSL_KEYTYPE_RSA,
    ];

    const basicCertConfg = [
        "digest_alg" => "sha256",
        "private_key_bits" => 4096,
        "private_key_type" => OPENSSL_KEYTYPE_RSA,
    ];

    const ServerExtensionsArgs = [
        'nsCertType' => 'server',
        'subjectAltName' => 'DNS:CN <Update with CN when creating certificate>',
        'extendedKeyUsage' => 'serverAuth',
        'keyUsage' => 'digitalSignature, nonRepudiation, keyEncipherment, keyAgreement',
        'basicConstraints'=> 'critical,CA:FALSE',
    ];


...


    public function createServerCert($form)
    {
        // Get the CA cert and key
        $caCertData = $this->extractCAData();

        // Get the DN data from a form
        $data = $this->extractFormData($form);

        // Generate the private key
        $res = openssl_pkey_new(self::pkeyConfigArgs);

        // Extract the private key from $res to $privKey
        openssl_pkey_export($res, $privKey);

        $extensionArgs = self::ServerExtensionsArgs;
        // Rewrite extension
        $extensionArgs['subjectAltName'] = 'DNS:' . $data['common']['commonName'];

        // Neither of these two cause csr include extensions,
        // regardless using x509|req as key
        $creqOptions['req_extensions'] = $extensionArgs;
        // $creqOptions['req_extensions'] = 'v3_req';

        $csrOptions = array_merge(self::basicCertConfg, $creqOptions);

        // Create CSR, no extensions generated. The DN is OK
        $csr = openssl_csr_new($data['common'], $privKey, $csrOptions);


        // These are for just debugging the CSR
        //openssl_csr_export($csr, $csrout);
        //dump($csrout, $creqOptions, $csrOptions);

        // Now we force to use x509_extensions, clearing anything previous
        $creqOptions = [];
        $creqOptions['x509_extensions'] = $extensionArgs;
        $csrOptions = array_merge(self::basicCertConfg, $creqOptions);
        $signcert = openssl_csr_sign($csr, $caCertData['cert'], $caCertData['privKey'], $data['interval']['duration'], $csrOptions);

        openssl_x509_export($signcert, $certout);
        $data['certdata'] = [
            'privKey' => $privKey,
            'cert' => $certout,
            'config' => $csrOptions,
        ];

        return $data;
    }

Back in the controller, I review $data['certdata'] just to make sure the config options are the intended ones, but I see that in extensions, there is basicConstraints" => "CA:TRUE". Any idea of what's wrong?

0

There are 0 best solutions below