Skip to content
Clone
e50e272
50 lines 1.5 KB Go
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
}