How to Extract a Key or Certificate from a PFX File Using PHP

If you’ve ever worked with PFX files, you may know they hold both the private key and public certificate, usually in a .pfx (or .p12) format. These files are useful for security purposes, such as SSL encryption for websites. However, if you’re working with PHP and need just the certificate or key separately, you might be wondering how to extract them from the PFX file. Let’s dive into a step-by-step guide on doing this in PHP!

What is a PFX File?

A PFX (Personal Information Exchange) file is a binary file that contains both the certificate and private key needed for secure communications. Think of it as a package that keeps these components together. To use these separately in PHP, we need to extract each component individually.

Why Extract the Key or Certificate?

You might need to extract the key or certificate for various reasons:

  • You’re setting up an HTTPS connection and need to use the certificate.
  • You need the private key for server-side encryption or decryption.
  • You’re working with APIs that require separate files for the key and certificate.

PHP provides a built-in way to do this using the openssl_pkcs12_read function, which allows us to access the key and certificate inside a PFX file.

Prerequisites

Before we start, make sure you have:

  • PHP installed on your system.
  • The OpenSSL extension enabled in PHP. If you’re unsure, you can check your php.ini file for the extension=openssl line or use phpinfo() in your PHP code to confirm.

Let’s go through the steps to extract the private key and certificate from a PFX file.

Step 1: Load the PFX File

First, make sure you have the PFX file in a place you can access, and remember the password associated with it. We’ll load the file’s contents in PHP so we can work with it.

Step 2: Use openssl_pkcs12_read to Extract Data

This is the magic step! The openssl_pkcs12_read function will parse the PFX file and give us access to both the certificate and private key, if they are present. To make things a bit easier, let’s create an HTML form that will allow us to upload the file and submit it for processing.

Create a folder with the following file in index.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Upload PFX File</title>
</head>
<body>
    <h2>Upload Your PFX File</h2>
    <form action="process_pfx.php" method="post" enctype="multipart/form-data">
        <label for="pfxFile">Select PFX file:</label>
        <input type="file" name="pfxFile" id="pfxFile" accept=".pfx" required>
        <label for="password">PFX Password:</label>
        <input type="password" name="password" id="password">
        <button type="submit">Upload and Process</button>
    </form>
</body>
</html>

Now in the same folder, create the following PHP file

<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // Check if the file was uploaded without errors
    if (isset($_FILES['pfxFile']) && $_FILES['pfxFile']['error'] === UPLOAD_ERR_OK) {
        $maxFileSize = 5 * 1024 * 1024; // 5MB in bytes
        if ($_FILES['pfxFile']['size'] > $maxFileSize) {
            die("Error: File size exceeds the maximum allowed limit of 5MB.");
        }

        // Validate file type using MIME type and file extension
        $fileTmpPath = $_FILES['pfxFile']['tmp_name'];
        $fileName = $_FILES['pfxFile']['name'];
        $fileExtension = strtolower(pathinfo($fileName, PATHINFO_EXTENSION));
        $allowedTypes = ['application/x-pkcs12', 'application/x-pkcs7-certificates'];
        if ($fileExtension !== 'pfx' && $fileExtension !== 'p7b' && !in_array(mime_content_type($fileTmpPath), $allowedTypes)) {
            die("Error: Only PFX files are allowed.");
        }

        // Sanitize the file name
        $fileName = basename(filter_var($fileName, FILTER_SANITIZE_STRING));

        $pfxPassword = $_POST['password'];
        $pfxContents = file_get_contents($fileTmpPath);
		        // Extract certificates and private key from the PFX file
        $certs = [];
        if (openssl_pkcs12_read($pfxContents, $certs, $pfxPassword)) {
            $privateKey = $certs['pkey'];
            $certificate = $certs['cert'];
            $caCerts = isset($certs['extracerts']) ? $certs['extracerts'] : [];

            echo "Private Key:<br><pre>" . htmlspecialchars($privateKey) . "</pre>";
            echo "Certificate:<br><pre>" . htmlspecialchars($certificate) . "</pre>";
            if (!empty($caCerts)) {
                echo "CA Certificates:<br><pre>" . htmlspecialchars(print_r($caCerts, true)) . "</pre>";
            }
        } else {
            echo "Error: Failed to read the PFX file. Please check your password.";
        }
    } else {
        echo "Error: File upload error.";
    }
} else {
    echo "Invalid request method.";
}
?>

At this point, you have two separate sections on the page. Your private key that will be formatted like:

