Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add PKCS11 support #1153

Merged
merged 10 commits into from
Sep 9, 2024
Merged

add PKCS11 support #1153

merged 10 commits into from
Sep 9, 2024

Conversation

JackDoanRivian
Copy link
Contributor

Adds PKCS11 support for the P256 curve. It could probably be generalized for curve 25519 as well, but this is what our HSMs support, and therefore what I could easily test.

I've tested very thoroughly against the difficult-to-obtain Microchip TA100, and did a quick verification with a Yubikey 5C.

Here's some quick examples of how this change can be exercised on a TA100. I'll follow up with Yubikey instructions when time permits:

This change requires building with CGO, so here's the exact invocation we used (adjust as needed for your target architecture of course):

CC=aarch64-linux-gnu-gcc CGO_ENABLED=1 GOARCH=arm64 go build -buildvcs=false -ldflags="${LDFLAGS}" -o nebula.arm64.${COMMIT_HASH} ./cmd/nebula
CC=aarch64-linux-gnu-gcc CGO_ENABLED=1 GOARCH=arm64 go build -buildvcs=false -ldflags="${LDFLAGS}" -o nebula-cert.arm64.${COMMIT_HASH} ./cmd/nebula-cert

Unfortunately static linking with musl doesn't work, because musl doesn't implement dlopen for statically-linked binaries. 😞

./nebula-cert keygen -out-pub test.pem -pkcs11 'pkcs11:slot-id=0;object=device;token=00ABC;type=private?module-path=/tmp/libcryptoauth.so'

A config file's pki section would look like this:

pki:
  ca: /path/to/ca.pem
  cert: /path/to/cert.pem
  key: 'pkcs11:slot-id=0;object=device;token=00ABC;type=private?module-path=/tmp/libcryptoauth.so'

Please let me know what you think! I'm very open to making adjustments to make this fit in better with the existing code.

Copy link

Thanks for the contribution! Before we can merge this, we need @JackDoanRivian to sign the Salesforce Inc. Contributor License Agreement.

Makefile Outdated Show resolved Hide resolved
@jasikpark
Copy link
Collaborator

Related: #328

@wadey wadey added this to the v1.10.0 milestone Jun 24, 2024
@numinit
Copy link
Contributor

numinit commented Jul 2, 2024

How tricky would it be to add support for ca and sign?

@JackDoanRivian
Copy link
Contributor Author

@numinit not that bad for sign, but I (perhaps incorrectly?) assume that most folks who want a hardware-backed key for their CA are operating Nebula "at scale", and therefore also want semi-custom signing logic, and so therefore they don't want to use the CLI to sign their client certs.

For ca, I could add code to generate a CA cert from the key pointed to by a pkcs11 URL, but I don't think it'd be reasonable to add key generation support, since most HSMs (at least the ones I've used) really push you to use their own tooling for creating/managing keys.

@numinit
Copy link
Contributor

numinit commented Jul 2, 2024

I think that's basically all I'd expect; just symmetry between the sign, CA and keygen commands :-)

I noticed the keygen command doesn't actually generate a key anyway, which was well within my expectation for PKCS#11. Fully agreed that using the HSM's native tooling is better there.

@numinit
Copy link
Contributor

numinit commented Jul 3, 2024

@JackDoanRivian this ought to be a good start :-)

numinit@fbdb4b8

@JackDoanRivian
Copy link
Contributor Author

@numinit this looks great! Is it okay with you if I cherrypick this? You'll have to sign the Salesforce CLA for this to land once I do.

@numinit
Copy link
Contributor

numinit commented Jul 5, 2024

Updated so the test suite passes.

https://github.com/numinit/nebula/tree/pkcs11-v1.9.3

@numinit
Copy link
Contributor

numinit commented Jul 8, 2024

@JackDoanRivian Go for it, CLA signed. I've been integration testing it and it works great: https://github.com/numinit/nixpkcs

@numinit
Copy link
Contributor

numinit commented Jul 9, 2024

I made minor fixes to the existing tests, but probably need to write some more CLI tests.

Regardless, a smoketest of the whole process with multiple Nebula nodes using libsoftokn works great.

https://github.com/numinit/nixpkcs/blob/master/test.nix#L221

@johnmaguire johnmaguire linked an issue Jul 10, 2024 that may be closed by this pull request
@numinit
Copy link
Contributor

numinit commented Jul 10, 2024

Running into some trouble with tpm2-pkcs11 using softhsm under QEMU. I'll debug a bit.

Error: error while getting public key with PKCS#11: asn1: syntax error: sequence truncated

pub, _, pubCurve, err = cert.UnmarshalPublicKey(rawPub)
if err != nil {
return fmt.Errorf("error while parsing in-pub: %s", err)
}
if pubCurve != curve {
return fmt.Errorf("curve of in-pub does not match ca")
}
} else if isP11 {
pub, err = p11Client.GetPubKey()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this could be a good spot to check that out pkcs11 public key matches the one in the CA-cert we're using

@numinit
Copy link
Contributor

numinit commented Jul 10, 2024

One more cherry-pick: numinit@98dbced

@JackDoanRivian
Copy link
Contributor Author

@numinit do you have setup instructions for tpm2? I'd love to try that out.

@numinit
Copy link
Contributor

numinit commented Aug 6, 2024

@JackDoanRivian Ack, I missed that comment. Good example that runs in the NixOS test suite is here:

https://github.com/numinit/nixpkcs/blob/master/nixos/tests/nebula.nix#L41

Config specializations (I test this with both nssdb and TPM2) are here:

https://github.com/numinit/nixpkcs/blob/master/flake.nix#L51

Ultimately nixpkcs creates all those declaratively, the imperative commands and environment are buried in that source, though. :-)

