aboutsummaryrefslogtreecommitdiff
path: root/src/bun.js/api/bun/socket.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/bun.js/api/bun/socket.zig')
-rw-r--r--src/bun.js/api/bun/socket.zig679
1 files changed, 675 insertions, 4 deletions
diff --git a/src/bun.js/api/bun/socket.zig b/src/bun.js/api/bun/socket.zig
index 1d85c705c..0a18dd015 100644
--- a/src/bun.js/api/bun/socket.zig
+++ b/src/bun.js/api/bun/socket.zig
@@ -16,6 +16,8 @@ const Which = @import("../../../which.zig");
const uws = @import("root").bun.uws;
const ZigString = JSC.ZigString;
const BoringSSL = bun.BoringSSL;
+const X509 = @import("./x509.zig");
+
// const Corker = struct {
// ptr: ?*[16384]u8 = null,
// holder: ?*anyopaque = null,
@@ -56,6 +58,79 @@ const BoringSSL = bun.BoringSSL;
// }
// };
+noinline fn getSSLException(globalThis: *JSC.JSGlobalObject, defaultMessage: []const u8) JSValue {
+ var zig_str: ZigString = ZigString.init("");
+ var output_buf: [4096]u8 = undefined;
+
+ output_buf[0] = 0;
+ var written: usize = 0;
+ var ssl_error = BoringSSL.ERR_get_error();
+ while (ssl_error != 0 and written < output_buf.len) : (ssl_error = BoringSSL.ERR_get_error()) {
+ if (written > 0) {
+ output_buf[written] = '\n';
+ written += 1;
+ }
+
+ if (BoringSSL.ERR_reason_error_string(
+ ssl_error,
+ )) |reason_ptr| {
+ const reason = std.mem.span(reason_ptr);
+ if (reason.len == 0) {
+ break;
+ }
+ @memcpy(output_buf[written..][0..reason.len], reason);
+ written += reason.len;
+ }
+
+ if (BoringSSL.ERR_func_error_string(
+ ssl_error,
+ )) |reason_ptr| {
+ const reason = std.mem.span(reason_ptr);
+ if (reason.len > 0) {
+ output_buf[written..][0.." via ".len].* = " via ".*;
+ written += " via ".len;
+ @memcpy(output_buf[written..][0..reason.len], reason);
+ written += reason.len;
+ }
+ }
+
+ if (BoringSSL.ERR_lib_error_string(
+ ssl_error,
+ )) |reason_ptr| {
+ const reason = std.mem.span(reason_ptr);
+ if (reason.len > 0) {
+ output_buf[written..][0] = ' ';
+ written += 1;
+ @memcpy(output_buf[written..][0..reason.len], reason);
+ written += reason.len;
+ }
+ }
+ }
+
+ if (written > 0) {
+ var message = output_buf[0..written];
+ zig_str = ZigString.init(std.fmt.allocPrint(bun.default_allocator, "OpenSSL {s}", .{message}) catch unreachable);
+ var encoded_str = zig_str.withEncoding();
+ encoded_str.mark();
+
+ // We shouldn't *need* to do this but it's not entirely clear.
+ BoringSSL.ERR_clear_error();
+ }
+
+ if (zig_str.len == 0) {
+ zig_str = ZigString.init(defaultMessage);
+ }
+
+ // store the exception in here
+ // toErrorInstance clones the string
+ const exception = zig_str.toErrorInstance(globalThis);
+
+ // reference it in stack memory
+ exception.ensureStillAlive();
+
+ return exception;
+}
+
fn normalizeHost(input: anytype) @TypeOf(input) {
if (input.len == 0) {
return "localhost";
@@ -66,7 +141,6 @@ fn normalizeHost(input: anytype) @TypeOf(input) {
return input;
}
-
const BinaryType = JSC.BinaryType;
const WrappedType = enum {
@@ -1175,7 +1249,7 @@ fn NewSocket(comptime ssl: bool) type {
// Add SNI support for TLS (mongodb and others requires this)
if (comptime ssl) {
- var ssl_ptr: *BoringSSL.SSL = @ptrCast(*BoringSSL.SSL, socket.getNativeHandle());
+ var ssl_ptr = this.socket.ssl();
if (!ssl_ptr.isInitFinished()) {
if (this.server_name) |server_name| {
const host = normalizeHost(server_name);
@@ -1880,6 +1954,107 @@ fn NewSocket(comptime ssl: bool) type {
return JSValue.jsUndefined();
}
+ pub fn getTLSTicket(
+ this: *This,
+ globalObject: *JSC.JSGlobalObject,
+ _: *JSC.CallFrame,
+ ) callconv(.C) JSValue {
+ if (comptime ssl == false) {
+ return JSValue.jsUndefined();
+ }
+
+ if (this.detached) {
+ return JSValue.jsUndefined();
+ }
+
+ var ssl_ptr = this.socket.ssl();
+ const session = BoringSSL.SSL_get_session(ssl_ptr) orelse return JSValue.jsUndefined();
+ var ticket: [*c]const u8 = undefined;
+ var length: usize = 0;
+ //The pointer is only valid while the connection is in use so we need to copy it
+ BoringSSL.SSL_SESSION_get0_ticket(session, @ptrCast([*c][*c]const u8, &ticket), &length);
+
+ if (ticket == null or length == 0) {
+ return JSValue.jsUndefined();
+ }
+
+ return JSC.ArrayBuffer.createBuffer(globalObject, ticket[0..length]);
+ }
+
+ pub fn setSession(
+ this: *This,
+ globalObject: *JSC.JSGlobalObject,
+ callframe: *JSC.CallFrame,
+ ) callconv(.C) JSValue {
+ if (comptime ssl == false) {
+ return JSValue.jsUndefined();
+ }
+
+ if (this.detached) {
+ return JSValue.jsUndefined();
+ }
+
+ const args = callframe.arguments(1);
+
+ if (args.len < 1) {
+ globalObject.throw("Expected session to be a string, Buffer or TypedArray", .{});
+ return .zero;
+ }
+
+ const session_arg = args.ptr[0];
+ var arena: bun.ArenaAllocator = bun.ArenaAllocator.init(bun.default_allocator);
+ defer arena.deinit();
+
+ var exception_ref = [_]JSC.C.JSValueRef{null};
+ var exception: JSC.C.ExceptionRef = &exception_ref;
+ if (JSC.Node.StringOrBuffer.fromJS(globalObject, arena.allocator(), session_arg, exception)) |sb| {
+ var session_slice = sb.slice();
+ var ssl_ptr = this.socket.ssl();
+ var tmp = @ptrCast([*c]const u8, session_slice.ptr);
+ const session = BoringSSL.d2i_SSL_SESSION(null, &tmp, @intCast(c_long, session_slice.len)) orelse return JSValue.jsUndefined();
+ if (BoringSSL.SSL_set_session(ssl_ptr, session) != 1) {
+ globalObject.throwValue(getSSLException(globalObject, "SSL_set_session error"));
+ return .zero;
+ }
+ return JSValue.jsUndefined();
+ } else if (exception.* != null) {
+ globalObject.throwValue(JSC.JSValue.c(exception.*));
+ return .zero;
+ } else {
+ globalObject.throw("Expected session to be a string, Buffer or TypedArray", .{});
+ return .zero;
+ }
+ }
+
+ pub fn getSession(
+ this: *This,
+ globalObject: *JSC.JSGlobalObject,
+ _: *JSC.CallFrame,
+ ) callconv(.C) JSValue {
+ if (comptime ssl == false) {
+ return JSValue.jsUndefined();
+ }
+
+ if (this.detached) {
+ return JSValue.jsUndefined();
+ }
+
+ var ssl_ptr = this.socket.ssl();
+ const session = BoringSSL.SSL_get_session(ssl_ptr) orelse return JSValue.jsUndefined();
+ const size = BoringSSL.i2d_SSL_SESSION(session, null);
+ if (size <= 0) {
+ return JSValue.jsUndefined();
+ }
+
+ const buffer_size = @intCast(usize, size);
+ var buffer = JSValue.createBufferFromLength(globalObject, buffer_size);
+ var buffer_ptr = @ptrCast([*c]u8, buffer.asArrayBuffer(globalObject).?.ptr);
+
+ const result_size = BoringSSL.i2d_SSL_SESSION(session, &buffer_ptr);
+ std.debug.assert(result_size == size);
+ return buffer;
+ }
+
pub fn getALPNProtocol(
this: *This,
globalObject: *JSC.JSGlobalObject,
@@ -1895,7 +2070,7 @@ fn NewSocket(comptime ssl: bool) type {
var alpn_proto: [*c]const u8 = null;
var alpn_proto_len: u32 = 0;
- var ssl_ptr: *BoringSSL.SSL = @ptrCast(*BoringSSL.SSL, this.socket.getNativeHandle());
+ var ssl_ptr = this.socket.ssl();
BoringSSL.SSL_get0_alpn_selected(ssl_ptr, &alpn_proto, &alpn_proto_len);
if (alpn_proto == null or alpn_proto_len == 0) {
return JSValue.jsBoolean(false);
@@ -1910,7 +2085,502 @@ fn NewSocket(comptime ssl: bool) type {
}
return ZigString.fromUTF8(slice).toValueGC(globalObject);
}
+ pub fn exportKeyingMaterial(
+ this: *This,
+ globalObject: *JSC.JSGlobalObject,
+ callframe: *JSC.CallFrame,
+ ) callconv(.C) JSValue {
+ if (comptime ssl == false) {
+ return JSValue.jsUndefined();
+ }
+
+ if (this.detached) {
+ return JSValue.jsUndefined();
+ }
+
+ const args = callframe.arguments(3);
+ if (args.len < 2) {
+ globalObject.throw("Expected length and label to be provided", .{});
+ return .zero;
+ }
+ const length_arg = args.ptr[0];
+ if (!length_arg.isNumber()) {
+ globalObject.throw("Expected length to be a number", .{});
+ return .zero;
+ }
+
+ const length = length_arg.coerceToInt64(globalObject);
+ if (length < 0) {
+ globalObject.throw("Expected length to be a positive number", .{});
+ return .zero;
+ }
+
+ const label_arg = args.ptr[1];
+ if (!label_arg.isString()) {
+ globalObject.throw("Expected label to be a string", .{});
+ return .zero;
+ }
+
+ var label = label_arg.toSliceOrNull(globalObject) orelse {
+ globalObject.throw("Expected label to be a string", .{});
+ return .zero;
+ };
+
+ defer label.deinit();
+ const label_slice = label.slice();
+ const ssl_ptr = @ptrCast(*BoringSSL.SSL, this.socket.getNativeHandle());
+
+ if (args.len > 2) {
+ const context_arg = args.ptr[2];
+
+ var arena: bun.ArenaAllocator = bun.ArenaAllocator.init(bun.default_allocator);
+ defer arena.deinit();
+
+ var exception_ref = [_]JSC.C.JSValueRef{null};
+ var exception: JSC.C.ExceptionRef = &exception_ref;
+ if (JSC.Node.StringOrBuffer.fromJS(globalObject, arena.allocator(), context_arg, exception)) |sb| {
+ const context_slice = sb.slice();
+
+ const buffer_size = @intCast(usize, length);
+ var buffer = JSValue.createBufferFromLength(globalObject, buffer_size);
+ var buffer_ptr = @ptrCast([*c]u8, buffer.asArrayBuffer(globalObject).?.ptr);
+
+ const result = BoringSSL.SSL_export_keying_material(ssl_ptr, buffer_ptr, buffer_size, @ptrCast([*c]const u8, label_slice.ptr), label_slice.len, @ptrCast([*c]const u8, context_slice.ptr), context_slice.len, 1);
+ if (result != 1) {
+ globalObject.throwValue(getSSLException(globalObject, "Failed to export keying material"));
+ return .zero;
+ }
+ return buffer;
+ } else if (exception.* != null) {
+ globalObject.throwValue(JSC.JSValue.c(exception.*));
+ return .zero;
+ } else {
+ globalObject.throw("Expected context to be a string, Buffer or TypedArray", .{});
+ return .zero;
+ }
+ } else {
+ const buffer_size = @intCast(usize, length);
+ var buffer = JSValue.createBufferFromLength(globalObject, buffer_size);
+ var buffer_ptr = @ptrCast([*c]u8, buffer.asArrayBuffer(globalObject).?.ptr);
+
+ const result = BoringSSL.SSL_export_keying_material(ssl_ptr, buffer_ptr, buffer_size, @ptrCast([*c]const u8, label_slice.ptr), label_slice.len, null, 0, 0);
+ if (result != 1) {
+ globalObject.throwValue(getSSLException(globalObject, "Failed to export keying material"));
+ return .zero;
+ }
+ return buffer;
+ }
+ }
+
+ pub fn getEphemeralKeyInfo(
+ this: *This,
+ globalObject: *JSC.JSGlobalObject,
+ _: *JSC.CallFrame,
+ ) callconv(.C) JSValue {
+ if (comptime ssl == false) {
+ return JSValue.jsNull();
+ }
+
+ if (this.detached) {
+ return JSValue.jsNull();
+ }
+
+ // only available for clients
+ if (this.handlers.is_server) {
+ return JSValue.jsNull();
+ }
+ var result = JSValue.createEmptyObject(globalObject, 3);
+
+ const ssl_ptr = @ptrCast(*BoringSSL.SSL, this.socket.getNativeHandle());
+ // TODO: investigate better option or compatible way to get the key
+ // this implementation follows nodejs but for BoringSSL SSL_get_server_tmp_key will always return 0
+ // wich will result in a empty object
+ // var raw_key: [*c]BoringSSL.EVP_PKEY = undefined;
+ // if (BoringSSL.SSL_get_server_tmp_key(ssl_ptr, @ptrCast([*c][*c]BoringSSL.EVP_PKEY, &raw_key)) == 0) {
+ // return result;
+ // }
+ var raw_key: [*c]BoringSSL.EVP_PKEY = BoringSSL.SSL_get_privatekey(ssl_ptr);
+ if (raw_key == null) {
+ return result;
+ }
+
+ const kid = BoringSSL.EVP_PKEY_id(raw_key);
+ const bits = BoringSSL.EVP_PKEY_bits(raw_key);
+
+ switch (kid) {
+ BoringSSL.EVP_PKEY_DH => {
+ result.put(globalObject, ZigString.static("type"), ZigString.static("DH").toValue(globalObject));
+ result.put(globalObject, ZigString.static("size"), JSValue.jsNumber(bits));
+ },
+
+ BoringSSL.EVP_PKEY_EC, BoringSSL.EVP_PKEY_X25519, BoringSSL.EVP_PKEY_X448 => {
+ var curve_name: []const u8 = undefined;
+ if (kid == BoringSSL.EVP_PKEY_EC) {
+ const ec = BoringSSL.EVP_PKEY_get1_EC_KEY(raw_key);
+ const nid = BoringSSL.EC_GROUP_get_curve_name(BoringSSL.EC_KEY_get0_group(ec));
+ const nid_str = BoringSSL.OBJ_nid2sn(nid);
+ if (nid_str != null) {
+ curve_name = nid_str[0..bun.len(nid_str)];
+ } else {
+ curve_name = "";
+ }
+ } else {
+ const kid_str = BoringSSL.OBJ_nid2sn(kid);
+ if (kid_str != null) {
+ curve_name = kid_str[0..bun.len(kid_str)];
+ } else {
+ curve_name = "";
+ }
+ }
+ result.put(globalObject, ZigString.static("type"), ZigString.static("ECDH").toValue(globalObject));
+ result.put(globalObject, ZigString.static("name"), ZigString.fromUTF8(curve_name).toValueGC(globalObject));
+ result.put(globalObject, ZigString.static("size"), JSValue.jsNumber(bits));
+ },
+ else => {},
+ }
+ return result;
+ }
+
+ pub fn getCipher(
+ this: *This,
+ globalObject: *JSC.JSGlobalObject,
+ _: *JSC.CallFrame,
+ ) callconv(.C) JSValue {
+ if (comptime ssl == false) {
+ return JSValue.jsUndefined();
+ }
+ if (this.detached) {
+ return JSValue.jsUndefined();
+ }
+ var result = JSValue.createEmptyObject(globalObject, 3);
+
+ const ssl_ptr = @ptrCast(*BoringSSL.SSL, this.socket.getNativeHandle());
+ const cipher = BoringSSL.SSL_get_current_cipher(ssl_ptr);
+ if (cipher == null) {
+ result.put(globalObject, ZigString.static("name"), JSValue.jsNull());
+ result.put(globalObject, ZigString.static("standardName"), JSValue.jsNull());
+ result.put(globalObject, ZigString.static("version"), JSValue.jsNull());
+ return result;
+ }
+
+ const name = BoringSSL.SSL_CIPHER_get_name(cipher);
+ if (name == null) {
+ result.put(globalObject, ZigString.static("name"), JSValue.jsNull());
+ } else {
+ result.put(globalObject, ZigString.static("name"), ZigString.fromUTF8(name[0..bun.len(name)]).toValueGC(globalObject));
+ }
+
+ const standard_name = BoringSSL.SSL_CIPHER_standard_name(cipher);
+ if (standard_name == null) {
+ result.put(globalObject, ZigString.static("standardName"), JSValue.jsNull());
+ } else {
+ result.put(globalObject, ZigString.static("standardName"), ZigString.fromUTF8(standard_name[0..bun.len(standard_name)]).toValueGC(globalObject));
+ }
+
+ const version = BoringSSL.SSL_CIPHER_get_version(cipher);
+ if (version == null) {
+ result.put(globalObject, ZigString.static("version"), JSValue.jsNull());
+ } else {
+ result.put(globalObject, ZigString.static("version"), ZigString.fromUTF8(version[0..bun.len(version)]).toValueGC(globalObject));
+ }
+
+ return result;
+ }
+
+ pub fn getTLSPeerFinishedMessage(
+ this: *This,
+ globalObject: *JSC.JSGlobalObject,
+ _: *JSC.CallFrame,
+ ) callconv(.C) JSValue {
+ if (comptime ssl == false) {
+ return JSValue.jsUndefined();
+ }
+
+ if (this.detached) {
+ return JSValue.jsUndefined();
+ }
+
+ const ssl_ptr = @ptrCast(*BoringSSL.SSL, this.socket.getNativeHandle());
+ // We cannot just pass nullptr to SSL_get_peer_finished()
+ // because it would further be propagated to memcpy(),
+ // where the standard requirements as described in ISO/IEC 9899:2011
+ // sections 7.21.2.1, 7.21.1.2, and 7.1.4, would be violated.
+ // Thus, we use a dummy byte.
+ var dummy: [1]u8 = undefined;
+ const size = BoringSSL.SSL_get_peer_finished(ssl_ptr, @ptrCast(*anyopaque, &dummy), @sizeOf(@TypeOf(dummy)));
+ if (size == 0) return JSValue.jsUndefined();
+
+ const buffer_size = @intCast(usize, size);
+ var buffer = JSValue.createBufferFromLength(globalObject, buffer_size);
+ var buffer_ptr = @ptrCast(*anyopaque, buffer.asArrayBuffer(globalObject).?.ptr);
+
+ const result_size = BoringSSL.SSL_get_peer_finished(ssl_ptr, buffer_ptr, buffer_size);
+ std.debug.assert(result_size == size);
+ return buffer;
+ }
+
+ pub fn getTLSFinishedMessage(
+ this: *This,
+ globalObject: *JSC.JSGlobalObject,
+ _: *JSC.CallFrame,
+ ) callconv(.C) JSValue {
+ if (comptime ssl == false) {
+ return JSValue.jsUndefined();
+ }
+
+ if (this.detached) {
+ return JSValue.jsUndefined();
+ }
+
+ const ssl_ptr = @ptrCast(*BoringSSL.SSL, this.socket.getNativeHandle());
+ // We cannot just pass nullptr to SSL_get_finished()
+ // because it would further be propagated to memcpy(),
+ // where the standard requirements as described in ISO/IEC 9899:2011
+ // sections 7.21.2.1, 7.21.1.2, and 7.1.4, would be violated.
+ // Thus, we use a dummy byte.
+ var dummy: [1]u8 = undefined;
+ const size = BoringSSL.SSL_get_finished(ssl_ptr, @ptrCast(*anyopaque, &dummy), @sizeOf(@TypeOf(dummy)));
+ if (size == 0) return JSValue.jsUndefined();
+
+ const buffer_size = @intCast(usize, size);
+ var buffer = JSValue.createBufferFromLength(globalObject, buffer_size);
+ var buffer_ptr = @ptrCast(*anyopaque, buffer.asArrayBuffer(globalObject).?.ptr);
+
+ const result_size = BoringSSL.SSL_get_finished(ssl_ptr, buffer_ptr, buffer_size);
+ std.debug.assert(result_size == size);
+ return buffer;
+ }
+
+ pub fn getSharedSigalgs(
+ this: *This,
+ globalObject: *JSC.JSGlobalObject,
+ _: *JSC.CallFrame,
+ ) callconv(.C) JSValue {
+ JSC.markBinding(@src());
+ if (comptime ssl == false) {
+ return JSValue.jsNull();
+ }
+
+ if (this.detached) {
+ return JSValue.jsNull();
+ }
+ const ssl_ptr = @ptrCast(*BoringSSL.SSL, this.socket.getNativeHandle());
+
+ const nsig = BoringSSL.SSL_get_shared_sigalgs(ssl_ptr, 0, null, null, null, null, null);
+
+ const array = JSC.JSValue.createEmptyArray(globalObject, @intCast(usize, nsig));
+
+ for (0..@intCast(usize, nsig)) |i| {
+ var hash_nid: c_int = 0;
+ var sign_nid: c_int = 0;
+ var sig_with_md: []const u8 = "";
+
+ _ = BoringSSL.SSL_get_shared_sigalgs(ssl_ptr, @intCast(c_int, i), &sign_nid, &hash_nid, null, null, null);
+ switch (sign_nid) {
+ BoringSSL.EVP_PKEY_RSA => {
+ sig_with_md = "RSA";
+ },
+ BoringSSL.EVP_PKEY_RSA_PSS => {
+ sig_with_md = "RSA-PSS";
+ },
+
+ BoringSSL.EVP_PKEY_DSA => {
+ sig_with_md = "DSA";
+ },
+
+ BoringSSL.EVP_PKEY_EC => {
+ sig_with_md = "ECDSA";
+ },
+
+ BoringSSL.NID_ED25519 => {
+ sig_with_md = "Ed25519";
+ },
+
+ BoringSSL.NID_ED448 => {
+ sig_with_md = "Ed448";
+ },
+ BoringSSL.NID_id_GostR3410_2001 => {
+ sig_with_md = "gost2001";
+ },
+
+ BoringSSL.NID_id_GostR3410_2012_256 => {
+ sig_with_md = "gost2012_256";
+ },
+ BoringSSL.NID_id_GostR3410_2012_512 => {
+ sig_with_md = "gost2012_512";
+ },
+ else => {
+ const sn_str = BoringSSL.OBJ_nid2sn(sign_nid);
+ if (sn_str != null) {
+ sig_with_md = sn_str[0..bun.len(sn_str)];
+ } else {
+ sig_with_md = "UNDEF";
+ }
+ },
+ }
+
+ const hash_str = BoringSSL.OBJ_nid2sn(hash_nid);
+ if (hash_str != null) {
+ const hash_str_len = bun.len(hash_str);
+ const hash_slice = hash_str[0..hash_str_len];
+ const buffer = bun.default_allocator.alloc(u8, sig_with_md.len + hash_str_len + 1) catch unreachable;
+ defer bun.default_allocator.free(buffer);
+
+ bun.copy(u8, buffer, sig_with_md);
+ buffer[sig_with_md.len] = '+';
+ bun.copy(u8, buffer[sig_with_md.len + 1 ..], hash_slice);
+ array.putIndex(globalObject, @intCast(u32, i), JSC.ZigString.fromUTF8(buffer).toValueGC(globalObject));
+ } else {
+ const buffer = bun.default_allocator.alloc(u8, sig_with_md.len + 6) catch unreachable;
+ defer bun.default_allocator.free(buffer);
+
+ bun.copy(u8, buffer, sig_with_md);
+ bun.copy(u8, buffer[sig_with_md.len..], "+UNDEF");
+ array.putIndex(globalObject, @intCast(u32, i), JSC.ZigString.fromUTF8(buffer).toValueGC(globalObject));
+ }
+ }
+ return array;
+ }
+
+ pub fn getTLSVersion(
+ this: *This,
+ globalObject: *JSC.JSGlobalObject,
+ _: *JSC.CallFrame,
+ ) callconv(.C) JSValue {
+ JSC.markBinding(@src());
+ if (comptime ssl == false) {
+ return JSValue.jsNull();
+ }
+
+ if (this.detached) {
+ return JSValue.jsNull();
+ }
+
+ const ssl_ptr = @ptrCast(*BoringSSL.SSL, this.socket.getNativeHandle());
+ const version = BoringSSL.SSL_get_version(ssl_ptr);
+ if (version == null) return JSValue.jsNull();
+ const version_len = bun.len(version);
+ if (version_len == 0) return JSValue.jsNull();
+ const slice = version[0..version_len];
+ return ZigString.fromUTF8(slice).toValueGC(globalObject);
+ }
+
+ pub fn setMaxSendFragment(
+ this: *This,
+ globalObject: *JSC.JSGlobalObject,
+ callframe: *JSC.CallFrame,
+ ) callconv(.C) JSValue {
+ JSC.markBinding(@src());
+ if (comptime ssl == false) {
+ return JSValue.jsBoolean(false);
+ }
+
+ if (this.detached) {
+ return JSValue.jsBoolean(false);
+ }
+
+ const args = callframe.arguments(1);
+
+ if (args.len < 1) {
+ globalObject.throw("Expected size to be a number", .{});
+ return .zero;
+ }
+
+ const arg = args.ptr[0];
+ if (!arg.isNumber()) {
+ globalObject.throw("Expected size to be a number", .{});
+ return .zero;
+ }
+ const size = args.ptr[0].coerceToInt64(globalObject);
+ if (size < 1) {
+ globalObject.throw("Expected size to be greater than 1", .{});
+ return .zero;
+ }
+ if (size > 16384) {
+ globalObject.throw("Expected size to be less than 16385", .{});
+ return .zero;
+ }
+
+ const ssl_ptr = @ptrCast(*BoringSSL.SSL, this.socket.getNativeHandle());
+ return JSValue.jsBoolean(BoringSSL.SSL_set_max_send_fragment(ssl_ptr, @intCast(usize, size)) == 1);
+ }
+ pub fn getPeerCertificate(
+ this: *This,
+ globalObject: *JSC.JSGlobalObject,
+ callframe: *JSC.CallFrame,
+ ) callconv(.C) JSValue {
+ JSC.markBinding(@src());
+ if (comptime ssl == false) {
+ return JSValue.jsUndefined();
+ }
+
+ if (this.detached) {
+ return JSValue.jsUndefined();
+ }
+
+ const args = callframe.arguments(1);
+ var abbreviated: bool = true;
+ if (args.len > 0) {
+ const arg = args.ptr[0];
+ if (!arg.isBoolean()) {
+ globalObject.throw("Expected abbreviated to be a boolean", .{});
+ return .zero;
+ }
+ abbreviated = arg.toBoolean();
+ }
+
+ const ssl_ptr = @ptrCast(*BoringSSL.SSL, this.socket.getNativeHandle());
+
+ if (abbreviated) {
+ if (this.handlers.is_server) {
+ const cert = BoringSSL.SSL_get_peer_certificate(ssl_ptr);
+ if (cert) |x509| {
+ return X509.toJS(x509, globalObject);
+ }
+ }
+
+ const cert_chain = BoringSSL.SSL_get_peer_cert_chain(ssl_ptr) orelse return JSValue.jsUndefined();
+ const cert = BoringSSL.sk_X509_value(cert_chain, 0) orelse return JSValue.jsUndefined();
+ return X509.toJS(cert, globalObject);
+ }
+ var cert: ?*BoringSSL.X509 = null;
+ if (this.handlers.is_server) {
+ cert = BoringSSL.SSL_get_peer_certificate(ssl_ptr);
+ }
+
+ const cert_chain = BoringSSL.SSL_get_peer_cert_chain(ssl_ptr);
+ const first_cert = if (cert) |c| c else if (cert_chain) |cc| BoringSSL.sk_X509_value(cc, 0) else null;
+
+ if (first_cert == null) {
+ return JSValue.jsUndefined();
+ }
+
+ // TODO: we need to support the non abbreviated version of this
+ return JSValue.jsUndefined();
+ }
+
+ pub fn getCertificate(
+ this: *This,
+ globalObject: *JSC.JSGlobalObject,
+ _: *JSC.CallFrame,
+ ) callconv(.C) JSValue {
+ if (comptime ssl == false) {
+ return JSValue.jsUndefined();
+ }
+
+ if (this.detached) {
+ return JSValue.jsUndefined();
+ }
+
+ const ssl_ptr = @ptrCast(*BoringSSL.SSL, this.socket.getNativeHandle());
+ const cert = BoringSSL.SSL_get_certificate(ssl_ptr);
+
+ if (cert) |x509| {
+ return X509.toJS(x509, globalObject);
+ }
+ return JSValue.jsUndefined();
+ }
pub fn setServername(
this: *This,
globalObject: *JSC.JSGlobalObject,
@@ -1952,7 +2622,7 @@ fn NewSocket(comptime ssl: bool) type {
const host = normalizeHost(@as([]const u8, slice));
if (host.len > 0) {
- var ssl_ptr: *BoringSSL.SSL = @ptrCast(*BoringSSL.SSL, this.socket.getNativeHandle());
+ var ssl_ptr = this.socket.ssl();
if (ssl_ptr.isInitFinished()) {
// match node.js exceptions
globalObject.throw("Already started.", .{});
@@ -2222,6 +2892,7 @@ pub fn NewWrappedHandler(comptime tls: bool) type {
if (comptime tls) {
TLSSocket.onData(this.tls, socket, data);
} else {
+ // tedius use this
TLSSocket.onData(this.tcp, socket, data);
}
}