2024-08-11 03:51:22 +02:00
|
|
|
package lysand
|
|
|
|
|
|
|
|
|
|
import (
|
2024-08-20 22:43:26 +02:00
|
|
|
"crypto"
|
2024-08-11 03:51:22 +02:00
|
|
|
"crypto/x509"
|
|
|
|
|
"encoding/base64"
|
|
|
|
|
"encoding/json"
|
|
|
|
|
)
|
|
|
|
|
|
2024-08-20 22:43:26 +02:00
|
|
|
// UserPublicKey represents a public key for a user. For more information, see the [Spec].
|
2024-08-11 03:51:22 +02:00
|
|
|
//
|
|
|
|
|
// [Spec]: https://lysand.org/security/keys#public-key-cryptography
|
2024-08-20 22:43:26 +02:00
|
|
|
type UserPublicKey struct {
|
|
|
|
|
Actor *URL `json:"actor"`
|
|
|
|
|
|
|
|
|
|
// Algorithm can only be `ed25519` for now
|
|
|
|
|
Algorithm string `json:"algorithm"`
|
|
|
|
|
|
|
|
|
|
Key *SPKIPublicKey `json:"-"`
|
|
|
|
|
RawKey json.RawMessage `json:"key"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (k *UserPublicKey) UnmarshalJSON(raw []byte) error {
|
|
|
|
|
type t UserPublicKey
|
|
|
|
|
k2 := (*t)(k)
|
|
|
|
|
|
|
|
|
|
if err := json.Unmarshal(raw, k2); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var err error
|
|
|
|
|
if k2.Key, err = unmarshalSPKIPubKey(k2.Algorithm, k2.RawKey); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*k = UserPublicKey(*k2)
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (k UserPublicKey) MarshalJSON() ([]byte, error) {
|
|
|
|
|
type t UserPublicKey
|
|
|
|
|
k2 := t(k)
|
|
|
|
|
|
|
|
|
|
var err error
|
|
|
|
|
if k2.RawKey, err = k2.Key.MarshalJSON(); err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return json.Marshal(k2)
|
2024-08-11 03:51:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SPKIPublicKey is a type that represents a [ed25519.PublicKey] in the SPKI
|
|
|
|
|
// format.
|
2024-08-20 22:43:26 +02:00
|
|
|
type SPKIPublicKey struct {
|
|
|
|
|
Key any
|
|
|
|
|
Algorithm string
|
|
|
|
|
}
|
2024-08-11 03:51:22 +02:00
|
|
|
|
2024-08-20 22:43:26 +02:00
|
|
|
func unmarshalSPKIPubKey(algorithm string, raw []byte) (*SPKIPublicKey, error) {
|
2024-08-11 03:51:22 +02:00
|
|
|
rawStr := ""
|
|
|
|
|
if err := json.Unmarshal(raw, &rawStr); err != nil {
|
2024-08-20 22:43:26 +02:00
|
|
|
return nil, err
|
2024-08-11 03:51:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
raw, err := base64.StdEncoding.DecodeString(rawStr)
|
|
|
|
|
if err != nil {
|
2024-08-20 22:43:26 +02:00
|
|
|
return nil, err
|
2024-08-11 03:51:22 +02:00
|
|
|
}
|
|
|
|
|
|
2024-08-20 22:43:26 +02:00
|
|
|
return NewSPKIPubKey(algorithm, raw)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NewSPKIPubKey decodes the public key from a base64 encoded string and then unmarshals it from the SPKI form.
|
|
|
|
|
func NewSPKIPubKey(algorithm string, raw []byte) (*SPKIPublicKey, error) {
|
2024-08-11 03:51:22 +02:00
|
|
|
parsed, err := x509.ParsePKIXPublicKey(raw)
|
|
|
|
|
if err != nil {
|
2024-08-20 22:43:26 +02:00
|
|
|
return nil, err
|
2024-08-11 03:51:22 +02:00
|
|
|
}
|
|
|
|
|
|
2024-08-20 22:43:26 +02:00
|
|
|
return &SPKIPublicKey{
|
|
|
|
|
Key: parsed,
|
|
|
|
|
Algorithm: algorithm,
|
|
|
|
|
}, nil
|
2024-08-11 03:51:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// MarshalJSON marshals the SPKI-encoded public key to a base64 encoded string.
|
|
|
|
|
func (k SPKIPublicKey) MarshalJSON() ([]byte, error) {
|
2024-08-20 22:43:26 +02:00
|
|
|
raw, err := x509.MarshalPKIXPublicKey(k.Key)
|
2024-08-11 03:51:22 +02:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return json.Marshal(base64.StdEncoding.EncodeToString(raw))
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-20 22:43:26 +02:00
|
|
|
func (k SPKIPublicKey) ToKey() crypto.PublicKey {
|
|
|
|
|
return k.Key
|
2024-08-11 03:51:22 +02:00
|
|
|
}
|