package main import ( "crypto" "crypto/rand" "crypto/rsa" "crypto/sha256" "crypto/x509" "encoding/base64" "encoding/json" "encoding/pem" "fmt" "math/big" ) func oidc(req request) (interface{}, error) { block, _ := pem.Decode([]byte(req.Token)) if block == nil { return nil, fmt.Errorf("OIDC private key must be PEM encoded") } var key *rsa.PrivateKey if parsed, err := x509.ParsePKCS8PrivateKey(block.Bytes); err == nil { key, _ = parsed.(*rsa.PrivateKey) } else { key, _ = x509.ParsePKCS1PrivateKey(block.Bytes) } if key == nil || key.N.BitLen() < 2048 { return nil, fmt.Errorf("OIDC requires an RSA key of at least 2048 bits") } encoding := base64.RawURLEncoding modulus := encoding.EncodeToString(key.N.Bytes()) exponent := encoding.EncodeToString(big.NewInt(int64(key.E)).Bytes()) thumbprint := sha256.Sum256([]byte(modulus)) kid := encoding.EncodeToString(thumbprint[:16]) if req.Op == "oidc_jwks" { return map[string]interface{}{"keys": []interface{}{map[string]interface{}{"kty": "RSA", "alg": "RS256", "use": "sig", "kid": kid, "n": modulus, "e": exponent}}}, nil } header, _ := json.Marshal(map[string]string{"alg": "RS256", "typ": "JWT", "kid": kid}) claims, err := json.Marshal(req.Value) if err != nil { return nil, err } message := encoding.EncodeToString(header) + "." + encoding.EncodeToString(claims) hash := sha256.Sum256([]byte(message)) signature, err := rsa.SignPKCS1v15(rand.Reader, key, crypto.SHA256, hash[:]) if err != nil { return nil, err } return message + "." + encoding.EncodeToString(signature), nil }