Generate and verify JWT tokens with Trusted Platform Module (TPM)

golang-jwt for Trusted Platform Module (TPM)

This is just an extension for go-jwt i wrote over thanksgiving that allows creating and verifying JWT tokens where the private key is embedded inside a Trusted platform module.

You can use this library to sign and verify a JWT using the standard go-jwt library semantics.

This library also includes a utility function to create an RSA key inside a TPM and also print its public key in RSA and JWK formats.

Using a TPM to sign or encrypt anything has some very specific applications which i will not go into it much (if your'e reading this, you probably already know). If a JWT is signed by a TPM and if the key that was used was setup in a specific format, the verifier can be sure that the JWT was signed by that TPM only.

For example, you can use a TPM to generate an RSA key with specifications that "this key was generated on a TPM with characteristics such that it cannot get exportable outside the TPM"..very necessarily, the RSA private key will never exist anywhere else other than in that TPM.

How a you trust that a specific RSA key happens to be from a given TPM with a given specification set is a rather complicated protocol that is also not covered in this repo. The specific trust protocol is called TPM Remote Attestation.

This repo assumes the verifier of the JWT has already established that the RSA key that is being used to sign the JWT

this repo is not supported by google

Other references

Much of this implementation is inspired templated form gcp-jwt-go

Supported Key Types

The following types are supported

  • RSA+SHA256

Setup

To use this library, you need a TPM to issue a JWT. You do not need a TPM to verify; you just need the public key. On linux, its usually at /dev/tpm0

The sample setup uses a GCP Shielded VM. You can use any system that has a TPM (including a raspberryPi with a fancy extra on chip)

Setup

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-10-buster-v20210916 --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 libtspi-dev

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

# git clone https://github.com/salrashid123/golang-jwt-tpm.git
# cd util
# go run keycreate.go 

2021/11/28 20:30:03 ======= Init  ========
2021/11/28 20:30:03 0 handles flushed
2021/11/28 20:30:03      key Name: 
5e41119a2fe12b8fcff3ad663d8aaa96d840ce765d92a256c503bf63060fc5d6
2021/11/28 20:30:03 ======= ContextSave (k) ========
2021/11/28 20:30:03      PublicKey: 
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyhUost8vRhTv/O3lsLQN
za3CdkBVntiZcny7jh2GXi16CtV8Y8bbmWlmACih+0f5SourEbTHiz1zr9AJ6VmQ
EuOVBv0WBXqUpeUVAUGDrJVJt3qwnTyLUgZmyE158J3HpuI9qV2Q4Z7mkUSGaapk
kWGvWd66Me2CqjKDVtJvVxdZhM6PkdrfAUuTdnmfOQ0637YxVzg6S9Jb/Tbmye17
ZsT+sbGx0Atn86r9anVWeXrraXYJ3t42ArYp0UV87hB/p1RU2yofUSu+afeX8tEU
PNAYZQZaCRCnkIjfFtyEpobsU0/9QZ9htPAfToca3YdTZ9W/QOUpYZrWIxWRxvM0
ZQIDAQAB
-----END PUBLIC KEY-----
2021/11/28 20:30:03 Public Key written to: key.pem
JWK Format:
{
  "e": "AQAB",
  "kid": "5e41119a2fe12b8fcff3ad663d8aaa96d840ce765d92a256c503bf63060fc5d6",
  "kty": "RSA",
  "n": "yhUost8vRhTv_O3lsLQNza3CdkBVntiZcny7jh2GXi16CtV8Y8bbmWlmACih-0f5SourEbTHiz1zr9AJ6VmQEuOVBv0WBXqUpeUVAUGDrJVJt3qwnTyLUgZmyE158J3HpuI9qV2Q4Z7mkUSGaapkkWGvWd66Me2CqjKDVtJvVxdZhM6PkdrfAUuTdnmfOQ0637YxVzg6S9Jb_Tbmye17ZsT-sbGx0Atn86r9anVWeXrraXYJ3t42ArYp0UV87hB_p1RU2yofUSu-afeX8tEUPNAYZQZaCRCnkIjfFtyEpobsU0_9QZ9htPAfToca3YdTZ9W_QOUpYZrWIxWRxvM0ZQ"
}

The output of the create command is key.bin which is a TPM public key reference to the embedded key. The output also includes key.pem (the public RSA)

Note that the output shows the PublicKey in RSA and JWK formats

Copy the file key.bin into the examples/ folder

Now create a test JWT and verify it with an RSA key that is extracted from a TPM and also directly.

# cd examples/
# go run main.go 
TOKEN: eyJhbGciOiJSUzI1NiIsImtpZCI6IjVlNDExMTlhMmZlMTJiOGZjZmYzYWQ2NjNkOGFhYTk2ZDg0MGNlNzY1ZDkyYTI1NmM1MDNiZjYzMDYwZmM1ZDYiLCJ0eXAiOiJKV1QifQ.eyJleHAiOjE2MzgxMzE1MzAsImlzcyI6InRlc3QifQ.R1CZ1XqXyrMHk77m1Ehj6r4c1pQVFqTRrJ-ij-Y3HFMY5n07orlWGffuiXQU-nXv9coqoncaj3T7a2inF0Qwow5GSPoBdueYVt7bGdU9p7Tb5fC-6OLMwm8JjqrCtFKAjjyLuBGiaLkZ6aZFCouzyQljL_TWx8Lz7_0wZewpX4SUlXNq3aa9pnP5AfmACfrj3_Ds4UllghGO2xHgNxFeAdlr3gvYOZmLIrLwT5KnAV4ZEu-tRJy6ej8qHHNUiNZZ1UkyY_U6SLDmzW8Cu9JbtXLF0b9kbU98bcGZr41bAdRbKxqclTNi04k7ZC2iVS6H0jFTHYwefLBdjXS9yDDLtA
2021/11/28 20:31:10      verified with TPM PublicKey
2021/11/28 20:31:10      verified with exported PubicKey

The JWT is formatted as:

{
  "alg": "RS256",
  "kid": "5e41119a2fe12b8fcff3ad663d8aaa96d840ce765d92a256c503bf63060fc5d6",
  "typ": "JWT"
}
{
  "exp": 1638131530,
  "iss": "test"
}

to use, just import the library configure the TPM:

package main

import (
	"context"
	"fmt"
	"log"
	"time"

	"github.com/golang-jwt/jwt"
	tpmjwt "github.com/salrashid123/golang-jwt-tpm"
)

var ()

func main() {

	ctx := context.Background()

	var keyctx interface{}
	claims := &jwt.StandardClaims{
		ExpiresAt: time.Now().Add(time.Minute * 1).Unix(),
		Issuer:    "test",
	}

	token := jwt.NewWithClaims(tpmjwt.SigningMethodTPMRS256, claims)

	config := &tpmjwt.TPMConfig{
		TPMDevice:     "/dev/tpm0",
		KeyHandleFile: "key.bin",
		KeyTemplate:   tpmjwt.AttestationKeyParametersRSA256,
		//KeyTemplate: tpmjwt.UnrestrictedKeyParametersRSA256,
	}

	keyctx, err := tpmjwt.NewTPMContext(ctx, config)
	if err != nil {
		log.Fatalf("Unable to initialize tpmJWT: %v", err)
	}

	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
	pubKey := config.GetPublicKey()

	v, err := jwt.Parse(vtoken.Raw, func(token *jwt.Token) (interface{}, error) {
		return pubKey, nil
	})
	if v.Valid {
		log.Println("     verified with exported PubicKey")
	}

}
Similar Resources

Generate a generic library of 2FA tokens compatible with Google Authenticator

towfa Generate a generic library of 2FA tokens compatible with Google Authenticator go get -u github.com/golandscape/twofa $twofa "you secret" result:

Mar 23, 2022

Platform-Agnostic Security Tokens implementation in GO (Golang)

Golang implementation of PASETO: Platform-Agnostic Security Tokens This is a 100% compatible pure Go (Golang) implementation of PASETO tokens. PASETO

Jan 2, 2023

A command-line tool to generate a DoorDash Developer JWT

make-doordash-jwt This simple CLI tool takes a DoorDash Access Key (a JSON object comprised of a developerId, key_id, and signing_secret) and creates

Feb 2, 2022

A simple and lightweight library for creating, formatting, manipulating, signing, and validating JSON Web Tokens in Go.

GoJWT - JSON Web Tokens in Go GoJWT is a simple and lightweight library for creating, formatting, manipulating, signing and validating Json Web Tokens

Nov 15, 2022

Safe, simple and fast JSON Web Tokens for Go

jwt JSON Web Token for Go RFC 7519, also see jwt.io for more. The latest version is v3. Rationale There are many JWT libraries, but many of them are h

Jan 4, 2023

Package go-otp implements one-time-password generators used in 2-factor authentication systems like RSA-tokens. Currently this supports both HOTP (RFC-4226), TOTP (RFC-6238) and Base32 encoding (RFC-3548) for Google Authenticator compatibility

OTP Package go-otp implements one-time-password generators used in 2-factor authentication systems like RSA-tokens and Google Authenticator. Currently

Oct 8, 2022

Microservice generates pair of access and refresh JSON web tokens signed by user identifier.

go-jwt-issuer Microservice generates pair access and refresh JSON web tokens signed by user identifier. 💡 Deployed on Heroku Run tests: export SECRET

Nov 21, 2022

OauthMicroservice-cassandraCluster - Implement microservice of oauth using golang and cassandra to store user tokens

implement microservice of oauth using golang and cassandra to store user tokens

Jan 24, 2022

Authenticated and encrypted API tokens using modern crypto

Branca Token Authenticated and encrypted API tokens using modern crypto. What? Branca is a secure, easy to use token format which makes it hard to sho

Dec 25, 2022
Gets Firebase auth tokens (for development purposes only)Gets Firebase auth tokens

Firebase Token Gets Firebase auth tokens (for development purposes only) Getting started Create Firebase project Setup Firebase authentication Setup G

Nov 17, 2021
:key: Secure alternative to JWT. Authenticated Encrypted API Tokens for Go.

branca branca is a secure alternative to JWT, This implementation is written in pure Go (no cgo dependencies) and implements the branca token specific

Dec 29, 2022
Golang implementation of JSON Web Tokens (JWT)

jwt-go A go (or 'golang' for search engine friendliness) implementation of JSON Web Tokens NEW VERSION COMING: There have been a lot of improvements s

Jan 6, 2023
Golang jwt tokens without any external dependency

Yet another jwt lib This is a simple lib made for small footprint and easy usage It allows creating, signing, reading and verifying jwt tokens easily

Oct 11, 2021
Go-gin-jwt - Secure web api using jwt token and caching mechanism

Project Description This project demonstrate how to create api and secure it wit

Jan 27, 2022
Go module with token package to request Azure Resource Manager and Azure Graph tokens.

azAUTH Go module with token package to request Azure Resource Manager and Azure Graph tokens. prerequisites Install azure cli: https://docs.microsoft.

Dec 1, 2021
JWT wrapper library which makes it simple to use ECDSA based JWT signing

JWT JWT wrapper library which makes it simple to user ECDSA based JWT signing. Usage package main import ( "context" "github.com/infiniteloopcloud

Feb 10, 2022
Account-jwt-go - Simple JWT api with go, gorm, gin
Account-jwt-go - Simple JWT api with go, gorm, gin

Account JWT on Go Go, gorm, Gin web framework 를 활용하여 만든 간단한 JWT API 입니다. Dajngo의

Apr 14, 2022
Krakend-jwt-header-rewriter - Kraken Plugin - JWT Header Rewriter

Kraken Plugin - JWT Header Rewriter 1 Plugin Configuration Name Desciption Defau

Feb 15, 2022
Utility to generate tokens to interact with GitHub API via GitHub App integration

GitHub App Authentication for integration with GitHub Introduction GitHub Apps are the officially recommended way to integrate with GitHub because of

Mar 16, 2022