Initial commit: Open sourcing all of the Maple Open Technologies code.
This commit is contained in:
commit
755d54a99d
2010 changed files with 448675 additions and 0 deletions
130
cloud/maplefile-backend/pkg/security/jwt_utils/jwt.go
Normal file
130
cloud/maplefile-backend/pkg/security/jwt_utils/jwt.go
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
package jwt_utils
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/awnumar/memguard"
|
||||
jwt "github.com/golang-jwt/jwt/v5"
|
||||
)
|
||||
|
||||
// GenerateJWTToken Generate the `access token` for the secret key.
|
||||
// SECURITY: HMAC secret is wiped from memory after signing to prevent memory dump attacks.
|
||||
func GenerateJWTToken(hmacSecret []byte, uuid string, ad time.Duration) (string, time.Time, error) {
|
||||
// SECURITY: Create a copy of the secret and wipe the copy after use
|
||||
// Note: The original hmacSecret is owned by the caller
|
||||
secretCopy := make([]byte, len(hmacSecret))
|
||||
copy(secretCopy, hmacSecret)
|
||||
defer memguard.WipeBytes(secretCopy) // SECURITY: Wipe secret copy after signing
|
||||
|
||||
token := jwt.New(jwt.SigningMethodHS256)
|
||||
expiresIn := time.Now().Add(ad)
|
||||
|
||||
// CWE-391: Safe type assertion even though we just created the token
|
||||
// Defensive programming to prevent future panics if jwt library changes
|
||||
claims, ok := token.Claims.(jwt.MapClaims)
|
||||
if !ok {
|
||||
return "", expiresIn, jwt.ErrTokenInvalidClaims
|
||||
}
|
||||
|
||||
claims["session_uuid"] = uuid
|
||||
claims["exp"] = expiresIn.Unix()
|
||||
|
||||
tokenString, err := token.SignedString(secretCopy)
|
||||
if err != nil {
|
||||
return "", expiresIn, err
|
||||
}
|
||||
|
||||
return tokenString, expiresIn, nil
|
||||
}
|
||||
|
||||
// GenerateJWTTokenPair Generate the `access token` and `refresh token` for the secret key.
|
||||
// SECURITY: HMAC secret is wiped from memory after signing to prevent memory dump attacks.
|
||||
func GenerateJWTTokenPair(hmacSecret []byte, uuid string, ad time.Duration, rd time.Duration) (string, time.Time, string, time.Time, error) {
|
||||
// SECURITY: Create a copy of the secret and wipe the copy after use
|
||||
secretCopy := make([]byte, len(hmacSecret))
|
||||
copy(secretCopy, hmacSecret)
|
||||
defer memguard.WipeBytes(secretCopy) // SECURITY: Wipe secret copy after signing
|
||||
|
||||
//
|
||||
// Generate token.
|
||||
//
|
||||
token := jwt.New(jwt.SigningMethodHS256)
|
||||
expiresIn := time.Now().Add(ad)
|
||||
|
||||
// CWE-391: Safe type assertion even though we just created the token
|
||||
claims, ok := token.Claims.(jwt.MapClaims)
|
||||
if !ok {
|
||||
return "", time.Now(), "", time.Now(), jwt.ErrTokenInvalidClaims
|
||||
}
|
||||
|
||||
claims["session_uuid"] = uuid
|
||||
claims["exp"] = expiresIn.Unix()
|
||||
|
||||
tokenString, err := token.SignedString(secretCopy)
|
||||
if err != nil {
|
||||
return "", time.Now(), "", time.Now(), err
|
||||
}
|
||||
|
||||
//
|
||||
// Generate refresh token.
|
||||
//
|
||||
refreshToken := jwt.New(jwt.SigningMethodHS256)
|
||||
refreshExpiresIn := time.Now().Add(rd)
|
||||
|
||||
// CWE-391: Safe type assertion for refresh token
|
||||
rtClaims, ok := refreshToken.Claims.(jwt.MapClaims)
|
||||
if !ok {
|
||||
return "", time.Now(), "", time.Now(), jwt.ErrTokenInvalidClaims
|
||||
}
|
||||
|
||||
rtClaims["session_uuid"] = uuid
|
||||
rtClaims["exp"] = refreshExpiresIn.Unix()
|
||||
|
||||
refreshTokenString, err := refreshToken.SignedString(secretCopy)
|
||||
if err != nil {
|
||||
return "", time.Now(), "", time.Now(), err
|
||||
}
|
||||
|
||||
return tokenString, expiresIn, refreshTokenString, refreshExpiresIn, nil
|
||||
}
|
||||
|
||||
// ProcessJWTToken validates either the `access token` or `refresh token` and returns either the `uuid` if success or error on failure.
|
||||
// CWE-347: Implements proper algorithm validation to prevent JWT algorithm confusion attacks
|
||||
// OWASP A02:2021: Cryptographic Failures - Prevents token forgery through algorithm switching
|
||||
// SECURITY: HMAC secret copy is wiped from memory after validation.
|
||||
func ProcessJWTToken(hmacSecret []byte, reqToken string) (string, error) {
|
||||
// SECURITY: Create a copy of the secret and wipe the copy after use
|
||||
secretCopy := make([]byte, len(hmacSecret))
|
||||
copy(secretCopy, hmacSecret)
|
||||
defer memguard.WipeBytes(secretCopy) // SECURITY: Wipe secret copy after validation
|
||||
|
||||
token, err := jwt.Parse(reqToken, func(t *jwt.Token) (any, error) {
|
||||
// CRITICAL SECURITY FIX: Validate signing method to prevent algorithm confusion attacks
|
||||
// Protects against:
|
||||
// 1. "none" algorithm bypass (CVE-2015-9235)
|
||||
// 2. HS256/RS256 algorithm confusion (CVE-2016-5431)
|
||||
// 3. Token forgery through algorithm switching
|
||||
if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
|
||||
return nil, jwt.ErrTokenSignatureInvalid
|
||||
}
|
||||
|
||||
// Additional check: Ensure it's specifically HS256
|
||||
if t.Method.Alg() != "HS256" {
|
||||
return nil, jwt.ErrTokenSignatureInvalid
|
||||
}
|
||||
|
||||
return secretCopy, nil
|
||||
})
|
||||
if err == nil && token.Valid {
|
||||
if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
|
||||
// Safe type assertion with validation
|
||||
sessionUUID, ok := claims["session_uuid"].(string)
|
||||
if !ok {
|
||||
return "", jwt.ErrTokenInvalidClaims
|
||||
}
|
||||
return sessionUUID, nil
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue