diff options
author | 2023-03-06 20:00:50 -0800 | |
---|---|---|
committer | 2023-03-06 20:00:50 -0800 | |
commit | 68e58605b6650093bb2708cb3f9799645f9c2544 (patch) | |
tree | 6ddfe5b291fd9ca11b5f961878ebbc6080c162cd | |
parent | 0a9cb0e13aba18c51eebcd4e246ac2620fac2fbc (diff) | |
download | bun-68e58605b6650093bb2708cb3f9799645f9c2544.tar.gz bun-68e58605b6650093bb2708cb3f9799645f9c2544.tar.zst bun-68e58605b6650093bb2708cb3f9799645f9c2544.zip |
throw invalid parameter errors in `crypto.scryptSync` (#2331)
* throw invalid parameter errors
* remove comptime, add empty buffer function
* remove error_name comptime
-rw-r--r-- | src/bun.js/base.zig | 8 | ||||
-rw-r--r-- | src/bun.js/bindings/bindings.zig | 13 | ||||
-rw-r--r-- | src/bun.js/webcore.zig | 209 |
3 files changed, 125 insertions, 105 deletions
diff --git a/src/bun.js/base.zig b/src/bun.js/base.zig index 044a04306..8de560b0f 100644 --- a/src/bun.js/base.zig +++ b/src/bun.js/base.zig @@ -1772,6 +1772,14 @@ pub const ArrayBuffer = extern struct { }; } + pub fn createEmpty(globalThis: *JSC.JSGlobalObject, comptime kind: JSC.JSValue.JSType) JSValue { + return switch (comptime kind) { + .Uint8Array => Bun__createUint8ArrayForCopy(globalThis, null, 0, false), + .ArrayBuffer => Bun__createArrayBufferForCopy(globalThis, null, 0), + else => @compileError("Not implemented yet"), + }; + } + pub fn createBuffer(globalThis: *JSC.JSGlobalObject, bytes: []const u8) JSValue { JSC.markBinding(@src()); return Bun__createUint8ArrayForCopy(globalThis, bytes.ptr, bytes.len, true); diff --git a/src/bun.js/bindings/bindings.zig b/src/bun.js/bindings/bindings.zig index 71295e157..49ff393a2 100644 --- a/src/bun.js/bindings/bindings.zig +++ b/src/bun.js/bindings/bindings.zig @@ -2414,6 +2414,19 @@ pub const JSGlobalObject = extern struct { return err; } + pub fn createError( + this: *JSGlobalObject, + code: JSC.Node.ErrorCode, + error_name: string, + comptime message: string, + args: anytype, + ) JSValue { + const err = createErrorInstance(this, message, args); + err.put(this, ZigString.static("code"), ZigString.init(@tagName(code)).toValue(this)); + err.put(this, ZigString.static("name"), ZigString.init(error_name).toValue(this)); + return err; + } + pub fn throw( this: *JSGlobalObject, comptime fmt: string, diff --git a/src/bun.js/webcore.zig b/src/bun.js/webcore.zig index c65c02ffd..c6481438b 100644 --- a/src/bun.js/webcore.zig +++ b/src/bun.js/webcore.zig @@ -8,6 +8,7 @@ pub usingnamespace @import("./webcore/body.zig"); const JSC = @import("bun").JSC; const std = @import("std"); const bun = @import("bun"); +const string = bun.string; pub const AbortSignal = @import("./bindings/bindings.zig").AbortSignal; pub const Lifetime = enum { @@ -388,88 +389,6 @@ pub const Crypto = struct { .{}, ); - pub fn scryptSyncValidate( - globalThis: *JSC.JSGlobalObject, - options: ?JSC.JSValue, - ) JSC.JSValue { - var blockSize: usize = 8; - var cost: usize = 16384; - var parallelization: usize = 1; - var maxmem: usize = 32 * 1024 * 1024; - - if (options) |options_value| outer: { - if (options_value.isUndefined() or options_value == .zero) - break :outer; - - if (!options_value.isObject()) { - return globalThis.createInvalidArgs("options must be an object", .{}); - } - - if (options_value.getTruthy(globalThis, "cost") orelse options_value.get(globalThis, "N")) |N_value| { - const N_int = N_value.to(i64); - if (N_int < 0 or !N_value.isNumber()) { - return globalThis.createRangeError("N must be a positive integer", .{}); - } else if (N_int != 0) { - cost = @intCast(usize, N_int); - } - } - - if (options_value.getTruthy(globalThis, "blockSize") orelse options_value.get(globalThis, "r")) |r_value| { - const r_int = r_value.to(i64); - if (r_int < 0 or !r_value.isNumber()) { - return globalThis.createRangeError("r must be a positive integer", .{}); - } else if (r_int != 0) { - blockSize = @intCast(usize, r_int); - } - } - - if (options_value.getTruthy(globalThis, "parallelization") orelse options_value.get(globalThis, "p")) |p_value| { - const p_int = p_value.to(i64); - if (p_int < 0 or !p_value.isNumber()) { - return globalThis.createRangeError("p must be a positive integer", .{}); - } else if (p_int != 0) { - parallelization = @intCast(usize, p_int); - } - } - - if (options_value.getTruthy(globalThis, "maxmem")) |value| { - const p_int = value.to(i64); - if (p_int < 0 or !value.isNumber()) { - return globalThis.createInvalidArgs("maxmem must be a positive integer", .{}); - } else if (p_int != 0) { - maxmem = @intCast(usize, p_int); - } - } - } - - if (cost < 2 or cost > 0x3fffffff) { - return globalThis.createRangeError("N must be greater than 1 and less than 2^30", .{}); - } - - if (cost == 0 or (cost & (cost - 1)) != 0) { - return globalThis.createRangeError("N must be a power of 2 greater than 1", .{}); - } - - if ((BoringSSL.EVP_PBE_scrypt( - null, - 0, - null, - 0, - cost, - blockSize, - parallelization, - maxmem, - null, - 0, - ) != 1)) { - BoringSSL.ERR_clear_error(); - return globalThis.createErrorInstance("scrypt parameters are invalid", .{}); - } - var slice: []u8 = undefined; - slice.len = 0; - return JSC.ArrayBuffer.create(globalThis, slice, .ArrayBuffer); - } - pub fn scryptSync( globalThis: *JSC.JSGlobalObject, password: JSC.Node.StringOrBuffer, @@ -480,22 +399,24 @@ pub const Crypto = struct { const password_string = password.slice(); const salt_string = salt.slice(); - if (keylen_value.isEmptyOrUndefinedOrNull()) { - return globalThis.createInvalidArgs("keylen must be a number", .{}); + if (keylen_value.isEmptyOrUndefinedOrNull() or !keylen_value.isAnyInt()) { + const err = globalThis.createInvalidArgs("keylen must be an integer", .{}); + globalThis.throwValue(err); + return .zero; } const keylen_int = keylen_value.to(i64); if (keylen_int < 0) { - return globalThis.createRangeError("keylen must be a positive integer", .{}); - } else if (keylen_int == 0) { - return scryptSyncValidate(globalThis, options); + globalThis.throwValue(globalThis.createRangeError("keylen must be a positive integer", .{})); + return .zero; } else if (keylen_int > 0x7fffffff) { - return globalThis.createRangeError("keylen must be less than 2^31", .{}); + globalThis.throwValue(globalThis.createRangeError("keylen must be less than 2^31", .{})); + return .zero; } - var blockSize: usize = 8; - var cost: usize = 16384; - var parallelization: usize = 1; + var blockSize: ?usize = null; + var cost: ?usize = null; + var parallelization: ?usize = null; var maxmem: usize = 32 * 1024 * 1024; const keylen = @intCast(u32, @truncate(i33, keylen_int)); @@ -504,31 +425,50 @@ pub const Crypto = struct { break :outer; if (!options_value.isObject()) { - return globalThis.createInvalidArgs("options must be an object", .{}); + globalThis.throwValue(globalThis.createInvalidArgs("options must be an object", .{})); + return .zero; } if (options_value.getTruthy(globalThis, "cost") orelse options_value.get(globalThis, "N")) |N_value| { + if (cost != null) return throwInvalidParameter(globalThis); const N_int = N_value.to(i64); if (N_int < 0 or !N_value.isNumber()) { - return globalThis.createRangeError("N must be a positive integer", .{}); + return throwInvalidParams( + globalThis, + "RangeError", + "Invalid scrypt params\n\n N must be a positive integer\n", + .{}, + ); } else if (N_int != 0) { cost = @intCast(usize, N_int); } } if (options_value.getTruthy(globalThis, "blockSize") orelse options_value.get(globalThis, "r")) |r_value| { + if (blockSize != null) return throwInvalidParameter(globalThis); const r_int = r_value.to(i64); if (r_int < 0 or !r_value.isNumber()) { - return globalThis.createRangeError("r must be a positive integer", .{}); + return throwInvalidParams( + globalThis, + "RangeError", + "Invalid scrypt params\n\n r must be a positive integer\n", + .{}, + ); } else if (r_int != 0) { blockSize = @intCast(usize, r_int); } } if (options_value.getTruthy(globalThis, "parallelization") orelse options_value.get(globalThis, "p")) |p_value| { + if (parallelization != null) return throwInvalidParameter(globalThis); const p_int = p_value.to(i64); if (p_int < 0 or !p_value.isNumber()) { - return globalThis.createRangeError("p must be a positive integer", .{}); + return throwInvalidParams( + globalThis, + "RangeError", + "Invalid scrypt params\n\n p must be a positive integer\n", + .{}, + ); } else if (p_int != 0) { parallelization = @intCast(usize, p_int); } @@ -537,19 +477,57 @@ pub const Crypto = struct { if (options_value.getTruthy(globalThis, "maxmem")) |value| { const p_int = value.to(i64); if (p_int < 0 or !value.isNumber()) { - return globalThis.createInvalidArgs("maxmem must be a positive integer", .{}); + return throwInvalidParams( + globalThis, + "RangeError", + "Invalid scrypt params\n\n N must be a positive integer\n", + .{}, + ); } else if (p_int != 0) { maxmem = @intCast(usize, p_int); } } } - if (cost < 2 or cost > 0x3fffffff) { - return globalThis.createRangeError("N must be greater than 1 and less than 2^30", .{}); + if (blockSize == null) blockSize = 8; + if (cost == null) cost = 16384; + if (parallelization == null) parallelization = 1; + + if (cost.? < 2 or cost.? > 0x3fffffff) { + return throwInvalidParams( + globalThis, + "RangeError", + "Invalid scrypt params\n\n N must be greater than 1 and less than 2^30\n", + .{}, + ); } - if (cost == 0 or (cost & (cost - 1)) != 0) { - return globalThis.createRangeError("N must be a power of 2 greater than 1", .{}); + if (cost.? == 0 or (cost.? & (cost.? - 1)) != 0) { + return throwInvalidParams( + globalThis, + "RangeError", + "Invalid scrypt params\n\n N must be a power of 2 greater than 1\n", + .{}, + ); + } + + if (keylen == 0) { + if ((BoringSSL.EVP_PBE_scrypt( + null, + 0, + null, + 0, + cost.?, + blockSize.?, + parallelization.?, + maxmem, + null, + 0, + ) != 1)) { + return throwInvalidParams(globalThis, "RangeError", "Invalid scrypt params\n", .{}); + } + + return JSC.ArrayBuffer.createEmpty(globalThis, .ArrayBuffer); } var stackbuf: [1024]u8 = undefined; @@ -572,20 +550,41 @@ pub const Crypto = struct { password_string.len, salt_string.ptr, salt_string.len, - cost, - blockSize, - parallelization, + cost.?, + blockSize.?, + parallelization.?, maxmem, buf.ptr, keylen, ) != 1) { - BoringSSL.ERR_clear_error(); - return globalThis.createErrorInstance("Failed to derive key", .{}); + return throwInvalidParams(globalThis, "RangeError", "Invalid scrypt params\n", .{}); } return JSC.ArrayBuffer.create(globalThis, buf, .ArrayBuffer); } + fn throwInvalidParameter(globalThis: *JSC.JSGlobalObject) JSC.JSValue { + const err = globalThis.createError( + .ERR_CRYPTO_SCRYPT_INVALID_PARAMETER, + "Error", + "Invalid scrypt parameters", + .{}, + ); + globalThis.throwValue(err); + return .zero; + } + + fn throwInvalidParams(globalThis: *JSC.JSGlobalObject, comptime error_name: string, comptime message: string, fmt: anytype) JSC.JSValue { + const err = globalThis.createError( + .ERR_CRYPTO_INVALID_SCRYPT_PARAMS, + error_name, + message, + fmt, + ); + globalThis.throwValue(err); + return .zero; + } + pub fn timingSafeEqual( globalThis: *JSC.JSGlobalObject, _: JSC.JSValue, |