mirror of
https://github.com/AikidoSec/safe-chain.git
synced 2026-05-26 12:10:49 +00:00
Some fixes
This commit is contained in:
parent
091e6ec5f8
commit
2bc6d249de
2 changed files with 121 additions and 8 deletions
|
|
@ -15,6 +15,8 @@ import { ui } from "../environment/userInteraction.js";
|
|||
*/
|
||||
function isParsable(pem) {
|
||||
if (!pem || typeof pem !== "string") return false;
|
||||
// Normalize Windows CRLF to LF to ensure consistent parsing
|
||||
pem = pem.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
||||
const begin = "-----BEGIN CERTIFICATE-----";
|
||||
const end = "-----END CERTIFICATE-----";
|
||||
const blocks = [];
|
||||
|
|
@ -95,6 +97,15 @@ export function getCombinedCaBundlePath() {
|
|||
return cachedPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize path
|
||||
* @param {string} p - Path to normalize
|
||||
* @returns {string}
|
||||
*/
|
||||
function normalizePathF(p) {
|
||||
return p.replace(/\\/g, "/");
|
||||
}
|
||||
|
||||
/**
|
||||
* Read and validate user certificate file
|
||||
* @param {string} certPath - Path to certificate file
|
||||
|
|
@ -102,32 +113,50 @@ export function getCombinedCaBundlePath() {
|
|||
*/
|
||||
function readUserCertificateFile(certPath) {
|
||||
try {
|
||||
// Perform security checks before reading
|
||||
// 1) Basic validation
|
||||
if (typeof certPath !== "string" || certPath.trim().length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (certPath.includes("..") || certPath.includes("//") || certPath.includes("\\\\")) {
|
||||
// 2) Reject path traversal attempts (normalize backslashes first for Windows paths)
|
||||
const normalizedPath = normalizePathF(certPath);
|
||||
if (normalizedPath.includes("..")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!fs.existsSync(certPath)) {
|
||||
// 3) Check if file exists and is not a directory or symlink
|
||||
let stats;
|
||||
try {
|
||||
stats = fs.lstatSync(certPath);
|
||||
} catch {
|
||||
// File doesn't exist or can't be accessed
|
||||
return null;
|
||||
}
|
||||
|
||||
const stats = fs.lstatSync(certPath);
|
||||
if (!stats.isFile() || stats.isSymbolicLink()) {
|
||||
if (!stats.isFile()) {
|
||||
// Reject directories and symlinks
|
||||
return null;
|
||||
}
|
||||
|
||||
// 4) Read file content
|
||||
let content;
|
||||
try {
|
||||
content = fs.readFileSync(certPath, "utf8");
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
|
||||
const content = fs.readFileSync(certPath, "utf8");
|
||||
if (!content || typeof content !== "string") {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 6) Validate PEM format
|
||||
// 5) Validate PEM format
|
||||
if (!isParsable(content)) {
|
||||
return null;
|
||||
// Fallback: accept if it at least contains PEM delimiters
|
||||
// (covers edge cases with unusual formatting that X509Certificate might reject)
|
||||
if (!content.includes("-----BEGIN CERTIFICATE-----") || !content.includes("-----END CERTIFICATE-----")) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return content;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue