HarperFast / HarperFast/harper-pro

fix(certificates): add_certificate does not fall back to reading the private key from disk, unlike create_csr

Open
#858 1 comment 0 reactions 1 assignee Claimed by @kriszyp View on GitHub
area:replication bug from-jira
Dominant language
JavaScript
Stars
3
Forks
0
Avg merge
1d 21h
Merged PRs (30d)
80

Description

## Summary

`add_certificate` cannot resolve a private key for a supplied non-CA certificate when the matching key exists on disk but is not in the in-memory `privateKeys` map. The call fails and the certificate is not added, even though the correct key is sitting in the keys directory.

`createCsr` already handles exactly this case with a disk fallback. `addCertificate` does not. The two code paths are inconsistent.

## Root cause

`addCertificate` (`security/certificate.ts`, current `main`) resolves the key by scanning `getPrivateKeys()` only:

```ts
const privateKeys: Map = getPrivateKeys();
...
} else {
// No key provided — search existing keys to see if one matches this cert.
for (const [keyName, key] of privateKeys) {
if (x509Cert.checkPrivateKey(createPrivateKey(key))) { ... }
}
}

if (!is_authority && !private_key && !matchingKeyFound)
throw new ClientError('A suitable private key was not found for this certificate');
```

Per the comment in `createCsr`, that map is populated from **config-referenced paths only**. A Harper-generated CA key that exists on disk but is not named in `tls.privateKey` never appears there, so the lookup fails.

`createCsr` covers this by reading the key from the keys directory by `private_key_name`:

```ts
private_key = await readFile(join(hdbKeysDir, cert.private_key_name));
```

That fallback was added in b454b9a3 ("fix: read Harper CA private key from disk when not in privateKeys Map", 2026-05-13), which did not touch `addCertificate`.

This is reachable on any node where the CA key was auto-generated rather than configured — i.e. the normal state after Harper regenerates a CA, where the key lands as `privateKey.pem`.

## Reproduction

On a node whose Harper CA key exists on disk but is not referenced by `harper-config.yaml`:

1. `create_csr` → returns `pem` and `privateKeyName`
2. `sign_certificate` with that CSR → returns `certificate`
3. `add_certificate` with `name`, `certificate`, `uses: ["replication"]`, `is_authority: false` and **no** `private_key`

Observed: `A suitable private key was not found for this certificate`. `list_certificates` shows the certificate was not added. Passing `private_key` explicitly succeeds.

## Impact

Found during recovery of a 34-node dev cluster on 5.1.15. Because every node in that cluster was in the auto-generated-CA state, `add_certificate` failed on all of them, and no replication certificates were installed.

## Suggested fix

Give `addCertificate` the same disk fallback `createCsr` has: when no key is provided and none matches in the `privateKeys` map, attempt to read the key from the keys directory by `private_key_name` before failing.

## Secondary — needs confirmation on a 5.1.15 build

The failure was originally reported as *silent*: HTTP 200 with the failure text in a bare `message` field (the same field used for success, `"Successfully added certificate: "`), with no `error` key. Repair tooling that checks for a non-2xx status or an `error` key read that as success and continued against an unmodified cluster.

That does not match current source and could not be reproduced from it:

- `security/certificate.ts` **throws** `ClientError`, which sets `statusCode = 400` (core `utility/errors/hdbError.ts:49`), and has done so since Feb 2026 — before 5.1.15.
- Core's error serializer emits `{ error, message, status }` (`server/serverHelpers/contentTypes.ts:47`) and `server/http.ts:829` writes the real status.

So the 200-with-bare-`message` shape is likely specific to the operations UDS client path or to the 5.1.15 build rather than to this operation. Worth confirming separately — if an operation error can reach a caller status-200 and success-shaped, that is a broader operations-API problem than this ticket, and it belongs in core.

## Environment

- harper-pro 5.1.15, single container per host (legacy 1:1 topology)
- Reproduced on multiple nodes via the operations UDS
- Related but distinct: the RSA-only key-parsing defect already tracked separately; that was the root cause of the incident this was found during. This issue is only about key resolution in `add_certificate`.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.