Support for PKCS12 file format inspection and creation.
What would you like to be added
Support for PKCS12, both for inspection through certificates and format.
Why this is needed
PKCS12 File format is very useful for distributing Client Certs.
It is not terribly difficult to do so with openssl, but it would be amazing to just need a single binary for a more or less common task.
Thanks for opening the issue!
I've added this to our backlog for prioritization, but I doubt we'll have time to accomplish this short term (unless we see a lot of support for it - in which case we'd reprioritize). If anyone from the community wants to jump in and take this on, we'd be happy to help/assist.
For research it seems the only library capable of working with PKCS12 bot read and write is: https://godoc.org/software.sslmate.com/src/go-pkcs12
That said this particular statement does not look very good:
It is intended for decoding P12/PFX files for use with the crypto/tls package, and for encoding P12/PFX files for use by legacy applications which do not support newer formats. Since PKCS#12 uses weak encryption primitives, it SHOULD NOT be used for new applications.
It boggles my mind that there is seemingly no other easy way to shoving a Client Certificate onto iOS devices and MacOS keychain.
I've used the go-pkcs12 library before and I'm interested in taking this on as P12 support in step would mean we could drop openssl and keytool from our build process entirely.
What should the CLI args look like? You can make both "identity stores" (a leaf certificate and private key, and any number of intermediate certs) and "trust stores" (any number of intermediates and CAs with a special flag to make Java use them to validate other certs), so there are a few possible commands:
//Command Name:
step [keystore/p12/truststore]
step certificate [keystore/p12/truststore]
//Identity Stores:
step certificate p12 <crt_file> <key_file>
step p12 identity <crt_file> <key_file>
step certificate p12 <crt_file> <key_file> <intermediate_file>
step certificate p12 <crt_file> <key_file> <intermediate_file> <ca_file>
//Trust Stores:
step certificate p12 <ca_file>
step p12 trust <crt_file> <key_file>
step certificate p12 <ca_file> --trust
step certificate p12 <intermediate_file> <ca_file>
What are the conventions so far for args vs options, and how to combine multiple modes of operation into a command?
@doug-fitzmaurice-rowden awesome! I'd love to see this functionality in step.
Some thoughts on the API:
- There's no hard rule, but we generally prefer positional arguments over flags if an argument is always required. It's easy to confuse the order of args if you have too many, though. I think the most we have on other subcommand is three. Looks like you have one subcommand (
step certificate p12) that would take four. I think I can live with that if needed.- Alternatively, could we make this two sub-commands? One could build the bundle and the second could add the bundle to the
p12? (We do havestep certificate bundlealready, but it only does PEM bundles at the moment.)
- Alternatively, could we make this two sub-commands? One could build the bundle and the second could add the bundle to the
- Regarding naming things:
- I usually go to the source material / spec for names (in this case it looks like that'd be RFC7292?).
- I also draw a lot of inspiration (i.e., plagiarize) from other APIs that implement the spec.
- The closest subcommand group to what you're doing here, I think, would be the
step crypto jwt keysetgroup, which lets youadd,remove,list, andfindJWKs to/from/in JWK sets.
- For these commands you don't appear to have an input and output for the identity/trust store. Are you planning to read from stdin and write to stdout? That can be tricky for in-place edits, which feel like they'd be common here.
- Regarding multiple modes of operation, it depends. Usually I'd make these multiple subcommands (so basically a positional). But there are exceptions like
step ssh config --host, where the--hostis a boolean that changes the operational mode.
We put a lot of energy into API design. Unfortunately, I'm not super familiar with p12, so I'm gonna have to learn as we go here. I'll have to find some tool that uses p12 to test with (I think curl uses p12 if you build against NSS, so maybe that'll do).
Thanks @mmalone, I really appreciate the feedback.
You're right, I completely missed the output argutment from my examples - in fact that's the only required argument for all of the commands.
Whilst writing the PR I made a couple of changes to the examples for ease of use. I went with: step certificate p12 <p12_path> <crt_path> <key_path> [--ca <ca_path>] for identity stores, and step certificate p12 <p12_path> --ca <ca_path> [--ca <ca_path>] for trust stores.
I thought that this was clearer for users who don't particuarly care or know what a trust store is. This gives 1 required positional arg, 2 optional ones, and a flag to pass as many times as required (like step certificate create --san).
I also chose p12 rather than pkcs12 as the command name as that's the most common way it's referred to, although the standard name is more accurate.
Does this interface make sense? I tried to copy existing patterns wherever possible.
In the first instance I was only planning to implement creation of new stores from certificates, not removing or updating as these are much more complicated and involve parsing the existing file. I think that create is by far the most common use case.
Some useful tools for working with p12 are openssl pkcs12 (sadly/obviously), Keystore Explorer which is great for inspecting and verifying output. The client/server I've been testing with (and the reason for writing this PR) is a closed source blob, so I think curl is a good shout.
Another question - if I'm only adding create support is it still worth putting a subcommand in - step certificate p12 create? That leaves space for future inspect update commands without needing to change the existing API.
@doug-fitzmaurice-rowden @mmalone step certificate p12 has already been merged to master.
If we want to add support later to create and inspect p12 files, that can be done in the existing commands i.e: step certificate create --p12 ....
For the update, I guess it we can do it by adding flags to step certificate p12.