fix: replace fmt.Errorf and errors.New with coreerr.E()
Replace all fmt.Errorf/errors.New calls in auth/auth.go, crypt/pgp/pgp.go, crypt/rsa/rsa.go, crypt/chachapoly/chachapoly.go, and trust/trust.go with coreerr.E(op, msg, err) from go-log. No stale pkg/framework imports found. Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
fb55abc52e
commit
39643ddba0
5 changed files with 70 additions and 47 deletions
17
auth/auth.go
17
auth/auth.go
|
|
@ -30,7 +30,6 @@ import (
|
|||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
|
|
@ -642,16 +641,18 @@ func (a *Authenticator) ReadResponseFile(userID, path string) (*Session, error)
|
|||
// Tries Argon2id (.hash) first, then falls back to legacy LTHN (.lthn).
|
||||
// Returns nil on success, or an error describing the failure.
|
||||
func (a *Authenticator) verifyPassword(userID, password string) error {
|
||||
const op = "auth.verifyPassword"
|
||||
|
||||
// Try Argon2id hash first (.hash file)
|
||||
if a.medium.IsFile(userPath(userID, ".hash")) {
|
||||
storedHash, err := a.medium.Read(userPath(userID, ".hash"))
|
||||
if err == nil && strings.HasPrefix(storedHash, "$argon2id$") {
|
||||
valid, verr := crypt.VerifyPassword(password, storedHash)
|
||||
if verr != nil {
|
||||
return errors.New("failed to verify password")
|
||||
return coreerr.E(op, "failed to verify password", nil)
|
||||
}
|
||||
if !valid {
|
||||
return errors.New("invalid password")
|
||||
return coreerr.E(op, "invalid password", nil)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -660,10 +661,10 @@ func (a *Authenticator) verifyPassword(userID, password string) error {
|
|||
// Fall back to legacy LTHN hash (.lthn file)
|
||||
storedHash, err := a.medium.Read(userPath(userID, ".lthn"))
|
||||
if err != nil {
|
||||
return errors.New("user not found")
|
||||
return coreerr.E(op, "user not found", nil)
|
||||
}
|
||||
if !lthn.Verify(password, storedHash) {
|
||||
return errors.New("invalid password")
|
||||
return coreerr.E(op, "invalid password", nil)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -671,9 +672,11 @@ func (a *Authenticator) verifyPassword(userID, password string) error {
|
|||
// createSession generates a cryptographically random session token and
|
||||
// stores the session via the SessionStore.
|
||||
func (a *Authenticator) createSession(userID string) (*Session, error) {
|
||||
const op = "auth.createSession"
|
||||
|
||||
tokenBytes := make([]byte, 32)
|
||||
if _, err := rand.Read(tokenBytes); err != nil {
|
||||
return nil, fmt.Errorf("auth: failed to generate session token: %w", err)
|
||||
return nil, coreerr.E(op, "failed to generate session token", err)
|
||||
}
|
||||
|
||||
session := &Session{
|
||||
|
|
@ -683,7 +686,7 @@ func (a *Authenticator) createSession(userID string) (*Session, error) {
|
|||
}
|
||||
|
||||
if err := a.store.Set(session); err != nil {
|
||||
return nil, fmt.Errorf("auth: failed to persist session: %w", err)
|
||||
return nil, coreerr.E(op, "failed to persist session", err)
|
||||
}
|
||||
|
||||
return session, nil
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
|
||||
coreerr "forge.lthn.ai/core/go-log"
|
||||
|
||||
"golang.org/x/crypto/chacha20poly1305"
|
||||
)
|
||||
|
||||
|
|
@ -32,7 +34,7 @@ func Decrypt(ciphertext []byte, key []byte) ([]byte, error) {
|
|||
|
||||
minLen := aead.NonceSize() + aead.Overhead()
|
||||
if len(ciphertext) < minLen {
|
||||
return nil, fmt.Errorf("ciphertext too short: got %d bytes, need at least %d bytes", len(ciphertext), minLen)
|
||||
return nil, coreerr.E("chachapoly.Decrypt", fmt.Sprintf("ciphertext too short: got %d bytes, need at least %d bytes", len(ciphertext), minLen), nil)
|
||||
}
|
||||
|
||||
nonce, ciphertext := ciphertext[:aead.NonceSize()], ciphertext[aead.NonceSize():]
|
||||
|
|
|
|||
|
|
@ -6,10 +6,10 @@ package pgp
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
coreerr "forge.lthn.ai/core/go-log"
|
||||
|
||||
"github.com/ProtonMail/go-crypto/openpgp"
|
||||
"github.com/ProtonMail/go-crypto/openpgp/armor"
|
||||
"github.com/ProtonMail/go-crypto/openpgp/packet"
|
||||
|
|
@ -25,9 +25,11 @@ type KeyPair struct {
|
|||
// If password is non-empty, the private key is encrypted with it.
|
||||
// Returns a KeyPair with armored public and private keys.
|
||||
func CreateKeyPair(name, email, password string) (*KeyPair, error) {
|
||||
const op = "pgp.CreateKeyPair"
|
||||
|
||||
entity, err := openpgp.NewEntity(name, "", email, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("pgp: failed to create entity: %w", err)
|
||||
return nil, coreerr.E(op, "failed to create entity", err)
|
||||
}
|
||||
|
||||
// Sign all the identities
|
||||
|
|
@ -39,12 +41,12 @@ func CreateKeyPair(name, email, password string) (*KeyPair, error) {
|
|||
if password != "" {
|
||||
err = entity.PrivateKey.Encrypt([]byte(password))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("pgp: failed to encrypt private key: %w", err)
|
||||
return nil, coreerr.E(op, "failed to encrypt private key", err)
|
||||
}
|
||||
for _, subkey := range entity.Subkeys {
|
||||
err = subkey.PrivateKey.Encrypt([]byte(password))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("pgp: failed to encrypt subkey: %w", err)
|
||||
return nil, coreerr.E(op, "failed to encrypt subkey", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -53,11 +55,11 @@ func CreateKeyPair(name, email, password string) (*KeyPair, error) {
|
|||
pubKeyBuf := new(bytes.Buffer)
|
||||
pubKeyWriter, err := armor.Encode(pubKeyBuf, openpgp.PublicKeyType, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("pgp: failed to create armored public key writer: %w", err)
|
||||
return nil, coreerr.E(op, "failed to create armored public key writer", err)
|
||||
}
|
||||
if err := entity.Serialize(pubKeyWriter); err != nil {
|
||||
pubKeyWriter.Close()
|
||||
return nil, fmt.Errorf("pgp: failed to serialize public key: %w", err)
|
||||
return nil, coreerr.E(op, "failed to serialize public key", err)
|
||||
}
|
||||
pubKeyWriter.Close()
|
||||
|
||||
|
|
@ -65,18 +67,18 @@ func CreateKeyPair(name, email, password string) (*KeyPair, error) {
|
|||
privKeyBuf := new(bytes.Buffer)
|
||||
privKeyWriter, err := armor.Encode(privKeyBuf, openpgp.PrivateKeyType, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("pgp: failed to create armored private key writer: %w", err)
|
||||
return nil, coreerr.E(op, "failed to create armored private key writer", err)
|
||||
}
|
||||
if password != "" {
|
||||
// Manual serialization to avoid re-signing encrypted keys
|
||||
if err := serializeEncryptedEntity(privKeyWriter, entity); err != nil {
|
||||
privKeyWriter.Close()
|
||||
return nil, fmt.Errorf("pgp: failed to serialize private key: %w", err)
|
||||
return nil, coreerr.E(op, "failed to serialize private key", err)
|
||||
}
|
||||
} else {
|
||||
if err := entity.SerializePrivate(privKeyWriter, nil); err != nil {
|
||||
privKeyWriter.Close()
|
||||
return nil, fmt.Errorf("pgp: failed to serialize private key: %w", err)
|
||||
return nil, coreerr.E(op, "failed to serialize private key", err)
|
||||
}
|
||||
}
|
||||
privKeyWriter.Close()
|
||||
|
|
@ -115,27 +117,29 @@ func serializeEncryptedEntity(w io.Writer, e *openpgp.Entity) error {
|
|||
// Encrypt encrypts data for the recipient identified by their armored public key.
|
||||
// Returns the encrypted data as armored PGP output.
|
||||
func Encrypt(data []byte, publicKeyArmor string) ([]byte, error) {
|
||||
const op = "pgp.Encrypt"
|
||||
|
||||
keyring, err := openpgp.ReadArmoredKeyRing(bytes.NewReader([]byte(publicKeyArmor)))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("pgp: failed to read public key ring: %w", err)
|
||||
return nil, coreerr.E(op, "failed to read public key ring", err)
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
armoredWriter, err := armor.Encode(buf, "PGP MESSAGE", nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("pgp: failed to create armor encoder: %w", err)
|
||||
return nil, coreerr.E(op, "failed to create armor encoder", err)
|
||||
}
|
||||
|
||||
w, err := openpgp.Encrypt(armoredWriter, keyring, nil, nil, nil)
|
||||
if err != nil {
|
||||
armoredWriter.Close()
|
||||
return nil, fmt.Errorf("pgp: failed to create encryption writer: %w", err)
|
||||
return nil, coreerr.E(op, "failed to create encryption writer", err)
|
||||
}
|
||||
|
||||
if _, err := w.Write(data); err != nil {
|
||||
w.Close()
|
||||
armoredWriter.Close()
|
||||
return nil, fmt.Errorf("pgp: failed to write data: %w", err)
|
||||
return nil, coreerr.E(op, "failed to write data", err)
|
||||
}
|
||||
w.Close()
|
||||
armoredWriter.Close()
|
||||
|
|
@ -146,16 +150,18 @@ func Encrypt(data []byte, publicKeyArmor string) ([]byte, error) {
|
|||
// Decrypt decrypts armored PGP data using the given armored private key.
|
||||
// If the private key is encrypted, the password is used to decrypt it first.
|
||||
func Decrypt(data []byte, privateKeyArmor, password string) ([]byte, error) {
|
||||
const op = "pgp.Decrypt"
|
||||
|
||||
keyring, err := openpgp.ReadArmoredKeyRing(bytes.NewReader([]byte(privateKeyArmor)))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("pgp: failed to read private key ring: %w", err)
|
||||
return nil, coreerr.E(op, "failed to read private key ring", err)
|
||||
}
|
||||
|
||||
// Decrypt the private key if it is encrypted
|
||||
for _, entity := range keyring {
|
||||
if entity.PrivateKey != nil && entity.PrivateKey.Encrypted {
|
||||
if err := entity.PrivateKey.Decrypt([]byte(password)); err != nil {
|
||||
return nil, fmt.Errorf("pgp: failed to decrypt private key: %w", err)
|
||||
return nil, coreerr.E(op, "failed to decrypt private key", err)
|
||||
}
|
||||
}
|
||||
for _, subkey := range entity.Subkeys {
|
||||
|
|
@ -168,17 +174,17 @@ func Decrypt(data []byte, privateKeyArmor, password string) ([]byte, error) {
|
|||
// Decode armored message
|
||||
block, err := armor.Decode(bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("pgp: failed to decode armored message: %w", err)
|
||||
return nil, coreerr.E(op, "failed to decode armored message", err)
|
||||
}
|
||||
|
||||
md, err := openpgp.ReadMessage(block.Body, keyring, nil, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("pgp: failed to read message: %w", err)
|
||||
return nil, coreerr.E(op, "failed to read message", err)
|
||||
}
|
||||
|
||||
plaintext, err := io.ReadAll(md.UnverifiedBody)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("pgp: failed to read plaintext: %w", err)
|
||||
return nil, coreerr.E(op, "failed to read plaintext", err)
|
||||
}
|
||||
|
||||
return plaintext, nil
|
||||
|
|
@ -188,19 +194,21 @@ func Decrypt(data []byte, privateKeyArmor, password string) ([]byte, error) {
|
|||
// the armored private key. If the key is encrypted, the password is used
|
||||
// to decrypt it first.
|
||||
func Sign(data []byte, privateKeyArmor, password string) ([]byte, error) {
|
||||
const op = "pgp.Sign"
|
||||
|
||||
keyring, err := openpgp.ReadArmoredKeyRing(bytes.NewReader([]byte(privateKeyArmor)))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("pgp: failed to read private key ring: %w", err)
|
||||
return nil, coreerr.E(op, "failed to read private key ring", err)
|
||||
}
|
||||
|
||||
signer := keyring[0]
|
||||
if signer.PrivateKey == nil {
|
||||
return nil, errors.New("pgp: private key not found in keyring")
|
||||
return nil, coreerr.E(op, "private key not found in keyring", nil)
|
||||
}
|
||||
|
||||
if signer.PrivateKey.Encrypted {
|
||||
if err := signer.PrivateKey.Decrypt([]byte(password)); err != nil {
|
||||
return nil, fmt.Errorf("pgp: failed to decrypt private key: %w", err)
|
||||
return nil, coreerr.E(op, "failed to decrypt private key", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -208,7 +216,7 @@ func Sign(data []byte, privateKeyArmor, password string) ([]byte, error) {
|
|||
config := &packet.Config{}
|
||||
err = openpgp.ArmoredDetachSign(buf, signer, bytes.NewReader(data), config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("pgp: failed to sign message: %w", err)
|
||||
return nil, coreerr.E(op, "failed to sign message", err)
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
|
|
@ -217,14 +225,16 @@ func Sign(data []byte, privateKeyArmor, password string) ([]byte, error) {
|
|||
// Verify verifies an armored detached signature against the given data
|
||||
// and armored public key. Returns nil if the signature is valid.
|
||||
func Verify(data, signature []byte, publicKeyArmor string) error {
|
||||
const op = "pgp.Verify"
|
||||
|
||||
keyring, err := openpgp.ReadArmoredKeyRing(bytes.NewReader([]byte(publicKeyArmor)))
|
||||
if err != nil {
|
||||
return fmt.Errorf("pgp: failed to read public key ring: %w", err)
|
||||
return coreerr.E(op, "failed to read public key ring", err)
|
||||
}
|
||||
|
||||
_, err = openpgp.CheckArmoredDetachedSignature(keyring, bytes.NewReader(data), bytes.NewReader(signature), nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("pgp: signature verification failed: %w", err)
|
||||
return coreerr.E(op, "signature verification failed", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -6,8 +6,9 @@ import (
|
|||
"crypto/sha256"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
coreerr "forge.lthn.ai/core/go-log"
|
||||
)
|
||||
|
||||
// Service provides RSA functionality.
|
||||
|
|
@ -20,12 +21,14 @@ func NewService() *Service {
|
|||
|
||||
// GenerateKeyPair creates a new RSA key pair.
|
||||
func (s *Service) GenerateKeyPair(bits int) (publicKey, privateKey []byte, err error) {
|
||||
const op = "rsa.GenerateKeyPair"
|
||||
|
||||
if bits < 2048 {
|
||||
return nil, nil, fmt.Errorf("rsa: key size too small: %d (minimum 2048)", bits)
|
||||
return nil, nil, coreerr.E(op, fmt.Sprintf("key size too small: %d (minimum 2048)", bits), nil)
|
||||
}
|
||||
privKey, err := rsa.GenerateKey(rand.Reader, bits)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to generate private key: %w", err)
|
||||
return nil, nil, coreerr.E(op, "failed to generate private key", err)
|
||||
}
|
||||
|
||||
privKeyBytes := x509.MarshalPKCS1PrivateKey(privKey)
|
||||
|
|
@ -36,7 +39,7 @@ func (s *Service) GenerateKeyPair(bits int) (publicKey, privateKey []byte, err e
|
|||
|
||||
pubKeyBytes, err := x509.MarshalPKIXPublicKey(&privKey.PublicKey)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to marshal public key: %w", err)
|
||||
return nil, nil, coreerr.E(op, "failed to marshal public key", err)
|
||||
}
|
||||
pubKeyPEM := pem.EncodeToMemory(&pem.Block{
|
||||
Type: "PUBLIC KEY",
|
||||
|
|
@ -48,24 +51,26 @@ func (s *Service) GenerateKeyPair(bits int) (publicKey, privateKey []byte, err e
|
|||
|
||||
// Encrypt encrypts data with a public key.
|
||||
func (s *Service) Encrypt(publicKey, data, label []byte) ([]byte, error) {
|
||||
const op = "rsa.Encrypt"
|
||||
|
||||
block, _ := pem.Decode(publicKey)
|
||||
if block == nil {
|
||||
return nil, errors.New("failed to decode public key")
|
||||
return nil, coreerr.E(op, "failed to decode public key", nil)
|
||||
}
|
||||
|
||||
pub, err := x509.ParsePKIXPublicKey(block.Bytes)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse public key: %w", err)
|
||||
return nil, coreerr.E(op, "failed to parse public key", err)
|
||||
}
|
||||
|
||||
rsaPub, ok := pub.(*rsa.PublicKey)
|
||||
if !ok {
|
||||
return nil, errors.New("not an RSA public key")
|
||||
return nil, coreerr.E(op, "not an RSA public key", nil)
|
||||
}
|
||||
|
||||
ciphertext, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, rsaPub, data, label)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to encrypt data: %w", err)
|
||||
return nil, coreerr.E(op, "failed to encrypt data", err)
|
||||
}
|
||||
|
||||
return ciphertext, nil
|
||||
|
|
@ -73,19 +78,21 @@ func (s *Service) Encrypt(publicKey, data, label []byte) ([]byte, error) {
|
|||
|
||||
// Decrypt decrypts data with a private key.
|
||||
func (s *Service) Decrypt(privateKey, ciphertext, label []byte) ([]byte, error) {
|
||||
const op = "rsa.Decrypt"
|
||||
|
||||
block, _ := pem.Decode(privateKey)
|
||||
if block == nil {
|
||||
return nil, errors.New("failed to decode private key")
|
||||
return nil, coreerr.E(op, "failed to decode private key", nil)
|
||||
}
|
||||
|
||||
priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse private key: %w", err)
|
||||
return nil, coreerr.E(op, "failed to parse private key", err)
|
||||
}
|
||||
|
||||
plaintext, err := rsa.DecryptOAEP(sha256.New(), rand.Reader, priv, ciphertext, label)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decrypt data: %w", err)
|
||||
return nil, coreerr.E(op, "failed to decrypt data", err)
|
||||
}
|
||||
|
||||
return plaintext, nil
|
||||
|
|
|
|||
|
|
@ -11,11 +11,12 @@
|
|||
package trust
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"iter"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
coreerr "forge.lthn.ai/core/go-log"
|
||||
)
|
||||
|
||||
// Tier represents an agent's trust level in the system.
|
||||
|
|
@ -98,10 +99,10 @@ func NewRegistry() *Registry {
|
|||
// Returns an error if the agent name is empty or the tier is invalid.
|
||||
func (r *Registry) Register(agent Agent) error {
|
||||
if agent.Name == "" {
|
||||
return errors.New("trust.Register: agent name is required")
|
||||
return coreerr.E("trust.Register", "agent name is required", nil)
|
||||
}
|
||||
if !agent.Tier.Valid() {
|
||||
return fmt.Errorf("trust.Register: invalid tier %d for agent %q", agent.Tier, agent.Name)
|
||||
return coreerr.E("trust.Register", fmt.Sprintf("invalid tier %d for agent %q", agent.Tier, agent.Name), nil)
|
||||
}
|
||||
if agent.CreatedAt.IsZero() {
|
||||
agent.CreatedAt = time.Now()
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue