Index | Thread | Search

From:
David Uhden Collado <daviduhden@gmail.com>
Subject:
[UPDATE] security/veracrypt 1.25.9 -> 1.26.29 + improvements
To:
ports@openbsd.org
Date:
Wed, 14 Oct 2026 19:51:00 +0000

Download raw body.

Thread
  • David Uhden Collado:

    [UPDATE] security/veracrypt 1.25.9 -> 1.26.29 + improvements

Hello,

Please find attached a patch updating security/veracrypt from 1.25.9 to 
1.26.29, including native OpenBSD privilege elevation and FFS support.

Upstream source:
https://launchpad.net/veracrypt/trunk/1.26.29/+download/

The main OpenBSD-specific changes are:

- Replace sudo with doas for the privileged core service.
- Support restricted doas.conf rules allowing only --core-service.
- Handle password authentication through a private pseudoterminal, 
without exposing credentials through argv or the environment.
- Add native FFS creation using /sbin/newfs through a restricted 
privileged service request.
- Preserve FAT as the default for noninteractive volume creation.
- Remove the obsolete coreutils dependency and add pcsc-lite.
- Fix reproducible-build date handling with OpenBSD's awk.
- Update distinfo, PLIST, patches, documentation and the desktop icon.
- Enable the upstream cryptographic self-tests through make test.

The doas implementation supports password authentication and retries 
after incorrect credentials. The FFS formatter validates the target vnd 
device before requesting the privileged operation.

I built, packaged, installed and tested VeraCrypt 1.26.29 on OpenBSD 
8.0-current amd64.

The cryptographic self-tests passed, including when executed by an 
unprivileged user.

I also verified restricted doas permissions, password authentication, 
FFS volume creation, mounting, writing, reading, unmounting and 
remounting. File integrity was confirmed using SHA256, and fsck_ffs 
reported no errors.

The existing FAT creation and mounting behavior was also tested 
successfully.

These tests uncovered and helped resolve several privilege-related 
problems that were not apparent when running as root.

Testing was limited to the CLI and regular file-backed volumes on amd64. 
The GUI builds but has not been tested interactively. Other 
architectures, physical devices, hidden volumes and smartcards remain 
untested.

I would particularly appreciate review of the privilege elevation 
changes and additional testing on other architectures.

Thank you for your time and consideration.

Best regards,
David.
Index: security/veracrypt/Makefile
===================================================================
RCS file: /cvs/ports/security/veracrypt/Makefile,v
diff -u -p -u -r1.8 Makefile
--- security/veracrypt/Makefile	17 Dec 2024 05:49:59 -0000	1.8
+++ security/veracrypt/Makefile	14 Oct 2026 19:04:23 -0000
@@ -2,23 +2,22 @@ BROKEN-sparc64=	relocation truncated to 
 
 COMMENT=		free open source disk encryption software
 
-V=			1.25.9
+V=			1.26.29
 DISTNAME=		VeraCrypt_${V}_Source
 PKGNAME=		veracrypt-${V}
 CATEGORIES=		security
 HOMEPAGE=		https://www.veracrypt.fr/
-REVISION=		1
 
 MAINTAINER=		Tietoturvamies <main@tietoturvamies.fi>
 
 # Apache2
-PERMIT_PACKAGE=	yes
+PERMIT_PACKAGE=	Yes
 
 SITES=			https://launchpad.net/veracrypt/trunk/${V}/+download/
 EXTRACT_SUFX=		.tar.bz2
 FIX_EXTRACT_PERMISSIONS=Yes
 
-# C++11
+# C++14
 COMPILER=		base-clang ports-gcc
 
 CXXFLAGS_base-clang =	-std=c++14
@@ -26,16 +25,16 @@ CXXFLAGS_base-clang =	-std=c++14
 WANTLIB += ${COMPILER_LIBCXX} c m fuse wx_baseu-3.2 wx_gtk3u_core-3.2
 
 BUILD_DEPENDS=		devel/yasm \
-			sysutils/coreutils
+			security/pcsc-lite
 
 LIB_DEPENDS=		x11/wxWidgets
 
 RUN_DEPENDS=		devel/desktop-file-utils \
-			security/sudo
+			security/pcsc-lite
 
 WRKDIST=		${WRKDIR}/src
 USE_GMAKE=		Yes
-ALL_TARGET=		
+ALL_TARGET=
 MAKE_FLAGS=		VERBOSE=1 \
 			NOTEST=1 \
 			CC="${CC}" \
@@ -43,7 +42,6 @@ MAKE_FLAGS=		VERBOSE=1 \
 			PORT_CFLAGS="${CFLAGS}" \
 			PORT_CXXFLAGS="${CXXFLAGS}"
 
-NO_TEST=		Yes
 
 .if ${MACHINE_ARCH:Mi386}
 MAKE_ENV+=		LFLAGS=-Wl,-z,notext
@@ -52,13 +50,16 @@ MAKE_ENV+=		LFLAGS=-Wl,-z,notext
 pre-configure:
 	${SUBST_CMD} ${WRKSRC}/Setup/FreeBSD/veracrypt.desktop
 
+do-test:
+	${WRKSRC}/Main/veracrypt --text --test
+
 do-install:
 	${INSTALL_PROGRAM} ${WRKSRC}/Main/veracrypt ${PREFIX}/bin
 	${INSTALL_DATA_DIR} ${PREFIX}/share/applications
 	${INSTALL_DATA} ${WRKSRC}/Setup/FreeBSD/veracrypt.desktop \
 		${PREFIX}/share/applications
 	${INSTALL_DATA_DIR} ${PREFIX}/share/pixmaps/
-	${INSTALL_DATA} ${WRKSRC}/Resources/Icons/VeraCrypt-48x48.xpm \
-		${PREFIX}/share/pixmaps/veracrypt.xpm
+	${INSTALL_DATA} ${WRKSRC}/Resources/Icons/VeraCrypt-48x48.png \
+		${PREFIX}/share/pixmaps/veracrypt.png
 
 .include <bsd.port.mk>
