# Doing the TWCA certificate replacement yourself: find the key, build the chain, install, confirm

> The TWCA notice zip holds only the new certificate and needs the original key. How to find the server and key, merge with TWCA's tool or openssl, then install.

Source: https://sheng.page/en/posts/twca-certificate-notice-without-an-engineer/ · Published: 2026-11-05 · Author: Sheng

This guide covers installing the new certificate after a TWCA (Taiwan-CA) replacement notice, for organisations without dedicated IT staff. The zip attached to the notice contains only the new certificate, with no key. Two things are needed before starting: the private key generated when the certificate was first applied for, and someone with permission to manage the server that runs the website. Without either, the certificate cannot be installed.

TWCA's notice of 31 October said the old intermediate certificate would be revoked before 00:00 on 6 November, with no time zone given. A later notice on 5 November says that from 00:00 on 6 November TWCA plans to revoke website certificates whose serial numbers do not meet the randomness requirement. Again no time zone or list of affected certificates is given. Under the path validation rules in RFC 5280, a revoked certificate fails validation; the standard has no grace period and no procedure for asking the issuer for an extension. A site that misses the deadline is fixed the same way as one that meets it, by installing the new certificate as described here. The notice does not say how quickly each browser picks up the revocation, or what its warning looks like, and this post did not test either. TWCA's own account of why it is replacing certificates is that serial numbers had to be brought into line with CA/Browser Forum randomness requirements, and that it was not prompted by a website intrusion or a leaked private key. The serial number issue and the Bugzilla record are covered in [Last year Chunghwa Telecom, this year TWCA: what to check before the 6 November deadline](/en/posts/twca-intermediate-replacement-what-to-check/). Sources for this post were checked up to 04:26 Taipei time on 5 November 2026, and again at 19:30.

Update (5 November 2026, 20:15 Taipei): added TWCA's 5 November notice on website certificate revocation and progress, and the Financial Supervisory Commission's figures for the financial sector. Installation steps now point to each vendor's documentation. Facts checked by Claude, trimmed by Claude Fable, second review by Codex (gpt-6-astra), tone by Grok.

## What the notice is about

When a browser connects over HTTPS, the server sends a stack of certificates: the site's own certificate first, then the intermediates that signed it, up to a root the browser already trusts. That stack is the certificate chain, and the padlock in the address bar means the chain validated. An incomplete chain makes some browsers warn about the very same certificate; see the SSL certificate chains section of [nginx, Configuring HTTPS servers](https://nginx.org/en/docs/http/configuring_https_servers.html#chains).

TWCA is replacing the middle of that chain. The deployment page lists the new chain from the top: TWCA Global Root CA (the root), TWCA CYBER Root CA, TWCA CYBER Root CA G3 Cross Cert, then either TWCA SSL Certification Authority or TWCA EVSSL Certification Authority depending on the type you applied for, then your site certificate. Because the intermediates changed, your site certificate was reissued too, and that is what the zip contains. The UserGuide says the zip holds "only the reissued certificate, no key" and "cannot be installed on a server directly" (translated from the Chinese).

Why does the original key matter? A certificate carries a public key. The server proves it is the site named on the certificate with the matching private key. According to the UserGuide, TWCA reissued from the original certificate signing request (CSR), so the new certificate still matches the key generated back then. TWCA's documents cannot say where that key is kept; the next section is about finding it.

