diff --git a/README.md b/README.md index f599da2..ebc5683 100644 --- a/README.md +++ b/README.md @@ -31,14 +31,26 @@ Reset the Yubikey's PIV applet and create a new PIN to access it. ### Generate a certificate ```shell -pivit --generate [--p256] +pivit --generate [--p256] [--self-sign | --no-csr] ``` -Generate a new key pair in the Yubikey's card authentication slot. If the -option `--p256` is not provided, the key pair is generated using elliptic curve -P-384. Otherwise, Curve P-256 is used. +Generate a new key pair in the Yubikey's card authentication slot. This command will also generate and store a x509 certificate for the generated key that's signed by Yubico. +If the option `--p256` is provided, the key pair is generated using elliptic curve P-256. +Otherwise, Curve P-384 is used. + +Add the `--self-sign` flag to generate a self-signed certificate; +the certificate is signed with the newly-generated key. +You will be prompted to confirm a self-signed certificate is really desired, +then prompted for the PIN, and then prompted to touch your Yubikey. +The output will contain 3 `CERTIFICATE` blocks instead of a `CERTIFICATE_REQUEST` at the end (example output below). +**This option is useful mostly for testing purposes.** + +Add the `--no-csr` flag to skip the certificate signing request being printed. In this case, you will not be prompted to touch your Yubikey. +This option is useful if you don't need the generated key to be a part of an existing PKI. +you can still verify the key's certificate using Yubico's certificate [here](https://developers.yubico.com/PIV/Introduction/PIV_attestation.html) + Output for the command will look like: ```text @@ -68,36 +80,6 @@ If you choose to issue and use your own certificate, it's important to also veri You can set the organization name, organization unit, and email address in the certificate request's subject by setting the `PIVIT_ORG`, `PIVIT_ORG_UNIT`, and `PIVIT_EMAIL` environment variables before executing this command. -#### Self-Signed Certificates - -```shell -pivit --generate --self-sign [--p256] -``` - -Generate a self-signed certificate; the certificate is signed with the newly-generated key. You will be prompted to configm a self-signed certificate is really desired, then prompted for the PIN, the prompted to touch your Yubikey. - -The output for the command is nearly identical to the above, but ends with a `CERTIFICATE` instead of a `CERTIFICATE_REQUEST`: - -```text -Are you sure you wish to generate a self-signed certificate?: y -PIN: ****** -Printing Yubikey device attestation certificate: ------BEGIN CERTIFICATE----- -... ------END CERTIFICATE----- - -Printing generated key certificate: ------BEGIN CERTIFICATE----- -... ------END CERTIFICATE----- - -Touch Yubikey now to sign your key... -Printing self-signed certificate: ------BEGIN CERTIFICATE----- -... ------END CERTIFICATE----- -``` - #### PIV slot support The PIV module supports multiple slots where keys and certificates can be stored. @@ -136,7 +118,7 @@ For example: ### Import certificate to Yubikey ```shell -pivit [--first-pem] --import [file] +pivit --import [--first-pem] [file] ``` Imports a certificate from `file`. @@ -147,7 +129,7 @@ This action prompts for the Yubikey PIN. Add `--first-pem` to import the first PEM block from `file`, ignoring the rest. This is helpful if using a CA that provides its issued certificates as a chain or bundle, with the end-entity certificate first (this is the convention). -## Print certificate information +### Print certificate information ```shell pivit --print diff --git a/cmd/pivit/generate.go b/cmd/pivit/generate.go index c64531c..56de1e9 100644 --- a/cmd/pivit/generate.go +++ b/cmd/pivit/generate.go @@ -21,7 +21,7 @@ import ( ) // commandGenerate generates a new key pair and certificate signing request -func commandGenerate(slot string, isP256 bool, selfSign bool) error { +func commandGenerate(slot string, isP256, selfSign, generateCsr bool) error { yk, err := yubikey.Yubikey() if err != nil { return err @@ -102,7 +102,7 @@ func commandGenerate(slot string, isP256 bool, selfSign bool) error { } fmt.Println("Printing self-signed certificate:") printCertificateRaw(certificate) - } else { + } else if generateCsr { certRequest, err := certificateRequest(strconv.FormatUint(uint64(attestation.Serial), 10), privateKey) if err != nil { return err diff --git a/cmd/pivit/main.go b/cmd/pivit/main.go index 9bb1b99..d830d50 100644 --- a/cmd/pivit/main.go +++ b/cmd/pivit/main.go @@ -33,6 +33,7 @@ func runCommand() error { tsaOpt := getopt.StringLong("timestamp-authority", 't', "", "URL of RFC3161 timestamp authority to use for timestamping", "url") p256Flag := getopt.BoolLong("p256", 0, "use P-256 elliptic curve for key pair generation. If missing, P-384 is used") selfSignFlag := getopt.BoolLong("self-sign", 0, "generate a self-signed certificate instead of a CSR") + noCsrFlag := getopt.BoolLong("no-csr", 0, "don't create and print a certificate signing request when generating a key pair") getopt.HelpColumn = 40 getopt.SetParameters("[files]") @@ -81,13 +82,21 @@ func runCommand() error { } if *generateFlag { - isP256 := false if *signFlag || *verifyFlag || *resetFlag || importFlag || *printFlag { return errors.New("specify --help, --sign, --verify, --import, --generate, --reset or --print") - } else if *p256Flag { + } + isP256 := false + if *p256Flag { isP256 = true } - return commandGenerate(*slot, isP256, *selfSignFlag) + if *selfSignFlag && *noCsrFlag { + return errors.New("can't specify both --self-sign and --no-csr") + } + generateCsr := true + if *noCsrFlag { + generateCsr = false + } + return commandGenerate(*slot, isP256, *selfSignFlag, generateCsr) } if importFlag {