From 8476b35cf6999939189cdf05cd7a91113c9dc674 Mon Sep 17 00:00:00 2001 From: Diego Fronza Date: Mon, 9 Nov 2026 17:12:10 -0300 Subject: [PATCH 1/2] Document the PKCS12 key formats for credential files Co-Authored-By: Claude Opus 5.5 --- platform/credential-files.mdx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/platform/credential-files.mdx b/platform/credential-files.mdx index 841f85a5..16e74dc8 100644 --- a/platform/credential-files.mdx +++ b/platform/credential-files.mdx @@ -1,5 +1,5 @@ --- -updated_at: October 26, 2026 +updated_at: November 9, 2026 title: Credential Files html_title: Write Credential Files Where Applications Expect Them description: Configure where the Smallstep Agent writes a credential's key, certificate, and root CA, with per-file owners, modes, POSIX ACLs, and Windows access lists. @@ -175,7 +175,7 @@ It requires `"protection": "NONE"` and `"store": "MACHINE"`. | Field | Applies to | Values | Default | | --- | --- | --- | --- | | `path` | key, certificate, root | Absolute path in the platform's style | The agent's directory for the credential | -| `format` | key | `DEFAULT`, `PKCS8`, `CLASSIC`, `TSS2` | `DEFAULT` | +| `format` | key | `DEFAULT`, `PKCS8`, `CLASSIC`, `TSS2`, `PKCS12`, `PKCS12_LEGACY` | `DEFAULT` | | `contents` | certificate | `CHAIN` (leaf and intermediates) or `LEAF` | `CHAIN` | | `owner`, `group` | Linux, macOS | A name or a numeric ID, as a string | The agent's user and group | | `mode` | Linux, macOS | Octal string, `"0000"` to `"0777"` | `"0640"`; `"0600"` for SSH user credentials | @@ -184,6 +184,10 @@ It requires `"protection": "NONE"` and `"store": "MACHINE"`. | `acl.entries` | Windows | List of `{principal, access}`, `access` one of `READ`, `MODIFY`, `FULL_CONTROL` | See [Windows defaults](#windows-defaults) | | `key.windowsStore` | Windows | `false` keeps the credential out of the Windows stores | `true` | +With `PKCS12` or `PKCS12_LEGACY`, the key file is written as PKCS#8, and the agent also writes `service.p12`, a PKCS#12 bundle of the key, the certificate chain, and the root, with its password in `password.txt`. +Both are written in the agent's directory for the credential, even when `key.path` is set, and take the key file's permissions. +`PKCS12` encrypts the bundle with AES-256 and a SHA-256 MAC. `PKCS12_LEGACY` uses 3DES and a SHA-1 MAC, for apps that can't read the modern encryption. + The root CA is always written to its own file and never into the certificate file. SSH credentials take `key` and `certificate` only. @@ -194,6 +198,7 @@ The API refuses a credential that breaks these rules, with an error that names t - **A custom key path needs a software key.** `key.path` is accepted only with `"protection": "NONE"` and without `key.pubFile`. The agent writes the key there and nowhere else. - **Paths are absolute** in the platform's style (`/…` on Linux and macOS, `C:\…` or `\\server\share\…` on Windows), and distinct within a block. - **Settings stay on their platform.** `owner`, `group`, and `mode` can't appear under `windows`, and a Windows access list can't appear under `linux` or `macos`. A block for an operating system the credential's `policy.operatingSystem` excludes is refused. +- **PKCS#12 needs a software key, and a machine key on Windows.** `"format": "PKCS12"` and `"PKCS12_LEGACY"` are accepted only with `"protection": "NONE"`. Under `windows`, they also need `"store": "MACHINE"`: a key in the user scope is held by the signed-in user's session, and the agent can't put it in a bundle. - **`SYSTEM` keeps full control on Windows.** An access list that gives `SYSTEM` (`NT AUTHORITY\SYSTEM`, `S-1-5-18`) less than `FULL_CONTROL` is refused, and each principal can be listed once. The API doesn't check owners, groups, or principals: they exist only on the device. From c1b3fbefa46ca9586c06e7cea11d9256691a5c71 Mon Sep 17 00:00:00 2001 From: Diego Fronza Date: Mon, 9 Nov 2026 19:40:53 -0300 Subject: [PATCH 2/2] Say how the PKCS12 bundle's permissions are set and reached on Windows Co-Authored-By: Claude Opus 5.5 --- platform/credential-files.mdx | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/platform/credential-files.mdx b/platform/credential-files.mdx index 16e74dc8..085db08c 100644 --- a/platform/credential-files.mdx +++ b/platform/credential-files.mdx @@ -185,9 +185,19 @@ It requires `"protection": "NONE"` and `"store": "MACHINE"`. | `key.windowsStore` | Windows | `false` keeps the credential out of the Windows stores | `true` | With `PKCS12` or `PKCS12_LEGACY`, the key file is written as PKCS#8, and the agent also writes `service.p12`, a PKCS#12 bundle of the key, the certificate chain, and the root, with its password in `password.txt`. -Both are written in the agent's directory for the credential, even when `key.path` is set, and take the key file's permissions. +Both are written in the agent's directory for the credential, even when `key.path` is set. `PKCS12` encrypts the bundle with AES-256 and a SHA-256 MAC. `PKCS12_LEGACY` uses 3DES and a SHA-1 MAC, for apps that can't read the modern encryption. +The bundle and password file take the key file's permissions: + +- **Linux and macOS:** the key's `owner`, `group`, `mode`, and `acl`. +- **Windows, with an `acl` on the key:** the key's access list, so an account the key grants can read them too. +- **Windows, without an `acl` on the key:** they inherit the permissions of the agent's folder for the credential, which grants only `SYSTEM` and `BUILTIN\Administrators`. That's the same access the key file's default list gives. + +On Windows, only `SYSTEM` and the Administrators can list the agent's folder for the credential. +An account the key's `acl` grants can open `service.p12` and `password.txt` by their full paths, but can't browse the folder. +Configure the app with the full path to each file. A file picker, or a tool that lists the folder first, such as `type` in `cmd`, is denied. + The root CA is always written to its own file and never into the certificate file. SSH credentials take `key` and `certificate` only.