The deployment page adds two warnings. Anyone who has hard-coded the chain into an app or onto a host should deploy the new chain early; see Android's [Network security configuration](https://developer.android.com/privacy-and-security/security-config). The new chain no longer supports clientAuth, meaning the server asking the browser for a certificate in return, so anyone relying on it needs to ask TWCA about an AP certificate; see Tomcat's [SSL/TLS Configuration How-To](https://tomcat.apache.org/tomcat-11.0-doc/ssl-howto.html). If unsure whether either applies, ask whoever built the app or system.

## Three things to find first: the server, a login, the original key

### Where the server is

The certificate goes on the machine that answers HTTPS for visitors; the computer the email arrived on is only where the tool runs. The server may be on your own premises, at a hosting company, in a cloud account, or on a machine a contractor set up. The notice went to the original applicant and the zip is named after the company registration number, so start with whoever applied, then with whoever the organisation pays each month for the website. Where the domain's DNS points is another clue; without access to the domain settings, skip this one. If a program such as Tomcat sits behind Apache or IIS, the front server handles SSL, as the Tomcat documentation explains. If a CDN or load balancer terminates TLS in front of the site, the browser sees that layer's certificate. The affected TWCA certificate may be on that layer, on the origin behind it, or on both. The two connections are set out in Cloudflare's [SSL/TLS concepts](https://developers.cloudflare.com/ssl/concepts/). If it is unclear whether there is a front layer, carry on; the section on server types sometimes reveals it.

### Who can log in

TWCA's tool runs on your own computer and produces a merged file. Installing it needs someone who can log in to the server: on Windows, Remote Desktop or IIS Manager rights; on Linux, an SSH account plus permission to edit configuration and restart services. If nobody in the organisation has this, find the original administrator, the contractor or the hosting provider. If a contractor maintains the site, check first whether they still have access. Until this is solved, no amount of file preparation gets the certificate installed, so tell a manager before spending more time on the files.

### The original key

The UserGuide accepts any one of three files:

- A `.key` file (sometimes `.pem`), generated together with the original CSR.
- A `.pfx` or `.p12` file, common on IIS and Windows, which must contain the original key.
- A `.jks` or `.keystore` file, the Java and Tomcat keystore, which must also contain the original key.

Where to look depends on the server:

- Nginx: someone who can log in runs `grep -r ssl_certificate_key /etc/nginx/` on the server, not on the computer that received the email; the file named on that line is the private key.
- Apache: the file named by `SSLCertificateKeyFile` in the configuration is the private key.
- IIS: the private key lives in the Windows certificate store, not as a separate file, and has to be exported as a PFX with a password; see Microsoft's [Export a certificate with its private key](https://learn.microsoft.com/en-us/windows-server/identity/ad-cs/export-certificate-private-key) (no Windows machine was available for this post, so this was not tested). If nobody has done it before, pass that document to the hosting provider and work through it together.
- Tomcat: the JKS or PKCS12 file named by `certificateKeystoreFile` in `server.xml`.

Some common situations:

- You only have a `.cer` or `.crt`. That is a certificate file with no private key; the UserGuide error "no private key found in file" (translated) refers to exactly this.
- The password is forgotten. The UserGuide asks people using PFX and JKS to have the old file password ready; a `.key` file needs one only if one was set. For a lost password the UserGuide says to ask the system administrator, meaning the people from the previous section. The OpenSSL documentation has no procedure for recovering a forgotten one.
- Not found yet, but not confirmed lost (including a password nobody can supply). Ask the administrator or contractor first, and do not delete any old file until the new certificate is confirmed working.
- The key is definitely lost. The UserGuide says this reissue reuses the original key and the new certificate cannot be used without it; contact TWCA support and apply again with a CSR from a new key. That takes time, so settle it early.

### What kind of server it is

The old file type is a strong hint. The UserGuide maps PFX to IIS, Windows Server, Exchange and appliances such as F5 and FortiGate; JKS to Java systems such as Tomcat, WebLogic, WebSphere and JBoss; PEM to Nginx and Apache 2.4.8 or later. From outside, open a terminal on any computer and run the line below with `www.example.test` replaced by the site's own address; it shows whether the response names the server software:

```bash
curl -sI https://www.example.test/ | grep -i '^server:'
```

In testing (curl 8.7.1), the TWCA site returned `Server: Apache`, the MODA site `server: cloudflare`, and the Chunghwa Post site no such field. A value like `cloudflare` means a CDN sits in front and says nothing about the server behind it. A missing field can also mean the request itself failed, since `-s` hides error messages. If it is still unclear, ask whoever applied or the hosting provider.

## Route A: a Windows computer and TWCA's replacement tool

This is the route TWCA provides. The following summarises the UserGuide. No Windows machine was available for this post, so the tool itself was not tested.

Have three things ready: the zip from the notice (saved whole, not extracted), the old key or certificate file (one of the three above) and its password. CertReplaceTool.zip and the UserGuide come from the [deployment page](https://twiddemo.twca.com.tw/acme/replace_cert.html), separate from the zip attached to the notice. Extract CertReplaceTool.zip completely into any folder and double-click `CertReplaceTool.exe`. If Windows shows "Windows protected your PC", the UserGuide says to click "More info" and then "Run anyway". That prompt is Microsoft SmartScreen; see [SmartScreen reputation](https://learn.microsoft.com/en-us/windows/apps/package-and-deploy/smartscreen-reputation). Before running the program, confirm it came from TWCA's deployment page. The UserGuide states that the tool runs entirely on your computer and uploads no files or passwords. That is the UserGuide's statement; this post did not verify it.

The screen has five steps from top to bottom:

1. Choose the zip from the notice. The tool shows the company registration number (the zip file name), company name, domain, validity period and issuing CA. Confirm it is your site; if anything is wrong, stop and contact SSLCC@twca.com.tw.
2. Choose the old file, one of three, and enter its password; a `.key` without a password can be left blank. If the private key inside a JKS has a different password, the tool asks for it during conversion. When producing PEM, the tool checks that the key and the new certificate match.
3. Root certificate. The UserGuide says to choose the matching root file only if the system administrator asks for a "full chain including the root"; a wrong choice can be cleared. If nobody has asked, skip it: servers generally do not need to send the root, because browsers already have it in their trust store.
4. Output format and new password. If the site used PFX before, choose PFX; if JKS, choose JKS; for Nginx and Apache, choose PEM. PEM is a single file with the site certificate and intermediates combined (a fullchain), with no key and no password. For PFX and JKS the new password is at least six characters, entered twice, with a "same as old password" option, and you will need it when installing. The PFX encryption is chosen by the tool: if the old file was a PFX it keeps that file's method; if the old file was a `.key` or a JKS it uses "the same method as the Windows default, compatible with older Windows" (translated).
5. Save location, defaulting to the zip's folder. Click "Start conversion". The tool checks that key and certificate match and that the chain is complete, then re-reads the result. The success screen shows the new file's location, certificate name, validity period and chain. For JKS, use the alias shown on that screen.

Afterwards, keep the old key, PFX or JKS until the new certificate is confirmed working. Hand the new file and its password to whoever installs on the server; if they need a PFX or JKS that contains the private key, agree first on who receives it and how, and do not send it through an open group chat or ordinary email.

The UserGuide also gives installation steps. All four are carried out on the server, not on the computer where the tool ran. If someone else does the login, hand them the new file, the password and these steps:

- IIS: in IIS Manager, open Server Certificates, import the new PFX, then in the site's Bindings switch https to the new certificate; the PFX import steps are in Microsoft's [Import a Server Authentication Certificate](https://learn.microsoft.com/en-us/windows-server/identity/ad-fs/deployment/import-a-server-authentication-certificate-to-the-default-web-site), and the HTTPS binding screens in [How to Set Up SSL on IIS](https://learn.microsoft.com/en-us/iis/manage/configuring-security/how-to-set-up-ssl-on-iis).
- Nginx: point `ssl_certificate` at the fullchain.pem the tool produced, leave `ssl_certificate_key` on the existing `.key`, run `nginx -t`, then `nginx -s reload`; the tested output is in the Nginx section below.
- Apache 2.4.8 or later: point `SSLCertificateFile` at the `<CN>_fullchain.pem` file, leave `SSLCertificateKeyFile` alone, and comment out any `SSLCertificateChainFile`, which is deprecated from 2.4.8; see Apache's [mod_ssl](https://httpd.apache.org/docs/2.4/mod/mod_ssl.html#sslcertificatechainfile).
- Tomcat: point the keystore in `server.xml` at the new JKS or PFX, update the password and restart, using the alias from the success screen; the settings are in Tomcat's [HTTP Connector](https://tomcat.apache.org/tomcat-11.0-doc/config/http.html) reference.

## Route B: no Windows, or a preference for the command line

macOS ships LibreSSL as `/usr/bin/openssl`, and most Linux systems have OpenSSL. The openssl commands below run on an ordinary computer: open a terminal and move into a new empty directory. The Nginx and Apache edits come later, after logging in to the server. This section covers checking the key, converting to PEM, building the chain and making a PFX; converting to JKS was not tested, so for a JKS go back to Route A and TWCA's tool. Commands and output marked as tested were run between 03:48 and 04:26 Taipei time on 5 November 2026 on macOS (LibreSSL 3.3.6 and Homebrew OpenSSL 4.1.0) and Ubuntu (OpenSSL 3.0.13, nginx 1.24.0). The site certificate and key are practice files signed by a test CA; the TWCA intermediates are the real files from the deployment page.

### Before starting: a fresh directory and backups

Three precautions first. They are standard practice and were not each tested here:

- Work in a new, empty directory rather than in the server's live certificate directory.
- Copy the current certificate, key and configuration files and note their original paths, so the old setup can be restored.
- Treat the original key as read-only. Every command below only reads it, and every new file gets a new name so nothing is overwritten.

For a rehearsal, this script creates practice files in a separate empty directory: `new.crt`, `server.key`, and a deliberately wrong `other.key`. It generates new keys, so run it only in a practice directory, never where the original key is kept:

```sh
#!/bin/sh
# Practice files only: a test CA, a test site certificate and keys. Not for production.
set -eu
O="${OPENSSL:-openssl}"
$O req -x509 -newkey rsa:2048 -nodes -keyout root.key -out root.pem -days 30 -subj "/CN=Test Root" 2>/dev/null
$O req -newkey rsa:2048 -nodes -keyout int.key -out int.csr -subj "/CN=Test Intermediate" 2>/dev/null
printf 'basicConstraints=critical,CA:true\nkeyUsage=critical,keyCertSign,cRLSign\n' > ca.ext
$O x509 -req -in int.csr -CA root.pem -CAkey root.key -CAcreateserial -out int.pem -days 30 -extfile ca.ext 2>/dev/null
$O req -newkey rsa:2048 -nodes -keyout server.key -out server.csr -subj "/CN=www.example.test" 2>/dev/null
printf 'subjectAltName=DNS:www.example.test\nextendedKeyUsage=serverAuth\n' > leaf.ext
$O x509 -req -in server.csr -CA int.pem -CAkey int.key -CAcreateserial -out new.crt -days 30 -extfile leaf.ext 2>/dev/null
$O genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out other.key 2>/dev/null
```

In testing it ran in an empty directory created with `mktemp -d` and left `new.crt`, `server.key`, `other.key`, `int.pem`, `root.pem` and a few other files behind. The commands below use those names for a rehearsal. For the real change, unzip the notice attachment, replace `new.crt` with the certificate file inside it, and replace `server.key` with the path to the original key. TWCA's documents do not give that file's name or say whether it is DER or PEM; the next section shows how to check.

### Convert everything that goes into the chain to PEM

Certificate files come in two common encodings. PEM is text and starts with `-----BEGIN CERTIFICATE-----`; DER is binary. The extension does not tell them apart: of the five `.cer` files on the deployment page, `TWCA CYBER Root CA.cer` is DER and the other four are PEM, and TWCA's documents do not say which encoding the new certificate in the zip uses (unverified).

Tools behave differently too. In testing, OpenSSL 4.1.0 read that DER file without being told its format and failed only when `-inform PEM` was given explicitly; LibreSSL 3.3.6 failed outright without `-inform DER`:

```text
unable to load certificate
```

So a file that opens is not necessarily PEM. To confirm PEM, read it with `-inform PEM` stated explicitly:

```bash
openssl x509 -inform PEM -in new.crt -noout -subject
```

If that fails, treat the file as DER and write a PEM copy under a new name, leaving the original alone:

```bash
openssl x509 -inform DER -in TWCA_CYBER_Root_CA.cer -out TWCA_CYBER_Root_CA.pem
```

This converted successfully under both LibreSSL 3.3.6 and OpenSSL 4.1.0 in testing; read the result back with `-inform PEM` to confirm. Every file that goes into the chain, including the new certificate from the zip, should be confirmed as PEM first.

### Check that the original key matches the new certificate

Hash the public key from the certificate and the public key derived from the private key, then compare:

```bash
openssl x509 -in new.crt -noout -pubkey | openssl sha256
openssl pkey -in server.key -pubout | openssl sha256
```

Tested output (OpenSSL 4.1.0), two identical lines:

```text
SHA2-256(stdin)= 6de5d1f3996c5975abe0fbc2a51080aa3482bb870ceb02ca95cbad48618bd127
SHA2-256(stdin)= 6de5d1f3996c5975abe0fbc2a51080aa3482bb870ceb02ca95cbad48618bd127
```

With the wrong `other.key`, the second line changes:

```text
SHA2-256(stdin)= 9fbae34166da61daeeedb1cc43b9b201811acce5c5052570efff6bd7028c94d5
```

LibreSSL 3.3.6 prints the hash without the prefix, and both lines read:

```text
6de5d1f3996c5975abe0fbc2a51080aa3482bb870ceb02ca95cbad48618bd127
```

Before trusting a match, check that neither command printed an error: when a file cannot be read, openssl prints an error, but `sha256` still hashes the empty input, and the two lines then agree. Tested with two files that do not exist (OpenSSL 4.1.0):

```text
Could not open file or uri for loading certificate from missing.crt: No such file or directory
SHA2-256(stdin)= e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
Could not open file or uri for loading private key of key from missing.key: No such file or directory
SHA2-256(stdin)= e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
```

A value starting with `e3b0c442` is the hash of nothing, so it means the previous step failed, and a match on it means nothing. Two different values mean the key does not belong to the certificate in the zip: possibly another site's key, or a zip that is not from this notice. If the `.key` has a password, `openssl pkey` stops and asks for it; the terminal shows nothing while the password is typed, which is normal, so press Enter at the end. Later prompts for a PFX password behave the same way.

With only an old PFX there is no need to extract the private key. This reissue reuses the original key, so the certificate inside the old PFX should carry the same public key as the new one, and those two can be compared directly:

```bash
openssl pkcs12 -in old.pfx -nokeys -clcerts | openssl x509 -noout -pubkey | openssl sha256
openssl x509 -in new.crt -noout -pubkey | openssl sha256
```

The first command asks for the PFX password. In testing, an `old.pfx` was built from the same practice key, the password was passed with `-passin`, and both lines gave the value below (this rehearsal generated fresh keys, hence a different hash from the one above):

```text
SHA2-256(stdin)= ec23ca974da08575800ea508b1ca26bd7ee86b0c97b3b28a5af2ce696d0041e0
```

### Build the fullchain

First check who signed the new certificate, which decides the intermediate to attach:

```bash
openssl x509 -in new.crt -noout -issuer
```

TWCA SSL Certification Authority means the ordinary SSL intermediate; TWCA EVSSL Certification Authority means the EV one. For the order after that, follow what sites already on the new chain send. At 03:49 on 5 November 2026, `openssl s_client -showcerts` against www.twca.com.tw, www.moda.gov.tw and www.post.gov.tw showed all three sending four certificates. This is the tested output for www.moda.gov.tw (OpenSSL 4.1.0, filtered to the `s:` and `i:` lines):

```text
 0 s:C=TW, ST=Taiwan, L=Taipei, O=Ministry of Digital Affairs, CN=*.moda.gov.tw
   i:C=TW, O=TAIWAN-CA, CN=TWCA SSL Certification Authority
 1 s:C=TW, O=TAIWAN-CA, CN=TWCA SSL Certification Authority
   i:C=TW, O=TAIWAN-CA, CN=TWCA CYBER Root CA G3
 2 s:C=TW, O=TAIWAN-CA, CN=TWCA CYBER Root CA G3
   i:C=TW, O=TAIWAN-CA, OU=Root CA, CN=TWCA CYBER Root CA
 3 s:C=TW, O=TAIWAN-CA, OU=Root CA, CN=TWCA CYBER Root CA
   i:C=TW, O=TAIWAN-CA, OU=Root CA, CN=TWCA Global Root CA
```

The first entry is the site certificate. None of the three sends TWCA Global Root CA itself, which sits in browsers' trust stores; the macOS system roots include it. The fullchain is therefore four certificates in order, all as PEM: the site certificate, the SSL or EVSSL CA, the G3 Cross Cert, then CYBER Root CA. Download the intermediates needed from the deployment page into this directory first and convert any DER file to PEM as above. The names below are the deployment page's file names with spaces replaced by underscores and a `.pem` extension; if a downloaded name differs, use the real one. The output file gets a new name:

```bash
cat new.crt TWCA_SSL_Certification_Authority.pem TWCA_CYBER_Root_CA_G3_Cross_Cert.pem TWCA_CYBER_Root_CA.pem > fullchain-new.pem
openssl crl2pkcs7 -nocrl -certfile fullchain-new.pem | openssl pkcs7 -print_certs -noout
```

The second command lists the subject and issuer of each certificate in the file. In testing the first entry was the practice certificate, so its issuer is Test Intermediate; in a real change it should be TWCA SSL or EVSSL Certification Authority, with each certificate issued by the next:

```text
subject=CN=www.example.test
issuer=CN=Test Intermediate

subject=C=TW, O=TAIWAN-CA, CN=TWCA SSL Certification Authority
issuer=C=TW, O=TAIWAN-CA, CN=TWCA CYBER Root CA G3

subject=C=TW, O=TAIWAN-CA, CN=TWCA CYBER Root CA G3
issuer=C=TW, O=TAIWAN-CA, OU=Root CA, CN=TWCA CYBER Root CA

subject=C=TW, O=TAIWAN-CA, OU=Root CA, CN=TWCA CYBER Root CA
issuer=C=TW, O=TAIWAN-CA, OU=Root CA, CN=TWCA Global Root CA
```

The listing shows what the file contains and in what order, not that the chain validates; that is what `openssl verify` is for. The practice files have a single intermediate; tested command and output:

```bash
openssl verify -CAfile root.pem -untrusted int.pem new.crt
```

```text
new.crt: OK
```

The real TWCA chain was checked too, with Global Root as the trust anchor, CYBER Root CA (as PEM) and the G3 Cross Cert as intermediates, verifying the SSL CA certificate. OpenSSL 4.1.0 and LibreSSL 3.3.6 both printed:

```bash
cat TWCA_CYBER_Root_CA.pem TWCA_CYBER_Root_CA_G3_Cross_Cert.cer > untrusted.pem
openssl verify -CAfile TWCA_Global_Root_CA.cer -untrusted untrusted.pem TWCA_SSL_Certification_Authority.cer
```

```text
TWCA_SSL_Certification_Authority.cer: OK
```

To check the site's own certificate, add the SSL or EVSSL CA to `untrusted.pem` and give the new certificate as the last argument; a successful check should print `OK`. This post had no real TWCA site certificate, so this step is untested.

### Nginx

After logging in to the server, find the current configuration line. The command below was run against a test configuration file, so go by the path it prints on the real server:

```bash
grep -r ssl_certificate_key /etc/nginx/
```

Copy `fullchain-new.pem` to the server, update the certificate path, and keep the private key path pointing at the original file. The paths below are only an example:

```nginx
ssl_certificate     /etc/nginx/ssl/fullchain-new.pem;
ssl_certificate_key /etc/nginx/ssl/server.key;
```

Then run `nginx -t`. With a mismatched key, nginx 1.24.0 refused the configuration in testing:

```text
[emerg] ... SSL_CTX_use_PrivateKey(".../other.key") failed (SSL: error:05800074:x509 certificate routines::key values mismatch)
nginx: configuration file .../nginx.conf test failed
```

With the matching key:

```text
nginx: the configuration file .../nginx.conf syntax is ok
nginx: configuration file .../nginx.conf test is successful
```

Only when `nginx -t` passes, run `nginx -s reload`; in testing the error log showed a single `signal process started` line afterwards. If `nginx -t` fails, do not reload; restore the backed-up configuration. The nginx documentation says the key file should have restricted permissions while staying readable by the master process.

### IIS: making a PFX

IIS needs a PFX that contains the private key. Combine the three intermediates into one file, then bundle the key, the new certificate and the intermediates; openssl asks for a new password:

```bash
cat TWCA_SSL_Certification_Authority.pem TWCA_CYBER_Root_CA_G3_Cross_Cert.pem TWCA_CYBER_Root_CA.pem > intermediates.pem
openssl pkcs12 -export -inkey server.key -in new.crt -certfile intermediates.pem -out new.pfx
```

The test used the practice files (`-certfile int.pem`). OpenSSL 4.1.0's default encryption, as shown by `openssl pkcs12 -in new.pfx -info -noout`, opens with:

```text
MAC: sha256, Iteration 2048
MAC length: 32, salt length: 16
PKCS7 Encrypted data: PBES2, PBKDF2, AES-256-CBC, Iteration 2048, PRF hmacWithSHA256
```

Some Windows versions cannot import that. Microsoft's troubleshooting article says affected versions of Windows and Windows Server do not support AES256-SHA256 encryption for imported PFX files, that the import fails with a message resembling "The password you entered is incorrect", and that the workaround is TripleDES-SHA1; newer versions support both. The article does not list the affected versions one by one; a post on the darkthread blog (a personal technical blog, 11 May 2024) records Windows Server 2012 R2 and 2016. Check the Windows version first, and build the 3DES variant only if the import fails with that error:

```bash
openssl pkcs12 -export -inkey server.key -in new.crt -certfile intermediates.pem -keypbe PBE-SHA1-3DES -certpbe PBE-SHA1-3DES -macalg sha1 -out new-legacy.pfx
```

Built from the practice files in testing, its `-info` output opens with:

```text
MAC: sha1, Iteration 2048
MAC length: 20, salt length: 16
PKCS7 Encrypted data: pbeWithSHA1And3-KeyTripleDES-CBC, Iteration 2048
```

No Windows machine was available, so neither PFX was actually imported. The import and binding follow the IIS step in Route A.

The key only needs extracting when the old file is a PFX and Nginx needs that key. `-nodes` writes the private key unencrypted, so restrict permissions first and write to a new file:

```bash
(umask 077; openssl pkcs12 -in old.pfx -nocerts -nodes -out old-key.pem)
```

In testing (macOS, OpenSSL 4.1.0) the resulting file had permissions `-rw-------`, readable only by its owner, and its public key hash matched the original key. Keep the extracted key in a restricted directory and delete spare copies afterwards. For a pairing check alone, the two old-PFX commands earlier are enough.

### Apache and Tomcat

On Apache 2.4.8 or later, follow the Apache step in Route A with `SSLCertificateFile` pointing at `fullchain-new.pem`, run `apachectl configtest` (see Apache's [apachectl](https://httpd.apache.org/docs/2.4/programs/apachectl.html)) and reload only if it passes. The Apache documentation says the key file should be readable by root only; see [SSLCertificateKeyFile](https://httpd.apache.org/docs/2.4/mod/mod_ssl.html#sslcertificatekeyfile). Tomcat supports PKCS12, but check the keystore type, password and alias against the Tomcat and Java versions in use before switching; see Tomcat's [SSL/TLS Configuration How-To](https://tomcat.apache.org/tomcat-11.0-doc/ssl-howto.html). Check the keystore type, password and `certificateKeyAlias` in `server.xml` against the [HTTP Connector](https://tomcat.apache.org/tomcat-11.0-doc/config/http.html) reference, since a new PFX may not carry the alias the existing configuration names. Neither Apache nor Tomcat was run for this post, and the keytool route to JKS was not tested. If in doubt, hand the new file, the password and the alias to whoever maintains the server, and take the reload or restart command from the vendor documentation.

## Confirming it worked

- Open the site in a browser, click the padlock and check that the validity period is the new certificate's. This is the UserGuide's check; if there is no padlock, skip it and use the checks below.
- Enter the site name on TWCA's SSL check page, linked from the [deployment page](https://twiddemo.twca.com.tw/acme/replace_cert.html).
- From outside, validate the chain the server sends and confirm the name matches: `-servername` only tells the server which site is wanted, and `-verify_hostname` is what checks the name on the certificate. The command and output below are the tested run for www.moda.gov.tw; to check another site, change the three copies of the address to that site's domain:

```bash
openssl s_client -connect www.moda.gov.tw:443 -servername www.moda.gov.tw -verify_hostname www.moda.gov.tw </dev/null
```

Tested at 04:26 Taipei time on 5 November 2026 (OpenSSL 4.1.0), the output ends with:

```text
Verification: OK
Verify return code: 0 (ok)
```

With `-verify_hostname` deliberately set to a different name, the same site gave:

```text
Verify return code: 62 (hostname mismatch)
```

LibreSSL 3.3.6 also returned `Verify return code: 0 (ok)` for the same site. None of these commands checks revocation status.

- Confirm that the certificate now being served is the new one: print the serial number of the first certificate the site sends and of the new certificate from the zip, and compare. Replace www.moda.gov.tw in the same way, and `new.crt` with the new certificate from the zip:

```bash
openssl s_client -connect www.moda.gov.tw:443 -servername www.moda.gov.tw </dev/null 2>/dev/null | openssl x509 -noout -serial -enddate -issuer
openssl x509 -in new.crt -noout -serial -enddate -issuer
```

Tested output for the MODA site:

```text
serial=47EA00000009B606E581A8DE645A11FE
notAfter=Dec 16 15:59:59 2026 GMT
issuer=C=TW, O=TAIWAN-CA, CN=TWCA SSL Certification Authority
```

The new certificate is live only when both commands print the same serial. In the Ubuntu nginx rehearsal, the served serial matched `new.crt`.

- In the practice setup (127.0.0.1:8443, with `-CAfile root.pem` naming the test root), the result was `Verify return code: 21 (unable to verify the first certificate)` with only the site certificate configured and no intermediate, and `0 (ok)` with the fullchain:

```text
 0 s:CN = www.example.test
Verify return code: 21 (unable to verify the first certificate)
```

```text
 0 s:CN = www.example.test
   i:CN = Test Intermediate
 1 s:CN = Test Intermediate
   i:CN = Test Root
Verify return code: 0 (ok)
```

- Where a CDN or load balancer terminates TLS in front of the site, the browser and `s_client` both see the front-end certificate. The MODA site's response headers gave `server: cloudflare` in testing, which is exactly this case. If the connection from there to the origin also uses HTTPS, whether the origin uses an affected certificate has to be checked separately; looking from outside cannot confirm both connections.
- An app that binds the chain needs a connection test with the updated app; a system that uses clientAuth needs the AP certificate route on the deployment page. Neither was tested here.

## When something fails

Error messages appear in three places: on the TWCA tool's screen, in the server's own log, and on the page the browser shows visitors. The wording differs in each. Before calling support, note which screen or log the error appeared in.

For the tool's messages, section 5 of the UserGuide gives the meaning. The messages below are translations of the Chinese UserGuide, not observed English interface text:

- "Old key does not match the new certificate in the zip": you chose another site's key or old file, or the zip is not the attachment from this notice. Check the domain matches, or switch to the PFX or JKS currently in use on the server.
- "Old file password incorrect": check case and full-width versus half-width characters; for a lost password, follow the original key section above, and do not delete the file.
- "This key file is password protected": enter the `.key` file's password in the old-password field.
- "No private key found in file": you chose a certificate file (`.cer`, `.crt`) rather than a key file.
- "No private key in old file": this PFX or JKS holds only a certificate; choose the one in use on the server that includes the key.
- "No certificate file found in zip": make sure you chose the original attachment from the notice.
- "Root certificate does not match this chain": the wrong file was chosen in step 3.

On the server side:

- Nginx `key values mismatch`: the key does not match the first certificate in the `ssl_certificate` file. Either the key is wrong (go back to the pairing check) or the fullchain is in the wrong order; the site certificate must come first.
- `Verify return code: 21`: in this post's test, the cause was a server sending only the site certificate and no intermediates, typically because `ssl_certificate` still points at the old single certificate or the fullchain was built wrongly. The same code can have other causes, so read the full message.
- Other Nginx `[emerg]` lines: `nginx -t` names the file. The log location is in nginx's [`error_log`](https://nginx.org/en/docs/ngx_core_module.html#error_log) reference, and Apache's in [Log Files](https://httpd.apache.org/docs/2.4/logs.html#errorlog).
- If Tomcat reports a keystore password or alias error at startup, check the keystore settings in `server.xml`; see Tomcat's [SSL/TLS Configuration How-To](https://tomcat.apache.org/tomcat-11.0-doc/ssl-howto.html). If IIS reports that the certificate has no private key, import a PFX that includes the key, since a certificate-only file will not do; see Microsoft's [IIS certificate troubleshooting](https://learn.microsoft.com/en-us/troubleshoot/developer/webapps/iis/www-authentication-authorization/troubleshooting-ssl-related-issues-server-certificate).

What to give support or anyone helping: the domain, the zip file name, the server type and version, which step you reached, the exact error text, and the relevant log lines. Do not send private keys, passwords or files containing private keys; the SSL Labs deployment guide wants as few people as possible handling the key. Whether TWCA support accepts files or performs installations is not covered by its documents, and this post does not guess; ask on the call.

## One page before the call

- The domain and the zip file name (the company registration number).
- Where the site runs, who can log in, and the contractor's or hosting provider's contact details.
- Which kind of key file exists, where it is, and whether it has a password.
- The type and version of the server or appliance.
- Which step you reached, and the exact error text and where it appeared.
- Whether any app binds the chain or uses client authentication (the clientAuth mentioned earlier).

When contacting support on (02) 2370-8886 ext. 9 or at SSLCC@twca.com.tw, state what you know and mark what is still unconfirmed.

## Still unknown

- The time zone for 00:00 on 6 November, and the list and fingerprints of the old intermediates being revoked; the notices still give neither.
- The file format (DER or PEM) and file name of the new certificate inside the zip; TWCA's documents do not say, so check it as the section on converting to PEM describes.
- How to run the replacement tool on macOS or Linux; neither the deployment page nor the UserGuide says.
- How many certificates are still unreplaced. TWCA's 5 November notice says more than 85% of customer websites across government, finance and other sectors had been updated by 10:30 that day; the Financial Supervisory Commission said the financial sector had about 4,190 certificates, roughly 95% done by 14:30; MODA's government figure still stops at 926 on the evening of 2 November. There is no separate figure for private companies.
- Which serial numbers count as non-compliant under TWCA's 5 November notice, and how to check whether a given site certificate is among them; the notice does not say.
- The full report on the CA certificate serial number incident, which TWCA committed to in [Bugzilla 2087236 Comment 3](https://bugzilla.mozilla.org/show_bug.cgi?id=2087236#c3) for 19:00 UTC on 12 November.

## Notes

- The zip contains only the new certificate. It needs the original key from the CSR and someone who can log in to the server; without either, nothing gets installed.
- Where the original key is depends on the server: `ssl_certificate_key` on Nginx, `SSLCertificateKeyFile` on Apache, an exported PFX with key from the certificate store on IIS, the keystore in `server.xml` on Tomcat.
- Comparing public key hashes shows whether key and certificate are a pair, provided neither command printed an error; a value starting with `e3b0c442` is the hash of empty input. The fullchain is the site certificate, the SSL or EVSSL CA, the G3 Cross Cert and CYBER Root CA, all converted to PEM first.
- Back up the current files first and give every new file a new name. A mismatched key fails `nginx -t` with key values mismatch; reload only after it passes. Apache, IIS and Tomcat installs were not tested here. Follow the UserGuide's four steps and the vendor documentation.
- To confirm, check the name with `-verify_hostname` and compare the served serial with the new certificate's. A PFX for IIS defaults to AES; some Windows versions need 3DES, and neither was tested on Windows here.
- Error messages live in three places, the tool's screen, the server log and the browser page; what you send to support never includes the private key or a password.

## Further reading

- [TWCA progress and revocation notice, 5 November 2026](https://www.twca.com.tw/news_detail/86016103-e8c0-4f4e-806b-654ea2264d04) (Chinese): TWCA's own account of update progress and the revocation of non-compliant website certificates.
- [CNA, 5 November 2026](https://www.cna.com.tw/news/afe/202611050296.aspx) (Chinese): the Financial Supervisory Commission's certificate count and progress for the financial sector, as reported.
- [TWCA SSL certificate replacement notice](https://ssl.twca.com.tw/news_detail/5f3395bf-bef6-4b40-b922-ceac4b06bf53) (Chinese): the issuer's notice of 31 October 2026 setting the 6 November deadline.
- [TWCA notice of 2 November 2026](https://twca.com.tw/news_detail/f18a3be8-5513-4ed5-b8f9-c5d468c82aec) (Chinese): TWCA's own account of why it is replacing certificates.
- [TWCA TLS/SSL chain update page](https://twiddemo.twca.com.tw/acme/replace_cert.html) (Chinese): the five chain files, the clientAuth warning, the replacement tool with its UserGuide, and the SSL check page.
- [MODA press release](https://web.moda.gov.tw/press/press-releases/21226) (Chinese): 2 November 2026, government certificate counts and that evening's progress.
- [nginx, Configuring HTTPS servers](https://nginx.org/en/docs/http/configuring_https_servers.html#chains): chain order, `ssl_certificate`, key file permissions and the cause of key values mismatch.
- [nginx `error_log`](https://nginx.org/en/docs/ngx_core_module.html#error_log): where the error log goes and its default.
- [Apache mod_ssl `SSLCertificateChainFile`](https://httpd.apache.org/docs/2.4/mod/mod_ssl.html#sslcertificatechainfile): deprecated from 2.4.8, intermediates move to `SSLCertificateFile`.
- [Apache, Log Files](https://httpd.apache.org/docs/2.4/logs.html#errorlog): the ErrorLog location.
- [Microsoft, Import a Server Authentication Certificate](https://learn.microsoft.com/en-us/windows-server/identity/ad-fs/deployment/import-a-server-authentication-certificate-to-the-default-web-site): importing a PFX under Server Certificates in IIS Manager.
- [Microsoft, How to Set Up SSL on IIS](https://learn.microsoft.com/en-us/iis/manage/configuring-security/how-to-set-up-ssl-on-iis): the Server Certificates and Bindings screens; [certutil](https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/certutil) for `-importPFX`; [IIS certificate troubleshooting](https://learn.microsoft.com/en-us/troubleshoot/developer/webapps/iis/www-authentication-authorization/troubleshooting-ssl-related-issues-server-certificate).
- [Microsoft, SmartScreen reputation](https://learn.microsoft.com/en-us/windows/apps/package-and-deploy/smartscreen-reputation): where the "Windows protected your PC" prompt comes from.
- [Apache Tomcat, SSL/TLS Configuration How-To](https://tomcat.apache.org/tomcat-11.0-doc/ssl-howto.html): JKS and PKCS12, aliases, and client authentication.
- OpenSSL [`openssl-pkcs12`](https://docs.openssl.org/master/man1/openssl-pkcs12/), [`openssl-x509`](https://docs.openssl.org/master/man1/openssl-x509/), [`openssl-s_client`](https://docs.openssl.org/master/man1/openssl-s_client/), [`openssl-req`](https://docs.openssl.org/master/man1/openssl-req/) and [format options](https://docs.openssl.org/master/man1/openssl-format-options/): the commands used in this post.
- [Microsoft, Can't import an AES256-SHA256-encrypted PFX certificate](https://learn.microsoft.com/en-us/troubleshoot/windows-server/certificates-and-public-key-infrastructure-pki/cannot-import-aes256-sha256-encrypted-pfx-certificate): affected Windows versions reject AES256-SHA256 PFX files; the workaround is TripleDES-SHA1.
- [Microsoft, Export a certificate with its private key](https://learn.microsoft.com/en-us/windows-server/identity/ad-cs/export-certificate-private-key): exporting a certificate and key from Windows.
- [Apache, apachectl](https://httpd.apache.org/docs/2.4/programs/apachectl.html): the `configtest` check.
- [Apache Tomcat, HTTP Connector](https://tomcat.apache.org/tomcat-11.0-doc/config/http.html): keystore type, password and `certificateKeyAlias`.
- [OpenSSL, verification options](https://docs.openssl.org/master/man1/openssl-verification-options/): `-verify_hostname` and related options.
- [darkthread, openssl-exported PFX rejected on Windows](https://blog.darkthread.net/blog/openssl-pfx-windows-issue/) (Chinese): a personal technical blog, 11 May 2024, on older Windows and AES-encrypted PFX files.
- [SSL Labs, SSL and TLS Deployment Best Practices](https://github.com/ssllabs/research/wiki/SSL-and-TLS-Deployment-Best-Practices): private key handling and chain completeness.
- [RFC 5280](https://www.rfc-editor.org/rfc/rfc5280#section-6.1.3): path validation requires the certificate to be within its validity period and not revoked, with no grace period.
- [Android, Network security configuration](https://developer.android.com/privacy-and-security/security-config): how certificate pinning in apps works.
- [Cloudflare, SSL/TLS concepts](https://developers.cloudflare.com/ssl/concepts/): the edge certificate and the origin certificate cover two separate connections.
- [Last year Chunghwa Telecom, this year TWCA: what to check before the 6 November deadline](/en/posts/twca-intermediate-replacement-what-to-check/): serial entropy, the Bugzilla record, and checking the chain a server sends from outside.

> Ideas and technical judgement by Sheng; drafted with Claude · Drafted by Claude Fable, question list and official documentation lookup by Grok, second review by Codex (gpt-6-astra), further testing and revision by Claude, trimmed by Claude Fable, tone by Grok; commands marked as tested were run on macOS (LibreSSL 3.3.6, OpenSSL 4.1.0) and Ubuntu (OpenSSL 3.0.13, nginx 1.24.0), sources checked to 04:26 Taipei time on 5 November 2026; TWCA's notices and progress figures rechecked at 19:30, without rerunning the commands.