mirror of
https://github.com/datarhei/core.git
synced 2025-10-05 07:57:13 +08:00
81 lines
1.9 KiB
Go
81 lines
1.9 KiB
Go
package jwks
|
|
|
|
import (
|
|
"crypto/ecdsa"
|
|
"crypto/elliptic"
|
|
"encoding/base64"
|
|
"fmt"
|
|
"math/big"
|
|
)
|
|
|
|
const (
|
|
// p256 represents a cryptographic elliptical curve type.
|
|
p256 = "P-256"
|
|
|
|
// p384 represents a cryptographic elliptical curve type.
|
|
p384 = "P-384"
|
|
|
|
// p521 represents a cryptographic elliptical curve type.
|
|
p521 = "P-521"
|
|
)
|
|
|
|
// ECDSA parses a JSONKey and turns it into an ECDSA public key.
|
|
func (j *jwkImpl) ecdsa() (publicKey *ecdsa.PublicKey, err error) {
|
|
// Check if the key has already been computed.
|
|
if j.precomputed != nil {
|
|
var ok bool
|
|
if publicKey, ok = j.precomputed.(*ecdsa.PublicKey); ok {
|
|
return publicKey, nil
|
|
}
|
|
}
|
|
|
|
// Confirm everything needed is present.
|
|
if j.key.X == "" || j.key.Y == "" || j.key.Curve == "" {
|
|
return nil, fmt.Errorf("%w: ecdsa", ErrMissingAssets)
|
|
}
|
|
|
|
// Decode the X coordinate from Base64.
|
|
//
|
|
// According to RFC 7518, this is a Base64 URL unsigned integer.
|
|
// https://tools.ietf.org/html/rfc7518#section-6.3
|
|
var xCoordinate []byte
|
|
if xCoordinate, err = base64.RawURLEncoding.DecodeString(j.key.X); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Decode the Y coordinate from Base64.
|
|
var yCoordinate []byte
|
|
if yCoordinate, err = base64.RawURLEncoding.DecodeString(j.key.Y); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Create the ECDSA public key.
|
|
publicKey = &ecdsa.PublicKey{}
|
|
|
|
// Set the curve type.
|
|
var curve elliptic.Curve
|
|
switch j.key.Curve {
|
|
case p256:
|
|
curve = elliptic.P256()
|
|
case p384:
|
|
curve = elliptic.P384()
|
|
case p521:
|
|
curve = elliptic.P521()
|
|
}
|
|
publicKey.Curve = curve
|
|
|
|
// Turn the X coordinate into *big.Int.
|
|
//
|
|
// According to RFC 7517, these numbers are in big-endian format.
|
|
// https://tools.ietf.org/html/rfc7517#appendix-A.1
|
|
publicKey.X = big.NewInt(0).SetBytes(xCoordinate)
|
|
|
|
// Turn the Y coordinate into a *big.Int.
|
|
publicKey.Y = big.NewInt(0).SetBytes(yCoordinate)
|
|
|
|
// Keep the public key so it won't have to be computed every time.
|
|
j.precomputed = publicKey
|
|
|
|
return publicKey, nil
|
|
}
|