smallstep / cli

🧰 A zero trust swiss army knife for working with X509, OAuth, JWT, OATH OTP, etc.
https://smallstep.com/cli
Apache License 2.0
3.67k stars 255 forks source link

Support for PKCS12 file format inspection and creation. #244

Open NonLogicalDev opened 4 years ago

NonLogicalDev commented 4 years ago

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.

dopey commented 4 years ago

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.

NonLogicalDev commented 4 years ago

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.

doug-fitzmaurice-rowden commented 4 years ago

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?

mmalone commented 4 years ago

@doug-fitzmaurice-rowden awesome! I'd love to see this functionality in step.

Some thoughts on the API:

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).

doug-fitzmaurice-rowden commented 4 years ago

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.

doug-fitzmaurice-rowden commented 4 years ago

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.

maraino commented 4 years ago

@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.