https://github.com/salrashid123/signer
golang crypto.Signer for Trusted Platform Module (TPM) and Google Cloud KMS
https://github.com/salrashid123/signer
golang hardware-security-module hashicorp-vault key-management-service kms trusted-platform-module
Last synced: 3 months ago
JSON representation
golang crypto.Signer for Trusted Platform Module (TPM) and Google Cloud KMS
- Host: GitHub
- URL: https://github.com/salrashid123/signer
- Owner: salrashid123
- License: apache-2.0
- Created: 2019-11-19T06:03:01.000Z (almost 6 years ago)
- Default Branch: master
- Last Pushed: 2024-06-17T11:19:03.000Z (over 1 year ago)
- Last Synced: 2024-06-19T12:12:35.487Z (over 1 year ago)
- Topics: golang, hardware-security-module, hashicorp-vault, key-management-service, kms, trusted-platform-module
- Language: Go
- Homepage:
- Size: 340 KB
- Stars: 26
- Watchers: 3
- Forks: 10
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
#### crypto.Signer, implementations for Trusted Platform Modules
where private keys as embedded inside `Trusted Platform Module (TPM)`
Basically, you will get a [crypto.Signer](https://pkg.go.dev/crypto#Signer) interface for the private key.
Use the signer to create a TLS session, sign CA/CSRs, or just sign anything.
For example, you can use this to sign data or to generate certificates/csr or for mTLS.
- `util/certgen/`: Library that generates a self-signed x509 certificate for the KMS and TPM based signers above
- `util/csrgen/`: Library that generates a CSR using the key in KMS or TPMsee the [example/](example/) folder for more information.
---
>> this library is not supported by google
---
### Usage Signer
Initialize a signer and directly use `.sign()` as shown in this below and in the samples
```golang
import (
saltpm "github.com/salrashid123/signer/tpm"
"github.com/google/go-tpm/tpmutil"
)rwc, err := tpmutil.OpenTPM(path)
stringToSign := []byte("foo")
h := sha256.New()
h.Write(b)
digest := h.Sum(nil)// assume the handle to the rsassa key is persistentHandle 0x81008001
r, err := saltpm.NewTPMCrypto(&saltpm.TPM{
TpmDevice: rwc,
Handle: tpm2.TPMHandle(handle),
})s, err := r.Sign(rand.Reader, digest, crypto.SHA256)
fmt.Printf("RSA Signed String: %s\n", base64.StdEncoding.EncodeToString(s))
```* [https://pkg.go.dev/github.com/salrashid123/signer/tpm](https://pkg.go.dev/github.com/salrashid123/signer/tpm)
---
### Sign/Verify
see `example/sign_verify_tpm` folder.
To use this, the key must be first created on the TPM and accessed as a PersistentHandle or TPM PEM file
You can create these keys using `go-tpm` or using `tpm2_tools`. The example below uses tpm2_tools but for others languages and standalone applicatoins, see [openssl tpm2 provider](https://github.com/salrashid123/tpm2?tab=readme-ov-file#tpm-based-private-key) or [tpm2genkey](https://github.com/salrashid123/tpm2genkey)
For this, install latest [tpm2_tools](https://tpm2-tools.readthedocs.io/en/latest/INSTALL/)
```bash
cd example/## if you want to use a software TPM,
# rm -rf /tmp/myvtpm && mkdir /tmp/myvtpm
# swtpm socket --tpmstate dir=/tmp/myvtpm --tpm2 --server type=tcp,port=2321 --ctrl type=tcp,port=2322 --flags not-need-init,startup-clear## then specify "127.0.0.1:2321" as the TPM device path in the examples
## and for tpm2_tools, export the following var
# export TPM2TOOLS_TCTI="swtpm:port=2321"## if you are using a real tpm set --tpm-path=/dev/tpmrm0
## note the primary can be the "H2" profile from https://www.hansenpartnership.com/draft-bottomley-tpm2-keys.html#name-parent
# printf '\x00\x00' > unique.dat
# tpm2_createprimary -C o -G ecc -g sha256 -c primary.ctx -a "fixedtpm|fixedparent|sensitivedataorigin|userwithauth|noda|restricted|decrypt" -u unique.dat## RSA - no password
tpm2_createprimary -C o -G rsa2048:aes128cfb -g sha256 -c primary.ctx -a 'restricted|decrypt|fixedtpm|fixedparent|sensitivedataorigin|userwithauth|noda'
tpm2_create -G rsa2048:rsassa:null -g sha256 -u key.pub -r key.priv -C primary.ctx
tpm2_flushcontext -t && tpm2_flushcontext -s && tpm2_flushcontext -l
tpm2_load -C primary.ctx -u key.pub -r key.priv -c key.ctx
tpm2_evictcontrol -C o -c key.ctx 0x81008001go run sign_verify_tpm/rsassa/main.go --tpm-path="127.0.0.1:2321" --handle 0x81008001
### RSA - no password with PEM key file
printf '\x00\x00' > unique.dat
tpm2_createprimary -C o -G ecc -g sha256 -c primary.ctx -a "fixedtpm|fixedparent|sensitivedataorigin|userwithauth|noda|restricted|decrypt" -u unique.dattpm2_create -G rsa2048:rsapss:null -g sha256 -u key.pub -r key.priv -C primary.ctx --format=pem --output=rsapss_public.pem
tpm2_flushcontext -t && tpm2_flushcontext -s && tpm2_flushcontext -l
tpm2_load -C primary.ctx -u key.pub -r key.priv -c key.ctx
tpm2_encodeobject -C primary.ctx -u key.pub -r key.priv -o key.pemgo run sign_verify_tpm/keyfile/main.go --tpm-path="127.0.0.1:2321" -pemFile /tmp/key.pem
## rsa-pss
tpm2_createprimary -C o -G rsa2048:aes128cfb -g sha256 -c primary.ctx -a 'restricted|decrypt|fixedtpm|fixedparent|sensitivedataorigin|userwithauth|noda'
tpm2_create -G rsa2048:rsapss:null -g sha256 -u key.pub -r key.priv -C primary.ctx
tpm2_flushcontext -t && tpm2_flushcontext -s && tpm2_flushcontext -l
tpm2_load -C primary.ctx -u key.pub -r key.priv -c key.ctx
tpm2_evictcontrol -C o -c key.ctx 0x81008004go run sign_verify_tpm/rsapss/main.go --tpm-path="127.0.0.1:2321" --handle 0x81008004
## ecc
tpm2_createprimary -C o -G rsa2048:aes128cfb -g sha256 -c primary.ctx -a 'restricted|decrypt|fixedtpm|fixedparent|sensitivedataorigin|userwithauth|noda'
tpm2_create -G ecc:ecdsa -g sha256 -u key.pub -r key.priv -C primary.ctx --format=pem --output=ecc_public.pem
tpm2_flushcontext -t && tpm2_flushcontext -s && tpm2_flushcontext -l
tpm2_load -C primary.ctx -u key.pub -r key.priv -c key.ctx
tpm2_evictcontrol -C o -c key.ctx 0x81008005go run sign_verify_tpm/ecc/main.go --tpm-path="127.0.0.1:2321" --handle 0x81008005
## for policyPCR
tpm2_pcrread sha256:23
tpm2_startauthsession -S session.dat
tpm2_policypcr -S session.dat -l sha256:23 -L policy.dat
tpm2_flushcontext session.dat
tpm2_flushcontext -t && tpm2_flushcontext -s && tpm2_flushcontext -l
tpm2_createprimary -C o -G rsa2048:aes128cfb -g sha256 -c primary.ctx -a 'restricted|decrypt|fixedtpm|fixedparent|sensitivedataorigin|userwithauth|noda'
tpm2_create -G rsa2048:rsassa:null -g sha256 -u key.pub -r key.priv -C primary.ctx -L policy.dat
tpm2_flushcontext -t && tpm2_flushcontext -s && tpm2_flushcontext -l
tpm2_load -C primary.ctx -u key.pub -r key.priv -c key.ctx
tpm2_evictcontrol -C o -c key.ctx 0x81008006go run sign_verify_tpm/policy_pcr/main.go --handle=0x81008006 --tpm-path="127.0.0.1:2321"
## for policyPassword
tpm2_createprimary -C o -G rsa2048:aes128cfb -g sha256 -c primary.ctx -a 'restricted|decrypt|fixedtpm|fixedparent|sensitivedataorigin|userwithauth|noda'
tpm2_create -G rsa2048:rsassa:null -p testpwd -g sha256 -u key.pub -r key.priv -C primary.ctx
tpm2_flushcontext -t && tpm2_flushcontext -s && tpm2_flushcontext -l
tpm2_load -C primary.ctx -u key.pub -r key.priv -c key.ctx
tpm2_evictcontrol -C o -c key.ctx 0x81008007go run sign_verify_tpm/policy_password/main.go --handle=0x81008007 --tpm-path="127.0.0.1:2321"
```
### Usage TLS
* for tpm see [mTLS with TPM bound private key](https://github.com/salrashid123/go_tpm_https_embed)
### Sign/Verify ECC
The default output signature format for ECC based keys is ASN1 format as described in [ecdsa.SignASN1](https://pkg.go.dev/crypto/ecdsa#Sign)
If you need the raw output format, set `ECCRawOutput: true` in the config.
See the examples folder for usage
### Usage: Generate CSR
The following will generate a TPM based key and then issue a CSR against it.
```bash
### create key, rsassa
# using H2 template ( https://gist.github.com/salrashid123/9822b151ebb66f4083c5f71fd4cdbe40 )
printf '\x00\x00' > unique.dat
tpm2_createprimary -C o -G ecc -g sha256 \
-c primary.ctx -a "fixedtpm|fixedparent|sensitivedataorigin|userwithauth|noda|restricted|decrypt" -u unique.dat
tpm2_create -G rsa2048:rsassa:null -g sha256 -u key.pub -r key.priv -C primary.ctx
tpm2_flushcontext -t
tpm2_load -C primary.ctx -u key.pub -r key.priv -c key.ctx
tpm2_evictcontrol -C o -c key.ctx 0x81008001
tpm2_flushcontext -t
tpm2_encodeobject -C primary.ctx -u key.pub -r key.priv -o private.pemcd util/csrgen/
go run csrgen/csrgen.go -cn server.domain.com --persistentHandle 0x81008001
```### Usage: Generate self-signed certificate
The following will generate a key on the tpm, then use that RSA key to issue a CSR and then sign that CSR with by itself to get an x509.
You can ofcourse modify it to just sign any csr with a TPM backed key
```bash
# using H2 template ( https://gist.github.com/salrashid123/9822b151ebb66f4083c5f71fd4cdbe40 )
printf '\x00\x00' > unique.dat
tpm2_createprimary -C o -G ecc -g sha256 \
-c primary.ctx -a "fixedtpm|fixedparent|sensitivedataorigin|userwithauth|noda|restricted|decrypt" -u unique.dattpm2_create -G rsa2048:rsassa:null -g sha256 -u key.pub -r key.priv -C primary.ctx
tpm2_flushcontext -t
tpm2_load -C primary.ctx -u key.pub -r key.priv -c key.ctx
tpm2_evictcontrol -C o -c key.ctx 0x81008002
tpm2_flushcontext -t
tpm2_encodeobject -C primary.ctx -u key.pub -r key.priv -o private.pemgo run certgen/certgen.go -cn server.domain.com --persistentHandle 0x81008002
```---
If you just want to issue JWT's, see
* [https://github.com/salrashid123/golang-jwt-tpm](https://github.com/salrashid123/golang-jwt-tpm)
* [https://github.com/salrashid123/golang-jwt-pkcs11](https://github.com/salrashid123/golang-jwt-pkcs11)or real random:
* [TPM backed crypto/rand Reader](https://github.com/salrashid123/tpmrand)
---
#### Keys with Auth Policy
If the key is setup with an AuthPolicy (eg, a policy that requires a passphrase or a predefined PCR values to exist), you can specify those in code or define your own
##### PasswordPolicy
If the key requires a password, initialize a `NewPasswordSession`
```golang
se, err := saltpm.NewPasswordSession(rwr, []byte(*keyPass))rr, err := saltpm.NewTPMCrypto(&saltpm.TPM{
TpmDevice: rwc,
Handle: tpm2.TPMHandle(*handle),
AuthSession: se,
})
```##### PCRPolicy
If the key requires a password, initialize a `NewPCRSession`
```golang
se, err := saltpm.NewPCRSession(rwr, []tpm2.TPMSPCRSelection{
{
Hash: tpm2.TPMAlgSHA256,
PCRSelect: tpm2.PCClientCompatible.PCRs(uint(*pcr)),
},
})rr, err := saltpm.NewTPMCrypto(&saltpm.TPM{
TpmDevice: rwc,
Handle: tpm2.TPMHandle(*handle),
AuthSession: se,
})```
##### CustomPolicy
Note, you can define your own policy for import too...just implement the "session" interface from the signer:
```golang
type Session interface {
GetSession() (auth tpm2.Session, closer func() error, err error) // this supplies the session handle to the library
}
```for example, for a PCR and [AuthPolicy](https://github.com/google/go-tpm/pull/359) enforcement (eg, a PCR and password), you can define a custom session callback.
```golang
type MyPCRAndPolicyAuthValueSession struct {
rwr transport.TPM
sel []tpm2.TPMSPCRSelection
password []byte
}func NewPCRAndPolicyAuthValueSession(rwr transport.TPM, sel []tpm2.TPMSPCRSelection, password []byte) (MyPCRAndPolicyAuthValueSession, error) {
return MyPCRAndPolicyAuthValueSession{rwr, sel, password}, nil
}func (p MyPCRAndPolicyAuthValueSession) GetSession() (auth tpm2.Session, closer func() error, err error) {
var options []tpm2.AuthOption
options = append(options, tpm2.Auth(p.password))sess, closer, err := tpm2.PolicySession(p.rwr, tpm2.TPMAlgSHA256, 16, options...)
if err != nil {
return nil, nil, err
}_, err = tpm2.PolicyPCR{
PolicySession: sess.Handle(),
Pcrs: tpm2.TPMLPCRSelection{
PCRSelections: p.sel,
},
}.Execute(p.rwr)
if err != nil {
return nil, nil, err
}_, err = tpm2.PolicyAuthValue{
PolicySession: sess.Handle(),
}.Execute(p.rwr)
if err != nil {
return nil, nil, err
}return sess, closer, nil
}```
which you can call as:
```golang
se, err := NewPCRAndPolicyAuthValueSession(rwr, []tpm2.TPMSPCRSelection{
{
Hash: tpm2.TPMAlgSHA256,
PCRSelect: tpm2.PCClientCompatible.PCRs(uint(*pcr)),
},
}, []byte("testpswd"))rr, err := saltpm.NewTPMCrypto(&saltpm.TPM{
TpmDevice: rwc,
Handle: tpm2.TPMHandle(*handle*),
AuthSession: se,
})
```---