Trying to create OpenVPN user certs manually

  • I need to be able to create a (large) set of user certs for OpenVPN, so I want to be able to run a local script to do this. The basic code I'm using is:

    $CA_CERT = "VPN-CA.crt";
    $CA_KEY  = "VPN-CA.key";
    $digest_alg = "sha512";
    $keylen = 4096;
    $args = array (
      "x509_extensions" => "usr_cert",
      "digest_alg" => $digest_alg,
      "private_key_bits" => (int)$keylen,
      "private_key_type" => OPENSSL_KEYTYPE_RSA,
      "encrypt_key" => false );
    $req_key = openssl_pkey_new( $args );
    if( openssl_pkey_export ( $req_key, $out_key ) ) {
      $dn = array(
        "countryName" => "GB",
        "stateOrProvinceName" => "...",
        "localityName" => "...",
        "organizationName" => "...",
        "emailAddress" => "...",
        "commonName" => "..."
      $req_csr  = openssl_csr_new  ( $dn, $req_key, $args );
      $req_cert = openssl_csr_sign ( $req_csr, "file://$CA_CERT", "file://$CA_KEY", 365, $args );
      if( openssl_x509_export ( $req_cert, $out_cert ) ) {
        $umask = umask(0066);
        if ( ! openssl_pkcs12_export_to_file( $req_cert, "user.p12", $req_key, "" ) )
          echo "Failed p12\n";

    Where "VPN-CA" is a self-signed CA generated using the pfSense Cert Manager. This is also used to create a server certificate for use by the OpenVPN server.

    I'm then using the .p12 this produces to replace the one in a client export produced using the OpenVPN Client Export package.

    The exported package (unmodified) works as expected and I can connect and create a tunnel.

    However, when I use the .p12 generated using my script I am seeing the following in the logs (Tunnelblick):

    2016-08-09 10:10:39 TLS: Initial packet from [AF_INET], sid=54773c0c d9fca608
    2016-08-09 10:10:39 VERIFY ERROR: depth=1, error=self signed certificate in certificate chain: C=..., ST=..., L=..., O=..., emailAddress=..., CN=...
    2016-08-09 10:10:39 OpenSSL: error:14090086:SSL routines:ssl3_get_server_certificate:certificate verify failed
    2016-08-09 10:10:39 TLS_ERROR: BIO read tls_read_plaintext error
    2016-08-09 10:10:39 TLS Error: TLS object -> incoming plaintext read error
    2016-08-09 10:10:39 TLS Error: TLS handshake failed

    I think my code has the same behaviour as the code pfSense uses to create the user cert (system_certmanager.php), but I must be missing something. Can anyone see what I'm doing wrong?

  • Should add that running:

    openssl verify -verbose -CAfile VPN-CA.crt user.crt

    where 'user.cdt' was extracted from 'user.p12' reports that the user cert is valid.

  • Ok, this:

    if ( ! openssl_pkcs12_export_to_file( $req_cert, "user.p12", $req_key, "" ) )

    is the problem. The .p12 produced only contains the user cert - I need to add the CA cert as well.

    However, it doesn't look like there's a php openssl_ function to do this - which is probably why the openVPN Client Export Plugin uses:

    exec("/usr/bin/openssl pkcs12 -export -in {$ecrtpath} -inkey {$ekeypath} -certfile {$ecapath} -out {$eoutpath} -passout pass:{$eoutpass}");

Log in to reply