Created
November 7, 2019 10:06
-
-
Save monmohan/f06914e527e032ec9512787ca9187eae to your computer and use it in GitHub Desktop.
Sample JWS Validation with RSA Key
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package jws | |
import ( | |
"bytes" | |
"crypto" | |
"crypto/rsa" | |
_ "crypto/sha256" | |
"encoding/base64" | |
"encoding/binary" | |
"math/big" | |
"strings" | |
) | |
type JWKS struct { | |
Keys []JWK | |
} | |
type JWK struct { | |
Alg string | |
Kty string | |
X5c []string | |
N string | |
E string | |
Kid string | |
X5t string | |
} | |
func verifySignature(jwtToken string, key JWK) error { | |
parts := strings.Split(jwtToken, ".") | |
message := []byte(strings.Join(parts[0:2], ".")) | |
signature, err := base64.RawURLEncoding.DecodeString(parts[2]) | |
if err != nil { | |
return err | |
} | |
n, _ := base64.RawURLEncoding.DecodeString(key.N) | |
e, _ := base64.RawURLEncoding.DecodeString(key.E) | |
z := new(big.Int) | |
z.SetBytes(n) | |
//decoding key.E returns a three byte slice, https://golang.org/pkg/encoding/binary/#Read and other conversions fail | |
//since they are expecting to read as many bytes as the size of int being returned (4 bytes for uint32 for example) | |
var buffer bytes.Buffer | |
buffer.WriteByte(0) | |
buffer.Write(e) | |
exponent := binary.BigEndian.Uint32(buffer.Bytes()) | |
publicKey := &rsa.PublicKey{N: z, E: int(exponent)} | |
// Only small messages can be signed directly; thus the hash of a | |
// message, rather than the message itself, is signed. | |
hasher := crypto.SHA256.New() | |
hasher.Write(message) | |
err = rsa.VerifyPKCS1v15(publicKey, crypto.SHA256, hasher.Sum(nil), signature) | |
return err | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package jws | |
import ( | |
"encoding/json" | |
"log" | |
"os" | |
"testing" | |
) | |
func TestPublicKey(t *testing.T) { | |
jwtToken := "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ik5FTXlNRUZDTXpVd01URTFRVE5CT1VGRE1FUTFPRGN6UmprNU56QkdRelk0UVRrMVEwWkVPUSJ9.eyJpc3MiOiJodHRwczovL2Rldi1lanRsOTg4dy5hdXRoMC5jb20vIiwic3ViIjoiZ1pTeXNwQ1k1ZEk0aDFaM3Fwd3BkYjlUNFVQZEdENWtAY2xpZW50cyIsImF1ZCI6Imh0dHA6Ly9oZWxsb3dvcmxkIiwiaWF0IjoxNTcyNDA2NDQ3LCJleHAiOjE1NzI0OTI4NDcsImF6cCI6ImdaU3lzcENZNWRJNGgxWjNxcHdwZGI5VDRVUGRHRDVrIiwiZ3R5IjoiY2xpZW50LWNyZWRlbnRpYWxzIn0.nupgm7iFqSnERq9GxszwBrsYrYfMuSfUGj8tGQlkY3Ksh3o_IDfq1GO5ngHQLZuYPD-8qPIovPBEVomGZCo_jYvsbjmYkalAStmF01TvSoXQgJd09ygZstH0liKsmINStiRE8fTA-yfEIuBYttROizx-cDoxiindbKNIGOsqf6yOxf7ww8DrTBJKYRnHVkAfIK8wm9LRpsaOVzWdC7S3cbhCKvANjT0RTRpAx8b_AOr_UCpOr8paj-xMT9Zc9HVCMZLBfj6OZ6yVvnC9g6q_SlTa--fY9SL5eqy6-q1JGoyK_-BQ_YrCwrRdrjoJsJ8j-XFRFWJX09W3oDuZ990nGA" | |
jwksFile, err := os.Open("./jwks.json") | |
if err != nil { | |
t.Fatalf("Error in reading jwks %s", err.Error()) | |
} | |
dec := json.NewDecoder(jwksFile) | |
var jwks JWKS | |
if err := dec.Decode(&jwks); err != nil { | |
t.Fatalf("Unable to read key %s", err) | |
} | |
log.Printf("%v", jwks) | |
err = verifySignature(jwtToken, jwks.Keys[0]) | |
if err != nil { | |
t.Fatalf("Failed signature verification : %s", err) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"keys": [ | |
{ | |
"alg": "RS256", | |
"kty": "RSA", | |
"use": "sig", | |
"x5c": [ | |
"MIIDBzCCAe+gAwIBAgIJakoPho0MJr56MA0GCSqGSIb3DQEBCwUAMCExHzAdBgNVBAMTFmRldi1lanRsOTg4dy5hdXRoMC5jb20wHhcNMTkxMDI5MjIwNzIyWhcNMzMwNzA3MjIwNzIyWjAhMR8wHQYDVQQDExZkZXYtZWp0bDk4OHcuYXV0aDAuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzkM1QHcP0v8bmwQ2fd3Pj6unCTx5k8LsW9cuLtUhAjjzRGpSEwGCKEgi1ej2+0Cxcs1t0wzhO+zSv1TJbsDI0x862PIFEs3xkGqPZU6rfQMzvCmncAcMjuW7r/Zewm0s58oRGyic1Oyp8xiy78czlBG03jk/+/vdttJkie8pUc9AHBuMxAaV4iPN3zSi/J5OVSlovk607H3AUiL3Bfg4ssS1bsJvaFG0kuNscoiP+qLRTjFK6LzZS99VxegeNzttqGbtj5BwNgbtuzrIyfLmYB/9VgEw+QdaQHvxoAvD0f7aYsaJ1R6rrqxo+1Pun7j1/h7kOCGB0UcHDLDw7gaP/wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQwIoo6QzzUL/TcNVpLGrLdd3DAIzAOBgNVHQ8BAf8EBAMCAoQwDQYJKoZIhvcNAQELBQADggEBALb8QycRmauyC/HRWRxTbl0w231HTAVYizQqhFQFl3beSQIhexGik+H+B4ve2rv94QRD3LlraUp+J26wLG89EnSCuCo/OxPAq+lxO6hNf6oKJ+Y2f48awIOxolO0f89qX3KMIkABXwKbYUcd+SBHX5ZP1V9cvJEyH0s3Fq9ObysPCH2j2Hjgz3WMIffSFMaO0DIfh3eNnv9hKQwavUO7fL/jqhBl4QxI2gMySi0Ni7PgAlBgxBx6YUp59q/lzMgAf19GOEOvI7l4dA0bc9pdsm7OhimskvOUSZYi5Pz3n/i/cTVKKhlj6NyINkMXlXGgyM9vEBpdcIpOWn/1H5QVy8Q=" | |
], | |
"n": "zkM1QHcP0v8bmwQ2fd3Pj6unCTx5k8LsW9cuLtUhAjjzRGpSEwGCKEgi1ej2-0Cxcs1t0wzhO-zSv1TJbsDI0x862PIFEs3xkGqPZU6rfQMzvCmncAcMjuW7r_Zewm0s58oRGyic1Oyp8xiy78czlBG03jk_-_vdttJkie8pUc9AHBuMxAaV4iPN3zSi_J5OVSlovk607H3AUiL3Bfg4ssS1bsJvaFG0kuNscoiP-qLRTjFK6LzZS99VxegeNzttqGbtj5BwNgbtuzrIyfLmYB_9VgEw-QdaQHvxoAvD0f7aYsaJ1R6rrqxo-1Pun7j1_h7kOCGB0UcHDLDw7gaP_w", | |
"e": "AQAB", | |
"kid": "NEMyMEFCMzUwMTE1QTNBOUFDMEQ1ODczRjk5NzBGQzY4QTk1Q0ZEOQ", | |
"x5t": "NEMyMEFCMzUwMTE1QTNBOUFDMEQ1ODczRjk5NzBGQzY4QTk1Q0ZEOQ" | |
} | |
] | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
How can I generate the
x5t
? I need this for my unit tests and still no clue how I get to that