diff --git a/README.md b/README.md index 0a52ecd..57ff85c 100644 --- a/README.md +++ b/README.md @@ -16,8 +16,6 @@ This repo assumes the verifier of the JWT has already established that the RSA k >> this repo is not supported by google -Much of this implementation is templated from [gcp-jwt-go](https://github.com/someone1/gcp-jwt-go) - ### Supported Key Types The following types are supported @@ -33,7 +31,7 @@ Use this library to issue JWTs in a way compatible with golang-jwt library. The ```golang import ( - "github.com/golang-jwt/jwt" + "github.com/golang-jwt/jwt/v5" tpmjwt "github.com/salrashid123/golang-jwt-tpm" "github.com/google/go-tpm-tools/client" @@ -58,8 +56,8 @@ config := &tpmjwt.TPMConfig{ keyctx, err := tpmjwt.NewTPMContext(ctx, config) -claims := &jwt.StandardClaims{ - ExpiresAt: time.Now().Add(time.Minute * 1).Unix(), +claims := &jwt.RegisteredClaims{ + ExpiresAt: &jwt.NumericDate{time.Now().Add(time.Minute * 1)}, Issuer: "test", } @@ -82,14 +80,14 @@ gcloud compute instances create tpm-device \ --zone=us-central1-a --machine-type=n1-standard-1 \ --tags tpm --no-service-account --no-scopes \ --shielded-secure-boot --shielded-vtpm --shielded-integrity-monitoring \ - --image=debian-11 --image-project=debian-cloud + --image-family=debian-11 --image-project=debian-cloud # ssh to VM - -## this library uses go-tpm-tools which...unfortunately requires the following ONLY on the system -## that generates the JWT; any verifier just needs the public key -## https://github.com/google/go-tpm-tools#trousers-errors-when-building-server -apt-get update && apt-get install gcc git libtspi-dev +apt-get update +apt-get install tpm2-tools +# wget https://go.dev/dl/go1.22.2.linux-amd64.tar.gz +#rm -rf /usr/local/go && tar -C /usr/local -xzf go1.22.2.linux-amd64.tar.gz +# export PATH=$PATH:/usr/local/go/bin ``` Once on the VM, create a key on TPM (if you already have an existing key on TPM, you can acquire a handle using `go-tpm-tools`). For now, create a key @@ -97,121 +95,72 @@ Once on the VM, create a key on TPM (if you already have an existing key on TPM, The key created is _persisted_ at a handle (default `0x81008001`) and you can pick any defined in pg 15 of [Registry of Reserved TPM 2.0 Handles and Localities](https://trustedcomputinggroup.org/wp-content/uploads/RegistryOfReservedTPM2HandlesAndLocalities_v1p1_pub.pdf) -```bash -$ git clone https://github.com/salrashid123/golang-jwt-tpm.git -$ cd util/ -``` +### Usage -generate RSA -```bash -$ go run keycreate.go --persistentHandle 0x81008001 --keyAlg=RSA +For simplicity, the following generates and embeds keys into a persistent handle using [tpm2_tools](https://github.com/tpm2-software/tpm2-tools) - 2024/03/31 12:15:45 ======= Init ======== - 2024/03/31 12:15:45 key Name: - b094a27c079ca2473446f59830a15963dc62731b267584a2e5b620cf74910f82 - 2024/03/31 12:15:45 ======= PersistHandle (k) ======== - 2024/03/31 12:15:45 PublicKey: - -----BEGIN PUBLIC KEY----- - MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx9mk8rvVB+Lf9RO1mkEV - jxZ4gUqLx/zk3k5gbCswk7POzR3t5J8gQBZbY55ieW2IcnqyK0lf/uW+d6fgI+bT - 34FtSlkk5QBcu5IEIyO9WZa/VpMf777ZZ0v/TXJUsVhpFMOj+Kk4WpaDkxRZ2KW0 - /PiM4BKm/PVE7X17Tz2VZwJuBDXIGUv4e+oSK84mbpzVGppGn6gF10LbGdbj64+K - +0LkXuelwtDkOXME/AndpPHsuEfIf3UgC48bipU5L/CTurCjJGeGcMdJeMxPMmSt - ilIqDUOlIik+vhETpoOvtd3mX80hxinG07KRpb6Gl04AS1fFViJkOSn5mKVUpjCj - VQIDAQAB - -----END PUBLIC KEY----- - 2024/03/31 12:15:45 Public Key written to: key.pem - JWK Format: - { - "e": "AQAB", - "kid": "WE1PnTXj03tE0bfU1BfSFh9J/+GQ955hxHSvXjK4uhE", - "kty": "RSA", - "n": "x9mk8rvVB-Lf9RO1mkEVjxZ4gUqLx_zk3k5gbCswk7POzR3t5J8gQBZbY55ieW2IcnqyK0lf_uW-d6fgI-bT34FtSlkk5QBcu5IEIyO9WZa_VpMf777ZZ0v_TXJUsVhpFMOj-Kk4WpaDkxRZ2KW0_PiM4BKm_PVE7X17Tz2VZwJuBDXIGUv4e-oSK84mbpzVGppGn6gF10LbGdbj64-K-0LkXuelwtDkOXME_AndpPHsuEfIf3UgC48bipU5L_CTurCjJGeGcMdJeMxPMmStilIqDUOlIik-vhETpoOvtd3mX80hxinG07KRpb6Gl04AS1fFViJkOSn5mKVUpjCjVQ" - } +#### RSA + +Create RSA key at handle `0x81008001` +```bash # or with tpm2_tools -# tpm2_createprimary -C e -c primary.ctx -# tpm2_create -G rsa -u key.pub -r key.priv -C primary.ctx -# 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 -s -l +# tpm2_evictcontrol -C o -c 0x81008001 + tpm2_createprimary -C e -c primary.ctx + tpm2_create -G rsa2048:rsassa:null -g sha256 -u key.pub -r key.priv -C primary.ctx + tpm2_load -C primary.ctx -u key.pub -r key.priv -c key.ctx + tpm2_evictcontrol -C o -c key.ctx 0x81008001 ``` -or ECC +Then, ```bash -$ go run keycreate.go --persistentHandle 0x81008002 --keyAlg=ECC +cd example/ +go run nopolicy/main.go --persistentHandle=0x81008001 - 2024/03/31 12:15:53 ======= Init ======== - 2024/03/31 12:15:53 key Name: - c2db8cb8dd2b93adafd5f0eb9d7b8b6ab1f7f9f68c7d120489ae447732b94d23 - 2024/03/31 12:15:53 ======= PersistHandle (k) ======== - 2024/03/31 12:15:53 PublicKey: + 2024/04/07 13:03:46 ======= Init ======== + 2024/04/07 13:03:46 Signing PEM -----BEGIN PUBLIC KEY----- - MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEhgCQBactv03N+4n0En2n5YdzKdBM - Xc9bk/pCN8Bpkd5XtKFHhsolNO7ri9xOGwrXmT+PfQu7yEjvqPbnQs8e4A== + MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr2hhvvxAtjSeYi+M07nV + weY/JqICYbJ4SsqvBdzguGrYVK9ITuZvHe8z0QG2d/+fCyEb+30rqgoy+0BugImV + YdCEg6WZJ/j2Tvj0v1ItmCQoPgNWZ/oqY4U11eSqb1RAho/HWbkCDBZoP1BbdQ/T + kdc+JKy94xETK+Mnq26Tr0tK9t4PwxPeXvweWwNB+kSBAWmDO9hJo+UKCysvPZ4K + 6SMOb8p4HmCjzAZ06VBgfrW/17rcdwKqS6ImDKhzAbkkC15Qdfx71YkZGnvLehi6 + 8FGDF7IHbk846ki5Z91Jvnp5jjcqqQYajYwn7lNHNgMPDS2REoUTzbVHzSAcpVgl + 9QIDAQAB -----END PUBLIC KEY----- - 2024/03/31 12:15:53 Public Key written to: key.pem - JWK Format: - { - "crv": "P-256", - "kid": "K2kf1bx2NHp31GtRjnggWyRfYqZbhK81U8AxY6UwPto", - "kty": "EC", - "x": "hgCQBactv03N-4n0En2n5YdzKdBMXc9bk_pCN8Bpkd4", - "y": "V7ShR4bKJTTu64vcThsK15k_j30Lu8hI76j250LPHuA" - } - -# tpm2_createprimary -C e -c primary.ctx -# tpm2_create -G ecc -u key.pub -r key.priv -C primary.ctx -# tpm2_load -C primary.ctx -u key.pub -r key.priv -c key.ctx -# tpm2_evictcontrol -C o -c key.ctx 0x81008002 + TOKEN: eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MTI0OTUwODYsImlzcyI6InRlc3QifQ.qVb3W2oS0GpgJgNpmsEP4PUKXzSGmihQadLCMYP04_qwlWnYFU7fU3KCTXZ9bpKs92ksRavIPOna_MCPrRj_VJBnEdjl1HGLw0B-_1BLz2JwuwGgOx2NCE-xmkYJJ7bLKiIV8nKbUvJq19GhoKaKzHl2f9Gy4dirKGSE3DztNUuWl3ValFtWyl69FpkJEAEWtQnnDhhQIJ1H3uu4iYJ1AY0L95C502oqD2BSaye0HImHolPN-UkCQ1iEOXMEYNnrllUTfPQ82p875ubvXCnilSasE0ozKOxPLyctkPlssojiM41kdj6-uqaoKvG84zEFGVZUIXk2bc7cFYhj8fR1Lw + 2024/04/07 13:03:46 verified with TPM PublicKey + 2024/04/07 13:03:46 verified with exported PubicKey ``` +#### ECC -If the handle is already defined, you can evict it with `-evict` flag (equivalent of `tpm2_evictcontrol -C o -c 0x81008001`) - -The output of the create command make a persistent key at the value of `persistentHandle`. The output also includes `key.pem` (the public `RSA`) - -Note that the output shows the PublicKey in RSA and JWK formats - -Now create a test JWT and verify it with an RSA key that is extracted from a TPM and also directly, a cached key. +```bash + tpm2_createprimary -C e -c primary.ctx + tpm2_create -G ecc:ecdsa -g sha256 -u key.pub -r key.priv -C primary.ctx + tpm2_load -C primary.ctx -u key.pub -r key.priv -c key.ctx + tpm2_evictcontrol -C o -c key.ctx 0x81008002 +``` -Now issue a JWT and notice the public key matches what we saved to the TPM: +Then ```bash cd example/ +go run nopolicy/main.go --persistentHandle=0x81008002 -$ go run main.go --persistentHandle 0x81008001 --template cached --keyAlg=RSA - - 2024/03/31 12:16:55 ======= Init ======== - 2024/03/31 12:16:56 Load SigningKey from template cached - 2024/03/31 12:16:56 Signing PEM + 2024/04/07 13:04:59 ======= Init ======== + 2024/04/07 13:04:59 Signing PEM -----BEGIN PUBLIC KEY----- - MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx9mk8rvVB+Lf9RO1mkEV - jxZ4gUqLx/zk3k5gbCswk7POzR3t5J8gQBZbY55ieW2IcnqyK0lf/uW+d6fgI+bT - 34FtSlkk5QBcu5IEIyO9WZa/VpMf777ZZ0v/TXJUsVhpFMOj+Kk4WpaDkxRZ2KW0 - /PiM4BKm/PVE7X17Tz2VZwJuBDXIGUv4e+oSK84mbpzVGppGn6gF10LbGdbj64+K - +0LkXuelwtDkOXME/AndpPHsuEfIf3UgC48bipU5L/CTurCjJGeGcMdJeMxPMmSt - ilIqDUOlIik+vhETpoOvtd3mX80hxinG07KRpb6Gl04AS1fFViJkOSn5mKVUpjCj - VQIDAQAB + MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEYt1Dra/va/RSzH+eQKGDbtr+CE4U + 7P1wnRR6Hb/S45i/PxI3PdIuZoFzswvVt0sLvSmG1pvyawDHwD04UXT01A== -----END PUBLIC KEY----- - TOKEN: eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MTE4ODc0NzYsImlzcyI6InRlc3QifQ.gRu9qBKYrNa8zW_Q1XxpbDLTQy0Gbq_ns9EPTAS9sl0qe6srT54zxjE0TOWnzhiS1sk8m4v7COfITKMSt7xYGk_-3gOmESBfofvQvoAQHyahZ920B2RrPXiKCLdf2T9LM2Dt_T_g-cAWdVuCo4yThY8SG5suvwpvqxMsBl-YpymLl8LrazYW7eRn3z3nP3HM3vTdMJji3DVALsROgjNXuVndcqzvkNFv78AXZaX2tXs1KoMgf5e_EhFjFqWzguQkma6HF-2yc6Bot-GTO_gVQOaOBvM8aR4sJVhUDVYKObwG80tCaIrQWF9V4dGIpkTECBAun3YmnZkW1Wzlk7WnVw - 2024/03/31 12:16:56 verified with TPM PublicKey - 2024/03/31 12:16:56 verified with exported PubicKey - + TOKEN: eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MTI0OTUxNTksImlzcyI6InRlc3QifQ.cnFyy1ByWW2yFukw3yFbBVyq1nGy63FEx_2a3bL1Wh7EFqJ3z-5Lg7Eh1W-dtYZPVK_k-OExBSjpBIGwJ4aQJQ + 2024/04/07 13:04:59 verified with TPM PublicKey + 2024/04/07 13:04:59 verified with exported PubicKey -$ go run main.go --persistentHandle 0x81008002 --template cached --keyAlg=ECC - - 2024/03/31 12:17:04 ======= Init ======== - 2024/03/31 12:17:04 Load SigningKey from template cached - 2024/03/31 12:17:04 Signing PEM - -----BEGIN PUBLIC KEY----- - MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEhgCQBactv03N+4n0En2n5YdzKdBM - Xc9bk/pCN8Bpkd5XtKFHhsolNO7ri9xOGwrXmT+PfQu7yEjvqPbnQs8e4A== - -----END PUBLIC KEY----- - TOKEN: eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MTE4ODc0ODQsImlzcyI6InRlc3QifQ.IikblaLKzoDAOzdYi0X4IHgjAPtY8OLI0HlPN5Oux0ujUAp0BifVn3mrP2MnwpYyLvngfOPhGoAza2ZSY7N1tg - 2024/03/31 12:17:04 verified with TPM PublicKey - 2024/03/31 12:17:04 verified with exported PubicKey ``` Notice the public key matches the one we saved to the handle @@ -241,134 +190,88 @@ The JWT is formatted as: } ``` -to use, just import the library configure the TPM. Remember to set the override so that the correct `alg` is defined in the JWT . - You must have a key already defined and persisted to NV (transient keys not supported) -### Attestation Key - -If you want to use the Attestation key, just get the handle in the same way. - -The example cited here uses a generated Attestation key. - -If your'e on a GCP Shielded VM, it comes with a built in (pregenerated) AK. To use the GCP AK, uncomment `k, err = client.GceAttestationKeyRSA(rwc)` in the example.go file. For example: - -```bash -$ go run main.go --persistentHandle 0x81008001 --template akrsa --keyAlg=RSA - - 2023/08/27 20:05:08 ======= Init ======== - 2023/08/27 20:05:08 Load SigningKey from template ak - 2023/08/27 20:05:08 Signing PEM - -----BEGIN PUBLIC KEY----- - MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoxPZjkDnKfUZ1XZXs3oP - t3B1j5H/xjDuV7UP8BsddHrAdUDEZYfF4OJr05zF4Wr80WD1GEzZmLPinAqzSGoR - pXfDETYGDMB55vHmS/+fFvsIiEHpH6JPFHFUpCLxlszLKSG5oGkcTp1ONe2GcyxQ - MQBPrf0/3PrcE1ze8v23Qj6k0ZFw4+X9qXuJe0cj/pshyt5Ckmq2ishxM0WhJLtM - g7B+Rn3yDx5RWmE6Zduh9e8ndViuDPW7vFjuITYOXsyFdUINPyUmPQLU14wB+k03 - MRqN84PdLmcwK72gnC2gTBSox9cj9cpuuHFOmpUPOYWfzVBsRc9BXTR36lPfmalf - gQIDAQAB - -----END PUBLIC KEY----- - TOKEN: eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTMxNjY3NjgsImlzcyI6InRlc3QifQ.l7SaJBvhKS3dywmWE6dmr91WV119lvs2FEzUXgewClAz3RiGx0Nhe7n2YICBzXNccZ3MiNJgMdfjPpLbbxY-YWAAm0FRGXZ2AqPs5lysNqtCtFU3w4buTxFsqy5shMsGb7hpGdWRJtyLRMWtWVhHUyr2fqmBhaHRldDQq30BjEvvviWlT0Dc_RHDkIXTz-DfS6UIvuc_LPbVksZwteyp0pLp9HsmXedqU9EcdUafi2W-m8JQ2_LLhmL7uBG2kzURgngnHfNPSgI4JvW2Wh56pexCJIINOVWmMXsT6BL-K2COiZQ2Trpg06WHtIF0-YPeT-bbewqIQZHCMoESt6qSNQ - 2023/08/27 20:05:08 verified with TPM PublicKey - 2023/08/27 20:05:08 verified with exported PubicKey -``` - -The specific advantage of GCP and `GceAttestationKeyRSA` is you can also get the AK via API - -```bash -$ gcloud compute instances get-shielded-identity instance-1 - - kind: compute#shieldedInstanceIdentity - signingKey: - ekPub: | - -----BEGIN PUBLIC KEY----- - MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoxPZjkDnKfUZ1XZXs3oP - t3B1j5H/xjDuV7UP8BsddHrAdUDEZYfF4OJr05zF4Wr80WD1GEzZmLPinAqzSGoR - pXfDETYGDMB55vHmS/+fFvsIiEHpH6JPFHFUpCLxlszLKSG5oGkcTp1ONe2GcyxQ - MQBPrf0/3PrcE1ze8v23Qj6k0ZFw4+X9qXuJe0cj/pshyt5Ckmq2ishxM0WhJLtM - g7B+Rn3yDx5RWmE6Zduh9e8ndViuDPW7vFjuITYOXsyFdUINPyUmPQLU14wB+k03 - MRqN84PdLmcwK72gnC2gTBSox9cj9cpuuHFOmpUPOYWfzVBsRc9BXTR36lPfmalf - gQIDAQAB - -----END PUBLIC KEY----- -``` - -also see - -* [Read EK keys on GCE](https://github.com/salrashid123/tpm2/tree/master/gcp_ek_ak) -* [Sign with AK saved to NV](https://github.com/salrashid123/tpm2/blob/master/ak_sign_nv) -* [Read NV](https://github.com/salrashid123/tpm2/tree/master/nv) - ### Imported Key If you want to [import an external RSA key to the TPM](https://github.com/salrashid123/tpm2/tree/master/tpm_import_external_rsa#importing-an-external-key), you will need to define a persistent handle as well. -using tpm2_tools: +using `tpm2_tools`: ```bash -openssl rsa -in private.pem -pubout openssl genrsa -out private.pem 2048 openssl rsa -in private.pem -outform PEM -pubout -out public.pem -tpm2_createprimary -C o -g sha256 -G rsa -c primary.ctx -tpm2_import -C primary.ctx -G rsa -i private.pem -u key.pub -r key.prv -tpm2_load -C primary.ctx -u key.pub -r key.prv -c key.ctx + tpm2_createprimary -C o -g sha256 -G rsa -c primary.ctx + tpm2_import -C primary.ctx -G rsa2048:rsassa:null -g sha256 -i private.pem -u key.pub -r key.prv + tpm2_load -C primary.ctx -u key.pub -r key.prv -c key.ctx + tpm2_evictcontrol -C o -c key.ctx 0x81008003 + +echo "my message" > message.dat +tpm2_sign -c key.ctx -g sha256 -o sig1.rssa message.dat +tpm2_verifysignature -c key.ctx -g sha256 -s sig1.rssa -m message.dat tpm2_evictcontrol -C o -c key.ctx 0x81008003 ``` +You can also see how to load the entire chain here [Loading TPM key chains](https://github.com/salrashid123/tpm2/context_chain) -In the following, we persisted an RSA key (private.pem) into key `0x81008003` -```bash -$ openssl rsa -in private.pem -pubout +#### With Session and Policy - -----BEGIN PUBLIC KEY----- - MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzozz2jOLieHBMrEobKaf - LGNKP5DWGTGU/C4md2klDJsrwRVsTnM0D1hdH4h3Xho5iM4Llz5Us6TAqzkO4sGg - 2iPfWz9C6P+j8ajRIK46KB9UAdd8+nGoKQzDJ8tpF/jFYyev7kHhPzbibK1GsrDq - u2+zZuNpp2Jv62iTDK160cmonADRzTB7GQMgFWdvSr0YvscwhH3+17Thph4tRXF8 - RDdumg+4TKiAKRVDSw8thdCapwLMz/5bh9Ourr0QNqHOJqNEfayg0sS9ugqbu2nG - FMyPtlMojcpTehujjms61MrDOwSYPq/boK24Y+2HlRyXYooLnzp/pKq8nbdht+Fi - OwIDAQAB - -----END PUBLIC KEY----- -``` +If a key is bound to a PCR policy, you can specify that inline during key initialization. -Reading specifications using tpm2_tools and verify that the private key exists on the TPM: +For example, the following has `PCR=23` policy bound: -```bash -$ tpm2_readpublic -Q -c 0x81008003 -f pem -o imported_key.pem +```golang + s, err := client.NewPCRSession(rwc, tpm2.PCRSelection{tpm2.AlgSHA256, []int{23}}) + defer s.Close() -$ cat imported_key.pem + sessionKey, err := client.LoadCachedKey(rwc, tpmutil.Handle(*persistentHandle), s) + defer sessionKey.Close() - -----BEGIN PUBLIC KEY----- - MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzozz2jOLieHBMrEobKaf - LGNKP5DWGTGU/C4md2klDJsrwRVsTnM0D1hdH4h3Xho5iM4Llz5Us6TAqzkO4sGg - 2iPfWz9C6P+j8ajRIK46KB9UAdd8+nGoKQzDJ8tpF/jFYyev7kHhPzbibK1GsrDq - u2+zZuNpp2Jv62iTDK160cmonADRzTB7GQMgFWdvSr0YvscwhH3+17Thph4tRXF8 - RDdumg+4TKiAKRVDSw8thdCapwLMz/5bh9Ourr0QNqHOJqNEfayg0sS9ugqbu2nG - FMyPtlMojcpTehujjms61MrDOwSYPq/boK24Y+2HlRyXYooLnzp/pKq8nbdht+Fi - OwIDAQAB - -----END PUBLIC KEY----- + sessionConfig := &tpmjwt.TPMConfig{ + TPMDevice: rwc, + Key: sessionKey, + } +``` +Which you can initialize though: -$ go run main.go --persistentHandle 0x81008003 --template cached --keyAlg=RSA - - 2024/03/31 12:48:14 ======= Init ======== - 2024/03/31 12:48:14 Load SigningKey from template cached - 2024/03/31 12:48:14 Signing PEM - -----BEGIN PUBLIC KEY----- - MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzozz2jOLieHBMrEobKaf - LGNKP5DWGTGU/C4md2klDJsrwRVsTnM0D1hdH4h3Xho5iM4Llz5Us6TAqzkO4sGg - 2iPfWz9C6P+j8ajRIK46KB9UAdd8+nGoKQzDJ8tpF/jFYyev7kHhPzbibK1GsrDq - u2+zZuNpp2Jv62iTDK160cmonADRzTB7GQMgFWdvSr0YvscwhH3+17Thph4tRXF8 - RDdumg+4TKiAKRVDSw8thdCapwLMz/5bh9Ourr0QNqHOJqNEfayg0sS9ugqbu2nG - FMyPtlMojcpTehujjms61MrDOwSYPq/boK24Y+2HlRyXYooLnzp/pKq8nbdht+Fi - OwIDAQAB - -----END PUBLIC KEY----- - TOKEN: eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MTE4ODkzNTQsImlzcyI6InRlc3QifQ.loMcBdqlVTJS8KzPYQhtcxSm83gnwFIurnk3WLkx_G_skrq4iqyyHOpVJDyqgMuRAxWz1HC-SoNiml1TCwvqTXs7SZ9tGkS6dFd4PDIQvtKh8c20bwK-rMydqXJfRopjkdD_xzvchdqacIxUjDIedFNXwX21Znxq3OAH1YDkT6LNYvIzFEWlq-fMX9dyird5PmgvzVEYnd8X3QNBU78drNEwTHsjhmJotEj2tpfxtg86Eg27K3AQfjOYgvzMoHTo1-AEYbNh8nIyGIg_DXQbbzSwbBqgn8HhqEADwBbgkyq2O0NJLSf2FjkDieTcSQgFKvknsF8JUcw0c7vs_bEkkw - 2024/03/31 12:48:14 verified with TPM PublicKey - 2024/03/31 12:48:14 verified with exported PubicKey +```bash +## first print the value at pcr 23: +# tpm2_flushcontext -t -s -l +# tpm2_evictcontrol -C o -c 0x81008004 +# tpm2_pcrread sha256:23 +# sha256: +# 23: 0x0000000000000000000000000000000000000000000000000000000000000000 + +## you can optionally 'extend' the value to get a new PCR to use (default for 23 if unset is usually all those 0's) +# tpm2_pcrextend 23:sha256=0x0000000000000000000000000000000000000000000000000000000000000000 +# tpm2_pcrread sha256:23 +# sha256: +# 23: 0xF5A5FD42D16A20302798EF6ED309979B43003D2320D9F0E8EA9831A92759FB4B + +## create an auth sesison and the two polcies +tpm2_startauthsession -S session.dat +tpm2_policypcr -S session.dat -l sha256:23 -L policy.dat +tpm2_flushcontext session.dat + +## create the parent +tpm2_createprimary -C o -c primary2.ctx + +tpm2_create -G rsa2048:rsassa:null -g sha256 -u rsa2.pub -r rsa2.priv -C primary2.ctx -L policy.dat +tpm2_load -C primary2.ctx -u rsa2.pub -r rsa2.priv -c rsa2.ctx + +## finally make the key persistent +tpm2_evictcontrol -C o -c rsa2.ctx 0x81008004 ``` -You can also see how to load the entire chain here [Loading TPM key chains](https://github.com/salrashid123/tpm2/context_chain) +Then, + +```bash +cd example/ +go run policy/main.go --persistentHandle=0x81008004 +``` +For more information, see (TPM2 Policy)[https://github.com/salrashid123/tpm2/tree/master/policy] diff --git a/example/go.mod b/example/go.mod index 9f31401..4e7e33f 100644 --- a/example/go.mod +++ b/example/go.mod @@ -3,21 +3,32 @@ module main go 1.20 require ( - github.com/golang-jwt/jwt v3.2.2+incompatible github.com/google/go-tpm-tools v0.4.0 github.com/salrashid123/golang-jwt-tpm v0.0.0 ) -require github.com/google/go-tpm v0.9.0 +require ( + github.com/golang-jwt/jwt/v5 v5.2.1 + github.com/google/go-tpm v0.9.0 + github.com/lestrrat-go/jwx/v2 v2.0.21 +) require ( + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect + github.com/goccy/go-json v0.10.2 // indirect github.com/google/go-sev-guest v0.6.1 // indirect github.com/google/logger v1.1.1 // indirect github.com/google/uuid v1.3.0 // indirect + github.com/lestrrat-go/blackmagic v1.0.2 // indirect + github.com/lestrrat-go/httpcc v1.0.1 // indirect + github.com/lestrrat-go/httprc v1.0.5 // indirect + github.com/lestrrat-go/iter v1.0.2 // indirect + github.com/lestrrat-go/option v1.0.1 // indirect github.com/pborman/uuid v1.2.0 // indirect github.com/pkg/errors v0.9.1 // indirect - golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e // indirect - golang.org/x/sys v0.8.0 // indirect + github.com/segmentio/asm v1.2.0 // indirect + golang.org/x/crypto v0.21.0 // indirect + golang.org/x/sys v0.18.0 // indirect google.golang.org/protobuf v1.28.0 // indirect ) diff --git a/example/go.sum b/example/go.sum index d479a0a..5f69d0d 100644 --- a/example/go.sum +++ b/example/go.sum @@ -1,5 +1,11 @@ -github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= -github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= +github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/google/certificate-transparency-go v1.1.2 h1:4hE0GEId6NAW28dFpC+LrRGwQX5dtmXQGDbg8+/MZOM= @@ -18,18 +24,41 @@ github.com/google/logger v1.1.1/go.mod h1:BkeJZ+1FhQ+/d087r4dzojEg1u2ZX+ZqG1jTUr github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/lestrrat-go/blackmagic v1.0.2 h1:Cg2gVSc9h7sz9NOByczrbUvLopQmXrfFx//N+AkAr5k= +github.com/lestrrat-go/blackmagic v1.0.2/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU= +github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE= +github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E= +github.com/lestrrat-go/httprc v1.0.5 h1:bsTfiH8xaKOJPrg1R+E3iE/AWZr/x0Phj9PBTG/OLUk= +github.com/lestrrat-go/httprc v1.0.5/go.mod h1:mwwz3JMTPBjHUkkDv/IGJ39aALInZLrhBp0X7KGUZlo= +github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI= +github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4= +github.com/lestrrat-go/jwx/v2 v2.0.21 h1:jAPKupy4uHgrHFEdjVjNkUgoBKtVDgrQPB/h55FHrR0= +github.com/lestrrat-go/jwx/v2 v2.0.21/go.mod h1:09mLW8zto6bWL9GbwnqAli+ArLf+5M33QLQPDggkUWM= +github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU= +github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= +github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= -golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e h1:T8NU3HyQ8ClP4SEE+KbFlg6n0NhuTsN4MyznaarGsZM= -golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/example/main.go b/example/main.go deleted file mode 100644 index e436610..0000000 --- a/example/main.go +++ /dev/null @@ -1,227 +0,0 @@ -package main - -import ( - "context" - "crypto/ecdsa" - "crypto/rsa" - "crypto/x509" - "encoding/pem" - "flag" - "fmt" - "log" - "time" - - "github.com/golang-jwt/jwt" - tpmjwt "github.com/salrashid123/golang-jwt-tpm" - - "github.com/google/go-tpm-tools/client" - "github.com/google/go-tpm/legacy/tpm2" - "github.com/google/go-tpm/tpmutil" -) - -var ( - tpmPath = flag.String("tpm-path", "/dev/tpm0", "Path to the TPM device (character device or a Unix socket).") - persistentHandle = flag.Uint("persistentHandle", 0x81008001, "Handle value") - keyAlg = flag.String("keyAlg", "RSA", "Key Algorithm") - template = flag.String("template", "akrsa", "Template to use, one of ak|cached") - flushHandles = flag.Bool("flushHandles", false, "FlushTPM Hanldles") - handleNames = map[string][]tpm2.HandleType{ - "all": {tpm2.HandleTypeLoadedSession, tpm2.HandleTypeSavedSession, tpm2.HandleTypeTransient}, - "loaded": {tpm2.HandleTypeLoadedSession}, - "saved": {tpm2.HandleTypeSavedSession}, - "transient": {tpm2.HandleTypeTransient}, - "none": {}, - } - - rsaKeyParams = tpm2.Public{ - Type: tpm2.AlgRSA, - NameAlg: tpm2.AlgSHA256, - Attributes: tpm2.FlagFixedTPM | tpm2.FlagFixedParent | tpm2.FlagSensitiveDataOrigin | - tpm2.FlagUserWithAuth | tpm2.FlagSign, - AuthPolicy: []byte{}, - RSAParameters: &tpm2.RSAParams{ - Sign: &tpm2.SigScheme{ - Alg: tpm2.AlgRSASSA, - Hash: tpm2.AlgSHA256, - }, - KeyBits: 2048, - }, - } - - eccKeyParams = tpm2.Public{ - Type: tpm2.AlgECC, - NameAlg: tpm2.AlgSHA256, - Attributes: tpm2.FlagFixedTPM | tpm2.FlagFixedParent | tpm2.FlagSensitiveDataOrigin | - tpm2.FlagUserWithAuth | tpm2.FlagSign, - AuthPolicy: []byte{}, - ECCParameters: &tpm2.ECCParams{ - Sign: &tpm2.SigScheme{Alg: tpm2.AlgECDSA, Hash: tpm2.AlgSHA256}, - CurveID: tpm2.CurveNISTP256, - Point: tpm2.ECPoint{ - XRaw: make([]byte, 32), - YRaw: make([]byte, 32), - }, - }, - } -) - -func main() { - - flag.Parse() - ctx := context.Background() - - log.Printf("======= Init ========") - - if !(*keyAlg == "RSA" || *keyAlg == "ECC") { - log.Fatalf("keyAlg must be either RSA or ECC") - } - - rwc, err := tpm2.OpenTPM(*tpmPath) - if err != nil { - log.Fatalf("can't open TPM %q: %v", *tpmPath, err) - } - defer func() { - if err := rwc.Close(); err != nil { - log.Fatalf("can't close TPM %q: %v", *tpmPath, err) - } - }() - - if *flushHandles { - totalHandles := 0 - for _, handleType := range handleNames["all"] { - handles, err := client.Handles(rwc, handleType) - if err != nil { - log.Fatalf("getting handles: %v", err) - } - for _, handle := range handles { - if err = tpm2.FlushContext(rwc, handle); err != nil { - log.Fatalf("flushing handle 0x%x: %v", handle, err) - } - log.Printf("Handle 0x%x flushed\n", handle) - totalHandles++ - } - } - log.Printf("%d handles flushed\n", totalHandles) - } - - claims := &jwt.StandardClaims{ - ExpiresAt: time.Now().Add(time.Minute * 1).Unix(), - Issuer: "test", - } - - var token *jwt.Token - - if *keyAlg == "RSA" { - tpmjwt.SigningMethodTPMRS256.Override() - token = jwt.NewWithClaims(tpmjwt.SigningMethodTPMRS256, claims) - } else if *keyAlg == "ECC" { - tpmjwt.SigningMethodTPMES256.Override() - token = jwt.NewWithClaims(tpmjwt.SigningMethodTPMES256, claims) - } else { - log.Printf("Unknown Key Type %s", *keyAlg) - } - log.Printf(" Load SigningKey from template %s ", *template) - - var k *client.Key - switch { - case *template == "akrsa": - k, err = client.AttestationKeyRSA(rwc) - //k, err = client.GceAttestationKeyRSA(rwc) - case *template == "akecc": - k, err = client.AttestationKeyECC(rwc) - //k, err = client.GceAKCertNVIndexECC(rwc) - case *template == "cached": - if *persistentHandle == 0 { - log.Printf("error: persistentHandle must be specified for cached keys") - return - } - // k, err = client.LoadCachedKey(rwc, tpmutil.Handle(*persistentHandle), client.EKSession{}) - k, err = client.LoadCachedKey(rwc, tpmutil.Handle(*persistentHandle), nil) - case *template == "created": - if *persistentHandle == 0 { - log.Printf("error: persistentHandle must be specified for created keys") - return - } - if *keyAlg == "RSA" { - k, err = client.NewCachedKey(rwc, tpm2.HandleOwner, rsaKeyParams, tpmutil.Handle(*persistentHandle)) - } else if *keyAlg == "ECC" { - k, err = client.NewCachedKey(rwc, tpm2.HandleOwner, eccKeyParams, tpmutil.Handle(*persistentHandle)) - } - default: - log.Printf("template type must be one of akrsa|akecc|imported|created") - return - } - if err != nil { - log.Printf("ERROR: could not initialize Key: %v", err) - return - } - - var akBytes []byte - - if *keyAlg == "RSA" { - pubKey := k.PublicKey().(*rsa.PublicKey) - akBytes, err = x509.MarshalPKIXPublicKey(pubKey) - } else if *keyAlg == "ECC" { - pubKey := k.PublicKey().(*ecdsa.PublicKey) - akBytes, err = x509.MarshalPKIXPublicKey(pubKey) - } - if err != nil { - log.Printf("ERROR: could not get MarshalPKIXPublicKey: %v", err) - return - } - - akPubPEM := pem.EncodeToMemory( - &pem.Block{ - Type: "PUBLIC KEY", - Bytes: akBytes, - }, - ) - log.Printf(" Signing PEM \n%s", string(akPubPEM)) - - config := &tpmjwt.TPMConfig{ - TPMDevice: rwc, - Key: k, - } - - keyctx, err := tpmjwt.NewTPMContext(ctx, config) - if err != nil { - log.Fatalf("Unable to initialize tpmJWT: %v", err) - } - - // optionally set a keyID - //token.Header["kid"] = config.GetKeyID() - - tokenString, err := token.SignedString(keyctx) - if err != nil { - log.Fatalf("Error signing %v", err) - } - fmt.Printf("TOKEN: %s\n", tokenString) - - // verify with TPM based publicKey - keyFunc, err := tpmjwt.TPMVerfiyKeyfunc(ctx, config) - if err != nil { - log.Fatalf("could not get keyFunc: %v", err) - } - - vtoken, err := jwt.Parse(tokenString, keyFunc) - if err != nil { - log.Fatalf("Error verifying token %v", err) - } - if vtoken.Valid { - log.Println(" verified with TPM PublicKey") - } - - // verify with provided RSAPublic key - pubKeyr := config.GetPublicKey() - - v, err := jwt.Parse(vtoken.Raw, func(token *jwt.Token) (interface{}, error) { - return pubKeyr, nil - }) - if err != nil { - log.Fatalf("Error parsing token %v", err) - } - if v.Valid { - log.Println(" verified with exported PubicKey") - } - -} diff --git a/example/nopolicy/main.go b/example/nopolicy/main.go new file mode 100644 index 0000000..3fea252 --- /dev/null +++ b/example/nopolicy/main.go @@ -0,0 +1,149 @@ +package main + +import ( + "context" + "crypto" + "crypto/ecdsa" + "crypto/rsa" + "crypto/x509" + "encoding/pem" + "flag" + "fmt" + "log" + "time" + + jwt "github.com/golang-jwt/jwt/v5" + "github.com/google/go-tpm-tools/client" + "github.com/google/go-tpm/legacy/tpm2" + "github.com/google/go-tpm/tpmutil" + tpmjwt "github.com/salrashid123/golang-jwt-tpm" +) + +/* +## RSA + tpm2_createprimary -C e -c primary.ctx + tpm2_create -G rsa2048:rsassa:null -g sha256 -u key.pub -r key.priv -C primary.ctx + tpm2_load -C primary.ctx -u key.pub -r key.priv -c key.ctx + tpm2_evictcontrol -C o -c key.ctx 0x81008001 + +## ECC + tpm2_createprimary -C e -c primary.ctx + tpm2_create -G ecc:ecdsa -g sha256 -u key.pub -r key.priv -C primary.ctx + tpm2_load -C primary.ctx -u key.pub -r key.priv -c key.ctx + tpm2_evictcontrol -C o -c key.ctx 0x81008002 +*/ + +var ( + tpmPath = flag.String("tpm-path", "/dev/tpm0", "Path to the TPM device (character device or a Unix socket).") + persistentHandle = flag.Uint("persistentHandle", 0x81008001, "Handle value") + template = flag.String("template", "akrsa", "Template to use, one of ak|cached") +) + +func main() { + + flag.Parse() + ctx := context.Background() + + log.Printf("======= Init ========") + + rwc, err := tpm2.OpenTPM(*tpmPath) + if err != nil { + log.Fatalf("can't open TPM %q: %v", *tpmPath, err) + } + defer func() { + if err := rwc.Close(); err != nil { + log.Fatalf("can't close TPM %q: %v", *tpmPath, err) + } + }() + + claims := &jwt.RegisteredClaims{ + ExpiresAt: &jwt.NumericDate{time.Now().Add(time.Minute * 1)}, + Issuer: "test", + } + + var token *jwt.Token + + k, err := client.LoadCachedKey(rwc, tpmutil.Handle(*persistentHandle), nil) + if err != nil { + log.Printf("ERROR: could not initialize Key: %v", err) + return + } + defer k.Close() + + var pubKey crypto.PublicKey + switch k.PublicKey().(type) { + case *rsa.PublicKey: + tpmjwt.SigningMethodTPMRS256.Override() + token = jwt.NewWithClaims(tpmjwt.SigningMethodTPMRS256, claims) + + pubKey = k.PublicKey().(*rsa.PublicKey) + case *ecdsa.PublicKey: + tpmjwt.SigningMethodTPMES256.Override() + token = jwt.NewWithClaims(tpmjwt.SigningMethodTPMES256, claims) + + pubKey = k.PublicKey().(*ecdsa.PublicKey) + default: + log.Printf("ERROR: unsupported key type: %v", k.PublicKey()) + return + } + + akBytes, err := x509.MarshalPKIXPublicKey(pubKey) + if err != nil { + log.Printf("ERROR: could not get MarshalPKIXPublicKey: %v", err) + return + } + + akPubPEM := pem.EncodeToMemory( + &pem.Block{ + Type: "PUBLIC KEY", + Bytes: akBytes, + }, + ) + log.Printf(" Signing PEM \n%s", string(akPubPEM)) + + config := &tpmjwt.TPMConfig{ + TPMDevice: rwc, + Key: k, + } + + keyctx, err := tpmjwt.NewTPMContext(ctx, config) + if err != nil { + log.Fatalf("Unable to initialize tpmJWT: %v", err) + } + + // optionally set a keyID + //token.Header["kid"] = config.GetKeyID() + + tokenString, err := token.SignedString(keyctx) + if err != nil { + log.Fatalf("Error signing %v", err) + } + fmt.Printf("TOKEN: %s\n", tokenString) + + // verify with TPM based publicKey + keyFunc, err := tpmjwt.TPMVerfiyKeyfunc(ctx, config) + if err != nil { + log.Fatalf("could not get keyFunc: %v", err) + } + + vtoken, err := jwt.Parse(tokenString, keyFunc) + if err != nil { + log.Fatalf("Error verifying token %v", err) + } + if vtoken.Valid { + log.Println(" verified with TPM PublicKey") + } + + // verify with provided RSAPublic key + pubKeyr := config.GetPublicKey() + + v, err := jwt.Parse(vtoken.Raw, func(token *jwt.Token) (interface{}, error) { + return pubKeyr, nil + }) + if err != nil { + log.Fatalf("Error parsing token %v", err) + } + if v.Valid { + log.Println(" verified with exported PubicKey") + } +} diff --git a/example/policy/main.go b/example/policy/main.go new file mode 100644 index 0000000..8e7f7ab --- /dev/null +++ b/example/policy/main.go @@ -0,0 +1,95 @@ +package main + +import ( + "context" + "flag" + "fmt" + "log" + "time" + + jwt "github.com/golang-jwt/jwt/v5" + "github.com/google/go-tpm-tools/client" + "github.com/google/go-tpm/legacy/tpm2" + "github.com/google/go-tpm/tpmutil" + tpmjwt "github.com/salrashid123/golang-jwt-tpm" +) + +/* +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_createprimary -C o -c primary2.ctx +tpm2_create -G rsa2048:rsassa:null -g sha256 -u rsa2.pub -r rsa2.priv -C primary2.ctx -L policy.dat +tpm2_load -C primary2.ctx -u rsa2.pub -r rsa2.priv -c rsa2.ctx +tpm2_evictcontrol -C o -c rsa2.ctx 0x81008004 +*/ + +var ( + tpmPath = flag.String("tpm-path", "/dev/tpm0", "Path to the TPM device (character device or a Unix socket).") + persistentHandle = flag.Uint("persistentHandle", 0x81008004, "Handle value") + pcr = flag.Int("pcr", 23, "PCR Bound value") +) + +func main() { + + flag.Parse() + ctx := context.Background() + + rwc, err := tpm2.OpenTPM(*tpmPath) + if err != nil { + log.Fatalf("can't open TPM %q: %v", *tpmPath, err) + } + defer func() { + if err := rwc.Close(); err != nil { + log.Fatalf("can't close TPM %q: %v", *tpmPath, err) + } + }() + + claims := &jwt.RegisteredClaims{ + ExpiresAt: &jwt.NumericDate{time.Now().Add(time.Minute * 1)}, + Issuer: "test", + } + + tpmjwt.SigningMethodTPMRS256.Override() + token := jwt.NewWithClaims(tpmjwt.SigningMethodTPMRS256, claims) + + s, err := client.NewPCRSession(rwc, tpm2.PCRSelection{tpm2.AlgSHA256, []int{*pcr}}) + if err != nil { + log.Fatalf("Unable to initialize tpmJWT: %v", err) + } + defer s.Close() + sessionKey, err := client.LoadCachedKey(rwc, tpmutil.Handle(*persistentHandle), s) + if err != nil { + log.Fatalf("Unable to Load Key: %v", err) + } + defer sessionKey.Close() + sessionConfig := &tpmjwt.TPMConfig{ + TPMDevice: rwc, + Key: sessionKey, + } + sessionKeyctx, err := tpmjwt.NewTPMContext(ctx, sessionConfig) + if err != nil { + log.Fatalf("Unable to initialize tpmJWT: %v", err) + } + + sessionTokenString, err := token.SignedString(sessionKeyctx) + if err != nil { + log.Fatalf("Error signing %v", err) + } + fmt.Printf("TOKEN: %s\n", sessionTokenString) + + sessionKeyFunc, err := tpmjwt.TPMVerfiyKeyfunc(ctx, sessionConfig) + if err != nil { + log.Fatalf("could not get keyFunc: %v", err) + } + + sessionVtoken, err := jwt.Parse(sessionTokenString, sessionKeyFunc) + if err != nil { + log.Fatalf("Error verifying token %v", err) + } + if sessionVtoken.Valid { + log.Println(" verified with TPM PublicKey") + } + +} diff --git a/util/keycreate.go b/example/util/keycreate.go similarity index 96% rename from util/keycreate.go rename to example/util/keycreate.go index a4c0e95..59eee77 100644 --- a/util/keycreate.go +++ b/example/util/keycreate.go @@ -18,11 +18,10 @@ import ( "log" - "github.com/golang/glog" "github.com/google/go-tpm-tools/client" "github.com/google/go-tpm/legacy/tpm2" "github.com/google/go-tpm/tpmutil" - "github.com/lestrrat-go/jwx/jwk" + "github.com/lestrrat-go/jwx/v2/jwk" ) const () @@ -148,13 +147,13 @@ func main() { if *evict { err = tpm2.EvictControl(rwc, "", tpm2.HandleOwner, pHandle, pHandle) if err != nil { - glog.Fatalf(" Unable evict persistentHandle: %v ", err) + log.Fatalf(" Unable evict persistentHandle: %v ", err) } } err = tpm2.EvictControl(rwc, "", tpm2.HandleOwner, kh, pHandle) if err != nil { - glog.Fatalf(" Unable to set persistentHandle: %v", err) + log.Fatalf(" Unable to set persistentHandle: %v", err) } defer tpm2.FlushContext(rwc, kh) @@ -194,7 +193,7 @@ func main() { hasher.Write(der) kid := base64.RawStdEncoding.EncodeToString(hasher.Sum(nil)) - jkey, err := jwk.New(ap) + jkey, err := jwk.FromRaw(ap) if err != nil { log.Fatalf("failed to create symmetric key: %s\n", err) } diff --git a/go.mod b/go.mod index 1aaee68..6b45dcf 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/salrashid123/golang-jwt-tpm go 1.20 require ( - github.com/golang-jwt/jwt v3.2.2+incompatible + github.com/golang-jwt/jwt/v5 v5.2.1 github.com/google/go-tpm v0.9.0 github.com/google/go-tpm-tools v0.4.0 ) diff --git a/go.sum b/go.sum index d479a0a..558809b 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= -github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= +github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= +github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/google/certificate-transparency-go v1.1.2 h1:4hE0GEId6NAW28dFpC+LrRGwQX5dtmXQGDbg8+/MZOM= diff --git a/tpmsigner.go b/tpmsigner.go index 182a0d6..7c1358f 100644 --- a/tpmsigner.go +++ b/tpmsigner.go @@ -4,12 +4,13 @@ import ( "context" "crypto" "crypto/ecdsa" - "encoding/base64" + "encoding/asn1" "errors" "fmt" "io" + "math/big" - jwt "github.com/golang-jwt/jwt" + jwt "github.com/golang-jwt/jwt/v5" "github.com/google/go-tpm-tools/client" "github.com/google/go-tpm/legacy/tpm2" @@ -38,7 +39,6 @@ var ( SigningMethodTPMRS256 *SigningMethodTPM SigningMethodTPMES256 *SigningMethodTPM errMissingConfig = errors.New("tpmjwt: missing configuration in provided context") - errMissingTPM = errors.New("tpmjwt: TPM device not available") ) type SigningMethodTPM struct { @@ -52,6 +52,15 @@ func NewTPMContext(parent context.Context, val *TPMConfig) (context.Context, err if val.TPMDevice == nil || val.Key == nil { return nil, fmt.Errorf("tpmjwt: tpm device or key not set") } + switch val.Key.PublicArea().Type { + case tpm2.AlgRSA: + // do optional validation + case tpm2.AlgECC: + // do optional validation + default: + return nil, fmt.Errorf("tpmjwt: unsupported Algorithm %s", val.Key.PublicArea().Type) + } + val.publicKeyFromTPM = val.Key.PublicKey() return context.WithValue(parent, tpmConfigKey{}, val), nil } @@ -101,79 +110,47 @@ func (s *SigningMethodTPM) Hash() crypto.Hash { return s.hasher } -func (s *SigningMethodTPM) Sign(signingString string, key interface{}) (string, error) { +func (s *SigningMethodTPM) Sign(signingString string, key interface{}) ([]byte, error) { var ctx context.Context switch k := key.(type) { case context.Context: ctx = k default: - return "", jwt.ErrInvalidKey + return nil, jwt.ErrInvalidKey } config, ok := TPMFromContext(ctx) if !ok { - return "", errMissingConfig + return nil, errMissingConfig } - - // first make the TPM hash the data. We need to do this incase the key is an attestation key - // (ie, a restricted key) - digest, hashValidation, err := tpm2.Hash(config.TPMDevice, tpm2.AlgSHA256, []byte(signingString), tpm2.HandleOwner) + tsig, err := config.Key.SignData([]byte(signingString)) if err != nil { - return "", fmt.Errorf("Hash failed unexpectedly: %v", err) + return nil, fmt.Errorf("tpmjwt: can't Sign %s: %v", config.TPMDevice, err) } - // signer cannot sign restricted Attestation keys yet - // https://pkg.go.dev/github.com/google/go-tpm-tools@v0.3.1/client#Key.SignData - - // cryptoSigner, err := config.Key.GetSigner() - // if err != nil { - // return "", fmt.Errorf("tpmjwt: can't get Signer %s: %v", config.TPMDevice, err) - // } - // signedBytes, err := cryptoSigner.Sign(config.TPMDevice, digest, s.hasher) - // if err != nil { - // return "", fmt.Errorf("tpmjwt: can't Sign %s: %v", config.TPMDevice, err) - // } - - // So for now we do this the long way - // https://github.com/salrashid123/tpm2/tree/master/sign_with_ak - var tsig *tpm2.Signature - if s.alg == "RS256" { - tsig, err = tpm2.Sign(config.TPMDevice, config.Key.Handle(), "", digest[:], hashValidation, &tpm2.SigScheme{ - Alg: tpm2.AlgRSASSA, - Hash: tpm2.AlgSHA256, - }) - } - if s.alg == "ES256" { - tsig, err = tpm2.Sign(config.TPMDevice, config.Key.Handle(), "", digest[:], hashValidation, &tpm2.SigScheme{ - Alg: tpm2.AlgECDSA, - Hash: tpm2.AlgSHA256, - }) - } - if err != nil { - return "", fmt.Errorf("tpmjwt: can't Sign %s: %v", config.TPMDevice, err) - } - switch tsig.Alg { - case tpm2.AlgRSASSA: - return base64.RawURLEncoding.EncodeToString(tsig.RSA.Signature), nil - case tpm2.AlgECDSA: - // dont' use asn1 - // sigStruct := struct{ R, S *big.Int }{tsig.ECC.R, tsig.ECC.S} - // return asn1.Marshal(sigStruct), nil - - // https://github.com/golang-jwt/jwt/blob/main/ecdsa.go#L92 - epub := config.publicKeyFromTPM.(*ecdsa.PublicKey) - curveBits := epub.Curve.Params().BitSize + + if config.Key.PublicArea().Type == tpm2.AlgECC { + // go-tpm-tools formats ECC signatures as asn1 but JWT expects raw so convert + // the asn1 back + epub, ok := config.Key.PublicKey().(*ecdsa.PublicKey) + if !ok { + return nil, fmt.Errorf("tpmjwt: error converting ECC keytype %v", err) + } + curveBits := epub.Params().BitSize keyBytes := curveBits / 8 if curveBits%8 > 0 { keyBytes += 1 } out := make([]byte, 2*keyBytes) - tsig.ECC.R.FillBytes(out[0:keyBytes]) - tsig.ECC.S.FillBytes(out[keyBytes:]) - return base64.RawURLEncoding.EncodeToString(out), nil - - default: - return "", fmt.Errorf("unsupported signing algorithm: %v", tsig.Alg) + var sigStruct struct{ R, S *big.Int } + _, err := asn1.Unmarshal(tsig, &sigStruct) + if err != nil { + return nil, fmt.Errorf("tpmjwt: can't unmarshall ecc struct %v", err) + } + sigStruct.R.FillBytes(out[0:keyBytes]) + sigStruct.S.FillBytes(out[keyBytes:]) + return out, nil } + return tsig, nil } func TPMVerfiyKeyfunc(ctx context.Context, config *TPMConfig) (jwt.Keyfunc, error) { @@ -182,6 +159,6 @@ func TPMVerfiyKeyfunc(ctx context.Context, config *TPMConfig) (jwt.Keyfunc, erro }, nil } -func (s *SigningMethodTPM) Verify(signingString, signature string, key interface{}) error { - return s.override.Verify(signingString, signature, key) +func (s *SigningMethodTPM) Verify(signingString string, signature []byte, key interface{}) error { + return s.override.Verify(signingString, []byte(signature), key) } diff --git a/util/go.mod b/util/go.mod deleted file mode 100644 index f6eaf1f..0000000 --- a/util/go.mod +++ /dev/null @@ -1,28 +0,0 @@ -module util - -go 1.20 - -require ( - github.com/golang/glog v1.1.2 - github.com/google/go-tpm v0.9.0 - github.com/google/go-tpm-tools v0.4.0 - github.com/lestrrat-go/jwx v1.2.26 -) - -require ( - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect - github.com/goccy/go-json v0.10.2 // indirect - github.com/google/go-sev-guest v0.6.1 // indirect - github.com/google/logger v1.1.1 // indirect - github.com/google/uuid v1.3.0 // indirect - github.com/lestrrat-go/backoff/v2 v2.0.8 // indirect - github.com/lestrrat-go/blackmagic v1.0.1 // indirect - github.com/lestrrat-go/httpcc v1.0.1 // indirect - github.com/lestrrat-go/iter v1.0.2 // indirect - github.com/lestrrat-go/option v1.0.1 // indirect - github.com/pborman/uuid v1.2.0 // indirect - github.com/pkg/errors v0.9.1 // indirect - golang.org/x/crypto v0.9.0 // indirect - golang.org/x/sys v0.8.0 // indirect - google.golang.org/protobuf v1.28.0 // indirect -) diff --git a/util/go.sum b/util/go.sum deleted file mode 100644 index c79ad23..0000000 --- a/util/go.sum +++ /dev/null @@ -1,103 +0,0 @@ -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= -github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= -github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= -github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= -github.com/google/certificate-transparency-go v1.1.2 h1:4hE0GEId6NAW28dFpC+LrRGwQX5dtmXQGDbg8+/MZOM= -github.com/google/go-attestation v0.4.4-0.20230613144338-a9b6eb1eb888 h1:HURgKPRPJSozDuMHpjdV+iyFVLhB6bi1JanhGgSzI1k= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-sev-guest v0.6.1 h1:NajHkAaLqN9/aW7bCFSUplUMtDgk2+HcN7jC2btFtk0= -github.com/google/go-sev-guest v0.6.1/go.mod h1:UEi9uwoPbLdKGl1QHaq1G8pfCbQ4QP0swWX4J0k6r+Q= -github.com/google/go-tpm v0.9.0 h1:sQF6YqWMi+SCXpsmS3fd21oPy/vSddwZry4JnmltHVk= -github.com/google/go-tpm v0.9.0/go.mod h1:FkNVkc6C+IsvDI9Jw1OveJmxGZUUaKxtrpOS47QWKfU= -github.com/google/go-tpm-tools v0.4.0 h1:bYRZAUvQEmn11WTKCkTLRCCv4aTlOBgBBeqCK0ABT2A= -github.com/google/go-tpm-tools v0.4.0/go.mod h1:G7PFUk8KKQzdYYGv/cpV9LB9sPT7czAAomnceugzNKQ= -github.com/google/go-tspi v0.3.0 h1:ADtq8RKfP+jrTyIWIZDIYcKOMecRqNJFOew2IT0Inus= -github.com/google/logger v1.1.1 h1:+6Z2geNxc9G+4D4oDO9njjjn2d0wN5d7uOo0vOIW1NQ= -github.com/google/logger v1.1.1/go.mod h1:BkeJZ+1FhQ+/d087r4dzojEg1u2ZX+ZqG1jTUrLM+zQ= -github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/lestrrat-go/backoff/v2 v2.0.8 h1:oNb5E5isby2kiro9AgdHLv5N5tint1AnDVVf2E2un5A= -github.com/lestrrat-go/backoff/v2 v2.0.8/go.mod h1:rHP/q/r9aT27n24JQLa7JhSQZCKBBOiM/uP402WwN8Y= -github.com/lestrrat-go/blackmagic v1.0.1 h1:lS5Zts+5HIC/8og6cGHb0uCcNCa3OUt1ygh3Qz2Fe80= -github.com/lestrrat-go/blackmagic v1.0.1/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU= -github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE= -github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E= -github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI= -github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4= -github.com/lestrrat-go/jwx v1.2.26 h1:4iFo8FPRZGDYe1t19mQP0zTRqA7n8HnJ5lkIiDvJcB0= -github.com/lestrrat-go/jwx v1.2.26/go.mod h1:MaiCdGbn3/cckbOFSCluJlJMmp9dmZm5hDuIkx8ftpQ= -github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= -github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU= -github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= -github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g= -github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= -go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= -golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= -google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=