-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDaEm3pC9f1M2xk
7ejyXBSRvGFAez9hd2V0R1FVWJ9POMw8ImHFz4wW/z3cPjKS+AHhbh+v8YOBM+eQ
OXLjB0MZJ3LTXNlhBfjXXgj0x7rU98PoZoUoDkEX5twCg0exGtfHjUFRpmTc8uSw
sXpBB0RvKmTWexgLBKOk94t5vYGKRY0IivLer/qk5KiZm84JcDr3fTfAxRABGnEP
1+YitRCD/fgHvB6oGQJVVEmFwO67JrNIt0Ua0jxKmDQ2AFO7hzR0a6Lt1g8HZYov
tDPZxHn1V90R7EL4pz1nwBKgsLBqVNlcOr2qxz3cBDX2vibkvazSMqGrUTqACXh
HCSZQQCTeeec0JFrIQ6SG4twGN5V2NKGoNB4Y9BS5sRGA3J5bccF4FLF9VuRth3r
VHMCsuDImvs7ziD3z+cK9ovz9KcSKx0ssNVYlZEhRVDZL3vvQByHUbeLAsSMjS2k
7JWSwYJONaGe9Qkx1w/dv8dmLH7RCKC9q0J3lDjHNQEvPuPZy02Z68NbpcGzrtNo
j6sreSa5X+MJxMnLuLf48IraJ7joeeEWu0GJrfBEAQKBgQDY2EzfaXLVN1QtxhJ6
pNfCdGnCC93r/ltoWYqYcDgaQDzui+ZDM+K7W4aMyog8a4fNu8dGKkwHU/oT3FFZ
NlPzbFGbIS3vSGp37kYq+Wsr1p/8sCnDVTlWph4SsnQisiHxUSZO2xRM1hoypEgV
GutSxGYlngg0zPS0zFWCGzH0wQKBgQDAXHemAobDus+o9KwRpAT2Yu+uYdvd6WZ6
3H0knV3sngWD/e/0Muf7FNnmSejINb6EwsWW2fCqS4dA5JKI47/jjor4b020J6Hq
FlyiBAWtWAxDiosFicdEFLJTfbRGtrj9zPfm2/e7bJhG9AEuL3G+I7Y5W2UQBNjV
-----END PRIVATE KEY-----

And your certificate:

-----BEGIN CERTIFICATE-----
MIIHdDCCBlygAwIBAgIQBWZKz7kto3A/WT4H0265KjANBgkqhkiG9w0BAQsFADBE
UITWxw5h4uLP4shoHT/6SNANxdwZGlGy/m6Xhp9s34+zG2kcewvaq+DBSuTmkEHg
HFAnORSkx8i36i9+2h3nKUWjCW/yFSqDLf7C2oieUGsNbfNry8ComZOnx4BsZNiq
6WtNmwgiM8FIzSlSvGe7d20rMrwlyp7uS0VyXMECux+GqbXBe/I9RTBjSrlUu9Gh
crA9ea6R/vFpwrnzUv6UHZie0FBoPeyGbt83k5UiWGAyr0VgrcF6JtPN10ixY/HZ
ZfOlokYsJuNPpdy4AxLZZW8koQV1mlb6sf2JCOtfdgmQk74qsWTeSy2pAgMBAAGj
ggPxMIID7TAfBgNVHSMEGDAWgBQo0s/uCYR13bWytb881aDGc4hdHzAdBgNVHQ4E
FgQUjXjUt+fIajzVxpUXvMuV6bQAlNkwgbIGA1UdEQSBqjCBp4IJcGF0bnQuY29t
gg13d3cucGF0bnQuY29tghZhdXRvZGlzY292ZXIucGF0bnQuY29tgg1jYXAucGF0
bnQuY29tgg5tYWlsLnBhdG50LmNvbYINdHRpdGZlcnJ5LmNvbYIRd3d3LnR0aXRm
ZXJyeS5jb22CDGd3LnBhdG50LmNvbYIVYm9va2luZy50dGl0ZmVycnkuY29tgg1m
dHAucGF0bnQuY29tMEoGA1UdIARDMEEwCwYJYIZIAYb9bAIBMDIGBWeBDAEBMCkw
JwYIKwYBBQUHAgEWG2h0dHA6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAOBgNVHQ8B
Af8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMHUGA1UdHwRu
-----END CERTIFICATE-----

Alternatively you can write each directly to file such as a “private.key" file and a “certificate.crt" file instead. Here’s the code you would use to do that

echo "Private Key:<br><pre>" . htmlspecialchars($privateKey) . "</pre>";
file_put_contents('private.key',htmlspecialchars($privateKey)); //write key to file
		
echo "Certificate:<br><pre>" . htmlspecialchars($certificate) . "</pre>";
file_put_contents('certificate.crt',htmlspecialchars($certificate)); //write certificate to file

Troubleshooting Common Issues

  1. Incorrect Password: If the password doesn’t match, the openssl_pkcs12_read function will return false, and the script will fail. Double-check the password you’re using.
  2. Permissions Errors: If PHP can’t write to the file paths you’ve specified, ensure your script has permission to write to those directories.
  3. Missing OpenSSL Extension: If openssl_pkcs12_read isn’t available, make sure the OpenSSL extension is enabled in your PHP configuration.

Conclusion

Extracting a certificate or private key from a PFX file in PHP is straightforward with openssl_pkcs12_read. Once extracted, you can save these as separate files and use them as needed for secure connections, API integrations, and more.

Now you have a quick and easy way to work with PFX files in PHP, even if you’re just getting started with programming!



Leave a Reply