# Install a TLS certificate on IIS

IIS imports TLS certificates as PKCS#12 archives, so PEM files must be bundled first — `openssl pkcs12 -export -out certificate.pfx -inkey private.key -in certificate.crt -certfile chain.crt`. Import through the IIS Manager server-level *Server Certificates* feature, then bind it to the site under *Bindings*. If the import rejects a password you know is correct, re-export with `-legacy`, because OpenSSL 3 encrypts archives with AES-256-CBC and the older Windows importer cannot read it.

Source: https://certguru.io/platforms/iis/
Last updated: 2026-08-19
Commands verified against OpenSSL 3.5.7.

---

## Step 1 — build the PFX

IIS does not read PEM. Bundle first:

*Certificate, key and chain into one archive*

```bash
openssl pkcs12 -export \
  -out certificate.pfx \
  -inkey private.key \
  -in certificate.crt \
  -certfile chain.crt \
  -name "example.com"
```

> **If the import fails on a correct password**
>
> Add `-legacy`. OpenSSL 3 defaults to AES-256-CBC, which older Windows builds cannot decrypt, and
>   the importer misreports that as a bad password rather than an unsupported cipher.
>
>   ```bash
>   openssl pkcs12 -export -legacy -out certificate.pfx \
>     -inkey private.key -in certificate.crt -certfile chain.crt
>   ```

Setting `-name` matters here — it becomes the friendly name shown in the IIS certificate list, and
an unnamed entry is hard to identify later.

## Step 2 — import

**IIS Manager:** select the **server** node (not the site), open **Server Certificates**, then
**Import…** in the Actions pane. Choose the PFX, enter the password, and leave the certificate store
as **Personal**.

Or in PowerShell:

```powershell
$password = Read-Host -AsSecureString -Prompt "PFX password"
Import-PfxCertificate -FilePath C:\certs\certificate.pfx `
  -CertStoreLocation Cert:\LocalMachine\My `
  -Password $password
```

## Step 3 — bind it to the site

Select the site, **Bindings…**, then **Add** or **Edit**:

- **Type:** https
- **Port:** 443
- **Host name:** `example.com`
- **Require Server Name Indication:** tick this if the server hosts more than one HTTPS site
- **SSL certificate:** the friendly name you set with `-name`

Or in PowerShell:

```powershell
$cert = Get-ChildItem Cert:\LocalMachine\My |
  Where-Object { $_.Subject -like "*example.com*" }

New-IISSiteBinding -Name "Default Web Site" `
  -BindingInformation "*:443:example.com" `
  -Protocol https `
  -CertificateThumbPrint $cert.Thumbprint `
  -CertStoreLocation "Cert:\LocalMachine\My" `
  -SslFlag "Sni"
```

## Step 4 — verify

*From any machine with OpenSSL*

```bash
openssl s_client -connect example.com:443 -servername example.com /dev/null \
  | grep "Verify return code"
```

Expected output:

```
Verify return code: 0 (ok)
```

*Confirm the intermediate is being sent*

```bash
openssl s_client -connect example.com:443 -servername example.com -showcerts /dev/null \
  | grep -c "BEGIN CERTIFICATE"
```

Expected output:

```
2
```

A count of 1 means the intermediate did not make it into the certificate store. Import it separately
into **Local Machine → Intermediate Certification Authorities**.

## Exporting a certificate out of IIS

To move an identity elsewhere, export it with its key and unpack it:

```powershell
$password = Read-Host -AsSecureString -Prompt "Export password"
Get-ChildItem Cert:\LocalMachine\My |
  Where-Object { $_.Subject -like "*example.com*" } |
  Export-PfxCertificate -FilePath C:\certs\export.pfx -Password $password
```

Then on the destination, [convert PFX to PEM](/convert/pfx-to-pem/).

> **The key must be marked exportable**
>
> A certificate imported without the exportable flag cannot be exported with its private key later.
>   Tick "Allow this certificate to be exported" during import if you may ever need to move it.

## Common IIS problems

| Symptom | Cause | Fix |
| --- | --- | --- |
| "The password you entered is incorrect" | OpenSSL 3 AES archive | Re-export with `-legacy` |
| Certificate missing from the bindings list | Imported to the wrong store, or key not present | Import to Local Machine → Personal |
| Chain incomplete for clients | Intermediate not in the store | Use `-certfile`, or import it separately |
| Binding conflict on port 443 | Another site holds the binding without SNI | Enable SNI on both bindings |
| Certificate works locally, fails externally | Firewall, or the wrong binding hostname | Check the host name on the binding |


## Frequently asked questions

### Why does IIS reject a password I know is correct?

Because the archive uses AES-256-CBC, which the older Windows importer cannot decrypt — and it reports every decryption failure as a wrong password. Re-export with `-legacy`. See the full explanation.

### Where does the certificate physically go?

Into the Windows certificate store, normally Local Machine → Personal, not into a file on disk. You can inspect it with `certlm.msc` or the PowerShell `Cert&#58;\\LocalMachine\\My` drive.

### How do I host several HTTPS sites on one IP?

Tick "Require Server Name Indication" on each binding. SNI has been supported since IIS 8 and Windows Server 2012 and lets each hostname present its own certificate.

### Does IIS need the intermediate certificates?

Yes, and they must be in the certificate store rather than a chain file. Including them with `-certfile` when building the PFX puts them there during the import.


## References

- [IIS: how to set up SSL](https://learn.microsoft.com/en-us/iis/manage/configuring-security/how-to-set-up-ssl-on-iis) — the certificate store IIS binds from
- [RFC 7292: PKCS #12](https://www.rfc-editor.org/rfc/rfc7292) — the archive format, including the MAC OpenSSL 3 rejects on legacy files

## Related pages

- https://certguru.io/convert/pem-to-pfx/
- https://certguru.io/errors/unsupported-mac-pkcs12-legacy/
- https://certguru.io/formats/pkcs12-pfx-p12/
- https://certguru.io/convert/pem-to-p7b/
- https://certguru.io/platforms/nginx/

--
CertGuru — https://certguru.io