@johnmaguire
Copy link
Collaborator

johnmaguire commented Aug 28, 2024

Finally got some time to test this on macOS with an old school YubiKey 4 (USB A!) and I am able to get it working. A couple notes:

  • IIUC, P256 curve is required
  • The Makefile currently doesn't build for anything but Linux. I will include a patch at the end of this comment that worked for me. This patch may have broken the Linux-specific build target though, and I think that may be important for your use case?

And here's how I configured it:

  1. brew install opensc yubico-piv-tool
  2. ykman piv reset (THIS IS DESTRUCTIVE!)
WARNING! This will delete all stored PIV data and restore factory settings. Proceed? [y/N]: y
Resetting PIV data...
Reset complete. All PIV data has been cleared from the YubiKey.
Your YubiKey now has the default PIN, PUK and Management Key:
	PIN:	123456
	PUK:	12345678
	Management Key:	010203040506070801020304050607080102030405060708
  1. ykman piv keys generate --algorithm ECCP256 9a pubkey.pem
Enter a management key [blank to use default key]:
/opt/homebrew/Cellar/ykman/5.5.1/libexec/lib/python3.12/site-packages/yubikit/piv.py:160: CryptographyDeprecationWarning: TripleDES has been moved to cryptography.hazmat.decrepit.ciphers.algorithms.TripleDES and will be removed from this module in 48.0.0.
  return algorithms.TripleDES(management_key)
Private key generated in slot 9A (AUTHENTICATION), public key written to pubkey.pem.
  1. pkcs11-tool --module /opt/homebrew/lib/libykcs11.dylib --list-slots
Available slots:
Slot 0 (0x0): Yubico Yubikey 4 OTP+U2F+CCID
  token label        : YubiKey PIV #5599240
  token manufacturer : Yubico (www.yubico.com)
  token model        : YubiKey YK4
  token flags        : login required, rng, token initialized, PIN initialized
  hardware version   : 1.0
  firmware version   : 4.34
  serial num         : 5599240
  pin min/max        : 6/64
  1. make bin-pkcs11 (This required a code change to Makefile!)
go build -tags cgo,pkcs11 -trimpath -ldflags "-X main.Build=1.9.3-upstream-master-1-g40cfd00-dirty" -o ./nebula "./cmd/nebula"
go build -tags cgo,pkcs11 -trimpath -ldflags "-X main.Build=1.9.3-upstream-master-1-g40cfd00-dirty" -o ./nebula-cert ./cmd/nebula-cert
  1. Build the URL using url-encoded values from step 4 by hand: pkcs11:model=YubiKey%20YK4;manufacturer=Yubico%20%28www.yubico.com%29;serial=5599240;token=YubiKey%20PIV%20%235599240;id=%01?module-path=/opt/homebrew/lib/libykcs11.dylib&pin-value=123456
  2. ./nebula-cert keygen -curve P256 -pkcs11 "pkcs11:model=YubiKey%20YK4;manufacturer=Yubico%20%28www.yubico.com%29;serial=5599240;token=YubiKey%20PIV%20%235599240;id=%01?module-path=/opt/homebrew/lib/libykcs11.dylib&pin-value=123456" -out-pub pkcs11.pub
  3. CA must use the P256 curve: nebula-cert ca -ips '100.100.0.0/24' -name 'Test CA for PKCS11' -curve P256
  4. Sign the cert: nebula-cert sign -in-pub pkcs11.pub -ip '100.100.0.1/24' -name pkcs11
  5. Fill out the pki section of the config:
pki:
 ca: /Users/jmaguire/src/nebula/ca.crt
 cert: /Users/jmaguire/src/nebula/pkcs11.crt
 key: pkcs11:model=YubiKey%20YK4;manufacturer=Yubico%20%28www.yubico.com%29;serial=5599240;token=YubiKey%20PIV%20%235599240;id=%01?module-path=/opt/homebrew/lib/libykcs11.dylib&pin-value=123456

Here's how I patched the Makefile:

diff --git a/Makefile b/Makefile
index 1b75dd5..bba5a4c 100644
--- a/Makefile
+++ b/Makefile
@@ -117,8 +117,9 @@ bin-freebsd-arm64: build/freebsd-arm64/nebula build/freebsd-arm64/nebula-cert
 bin-boringcrypto: build/linux-$(shell go env GOARCH)-boringcrypto/nebula build/linux-$(shell go env GOARCH)-boringcrypto/nebula-cert
        mv $? .

-bin-pkcs11: build/linux-$(shell go env GOARCH)-pkcs11/nebula build/linux-$(shell go env GOARCH)-pkcs11/nebula-cert
-       mv $? .
+bin-pkcs11: BUILD_ARGS += -tags pkcs11
+bin-pkcs11: CGO_ENABLED = 1
+bin-pkcs11: bin

 bin:
        go build $(BUILD_ARGS) -ldflags "$(LDFLAGS)" -o ./nebula${NEBULA_CMD_SUFFIX} ${NEBULA_CMD_PATH}

@wadey wadey merged commit 35603d1 into slackhq:master Sep 9, 2024
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support for HSM (Hardware Security Module) or PKCS#11
5 participants