# How to Generate PKCS12 PFX Files with mkcert for Legacy Applications

> Generate PKCS12 PFX files with mkcert for legacy apps. Use the -p12 flag for P12 output compatible with Windows and Java. Rename .p12 to .pfx easily.

- Repository: [Filippo Valsorda/mkcert](https://github.com/FiloSottile/mkcert)
- Tags: how-to-guide
- Published: 2026-03-05

---

**Use the `-p12` flag when running mkcert to output a PKCS#12 archive instead of separate PEM files, then rename the `.p12` extension to `.pfx` for compatibility with Windows and Java applications.**

mkcert, maintained by FiloSottile, is a zero-configuration tool for creating locally-trusted development certificates. While it defaults to outputting separate certificate and key files in PEM format, you can **generate PKCS12 PFX files with mkcert** to satisfy legacy enterprise applications that require binary certificate containers bundling the private key, leaf certificate, and CA chain into a single file.

## Why Legacy Systems Require PKCS12 (PFX) Format

Many enterprise platforms cannot consume raw PEM-encoded certificates and instead mandate the PKCS#12 standard (often stored with a `.pfx` extension on Windows).

### Windows Certificate Stores and IIS

Legacy Windows services such as Internet Information Services (IIS) and older .NET Framework applications rely on the Windows CryptoAPI, which only imports certificates through `.pfx` or `.p12` files into the system certificate store.

### Java Keystores and Keytool

Java applications running on Tomcat, Jetty, or Spring Boot typically use the `keytool` utility to manage keystores. The `keytool -importkeystore` command can consume a PKCS#12 archive directly to populate a JKS or PKCS12 keystore, making the PFX format essential for Java deployments.

### Mobile Development SDKs

Certain iOS and Android build pipelines require a single PFX bundle for code-signing or TLS client authentication during development, as they cannot easily reference separate key and certificate files from the filesystem.

## How mkcert Implements PKCS12 Generation

The implementation resides in **[`cert.go`](https://github.com/FiloSottile/mkcert/blob/main/cert.go)**, where mkcert handles the `-p12` flag and converts the generated PEM material into a binary PKCS#12 archive using Go’s `crypto/x509` and the `software.sslmate.com/src/go-pkcs12` library.

### The -p12 Flag in cert.go

The command-line flag is defined around lines 70–78 of [`cert.go`](https://github.com/FiloSottile/mkcert/blob/main/cert.go). When present, it sets an internal boolean that triggers the PKCS#12 export path instead of the default PEM writer.

```go
// Simplified representation from cert.go
p12Flag := flag.Bool("p12", false, "Generate a PKCS#12 file instead of separate PEM files")

```

### The writePKCS12 Function

The actual serialization logic lives in the `writePKCS12` helper near lines 220–240 of [`cert.go`](https://github.com/FiloSottile/mkcert/blob/main/cert.go). This function bundles the leaf certificate, private key, and any intermediate CA certificates into a single encrypted container.

```go
// Conceptual flow from cert.go#L220-L240
func (m *mkcert) writePKCS12(cert *x509.Certificate, key crypto.PrivateKey, filename string) {
    // Uses software.sslmate.com/src/go-pkcs12 to encode
    p12Data, err := pkcs12.Encode(rand.Reader, key, cert, m.caCert, "")
    // Writes to <filename>.p12
}

```

### Default Password Behavior

By default, mkcert generates **unencrypted** PKCS#12 files (empty password). This simplifies development workflows but may require post-processing with OpenSSL for environments that mandate password protection.

## Step-by-Step: Generate PKCS12 PFX Files with mkcert

Follow these steps to create a locally-trusted PFX archive suitable for IIS, Java, or other legacy platforms.

### Install mkcert and Initialize the Local CA

First, install mkcert and create a local certificate authority trusted by your system.

```bash

# macOS

brew install mkcert
mkcert -install

# Linux (download latest release)

wget https://github.com/FiloSottile/mkcert/releases/download/v1.4.4/mkcert-v1.4.4-linux-amd64 -O mkcert
chmod +x mkcert
sudo mv mkcert /usr/local/bin/
mkcert -install

```

### Create the PKCS12 Archive

Use the `-p12` flag to generate the binary archive. You can specify multiple **Subject Alternative Names (SANs)** in a single command.

```bash
mkcert -p12 "myapp.local" "localhost" "127.0.0.1" "::1"

```

This creates `myapp.local.p12` containing the private key, leaf certificate, and CA chain.

### Rename to .pfx Extension

Windows and some Java tools expect the `.pfx` extension. Simply rename the file:

```bash
mv myapp.local.p12 myapp.local.pfx

```

### Add Password Protection with OpenSSL

Since mkcert outputs unencrypted PKCS#12 files by default, use **OpenSSL** to add a password for environments requiring encryption.

```bash
openssl pkcs12 -in myapp.local.pfx -export -out myapp.local-secure.pfx -passout pass:YourSecretPassword

```

The `-export` flag ensures the output is a new PKCS#12 archive with the specified password.

## Importing PFX Files into Target Systems

Once you generate the PFX file, import it into your legacy application or system store.

### Windows IIS Import

1. Open the **Certificate Manager** (`certmgr.msc`) or IIS Manager.
2. Navigate to **Personal** > **Certificates**.
3. Right-click, select **All Tasks** > **Import**.
4. Browse to your `.pfx` file and complete the wizard. If prompted for a password, leave it blank (for mkcert defaults) or enter the password you set with OpenSSL.

### Java Keytool Import

Import the PFX into a Java KeyStore (JKS) or PKCS12 keystore for Tomcat or Spring Boot:

```bash
keytool -importkeystore \
  -srckeystore myapp.local.pfx \
  -srcstoretype PKCS12 \
  -srcstorepass YourSecretPassword \
  -destkeystore myapp.jks \
  -deststoretype JKS \
  -deststorepass changeit

```

If the mkcert PFX has no password, use `-srcstorepass ""` (empty string).

## Advanced Configuration

### Multiple Subject Alternative Names (SANs)

Legacy applications often bind to multiple hostnames or IPs. mkcert automatically embeds all arguments as **Subject Alternative Names** in the certificate.

```bash
mkcert -p12 "app.local" "*.app.local" "192.168.1.50" "localhost"

```

This generates a single PFX valid for all specified identities.

### Certificate Renewal Workflow

When certificates expire, re-run the same command. mkcert maintains the same local CA in your system trust store, so the renewed certificate is automatically trusted without re-importing the CA.

```bash

# Re-generate with the same parameters

mkcert -p12 "myapp.local"

```

Replace the old PFX file in your application configuration.

## Summary

- **mkcert** generates locally-trusted development certificates and supports **PKCS#12 output** via the `-p12` flag.
- The implementation in **[`cert.go`](https://github.com/FiloSottile/mkcert/blob/main/cert.go)** (lines 70–78 and 220–240) uses the `software.sslmate.com/src/go-pkcs12` library to bundle the private key, certificate, and CA chain.
- By default, mkcert creates **unencrypted** `.p12` files; use **OpenSSL** to add password protection for legacy systems requiring it.
- Rename the output from `.p12` to `.pfx` for compatibility with **Windows IIS**, **Java keystores**, and other enterprise platforms.
- Include multiple **Subject Alternative Names** in a single command to support complex local development environments.

## Frequently Asked Questions

### What is the difference between .p12 and .pfx files?

There is no technical difference; both extensions refer to the **PKCS#12** archive format. The `.pfx` extension originated with Microsoft and is standard on Windows platforms, while `.p12` is more common on macOS and Linux systems. mkcert outputs `.p12` by default, but you can safely rename the file to `.pfx` for Windows compatibility.

### Does mkcert support password-protected PKCS12 files by default?

No. As implemented in **[`cert.go`](https://github.com/FiloSottile/mkcert/blob/main/cert.go)**, the `writePKCS12` function creates **unencrypted** PKCS#12 archives with an empty password to streamline development workflows. If your legacy application requires a password, you must post-process the file using **OpenSSL** with the `-export` and `-passout` flags to add encryption.

### Can I use mkcert-generated PFX files in production?

No. mkcert is explicitly designed for **local development** only. It creates certificates signed by a locally-installed CA that is not publicly trusted. While the PKCS#12 format itself is production-ready, the trust chain is valid only on your development machine. For production environments, use certificates issued by a public CA or your organization's internal PKI.

### How do I import a mkcert PFX into a Java keystore?

Use the **keytool** utility bundled with the JDK. Since mkcert PFX files typically have no password, specify an empty source store password. Run: `keytool -importkeystore -srckeystore myapp.local.pfx -srcstoretype PKCS12 -srcstorepass "" -destkeystore myapp.jks -deststoretype JKS -deststorepass changeit`. This converts the PKCS#12 archive into a Java KeyStore (JKS) format suitable for Tomcat or Spring Boot applications.