...
Code Block | ||||
---|---|---|---|---|
| ||||
package main import ( "crypto/rsa" "crypto/sha1" "crypto/x509" "encoding/base64" "encoding/json" "encoding/pem" "flag" "fmt" "golang.org/x/crypto/ssh" "io/ioutil" "math/big" ) type Jwks struct { Keys []Key `json:"keys"` } type Key struct { Kid string `json:"kid,omitempty"` Kty string `json:"kty"` Use string `json:"use"` N string `json:"n"` E string `json:"e"` X5c []string `json:"x5c"` X5t string `json:"x5t"` } var keyFile string var keyType string var certFile string func getKeyFromPrivate(key []byte) (*rsa.PublicKey){ parsed, err := ssh.ParseRawPrivateKey(key) if err != nil { fmt.Println(err) } // Convert back to an *rsa.PrivateKey privateKey := parsed.(*rsa.PrivateKey) publicKey := &privateKey.PublicKey return publicKey } func getKeyFromPublic(key []byte) (*rsa.PublicKey){ pubPem, _ := pem.Decode(key) parsed, err := x509.ParsePKIXPublicKey(pubPem.Bytes) if err != nil { fmt.Println("Unable to parse RSA public key", err) } // Convert back to an *rsa.PublicKey publicKey := parsed.(*rsa.PublicKey) return publicKey } func maingetCert(cert []byte) *x509.Certificate { flag.StringVar(&keyFile, "keyFile", "/mnt/c/Users/ktimoney/keycloak-certs/client_pub.key", "Location of key file"certPem, _ := pem.Decode(cert) flag.StringVar(&keyType, "keyType", "public", "Type of key file") if certPem == nil { flag.Parse() panic("Failed to key,parse err := ioutil.ReadFile(keyFilepem file") if} err != // pass cert bytes certificate, err := x509.ParseCertificate(certPem.Bytes) if err != nil { fmt.Println("Unable to parse Certificate", err) } return certificate } func main() { flag.StringVar(&keyFile, "keyFile", "/mnt/c/Users/ktimoney/keycloak-certs/client_pub.key", "Location of key file") flag.StringVar(&keyType, "keyType", "public", "Type of key file") flag.StringVar(&certFile, "certFile", "/mnt/c/Users/ktimoney/keycloak-certs/client.crt", "Location of cert file") flag.Parse() key, err := ioutil.ReadFile(keyFile) if err != nil { fmt.Println(err) } var publicKey *rsa.PublicKey if keyType == "public" { publicKey = getKeyFromPublic(key) }else{ publicKey = getKeyFromPrivate(key) } cert, err := ioutil.ReadFile(certFile) if err != nil { fmt.Println(err) } varcertificate publicKey *rsa.PublicKey := getCert(cert) // generate fingerprint with sha1 if// keyTypeyou == "public" { can also use md5, sha256, etc. publicKeyfingerprint := getKeyFromPublic(keysha1.Sum(certificate.Raw) }elsejwksKey := Key{ publicKey = getKeyFromPrivate(key) Kid: "SIGNING_KEY", } Kty: "RSA", jwksKey Use:= Key{ "sig", "something" N: base64.RawStdEncoding.EncodeToString(publicKey.N.Bytes()), "RSA"E: base64.RawStdEncoding.EncodeToString(big.NewInt(int64(publicKey.E)).Bytes()), "sig", X5c: []string{base64.RawStdEncoding.EncodeToString(publicKey.N.Bytes())certificate.Raw)}, X5t: base64.RawStdEncoding.EncodeToString(big.NewInt(int64(publicKey.E)).Bytes()fingerprint[:]), } jwksKeys := []Key{jwksKey} jwks := Jwks{jwksKeys} jwksJson, err := json.Marshal(jwks) if err != nil { fmt.Println(err) return } fmt.Println(string(jwksJson)) } |
...
The output will look like this:
{"keys":[{"kid":"somethingSIGNING_KEY","kty":"RSA","use":"sig","n":"70XsremwRthZafooWzoDbpj1VnebGnHHLBOTT+A87SWv+WLYtnsDRAew/2XlHA8Q2c1sRU5xeEOtV6tNzk7qk8b4Kp6ZjDSeyUu7IjDEKhJUVaW2rJKj6Cyp9V8Iu82owvMdkyipWp2ZRs7GPtT0CDWSjQnu3nhQ2k0KKybZL9OQ7evpEid7q/pzFPZVU3lEUXiNJZAXTx4AIBZTgM2x74NgORg3WDCpxIPoHB1E2lOkOviAhTC6UmOpUBuLhQIrYTrVfpq0FtlgwCho0hf6uMN2fv60d0EOCEvb1a/8uBLZ2CX5oPvMZ1UfJiLwp/FaYOATmmdRF5CQoLO5AvV7CnOWdisISHIDwq+lMmO9qa8TFbgLZ0OcElgws/O1qJSHXISvWYiruT36XRuxRGg17ctTiI1Fb8qtyz1B7Rmpn0dG52aYfwJ+fZbhkKXwo4Q9SAUsAO8aPEotpCmHXPDeLbXVhgxzevr0WOE2bInU+yQYaF43e4AmzuCRPI2EruM4mAogxj8GkG/SCAVT7lWQeuIFyx3BD5wkOgPrniNVsnMeFq7VvXGpIEcbBz4KfVvlMOiNFh8XCP1YIKPtFqdEhx/NerNLVw0EMWx4iyFlTOr+TSVIi0NDr1GCMwu8SSz5gXHWnWTCZAo7lEFlZevYRV/YphJT310Q78CVyh/uPgE","e":"AQAB","x5c":["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"],"x5t":"IIj3g74+BJHIkUZxKWb4zwZeFuw"}]}
We can paste this into the "JWKS" test box.
...
For this to work with you JWT code you'll need to copy the "kid" value and update you code so this is included in the header: This is necessary when the JWKS has multiple keys.
Code Block | ||||
---|---|---|---|---|
| ||||
claims["iss"] = "jwtclient3" claims["aud"] = "https://192.168.49.2:31561/auth/realms/x509" token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims) token.Header["kid"] = "AKAwbsKtqu9OmIwIsPOUf5zTJkIC73hzY9Myv4srjTs" tokenString, err := token.SignedString(key) if err != nil { return "", fmt.Errorf("create: sign token: %w", err) } return tokenString, nil } |
...