mirror of
https://github.com/steveiliop56/tinyauth.git
synced 2025-12-31 04:22:28 +00:00
Replace SHA256 with HKDF for key derivation and fix scope validation
Security improvements:
1. HKDF key derivation:
- Replace raw sha256.Sum256() with proper HKDF (HMAC-based KDF)
- Uses domain-separated label 'oidc-aes-256-key-v1' for key derivation
- Applied to both encryptPrivateKey and decryptPrivateKey
- Provides better security properties than raw hash
2. Scope validation fix:
- Only add 'openid' scope if it's both requested AND in client's
allowedScopes
- Prevents bypassing client scope restrictions
- Respects configured allowedScopes
Both changes improve security posture while maintaining backward
compatibility.
This commit is contained in:
@@ -12,6 +12,7 @@ import (
|
|||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -24,6 +25,7 @@ import (
|
|||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
"golang.org/x/crypto/hkdf"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -55,10 +57,14 @@ func (oidc *OIDCService) encryptPrivateKey(plaintext string) (string, error) {
|
|||||||
return plaintext, nil
|
return plaintext, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Derive AES-256 key from master key using SHA256
|
// Derive AES-256 key from master key using HKDF
|
||||||
key := sha256.Sum256(oidc.masterKey)
|
hkdfReader := hkdf.New(sha256.New, oidc.masterKey, nil, []byte("oidc-aes-256-key-v1"))
|
||||||
|
key := make([]byte, 32) // AES-256 requires 32 bytes
|
||||||
|
if _, err := io.ReadFull(hkdfReader, key); err != nil {
|
||||||
|
return "", fmt.Errorf("failed to derive encryption key: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
block, err := aes.NewCipher(key[:])
|
block, err := aes.NewCipher(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("failed to create cipher: %w", err)
|
return "", fmt.Errorf("failed to create cipher: %w", err)
|
||||||
}
|
}
|
||||||
@@ -92,10 +98,14 @@ func (oidc *OIDCService) decryptPrivateKey(encrypted string) (string, error) {
|
|||||||
return encrypted, nil
|
return encrypted, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Derive AES-256 key from master key using SHA256
|
// Derive AES-256 key from master key using HKDF
|
||||||
key := sha256.Sum256(oidc.masterKey)
|
hkdfReader := hkdf.New(sha256.New, oidc.masterKey, nil, []byte("oidc-aes-256-key-v1"))
|
||||||
|
key := make([]byte, 32) // AES-256 requires 32 bytes
|
||||||
|
if _, err := io.ReadFull(hkdfReader, key); err != nil {
|
||||||
|
return "", fmt.Errorf("failed to derive decryption key: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
block, err := aes.NewCipher(key[:])
|
block, err := aes.NewCipher(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("failed to create cipher: %w", err)
|
return "", fmt.Errorf("failed to create cipher: %w", err)
|
||||||
}
|
}
|
||||||
@@ -313,7 +323,10 @@ func (oidc *OIDCService) ValidateScope(client *model.OIDCClient, requestedScopes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always include "openid" if it was requested
|
// Only include "openid" if it was requested AND it's in the client's allowed scopes
|
||||||
|
// This respects client scope restrictions and doesn't bypass allowedScopes
|
||||||
|
if contains(requestedScopesList, "openid") && contains(allowedScopes, "openid") {
|
||||||
|
// Check if "openid" is already in validScopes (added by the loop above)
|
||||||
hasOpenID := false
|
hasOpenID := false
|
||||||
for _, scope := range validScopes {
|
for _, scope := range validScopes {
|
||||||
if scope == "openid" {
|
if scope == "openid" {
|
||||||
@@ -321,10 +334,10 @@ func (oidc *OIDCService) ValidateScope(client *model.OIDCClient, requestedScopes
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if !hasOpenID {
|
||||||
if !hasOpenID && contains(requestedScopesList, "openid") {
|
|
||||||
validScopes = append(validScopes, "openid")
|
validScopes = append(validScopes, "openid")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return validScopes, nil
|
return validScopes, nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user