Index: security/veracrypt/distinfo
===================================================================
RCS file: /cvs/ports/security/veracrypt/distinfo,v
diff -u -p -u -r1.2 distinfo
--- security/veracrypt/distinfo	14 Mar 2022 11:07:46 -0000	1.2
+++ security/veracrypt/distinfo	14 Oct 2026 19:04:23 -0000
@@ -1,2 +1,2 @@
-SHA256 (VeraCrypt_1.25.9_Source.tar.bz2) = drbhgYS8IaQdKUn/Y9ch1JBUpxbO/zpL13tcNRC3lK8=
-SIZE (VeraCrypt_1.25.9_Source.tar.bz2) = 24438846
+SHA256 (VeraCrypt_1.26.29_Source.tar.bz2) = YIJnMeKYK0vSMeOTDoWkQ5EWljhnGhsgDFGPjItGyyo=
+SIZE (VeraCrypt_1.26.29_Source.tar.bz2) = 36302144
Index: security/veracrypt/patches/patch-Makefile
===================================================================
RCS file: /cvs/ports/security/veracrypt/patches/patch-Makefile,v
diff -u -p -u -r1.3 patch-Makefile
--- security/veracrypt/patches/patch-Makefile	14 Mar 2022 11:07:46 -0000	1.3
+++ security/veracrypt/patches/patch-Makefile	14 Oct 2026 19:04:23 -0000
@@ -4,16 +4,16 @@
 Index: Makefile
 --- Makefile.orig
 +++ Makefile
-@@ -47,7 +47,7 @@ export CFLAGS := -Wall
+@@ -50,7 +50,7 @@
  export CXXFLAGS := -Wall -Wno-unused-parameter
- C_CXX_FLAGS := -MMD -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGE_FILES -I$(BASE_DIR) -I$(BASE_DIR)/Crypto
+ C_CXX_FLAGS := -MMD -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGE_FILES -I$(BASE_DIR) -I$(BASE_DIR)/Crypto -DARGON2_NO_THREADS -I$(BASE_DIR)/Crypto/Argon2/include
  export ASFLAGS := -D __GNUC__ -D __YASM__
 -export LFLAGS :=
 +export LFLAGS ?=
  
+ export PKG_CONFIG ?= pkg-config
  export PKG_CONFIG_PATH ?= /usr/local/lib/pkgconfig
- 
-@@ -109,7 +109,7 @@ endif
+@@ -111,7 +111,7 @@
  
  ifeq "$(TC_BUILD_CONFIG)" "Release"
  
@@ -22,7 +22,7 @@ Index: Makefile
  	export WX_BUILD_DIR ?= $(BASE_DIR)/wxrelease
  	WX_CONFIGURE_FLAGS += --disable-debug_flag --disable-debug_gdb --disable-debug_info
  
-@@ -441,8 +441,8 @@ endif
+@@ -585,8 +585,8 @@
  
  #------ Common configuration ------
  
@@ -32,4 +32,4 @@ Index: Makefile
 +CXXFLAGS := $(C_CXX_FLAGS) $(CXXFLAGS) $(TC_EXTRA_CXXFLAGS) $(PORT_CXXFLAGS)
  LFLAGS := $(LFLAGS) $(TC_EXTRA_LFLAGS)
  
- WX_CONFIGURE_FLAGS += --enable-unicode -disable-shared --disable-dependency-tracking --enable-exceptions --enable-std_string --enable-dataobj --enable-mimetype
+ #------ Reproducible build configuration ------
Index: security/veracrypt/patches/patch-Setup_FreeBSD_veracrypt_desktop
===================================================================
RCS file: /cvs/ports/security/veracrypt/patches/patch-Setup_FreeBSD_veracrypt_desktop,v
diff -u -p -u -r1.2 patch-Setup_FreeBSD_veracrypt_desktop
--- security/veracrypt/patches/patch-Setup_FreeBSD_veracrypt_desktop	11 Mar 2022 19:54:08 -0000	1.2
+++ security/veracrypt/patches/patch-Setup_FreeBSD_veracrypt_desktop	14 Oct 2026 19:04:23 -0000
@@ -1,12 +1,15 @@
+Point the desktop launcher at the executable installed under TRUEPREFIX
+rather than the upstream /usr/bin path.
+
 Index: Setup/FreeBSD/veracrypt.desktop
 --- Setup/FreeBSD/veracrypt.desktop.orig
 +++ Setup/FreeBSD/veracrypt.desktop
-@@ -3,7 +3,7 @@ Encoding=UTF-8
- Name=VeraCrypt
- GenericName=VeraCrypt
- Comment=VeraCrypt
--Exec=/usr/bin/veracrypt
-+Exec=${TRUEPREFIX}/bin/veracrypt
+@@ -4,7 +4,7 @@
+ GenericName=VeraCrypt volume manager
+ Comment=Create and mount VeraCrypt encrypted volumes
  Icon=veracrypt
+-Exec=/usr/bin/veracrypt %f
++Exec=${TRUEPREFIX}/bin/veracrypt %f
+ Categories=Security;Utility;Filesystem
+ Keywords=encryption,filesystem
  Terminal=false
- Type=Application
Index: security/veracrypt/pkg/PLIST
===================================================================
RCS file: /cvs/ports/security/veracrypt/pkg/PLIST,v
diff -u -p -u -r1.2 PLIST
--- security/veracrypt/pkg/PLIST	11 Mar 2022 19:54:08 -0000	1.2
+++ security/veracrypt/pkg/PLIST	14 Oct 2026 19:04:23 -0000
@@ -1,5 +1,6 @@
 @bin bin/veracrypt
 share/applications/veracrypt.desktop
+share/doc/pkg-readmes/${PKGSTEM}
 share/pixmaps/
-share/pixmaps/veracrypt.xpm
+share/pixmaps/veracrypt.png
 @tag update-desktop-database
Index: security/veracrypt/patches/patch-Build_Tools_source_date_epoch_sh
===================================================================
--- /dev/null
+++ security/veracrypt/patches/patch-Build_Tools_source_date_epoch_sh
@@ -0,0 +1,20 @@
+Continue the month_number ternary expression explicitly: OpenBSD's awk
+does not accept a bare newline after ':' as a line continuation, so the
+release date could not be derived from Common/Tcdefs.h.
+
+Index: Build/Tools/source_date_epoch.sh
+--- Build/Tools/source_date_epoch.sh.orig
++++ Build/Tools/source_date_epoch.sh
+@@ -60,9 +60,9 @@
+ RELEASE_EPOCH=$(awk '
+     function leap(y) { return ((y % 4 == 0 && y % 100 != 0) || (y % 400 == 0)) }
+     function month_number(name) {
+-        return (name == "January" ? 1 : name == "February" ? 2 : name == "March" ? 3 :
+-            name == "April" ? 4 : name == "May" ? 5 : name == "June" ? 6 :
+-            name == "July" ? 7 : name == "August" ? 8 : name == "September" ? 9 :
++        return (name == "January" ? 1 : name == "February" ? 2 : name == "March" ? 3 : \
++            name == "April" ? 4 : name == "May" ? 5 : name == "June" ? 6 : \
++            name == "July" ? 7 : name == "August" ? 8 : name == "September" ? 9 : \
+             name == "October" ? 10 : name == "November" ? 11 : name == "December" ? 12 : 0);
+     }
+     function mdays(m, y) { return (m == 2 ? 28 + leap(y) : (m == 4 || m == 6 || m == 9 || m == 11 ? 30 : 31)) }
Index: security/veracrypt/patches/patch-Common_Tcdefs_h
===================================================================
--- /dev/null
+++ security/veracrypt/patches/patch-Common_Tcdefs_h
@@ -0,0 +1,16 @@
+Set TC_STR_RELEASE_DATE to June 9, 2026, matching TC_RELEASE_DATE_DAY
+and the upstream "Set release date to June 9th 2026" commit.  The awk
+helper in Build/Tools/source_date_epoch.sh requires both dates to agree.
+
+Index: Common/Tcdefs.h
+--- Common/Tcdefs.h.orig
++++ Common/Tcdefs.h
+@@ -73,7 +73,7 @@
+ #define VERSION_NUM						0x0126
+ 
+ // Release date
+-#define TC_STR_RELEASE_DATE			L"June 8, 2026"
++#define TC_STR_RELEASE_DATE			L"June 9, 2026"
+ #define TC_RELEASE_DATE_YEAR			2026
+ #define TC_RELEASE_DATE_MONTH			 6
+ #define TC_RELEASE_DATE_DAY			 9
Index: security/veracrypt/patches/patch-Core_Unix_CoreServiceRequest_cpp
===================================================================
--- /dev/null
+++ security/veracrypt/patches/patch-Core_Unix_CoreServiceRequest_cpp
@@ -0,0 +1,42 @@
+Run OpenBSD FFS formatting through the elevated core service.
+
+--- Core/Unix/CoreServiceRequest.cpp.orig
++++ Core/Unix/CoreServiceRequest.cpp
+@@ -245,6 +245,27 @@
+ 	}
+ #endif
+ 
++#ifdef TC_OPENBSD
++	void ExecuteOpenBSDFFSFormatterRequest::Deserialize (shared_ptr <Stream> stream)
++	{
++		CoreServiceRequest::Deserialize (stream);
++		Serializer sr (stream);
++		Device = sr.DeserializeWString ("Device");
++	}
++
++	bool ExecuteOpenBSDFFSFormatterRequest::RequiresElevation () const
++	{
++		return !Core->HasAdminPrivileges();
++	}
++
++	void ExecuteOpenBSDFFSFormatterRequest::Serialize (shared_ptr <Stream> stream) const
++	{
++		CoreServiceRequest::Serialize (stream);
++		Serializer sr (stream);
++		sr.Serialize ("Device", wstring (Device));
++	}
++#endif
++
+ 	// MountVolumeRequest
+ 	void MountVolumeRequest::Deserialize (shared_ptr <Stream> stream)
+ 	{
+@@ -326,6 +347,9 @@
+ 	TC_SERIALIZER_FACTORY_ADD_CLASS (GetDeviceSectorSizeRequest);
+ 	TC_SERIALIZER_FACTORY_ADD_CLASS (GetDeviceSizeRequest);
+ 	TC_SERIALIZER_FACTORY_ADD_CLASS (GetHostDevicesRequest);
++#ifdef TC_OPENBSD
++	TC_SERIALIZER_FACTORY_ADD_CLASS (ExecuteOpenBSDFFSFormatterRequest);
++#endif
+ 	TC_SERIALIZER_FACTORY_ADD_CLASS (MountVolumeRequest);
+ 	TC_SERIALIZER_FACTORY_ADD_CLASS (SetFileOwnerRequest);
+ }
Index: security/veracrypt/patches/patch-Core_Unix_CoreServiceRequest_h
===================================================================
--- /dev/null
+++ security/veracrypt/patches/patch-Core_Unix_CoreServiceRequest_h
@@ -0,0 +1,22 @@
+Run OpenBSD FFS formatting through the elevated core service.
+
+--- Core/Unix/CoreServiceRequest.h.orig
++++ Core/Unix/CoreServiceRequest.h
+@@ -142,6 +142,17 @@
+ 	};
+ #endif
+ 
++#ifdef TC_OPENBSD
++	struct ExecuteOpenBSDFFSFormatterRequest : CoreServiceRequest
++	{
++		ExecuteOpenBSDFFSFormatterRequest () { }
++		ExecuteOpenBSDFFSFormatterRequest (const DevicePath &devicePath) : Device (devicePath) { }
++		TC_SERIALIZABLE (ExecuteOpenBSDFFSFormatterRequest);
++		virtual bool RequiresElevation () const;
++		DevicePath Device;
++	};
++#endif
++
+ 	struct MountVolumeRequest : CoreServiceRequest
+ 	{
+ 		MountVolumeRequest () { }
Index: security/veracrypt/patches/patch-Core_Unix_CoreServiceResponse_cpp
===================================================================
--- /dev/null
+++ security/veracrypt/patches/patch-Core_Unix_CoreServiceResponse_cpp
@@ -0,0 +1,32 @@
+Run OpenBSD FFS formatting through the elevated core service.
+
+--- Core/Unix/CoreServiceResponse.cpp.orig
++++ Core/Unix/CoreServiceResponse.cpp
+@@ -100,6 +100,17 @@
+ 	}
+ #endif
+ 
++#ifdef TC_OPENBSD
++	void ExecuteOpenBSDFFSFormatterResponse::Deserialize (shared_ptr <Stream> stream)
++	{
++	}
++
++	void ExecuteOpenBSDFFSFormatterResponse::Serialize (shared_ptr <Stream> stream) const
++	{
++		Serializable::Serialize (stream);
++	}
++#endif
++
+ 	// MountVolumeResponse
+ 	void MountVolumeResponse::Deserialize (shared_ptr <Stream> stream)
+ 	{
+@@ -133,6 +144,9 @@
+ #ifdef TC_MACOSX
+ 	TC_SERIALIZER_FACTORY_ADD_CLASS (ExecuteMacOSXAPFSFormatterResponse);
+ #endif
++#ifdef TC_OPENBSD
++	TC_SERIALIZER_FACTORY_ADD_CLASS (ExecuteOpenBSDFFSFormatterResponse);
++#endif
+ 	TC_SERIALIZER_FACTORY_ADD_CLASS (MountVolumeResponse);
+ 	TC_SERIALIZER_FACTORY_ADD_CLASS (SetFileOwnerResponse);
+ }
Index: security/veracrypt/patches/patch-Core_Unix_CoreServiceResponse_h
===================================================================
--- /dev/null
+++ security/veracrypt/patches/patch-Core_Unix_CoreServiceResponse_h
@@ -0,0 +1,18 @@
+Run OpenBSD FFS formatting through the elevated core service.
+
+--- Core/Unix/CoreServiceResponse.h.orig
++++ Core/Unix/CoreServiceResponse.h
+@@ -77,6 +77,13 @@
+ 	};
+ #endif
+ 
++#ifdef TC_OPENBSD
++	struct ExecuteOpenBSDFFSFormatterResponse : CoreServiceResponse
++	{
++		TC_SERIALIZABLE (ExecuteOpenBSDFFSFormatterResponse);
++	};
++#endif
++
+ 	struct MountVolumeResponse : CoreServiceResponse
+ 	{
+ 		MountVolumeResponse () { }
Index: security/veracrypt/patches/patch-Core_Unix_CoreService_cpp
===================================================================
--- /dev/null
+++ security/veracrypt/patches/patch-Core_Unix_CoreService_cpp
@@ -0,0 +1,392 @@
+Use doas with rules restricted to --core-service and a private authentication
+terminal. Keep its slave on stderr across doas closefrom(), forward one
+password response, and detach the elevated worker before releasing the tty.
+Format OpenBSD FFS through a restricted privileged service request.
+
+--- Core/Unix/CoreService.cpp.orig
++++ Core/Unix/CoreService.cpp
+@@ -14,6 +14,15 @@
+ #include <fcntl.h>
+ #include <sys/wait.h>
+ #include <stdio.h>
++#ifdef TC_OPENBSD
++#include <errno.h>
++#include <signal.h>
++#include <stdlib.h>
++#include <string.h>
++#include <sys/ioctl.h>
++#include <termios.h>
++#include <unistd.h>
++#endif
+ #include "Platform/FileStream.h"
+ #include "Platform/MemoryStream.h"
+ #include "Platform/Serializable.h"
+@@ -28,6 +37,24 @@
+ 
+ namespace VeraCrypt
+ {
++#ifdef TC_OPENBSD
++	// doas(1) reads the password from its controlling terminal. A private
++	// pseudoterminal is used for that, so the elevated process does not need
++	// a terminal of its own and the password entered in the user interface
++	// can be forwarded without exposing it on the command line or in the
++	// environment.
++	static int DoasAuthTerminalFd = -1;
++
++	static void CloseDoasAuthTerminal ()
++	{
++		if (DoasAuthTerminalFd != -1)
++		{
++			close (DoasAuthTerminalFd);
++			DoasAuthTerminalFd = -1;
++		}
++	}
++#endif
++
+ #ifdef TC_MACOSX
+ 	static bool IsMacOSXDevicePathWithPrefix (const string &path, const string &prefix)
+ 	{
+@@ -111,6 +138,10 @@
+ 		{
+ 			try
+ 			{
++#ifdef TC_OPENBSD
++				// Detach the elevated worker before releasing its auth terminal.
++				throw_sys_if (setsid () == -1);
++#endif
+ 				int f = open ("/dev/null", 0);
+ 				throw_sys_sub_if (f == -1, "/dev/null");
+ 				throw_sys_if (dup2 (f, STDERR_FILENO) == -1);
+@@ -149,6 +180,10 @@
+ 
+ 	void CoreService::ProcessRequests (int inputFD, int outputFD)
+ 	{
++#ifdef TC_OPENBSD
++		finally_do ({ CloseDoasAuthTerminal (); });
++#endif
++
+ 		try
+ 		{
+ 			Core = move_ptr(CoreDirect);
+@@ -273,6 +308,34 @@
+ 					}
+ #endif
+ 
++#ifdef TC_OPENBSD
++					ExecuteOpenBSDFFSFormatterRequest *formatRequest = dynamic_cast <ExecuteOpenBSDFFSFormatterRequest*> (request.get());
++					if (formatRequest)
++					{
++						string device = formatRequest->Device;
++						if (device.size() != 10 || device.compare (0, 8, "/dev/vnd") != 0
++							|| device[8] < '0' || device[8] > '3' || device[9] != 'c')
++							throw ParameterIncorrect (SRC_POS);
++
++						// Format only a VeraCrypt virtual device without a mounted
++						// filesystem, never an arbitrary host disk or active filesystem.
++						bool mountedVolumeFound = false;
++						foreach (shared_ptr <VolumeInfo> volume, Core->GetMountedVolumes())
++						{
++							if (volume->VirtualDevice == formatRequest->Device && volume->MountPoint.IsEmpty())
++								mountedVolumeFound = true;
++						}
++						if (!mountedVolumeFound)
++							throw ParameterIncorrect (SRC_POS);
++
++						list <string> arguments;
++						arguments.push_back ("/dev/r" + device.substr (5));
++						Process::Execute ("/sbin/newfs", arguments);
++						ExecuteOpenBSDFFSFormatterResponse().Serialize (outputStream);
++						continue;
++					}
++#endif
++
+ 					// MountVolumeRequest
+ 					MountVolumeRequest *mountRequest = dynamic_cast <MountVolumeRequest*> (request.get());
+ 					if (mountRequest)
+@@ -372,6 +435,14 @@
+ 	{
+ 		ExecuteMacOSXAPFSFormatterRequest request (devicePath, userId, groupId);
+ 		SendRequest <ExecuteMacOSXAPFSFormatterResponse> (request);
++	}
++#endif
++
++#ifdef TC_OPENBSD
++	void CoreService::RequestExecuteOpenBSDFFSFormatter (const DevicePath &devicePath)
++	{
++		ExecuteOpenBSDFFSFormatterRequest request (devicePath);
++		SendRequest <ExecuteOpenBSDFFSFormatterResponse> (request);
+ 	}
+ #endif
+ 
+@@ -408,6 +479,7 @@
+ 			{
+ 				//	Test if the user has an active "sudo" session.
+ 				bool authCheckDone = false;
++#ifndef TC_OPENBSD
+ 				if (!Core->GetUseDummySudoPassword ())
+ 				{	
+ 					// We are using -n to avoid prompting the user for a password.
+@@ -452,6 +524,9 @@
+ 						request.FastElevation = false;
+ 					}
+ 				}
++#endif
++				// On OpenBSD, test the actual service with doas -n. A rule
++				// restricted to --core-service need not allow /usr/bin/true.
+ 			
+ 				try
+ 				{
+@@ -507,6 +582,36 @@
+ 
+ 	void CoreService::StartElevated (const CoreServiceRequest &request)
+ 	{
++#ifdef TC_OPENBSD
++		CloseDoasAuthTerminal();
++
++		int authTerminalFd = -1;
++		string authTerminalPath;
++		bool authTerminalKept = false;
++
++		finally_do_arg2 (int *, &authTerminalFd, bool *, &authTerminalKept,
++		{
++			if (!*finally_arg2 && *finally_arg != -1)
++			{
++				close (*finally_arg);
++				*finally_arg = -1;
++			}
++		});
++
++		if (!request.FastElevation)
++		{
++			authTerminalFd = posix_openpt (O_RDWR | O_NOCTTY);
++			throw_sys_sub_if (authTerminalFd == -1, "posix_openpt");
++			throw_sys_if (fcntl (authTerminalFd, F_SETFD, FD_CLOEXEC) == -1);
++			throw_sys_if (grantpt (authTerminalFd) == -1);
++			throw_sys_if (unlockpt (authTerminalFd) == -1);
++
++			char *slavePath = ptsname (authTerminalFd);
++			throw_sys_sub_if (slavePath == nullptr, "ptsname");
++			authTerminalPath = slavePath;
++		}
++#endif
++
+ 		unique_ptr <Pipe> inPipe (new Pipe());
+ 		unique_ptr <Pipe> outPipe (new Pipe());
+ 		Pipe errPipe;
+@@ -522,7 +627,11 @@
+ 				{
+ 					// Throw exception if sudo is not found in secure locations
+ 					std::string errorMsg;
++#ifdef TC_OPENBSD
++					string sudoPath = Process::FindSystemBinary("doas", errorMsg);
++#else
+ 					string sudoPath = Process::FindSystemBinary("sudo", errorMsg);
++#endif
+ 					if (sudoPath.empty())
+ 						throw SystemException(SRC_POS, errorMsg);
+ 
+@@ -551,7 +660,54 @@
+ 					throw_sys_if (dup2 (outPipe->GetWriteFD(), STDOUT_FILENO) == -1);
+ 					throw_sys_if (dup2 (errPipe.GetWriteFD(), STDERR_FILENO) == -1);
+ 
++#ifdef TC_OPENBSD
++					const char *args[8];
++
++					if (!authTerminalPath.empty())
++					{
++						throw_sys_if (setsid () == -1);
++
++						int authFd = open (authTerminalPath.c_str(), O_RDWR);
++						throw_sys_sub_if (authFd == -1, authTerminalPath);
++
++						// Keep the admin password out of the terminal echo.
++						struct termios tios;
++						throw_sys_if (tcgetattr (authFd, &tios) == -1);
++						{
++							tios.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL | ISIG | IEXTEN);
++							tios.c_iflag &= ~(BRKINT | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
++							tios.c_cc[VMIN] = 1;
++							tios.c_cc[VTIME] = 0;
++							throw_sys_if (tcsetattr (authFd, TCSANOW, &tios) == -1);
++						}
++
++						if (ioctl (authFd, TIOCSCTTY, 0) == -1 && errno != EINVAL)
++						{
++							close (authFd);
++							throw SystemException (SRC_POS, "TIOCSCTTY");
++						}
++
++						// doas closes descriptors above stderr before authentication.
++						// Keep the slave on stderr so /dev/tty remains available.
++						throw_sys_if (dup2 (authFd, STDERR_FILENO) == -1);
++						close (authFd);
++
++						args[0] = sudoPath.c_str();
++						args[1] = appPath.c_str();
++						args[2] = TC_CORE_SERVICE_CMDLINE_OPTION;
++						args[3] = nullptr;
++					}
++					else
++					{
++						args[0] = sudoPath.c_str();
++						args[1] = "-n";
++						args[2] = appPath.c_str();
++						args[3] = TC_CORE_SERVICE_CMDLINE_OPTION;
++						args[4] = nullptr;
++					}
++#else
+ 					const char *args[] = { sudoPath.c_str(), "-S", "-p", "", appPath.c_str(), TC_CORE_SERVICE_CMDLINE_OPTION, nullptr };
++#endif
+ 					execvp (args[0], ((char* const*) args));
+ 					throw SystemException (SRC_POS, args[0]);
+ 				}
+@@ -601,9 +757,13 @@
+ #if defined(TC_LINUX )
+ 		Thread::Sleep (1000); // wait 1 second for the forked sudo to start
+ #endif
++#ifndef TC_OPENBSD
+ 		if (write (inPipe->GetWriteFD(), &adminPassword.front(), adminPassword.size())) { } // Errors ignored
+-
+-		burn (&adminPassword.front(), adminPassword.size());
++#endif
++		finally_do_arg (vector <char> *, &adminPassword,
++		{
++			burn (&finally_arg->front(), finally_arg->size());
++		});
+ 
+ 		throw_sys_if (fcntl (outPipe->GetReadFD(), F_SETFL, O_NONBLOCK) == -1);
+ 		throw_sys_if (fcntl (errPipe.GetReadFD(), F_SETFL, O_NONBLOCK) == -1);
+@@ -611,11 +771,77 @@
+ 		char buffer[4096];
+ 		vector <char> errOutput;
+ 		errOutput.reserve (4096);
++#ifdef TC_OPENBSD
++		vector <char> authOutput;
++#endif
+ 
+ 		Poller poller (outPipe->GetReadFD(), errPipe.GetReadFD());
+ 		int status, waitRes;
+ 		int exitCode = 1;
+ 
++#ifdef TC_OPENBSD
++		if (authTerminalFd != -1)
++		{
++			throw_sys_if (fcntl (authTerminalFd, F_SETFL, O_NONBLOCK) == -1);
++			Poller authPoller (outPipe->GetReadFD(), errPipe.GetReadFD(), authTerminalFd);
++			bool passwordSent = false;
++
++			while ((waitRes = waitpid (forkedPid, &status, WNOHANG)) == 0)
++			{
++				list <int> ready;
++				try
++				{
++					ready = authPoller.WaitForData (timeout);
++				}
++				catch (TimeOut&)
++				{
++					kill (forkedPid, SIGTERM);
++					close (authTerminalFd);
++					authTerminalFd = -1;
++					waitpid (forkedPid, &status, 0);
++					throw ElevationFailed (SRC_POS, "doas", 1, "Authentication timed out");
++				}
++
++				foreach (int fd, ready)
++				{
++					ssize_t bytesRead = read (fd, buffer, sizeof (buffer));
++					if (bytesRead <= 0)
++						continue;
++
++					if (fd == errPipe.GetReadFD())
++						errOutput.insert (errOutput.end(), buffer, buffer + bytesRead);
++
++					if (fd == authTerminalFd)
++					{
++						authOutput.insert (authOutput.end(), buffer, buffer + bytesRead);
++						if (!passwordSent)
++						{
++							// readpassphrase has opened the terminal and printed its prompt.
++							size_t sent = 0;
++							while (sent < adminPassword.size())
++							{
++								ssize_t n = write (authTerminalFd, &adminPassword[sent], adminPassword.size() - sent);
++								if (n < 0 && errno == EINTR)
++									continue;
++								throw_sys_if (n <= 0);
++								sent += n;
++							}
++							burn (&adminPassword.front(), adminPassword.size());
++							passwordSent = true;
++						}
++						else if (string (authOutput.begin(), authOutput.end()).find ("Authentication failed") != string::npos)
++						{
++							// Let the frontend request a new password, rather than leaving
++							// doas waiting for another response on its private terminal.
++							kill (forkedPid, SIGTERM);
++						}
++					}
++				}
++			}
++		}
++		else
++#endif
++		{
+ 		try
+ 		{
+ 			do
+@@ -667,11 +893,17 @@
+ 					Thread thread;
+ 					thread.Start (new WaitFunctor (forkedPid));
+ 
++#ifdef TC_OPENBSD
++					throw ElevationFailed (SRC_POS, "doas", 1, "");
++#else
+ 					throw ElevationFailed (SRC_POS, "sudo", 1, "");
++#endif
+ 				}
+ 
+ 				waitRes = waitpid (forkedPid, &status, 0);
+ 			}
++		}
++
+ 		}
+ 
+ 		if (!errOutput.empty())
+@@ -700,11 +932,19 @@
+ 			if (!errOutput.empty())
+ 				strErrOutput.insert (strErrOutput.begin(), errOutput.begin(), errOutput.end());
+ 
++#ifdef TC_OPENBSD
++			strErrOutput.insert (strErrOutput.end(), authOutput.begin(), authOutput.end());
++			if (strErrOutput.find (" tty") != string::npos)
++				strErrOutput += "\nTo allow VeraCrypt to elevate privileges, add an appropriate rule for it to '/etc/doas.conf'.";
++
++			throw ElevationFailed (SRC_POS, "doas", exitCode, strErrOutput);
++#else
+ 			// sudo may require a tty even if -S is used
+ 			if (strErrOutput.find (" tty") != string::npos)
+ 				strErrOutput += "\nTo enable use of 'sudo' by applications without a terminal window, please disable 'requiretty' option in '/etc/sudoers'. Newer versions of sudo automatically determine whether a terminal is required ('requiretty' option is obsolete).";
+ 
+ 			throw ElevationFailed (SRC_POS, "sudo", exitCode, strErrOutput);
++#endif
+ 		}
+ 
+ 		throw_sys_if (fcntl (outPipe->GetReadFD(), F_SETFL, 0) == -1);
+@@ -718,6 +958,17 @@
+ 
+ 		AdminInputPipe = move_ptr(inPipe);
+ 		AdminOutputPipe = move_ptr(outPipe);
++
++#ifdef TC_OPENBSD
++		if (authTerminalFd != -1)
++		{
++			// Keep the authentication terminal open for the lifetime of the
++			// elevated service. Closing the master would hang up the service.
++			authTerminalKept = true;
++			DoasAuthTerminalFd = authTerminalFd;
++			authTerminalFd = -1;
++		}
++#endif
+ 	}
+ 
+ 	void CoreService::Stop ()
Index: security/veracrypt/patches/patch-Core_Unix_CoreService_h
===================================================================
--- /dev/null
+++ security/veracrypt/patches/patch-Core_Unix_CoreService_h
@@ -0,0 +1,14 @@
+Run OpenBSD FFS formatting through the elevated core service.
+
+--- Core/Unix/CoreService.h.orig
++++ Core/Unix/CoreService.h
+@@ -39,6 +39,9 @@
+ 		static const char *GetMacOSXAPFSFormatterPath ();
+ 		static void RequestExecuteMacOSXAPFSFormatter (const DevicePath &devicePath, uint64 userId, uint64 groupId);
+ #endif
++#ifdef TC_OPENBSD
++		static void RequestExecuteOpenBSDFFSFormatter (const DevicePath &devicePath);
++#endif
+ 		static shared_ptr <VolumeInfo> RequestMountVolume (MountOptions &options);
+ 		static void RequestSetFileOwner (const FilesystemPath &path, const UserId &owner);
+ 		static void SetAdminPasswordCallback (shared_ptr <GetStringFunctor> functor) { AdminPasswordCallback = functor; }
Index: security/veracrypt/patches/patch-Core_VolumeCreator_h
===================================================================
--- /dev/null
+++ security/veracrypt/patches/patch-Core_VolumeCreator_h
@@ -0,0 +1,34 @@
+Represent FFS as the OpenBSD native filesystem and select /sbin/newfs
+for its formatter.
+
+Index: Core/VolumeCreator.h
+--- Core/VolumeCreator.h.orig
++++ Core/VolumeCreator.h
+@@ -55,7 +55,8 @@
+ 				Btrfs,
+ 				MacOsExt,
+ 				APFS,
+-				UFS
++				UFS,
++				FFS
+ 			};
+ 
+ 			static Enum GetPlatformNative ()
+@@ -68,6 +69,8 @@
+ 				return VolumeCreationOptions::FilesystemType::MacOsExt;
+ #elif defined (TC_FREEBSD) || defined (TC_SOLARIS)
+ 				return VolumeCreationOptions::FilesystemType::UFS;
++#elif defined (TC_OPENBSD)
++				return VolumeCreationOptions::FilesystemType::FFS;
+ #else
+ 				return VolumeCreationOptions::FilesystemType::FAT;
+ #endif
+@@ -90,6 +93,8 @@
+ 				case VolumeCreationOptions::FilesystemType::APFS:		return "newfs_apfs";
+ 	#elif defined (TC_FREEBSD) || defined (TC_SOLARIS)
+ 				case VolumeCreationOptions::FilesystemType::UFS:		return "newfs" ;
++	#elif defined (TC_OPENBSD)
++				case VolumeCreationOptions::FilesystemType::FFS:		return "/sbin/newfs" ;
+ 	#endif
+ 				default: return NULL;
+ 				}
Index: security/veracrypt/patches/patch-Main_CommandLineInterface_cpp
===================================================================
--- /dev/null
+++ security/veracrypt/patches/patch-Main_CommandLineInterface_cpp
@@ -0,0 +1,15 @@
+Accept FFS as an explicit filesystem selection on the OpenBSD CLI.
+
+Index: Main/CommandLineInterface.cpp
+--- Main/CommandLineInterface.cpp.orig
++++ Main/CommandLineInterface.cpp
+@@ -415,6 +415,9 @@
+ 					ArgFilesystem = VolumeCreationOptions::FilesystemType::NTFS;
+ 				else if (str.IsSameAs (L"exFAT", false))
+ 					ArgFilesystem = VolumeCreationOptions::FilesystemType::exFAT;
++#elif defined (TC_OPENBSD)
++				else if (str.IsSameAs (L"FFS", false))
++					ArgFilesystem = VolumeCreationOptions::FilesystemType::FFS;
+ #endif
+ 				else
+ 					throw_err (LangString["UNKNOWN_OPTION"] + L": " + str);
Index: security/veracrypt/patches/patch-Main_Forms_VolumeCreationWizard_cpp
===================================================================
--- /dev/null
+++ security/veracrypt/patches/patch-Main_Forms_VolumeCreationWizard_cpp
@@ -0,0 +1,32 @@
+Run OpenBSD FFS formatting through the elevated core service.
+
+--- Main/Forms/VolumeCreationWizard.cpp.orig
++++ Main/Forms/VolumeCreationWizard.cpp
+@@ -17,6 +17,9 @@
+ #include <unistd.h>
+ #include <sys/statvfs.h> // header for statvfs
+ #include "Platform/Unix/Process.h"
++#endif
++#ifdef TC_OPENBSD
++#include "Core/Unix/CoreService.h"
+ #endif
+ #include "Core/RandomNumberGenerator.h"
+ #include "Core/VolumeCreator.h"
+@@ -869,7 +872,7 @@
+ 					bool useElevatedAPFSFormatter = UseElevatedMacOSXAPFSFormatter (fsFormatter);
+ 					if (!useElevatedAPFSFormatter)
+ 						PrepareMacOSXFormatterDevice (virtualDevice, changedDeviceOwners);
+-#else
++#elif !defined(TC_OPENBSD)
+ 					UserId origDeviceOwner ((uid_t) -1);
+ 
+ 					try
+@@ -926,6 +929,8 @@
+ 					SetCreationProgressText (StringFormatter (LangString["FORMAT_STAGE_CREATING_FILESYSTEM"], fsFormatter));
+ #ifdef TC_MACOSX
+ 					ExecuteMacOSXFilesystemFormatter (fsFormatter, args);
++#elif defined(TC_OPENBSD)
++					CoreService::RequestExecuteOpenBSDFFSFormatter (virtualDevice);
+ #else
+ 					Process::Execute (fsFormatter, args);
+ #endif
Index: security/veracrypt/patches/patch-Main_Forms_VolumeFormatOptionsWizardPage_cpp
===================================================================
--- /dev/null
+++ security/veracrypt/patches/patch-Main_Forms_VolumeFormatOptionsWizardPage_cpp
@@ -0,0 +1,23 @@
+Offer FFS in the OpenBSD GUI filesystem selector and restore that
+selection when displaying existing creation options.
+
+Index: Main/Forms/VolumeFormatOptionsWizardPage.cpp
+--- Main/Forms/VolumeFormatOptionsWizardPage.cpp.orig
++++ Main/Forms/VolumeFormatOptionsWizardPage.cpp
+@@ -52,6 +52,8 @@
+ 			FilesystemTypeChoice->Append (L"APFS",			(void *) VolumeCreationOptions::FilesystemType::APFS);
+ #elif defined (TC_FREEBSD) || defined (TC_SOLARIS)
+ 		FilesystemTypeChoice->Append (L"UFS",				(void *) VolumeCreationOptions::FilesystemType::UFS);
++#elif defined (TC_OPENBSD)
++		FilesystemTypeChoice->Append (L"FFS",				(void *) VolumeCreationOptions::FilesystemType::FFS);
+ #endif
+ 
+ 		if (!disable32bitFilesystems && filesystemSize <= TC_MAX_FAT_SECTOR_COUNT * sectorSize)
+@@ -94,6 +96,7 @@
+ 		case VolumeCreationOptions::FilesystemType::MacOsExt:	FilesystemTypeChoice->SetStringSelection (L"Mac OS Extended"); break;
+ 		case VolumeCreationOptions::FilesystemType::APFS:		FilesystemTypeChoice->SetStringSelection (L"APFS"); break;
+ 		case VolumeCreationOptions::FilesystemType::UFS:		FilesystemTypeChoice->SetStringSelection (L"UFS"); break;
++		case VolumeCreationOptions::FilesystemType::FFS:		FilesystemTypeChoice->SetStringSelection (L"FFS"); break;
+ 
+ 		default:
+ 			throw ParameterIncorrect (SRC_POS);
Index: security/veracrypt/patches/patch-Main_TextUserInterface_cpp
===================================================================
--- /dev/null
+++ security/veracrypt/patches/patch-Main_TextUserInterface_cpp
@@ -0,0 +1,55 @@
+Run OpenBSD FFS formatting through the elevated core service.
+
+--- Main/TextUserInterface.cpp.orig
++++ Main/TextUserInterface.cpp
+@@ -24,6 +24,9 @@
+ #include "Common/Token.h"
+ #include "Common/SecurityToken.h"
+ #include "Common/EMVToken.h"
++#ifdef TC_OPENBSD
++#include "Core/Unix/CoreService.h"
++#endif
+ #include "Core/RandomNumberGenerator.h"
+ #include "Application.h"
+ #ifdef TC_MACOSX
+@@ -930,7 +933,13 @@
+ 		{
+ 			if (Preferences.NonInteractive)
+ 			{
++#ifdef TC_OPENBSD
++				// Preserve the historical OpenBSD batch default. Native FFS
++				// formatting requires elevation, so scripts should opt in.
++				options->Filesystem = VolumeCreationOptions::FilesystemType::FAT;
++#else
+ 				options->Filesystem = VolumeCreationOptions::FilesystemType::GetPlatformNative();
++#endif
+ 			}
+ 			else
+ 			{
+@@ -971,6 +980,8 @@
+ 				}
+ #elif defined (TC_FREEBSD) || defined (TC_SOLARIS)
+ 				ShowInfo (wxString::Format (L" %li) %s", filesystems.size() + 1, "UFS")); filesystems.push_back (VolumeCreationOptions::FilesystemType::UFS);
++#elif defined (TC_OPENBSD)
++				ShowInfo (wxString::Format (L" %li) %s", filesystems.size() + 1, "FFS")); filesystems.push_back (VolumeCreationOptions::FilesystemType::FFS);
+ #endif
+ 
+ 				ssize_t defaultFilesystem = fatAvailable ? 2 : 1;
+@@ -1132,7 +1143,7 @@
+ 			bool useElevatedAPFSFormatter = UseElevatedMacOSXAPFSFormatter (fsFormatter);
+ 			if (!useElevatedAPFSFormatter)
+ 				PrepareMacOSXFormatterDevice (virtualDevice, changedDeviceOwners);
+-#else
++#elif !defined(TC_OPENBSD)
+ 			UserId origDeviceOwner ((uid_t) -1);
+ 
+ 			try
+@@ -1188,6 +1199,8 @@
+ 
+ #ifdef TC_MACOSX
+ 			ExecuteMacOSXFilesystemFormatter (fsFormatter, args);
++#elif defined(TC_OPENBSD)
++			CoreService::RequestExecuteOpenBSDFFSFormatter (virtualDevice);
+ #else
+ 			Process::Execute (fsFormatter, args);
+ #endif
Index: security/veracrypt/patches/patch-Main_UserInterface_cpp
===================================================================
--- /dev/null
+++ security/veracrypt/patches/patch-Main_UserInterface_cpp
@@ -0,0 +1,18 @@
+Name doas in OpenBSD elevation failures to match the core service
+launcher, retaining sudo diagnostics on other platforms.
+
+Index: Main/UserInterface.cpp
+--- Main/UserInterface.cpp.orig
++++ Main/UserInterface.cpp
+@@ -40,7 +40,11 @@
+ 		public:
+ 		virtual void operator() (string &str)
+ 		{
++#ifdef TC_OPENBSD
++			throw ElevationFailed (SRC_POS, "doas", 1, "");
++#else
+ 			throw ElevationFailed (SRC_POS, "sudo", 1, "");
++#endif
+ 		}
+ 	};
+ 
Index: security/veracrypt/pkg/README
===================================================================
--- /dev/null
+++ security/veracrypt/pkg/README
@@ -0,0 +1,35 @@
++-------------------------------------------------------------------------------
+| Running ${PKGSTEM} on OpenBSD
++-------------------------------------------------------------------------------
+
+Privilege elevation
+===================
+
+VeraCrypt runs its privileged core service through doas(1).  Add a rule to
+/etc/doas.conf before mounting, creating or formatting volumes:
+
+    permit :wheel cmd ${TRUEPREFIX}/bin/veracrypt args --core-service
+
+This rule permits only the privileged core service used internally by
+VeraCrypt. Run the normal CLI or GUI as your own user. Do not use
+"permit nopass" unless you accept passwordless elevation for every user
+allowed by the rule.
+
+The core service is used for operations that require root privileges, such as
+configuring vnd(4) loop devices, mounting and unmounting filesystems,
+changing ownership of mount points and device nodes, and running newfs(8)
+when an OpenBSD FFS filesystem is created inside a volume.
+
+Filesystem creation
+===================
+
+OpenBSD FFS filesystems can be created inside a new volume by selecting the
+"FFS" filesystem in the volume creation wizard or by passing
+"--filesystem=FFS" on the command line.  The filesystem is created with
+newfs(8) on the raw vnd(4) character device through the elevated core
+service. Changing device ownership alone is insufficient: reading the disk
+label requires privileged ioctls on OpenBSD.
+
+Noninteractive creation retains FAT as its default. Request FFS explicitly
+with --filesystem=FFS. Without a passwordless doas rule, use interactive mode
+so VeraCrypt can request your account password.
Index: security/veracrypt/patches/patch-Core_Unix_OpenBSD_CoreOpenBSD_cpp
===================================================================
--- security/veracrypt/patches/patch-Core_Unix_OpenBSD_CoreOpenBSD_cpp
+++ /dev/null
@@ -1,14 +0,0 @@
-The -c option is no more. https://github.com/veracrypt/VeraCrypt/pull/1002
-
-Index: Core/Unix/OpenBSD/CoreOpenBSD.cpp
---- Core/Unix/OpenBSD/CoreOpenBSD.cpp.orig
-+++ Core/Unix/OpenBSD/CoreOpenBSD.cpp
-@@ -69,8 +69,6 @@ namespace VeraCrypt
- 		if (freeVnd == -1)
- 			throw "couldn't find free vnd";
- 
--		args.push_back ("-c");
--
- 		stringstream freePath;
- 		freePath << "vnd" << freeVnd;
- 		args.push_back (freePath.str());