{"id":21354956,"url":"https://github.com/salrashid123/mtls_pkcs11","last_synced_at":"2025-07-12T22:32:24.968Z","repository":{"id":57577259,"uuid":"359215767","full_name":"salrashid123/mtls_pkcs11","owner":"salrashid123","description":"mTLS with PKCS11 keys","archived":false,"fork":false,"pushed_at":"2024-06-07T21:29:59.000Z","size":117,"stargazers_count":12,"open_issues_count":0,"forks_count":2,"subscribers_count":3,"default_branch":"main","last_synced_at":"2024-06-07T22:40:27.396Z","etag":null,"topics":["cryptography","pkcs11","tls"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/salrashid123.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-04-18T17:54:46.000Z","updated_at":"2024-06-07T21:30:02.000Z","dependencies_parsed_at":"2022-09-11T22:50:48.697Z","dependency_job_id":"155561d7-0df1-47b6-bd9b-f2f1ac225460","html_url":"https://github.com/salrashid123/mtls_pkcs11","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/salrashid123%2Fmtls_pkcs11","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/salrashid123%2Fmtls_pkcs11/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/salrashid123%2Fmtls_pkcs11/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/salrashid123%2Fmtls_pkcs11/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/salrashid123","download_url":"https://codeload.github.com/salrashid123/mtls_pkcs11/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225839601,"owners_count":17532308,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cryptography","pkcs11","tls"],"created_at":"2024-11-22T04:15:25.099Z","updated_at":"2024-11-22T04:15:25.742Z","avatar_url":"https://github.com/salrashid123.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n## mTLS with PKCS11 \n\nSample application and library that establishes mTLS using keys stored in HSM/TPM/Yubikey via [PKCS-11 interface](http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/os/pkcs11-base-v2.40-os.html).  Essentially this library and sample provides a way to use HSM/TPM/Yubikey embedded private keys for mTLS.  \n\nTo use this, you must configure the pkcs device to include a private key and then specify loading and using its corresponding PKCS module/driver.  Each type of pkcs device has its own driver that translates/brokers PKCS-11 API commands to its native interface.  For example, a Yubikey interface driver will need to be installed in order to access the device's keys by translating standard PKCS API calls to native driver directives for YubiKey.  Similar situation for any other HSM device or Trusted Platform Module (TPM).   \n\nThis library provides the same root golang interface which is used to access any PKCS target for mTLS.  We will be using the [crypto.Signer](https://golang.org/pkg/crypto/#Signer) implementation provided by [ThalesIgnite/crypto11](https://github.com/ThalesIgnite/crypto11) as the underlying command set.  [LetsEncrypt](https://github.com/letsencrypt/pkcs11key) also provides an interface but in this case, we'll just use the ready made Singer\n\nThis tutorial also installs openssl PKCS module which we will use to test.  You do not need to install openssl on each system during production since the underlying driver can handle the PKCS APIs on its own; we are just using openssl for testing.\n\n\u003e\u003e NOTE: this repo is NOT supported by Google\n\n\n\u003e\u003e This repo will demonstrate using SoftHSM mTLS but also shows the configurations for YubiKey and Trusted Platform Module\n\n### References\n\n* OpenSSL Provider\n  - `/usr/lib/x86_64-linux-gnu/engines-1.1/libpkcs11.so`:  OpenSSL Engine that allows dynamic PKCS11 providers\n\n* PKCS11 Modules\n  - `/usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so`: [SoftHSM PKCS Driver](https://packages.ubuntu.com/xenial/libsofthsm2)\n  - `/usr/lib/x86_64-linux-gnu/libtpm2_pkcs11.so.1`: [TPM PKCS11 Driver](https://github.com/tpm2-software/tpm2-pkcs11)\n  - `/usr/lib/x86_64-linux-gnu/libykcs11.so`:  [Yubikey PKCS Driver](https://developers.yubico.com/yubico-piv-tool/YKCS11/)\n  - `/usr/lib/x86_64-linux-gnu/opensc-pkcs11.so`:  Older PKCS11 provider for SmartCards.  [No longer required](https://developers.yubico.com/PIV/Guides/SSH_with_PIV_and_PKCS11.html) for Yubikey \n\nAnyway, lets get started..\n\n---\n\n### Install PKCS11 support and Verify with OpenSSL\n\nThe following will install and test softHSM using openssl.  Once this is done, we will use the golang mTLS clients to establish client-server communication.\n\n#### Install openssl with pkcs11 \n\nFirst install openssl with its [PKCS11 engine](https://github.com/OpenSC/libp11#openssl-engines).\n\nOn debian\n\n```bash\n# add to /etc/apt/sources.list\n  deb http://http.us.debian.org/debian/ testing non-free contrib main\n\n# then\n$ export DEBIAN_FRONTEND=noninteractive \n$ apt-get update \u0026\u0026 apt-get install libtpm2-pkcs11-1 tpm2-tools libengine-pkcs11-openssl opensc softhsm2 libsofthsm2 -y\n```\n\nNote, the installation above adds in the libraries for all modules in this repo (TPM, OpenSC, etc)..you may only need `libengine-pkcs11-openssl` here to verify\n\nOnce installed, you can check that it can be loaded:\n\nSet the pkcs11 provider and module directly into openssl (make sure `libpkcs11.so` engine reference exists first!)\n\n\nVerify the path,\n\n```bash\n$ ls /usr/lib/x86_64-linux-gnu/engines-3/\n## or\n$ ls /usr/lib/x86_64-linux-gnu/engines-1.1/\n\n\nedit `/etc/ssl/openssl.cnf`\n```bash\nopenssl_conf = openssl_def\n[openssl_def]\nengines = engine_section\n\n[engine_section]\npkcs11 = pkcs11_section\n\n[pkcs11_section]\nengine_id = pkcs11\ndynamic_path = /usr/lib/x86_64-linux-gnu/engines-3/libpkcs11.so\n```\n\n\n```bash\n$ openssl engine\n  (rdrand) Intel RDRAND engine\n  (dynamic) Dynamic engine loading support\n\n$ openssl engine -t -c pkcs11\n  (pkcs11) pkcs11 engine\n  [RSA, rsaEncryption, id-ecPublicKey]\n      [ available ]\n```\n\n---\n\n#### SOFTHSM\n\nSoftHSM is as the name suggests, a sofware \"HSM\" module used for testing.   It is ofcourse not hardware backed but the module does allow for a PKCS11 interface which we will also use for testing.\n\nFirst make sure the softhsm library is installed\n\n- [SoftHSM Install](https://www.opendnssec.org/softhsm/)\n\nSetup a config file where the `directories.tokendir` points to a existing folder where softHSM will save all its data (in this case its `misc/tokens/`)\n\n\u003e\u003e This repo already contains a sample configuration/certs to use with the softhsm token directory...just delete the folder and start from scratch if you want..\n\nNow, make sure that the installation created the softhsm module for openssl:  `/usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so`\n\n```bash\nopenssl engine dynamic \\\n -pre SO_PATH:/usr/lib/x86_64-linux-gnu/engines-3/libpkcs11.so \\\n -pre ID:pkcs11 -pre LIST_ADD:1 \\\n -pre LOAD \\\n -pre MODULE_PATH:/usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so \\\n -t -c\n\n  (dynamic) Dynamic engine loading support\n  [Success]: SO_PATH:/usr/lib/x86_64-linux-gnu/engines-3/libpkcs11.so\n  [Success]: ID:pkcs11\n  [Success]: LIST_ADD:1\n  [Success]: LOAD\n  [Success]: MODULE_PATH:/usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so\n  Loaded: (pkcs11) pkcs11 engine\n  [RSA, rsaEncryption, id-ecPublicKey]\n      [ available ]\n```\n\nUse [pkcs11-too](https://manpages.debian.org/testing/opensc/pkcs11-tool.1.en.html) which comes with the installation of opensc\n\n```bash\nexport SOFTHSM2_CONF=/absolute/path/to/mtls_pkcs11/misc/softhsm.conf\nrm -rf /tmp/tokens\nmkdir /tmp/tokens\n\npkcs11-tool --module /usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so --slot-index=0 --init-token --label=\"token1\" --so-pin=\"123456\"\npkcs11-tool --module /usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so  --label=\"token1\" --init-pin --so-pin \"123456\" --pin mynewpin\n\npkcs11-tool --module /usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so --list-token-slots\n        Available slots:\n        Slot 0 (0x2593104d): SoftHSM slot ID 0x2593104d\n          token label        : token1\n          token manufacturer : SoftHSM project\n          token model        : SoftHSM v2\n          token flags        : login required, rng, token initialized, PIN initialized, other flags=0x20\n          hardware version   : 2.6\n          firmware version   : 2.6\n          serial num         : 2c6106832593104d\n          pin min/max        : 4/255\n        Slot 1 (0x1): SoftHSM slot ID 0x1\n          token state:   uninitialized\n\n\n\n### \u003e\u003e\u003e Important NOTE the serial num   2c6106832593104d  \n## we will use this in the PKCS-11 URI\n\n# Create Server's private key as id=4142, keylabel1;  client as id=4143, keylabel2\npkcs11-tool --module /usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so -l -k --key-type rsa:2048 --id 4142 --label keylabel1 --pin mynewpin\npkcs11-tool --module /usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so -l -k --key-type rsa:2048 --id 4143 --label keylabel2 --pin mynewpin\n\npkcs11-tool --module /usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so  --list-objects\n\n## get the serial number from the previous --list-token-slots command\nexport serial_number=\"2c6106832593104d\"\n### Use openssl module to sign and print the public key (not, your serial number will be different)\n# server\nexport PKCS11_SERVER_PRIVATE_KEY=\"pkcs11:model=SoftHSM%20v2;manufacturer=SoftHSM%20project;serial=$serial_number;token=token1;type=private;object=keylabel1?pin-value=mynewpin\"\nexport PKCS11_SERVER_PUBLIC_KEY=\"pkcs11:model=SoftHSM%20v2;manufacturer=SoftHSM%20project;serial=$serial_number;token=token1;type=public;object=keylabel1?pin-value=mynewpin\"\n\n# client\nexport PKCS11_CLIENT_PRIVATE_KEY=\"pkcs11:model=SoftHSM%20v2;manufacturer=SoftHSM%20project;serial=$serial_number;token=token1;type=private;object=keylabel2?pin-value=mynewpin\"\nexport PKCS11_CLIENT_PUBLIC_KEY=\"pkcs11:model=SoftHSM%20v2;manufacturer=SoftHSM%20project;serial=$serial_number;token=token1;type=public;object=keylabel2?pin-value=mynewpin\"\n\n### Display the public keys\nopenssl rsa -engine pkcs11  -inform engine -in \"$PKCS11_SERVER_PUBLIC_KEY\" -pubout\nopenssl rsa -engine pkcs11  -inform engine -in \"$PKCS11_CLIENT_PUBLIC_KEY\" -pubout\n\n### Sign and verify\necho \"sig data\" \u003e \"data.txt\"\nopenssl rsa -engine pkcs11  -inform engine -in \"$PKCS11_SERVER_PUBLIC_KEY\" -pubout -out pub.pem\nopenssl pkeyutl -engine pkcs11 -keyform engine -inkey $PKCS11_SERVER_PRIVATE_KEY -sign -in data.txt -out data.sig\nopenssl pkeyutl -pubin -inkey pub.pem -verify -in data.txt -sigfile data.sig\n```\n\n#### Generate mTLS certs\n\nAt this point, we can use the embedded private keys to generate x509 certificate CSRs. Note: devices can already generate x509 certs associated with  its private key but in this case, we will use an externally generated CA using the private key alone\n\n\nUsing a sample CA,\n\n- Generate CSR\n\n```bash\nexport SOFTHSM2_CONF=/absolute/path/to/pkcs11_signer/misc/softhsm.conf\n\n$ go run csr/csr.go --csrFile=ca_scratchpad/certs/softhsm-server.csr --sni server.domain.com --keyLabel=keylabel1\n$ go run csr/csr.go --csrFile=ca_scratchpad/certs/softhsm-client.csr --sni client.domain.com --keyLabel=keylabel2\n```\n\n- Generate Certs\n```bash\ncd ca_scratchpad/\n\nexport NAME=softhsm-server\nexport SAN=DNS:server.domain.com\n\nopenssl ca \\\n    -config single-root-ca.conf \\\n    -in certs/$NAME.csr \\\n    -out certs/$NAME.crt \\\n    -extensions server_ext  \n\n\n## generate client cert\nexport NAME=softhsm-client\nexport SAN=DNS:client.domain.com\n\nopenssl ca \\\n    -config single-root-ca.conf \\\n    -in certs/$NAME.csr \\\n    -out certs/$NAME.crt \\\n    -policy extern_pol \\\n    -extensions client_ext\n```\n\n\n- Upload the certs to the server:\n\n```bash\nexport NAME=softhsm-server\nopenssl x509 -in certs/$NAME.crt -out certs/$NAME.der -outform DER\npkcs11-tool --module /usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so -l --id 4142 --label keylabel1 -y cert -w certs/$NAME.der --pin mynewpin\n\nexport NAME=softhsm-client\nopenssl x509 -in certs/$NAME.crt -out certs/$NAME.der -outform DER\npkcs11-tool --module /usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so -l --id 4143 --label keylabel2 -y cert -w certs/$NAME.der --pin mynewpin\n\n## list the objects..you sould now see certificates too\n$ pkcs11-tool --module /usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so  --list-objects\n\n      Using slot 0 with a present token (0x1ce44146)\n      Certificate Object; type = X.509 cert\n        label:      keylabel2\n        subject:    DN: C=US, ST=California, L=Mountain View, O=Google, OU=Enterprise, CN=client.domain.com\n        serial:     05\n        ID:         4143\n      Public Key Object; RSA 2048 bits\n        label:      keylabel2\n        ID:         4143\n        Usage:      encrypt, verify, verifyRecover, wrap\n        Access:     local\n      Public Key Object; RSA 2048 bits\n        label:      keylabel1\n        ID:         4142\n        Usage:      encrypt, verify, verifyRecover, wrap\n        Access:     local\n      Certificate Object; type = X.509 cert\n        label:      keylabel1\n        subject:    DN: C=US, ST=California, L=Mountain View, O=Google, OU=Enterprise, CN=server.domain.com\n        serial:     04\n        ID:         4142\n\n```\n\n### golang mTLS\n\nWe're finally ready to use the private key in the PKCS device and the x509 which we generated externally:\n\nFirst to setup and use this library, we will need to configure the PKCS provider and surface [tls.Config](https://golang.org/pkg/crypto/tls/#Config) that handles the traffic and cert-signing:\n\n\nFor softHSM Server:\n\n```golang\nimport (\n  salpkcs \"github.com/salrashid123/mtls_pkcs11/signer/pkcs\"\n)\n\n\t// export SOFTHSM2_CONF=/absolute/path/to/pkcs11_signer/misc/softhsm.conf\n\tconfig := \u0026crypto11.Config{\n\t\tPath:       \"/usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so\",\n\t\tTokenLabel: \"token1\",\n\t\tPin:        \"mynewpin\",\n\t}\n  ctx, err := crypto11.Configure(config)\n\tclientCaCert, err := ioutil.ReadFile(\"ca_scratchpad/ca/root-ca.crt\")\n\tclientCaCertPool := x509.NewCertPool()\n\tclientCaCertPool.AppendCertsFromPEM(clientCaCert)\n\n\tr, err := salpkcs.NewPKCSCrypto(\u0026salpkcs.PKCS{\n\t\tContext:        ctx,\n\t\tPkcsId:         nil,                                      //softhsm\n\t\tPkcsLabel:      []byte(\"keylabel1\"),                      //softhsm\n\t\tPublicCertFile: \"ca_scratchpad/certs/softhsm-server.crt\", //softhsm, you can omit this parameter if you have the x509 on the HSM device\n\t\tExtTLSConfig: \u0026tls.Config{\n\t\t\tRootCAs:    clientCaCertPool,\n\t\t\tClientCAs:  clientCaCertPool,\n\t\t\tClientAuth: tls.RequireAndVerifyClientCert,\n\t\t},\n  }) \n  \n\tvar server *http.Server\n\tserver = \u0026http.Server{\n\t\tAddr:      \":8081\",\n\t\tTLSConfig: r.TLSConfig(),\n\t}  \n```\n\nNote, we are specifying the `PublicCertFile` directly...hardware like YubiKeys can use embedded x509 certs.  If the device supports the cert, omit this parameter. \n\nRun Server\n```bash\nexport SOFTHSM2_CONF=/absolute/path/to/pkcs11_signer/misc/softhsm.conf\ngo run server/server.go\n```\n\nRun Client\n```bash\nexport SOFTHSM2_CONF=/absolute/path/to/pkcs11_signer/misc/softhsm.conf\ngo run client/client.go\n```\n\n### curl mTLS\n\nTo use curl for client certs, you can use the `--engine` directive and specify that the private key referenced to by the `PKCS11_PRIVATE_KEY` uri\n\n```bash\ncurl -vvv -tls13  --cacert ca_scratchpad/ca/root-ca.crt \\\n   --cert ca_scratchpad/certs/softhsm-client.crt  --engine pkcs11  --key-type ENG --key \"$PKCS11_CLIENT_PRIVATE_KEY\"  \\\n   --resolve server.domain.com:8081:127.0.0.1   -H \"host: server.domain.com\" \\\n         https://server.domain.com:8081/\n```\n\n---\n\n- [mTLS with TPM bound private key](https://github.com/salrashid123/go_tpm_https_embed):  mTLS with TPM backed keys using [go-tpm](https://github.com/google/go-tpm-tools).  This does not use PKCS11\n- [crypto.Signer, crypto.Decrypter implementations](https://github.com/salrashid123/signer#usage-tls):  Various crypto.Sginer implementations that do not use PKCS11 and instead use native drivers.\n- [Trusted Platform Module (TPM) recipes with tpm2_tools and go-tpm](https://github.com/salrashid123/tpm2): Samples for using TPMs in golang\n- [YubiKeyTokenSource](https://github.com/salrashid123/yubikey): This implements a crypto.Signer for a yubikey by using yubikey APIs directly (not via PKCS11)!\n- [Sample CA for mTLS](https://github.com/salrashid123/ca_scratchpad)\n- [OpenSSL docker with TLS trace enabled (enable-ssl-trace)](https://github.com/salrashid123/openssl_trace)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsalrashid123%2Fmtls_pkcs11","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsalrashid123%2Fmtls_pkcs11","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsalrashid123%2Fmtls_pkcs11/lists"}