diff --git a/.gitignore b/.gitignore
index 44abb66..bb4ee15 100644
--- a/.gitignore
+++ b/.gitignore
@@ -88,3 +88,7 @@ Release/
x64/
x86/
out/
+
+# iOS build trees and Qt installer logs
+/build-ios*/
+aqtinstall.log
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c1aed6c..cc57c22 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -67,7 +67,26 @@ if(ANDROID)
endif()
# Core Qt components (GuiPrivate handled separately for cross-platform compatibility)
-find_package(Qt6 REQUIRED COMPONENTS Core Widgets Network Multimedia ShaderTools Gui SerialPort Svg)
+# QtSerialPort is used only by the desktop serial keyer path; the HaliKey/KPOD
+# serial code is stubbed on both iOS and Android, so require SerialPort on
+# desktop only (the mobile Qt kits may not ship it).
+set(QK4_QT_COMPONENTS Core Widgets Network Multimedia ShaderTools Gui Svg)
+if(NOT IOS AND NOT ANDROID)
+ list(APPEND QK4_QT_COMPONENTS SerialPort)
+endif()
+find_package(Qt6 REQUIRED COMPONENTS ${QK4_QT_COMPONENTS})
+
+# TLS-PSK backend for the K4 link. Qt's iOS kit ships only the Secure
+# Transport TLS plugin, which has no PSK support, so iOS drives a statically
+# linked OpenSSL directly (see src/network/psktlssocket_openssl.cpp).
+if(IOS)
+ set(_qk4_psk_openssl_default ON)
+else()
+ set(_qk4_psk_openssl_default OFF)
+endif()
+option(QK4_PSK_TLS_OPENSSL "Use OpenSSL directly for TLS-PSK instead of QSslSocket" ${_qk4_psk_openssl_default})
+unset(_qk4_psk_openssl_default)
+set(QK4_OPENSSL_ROOT "" CACHE PATH "OpenSSL install prefix (include/, lib/) used when QK4_PSK_TLS_OPENSSL is ON")
# GuiPrivate is needed for QRhi access but may not have CMake config on all platforms
if(APPLE)
@@ -130,6 +149,26 @@ if(ANDROID)
"Android build requires Opus. Provide -DQK4_OPUS_INCLUDE_DIR and -DQK4_OPUS_LIBRARY, "
"or install an Opus package that exports Opus::opus.")
endif()
+elseif(IOS)
+ # iOS: HID/serial/MIDI hardware is stubbed. Opus and OpenSSL are static
+ # fat libraries (x86_64 simulator + arm64 device) under third_party/ios;
+ # see third_party/ios/README.md for how they are built.
+ set(HIDAPI_INCLUDE_DIRS "")
+ set(HIDAPI_LIBRARIES "")
+ if(NOT QK4_OPUS_INCLUDE_DIR OR NOT QK4_OPUS_LIBRARY)
+ set(QK4_OPUS_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/ios/opus/include")
+ set(QK4_OPUS_LIBRARY "${CMAKE_CURRENT_SOURCE_DIR}/third_party/ios/opus/lib/libopus.a")
+ endif()
+ if(NOT EXISTS "${QK4_OPUS_INCLUDE_DIR}/opus/opus.h" OR NOT EXISTS "${QK4_OPUS_LIBRARY}")
+ message(FATAL_ERROR
+ "iOS build requires a static Opus. Expected ${QK4_OPUS_INCLUDE_DIR}/opus/opus.h and "
+ "${QK4_OPUS_LIBRARY}; see third_party/ios/README.md.")
+ endif()
+ set(OPUS_INCLUDE_DIRS "${QK4_OPUS_INCLUDE_DIR}")
+ set(OPUS_LIBRARIES "${QK4_OPUS_LIBRARY}")
+ if(NOT QK4_OPENSSL_ROOT)
+ set(QK4_OPENSSL_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/third_party/ios/openssl")
+ endif()
elseif(APPLE)
# macOS with Homebrew
set(OPUS_PREFIX "/opt/homebrew/opt/opus")
@@ -157,6 +196,7 @@ set(SOURCES
src/main.cpp
src/mainwindow.cpp
src/network/tcpclient.cpp
+ src/network/psktlssocket.h
src/network/protocol.cpp
src/network/kpa1500client.cpp
src/network/catserver.cpp
@@ -228,18 +268,47 @@ set(SOURCES
src/ui/k4popupbase.cpp
src/ui/kpa1500panel.cpp
src/ui/kpa1500window.cpp
+ src/ui/adjustoverlay.cpp
src/ui/sidecontroloverlay.cpp
src/ui/monoverlay.cpp
src/ui/baloverlay.cpp
src/ui/wheelaccumulator.cpp
)
+if(QK4_PSK_TLS_OPENSSL)
+ list(APPEND SOURCES src/network/psktlssocket_openssl.cpp)
+else()
+ list(APPEND SOURCES src/network/psktlssocket_qssl.cpp)
+endif()
+
+if(IOS)
+ # iOS-only AVAudioSession backend (Objective-C++). Needed so the mic can be
+ # captured for TX; RX works without it. Built with ARC.
+ list(APPEND SOURCES
+ src/ios/iosaudiosession.mm src/ios/iosaudiosession.h
+ src/ios/iosorientation.mm src/ios/iosorientation.h
+ src/ios/iossecurecredentials.mm src/ios/iossecurecredentials.h)
+ set_source_files_properties(
+ src/ios/iosaudiosession.mm src/ios/iosorientation.mm src/ios/iossecurecredentials.mm
+ PROPERTIES COMPILE_FLAGS "-fobjc-arc")
+endif()
+
if(ANDROID)
- # Keep class availability on Android via no-op implementations.
+ # Android: KPOD/HaliKey serial+MIDI keying is stubbed (no-op implementations).
list(APPEND SOURCES
src/hardware/kpoddevice.cpp
src/hardware/halikeydevice.cpp
)
+elseif(IOS)
+ # iOS: MIDI keyer only (CoreMIDI via RtMidi). No serial/HID V14 worker; KPOD
+ # stays stubbed inside kpoddevice.cpp.
+ list(APPEND SOURCES
+ src/hardware/kpoddevice.cpp
+ src/hardware/halikeydevice.cpp
+ src/hardware/halikeyworkerbase.cpp
+ src/hardware/halikeymidiworker.cpp
+ third_party/rtmidi/RtMidi.cpp
+ )
else()
list(APPEND SOURCES
src/hardware/kpoddevice.cpp
@@ -322,6 +391,7 @@ set(HEADERS
src/ui/inwindowdialog.h
src/ui/kpa1500panel.h
src/ui/kpa1500window.h
+ src/ui/adjustoverlay.h
src/ui/sidecontroloverlay.h
src/ui/monoverlay.h
src/ui/baloverlay.h
@@ -333,6 +403,13 @@ if(ANDROID)
src/hardware/kpoddevice.h
src/hardware/halikeydevice.h
)
+elseif(IOS)
+ list(APPEND HEADERS
+ src/hardware/kpoddevice.h
+ src/hardware/halikeydevice.h
+ src/hardware/halikeyworkerbase.h
+ src/hardware/halikeymidiworker.h
+ )
else()
list(APPEND HEADERS
src/hardware/kpoddevice.h
@@ -346,6 +423,30 @@ endif()
# On Android, create Qt executable package target
if(ANDROID)
qt_add_executable(${PROJECT_NAME} MANUAL_FINALIZATION ${SOURCES} ${HEADERS})
+elseif(IOS)
+ # Qt for iOS is static and needs qt_add_executable for plugin import.
+ # Build with the Xcode generator (qt-cmake defaults to it) and pick the
+ # SDK at build time: cmake --build . -- -sdk iphonesimulator
+ set(MACOSX_BUNDLE_BUNDLE_NAME ${PROJECT_NAME})
+ set(MACOSX_BUNDLE_BUNDLE_VERSION ${QK4_VERSION_FULL})
+ set(MACOSX_BUNDLE_SHORT_VERSION_STRING ${QK4_VERSION_FULL})
+ set(MACOSX_BUNDLE_GUI_IDENTIFIER "com.w9wdx.qk4phone")
+ # App icon: compile the iOS asset catalog (AppIcon) into the bundle.
+ set(QK4_IOS_ASSETS "${CMAKE_SOURCE_DIR}/resources/ios/Assets.xcassets")
+ set_source_files_properties(${QK4_IOS_ASSETS} PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
+ qt_add_executable(${PROJECT_NAME} MANUAL_FINALIZATION MACOSX_BUNDLE ${SOURCES} ${HEADERS} ${QK4_IOS_ASSETS})
+ set_target_properties(${PROJECT_NAME} PROPERTIES
+ MACOSX_BUNDLE_INFO_PLIST "${CMAKE_SOURCE_DIR}/resources/Info.plist.ios.in"
+ XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "com.w9wdx.qk4phone"
+ XCODE_ATTRIBUTE_TARGETED_DEVICE_FAMILY "1,2"
+ XCODE_ATTRIBUTE_ASSETCATALOG_COMPILER_APPICON_NAME "AppIcon"
+ )
+ # AVAudioSession (src/ios/iosaudiosession.mm) lives in AVFoundation.
+ target_link_libraries(${PROJECT_NAME} PRIVATE "-framework AVFoundation" "-framework Foundation" "-framework Security" "-framework UIKit")
+ # Static Qt auto-imports every Multimedia plugin. QK4 only uses
+ # QAudioSink/QAudioSource/QMediaDevices, which live in QtMultimedia itself,
+ # so drop the FFmpeg plugin and its five xcframeworks.
+ qt_import_plugins(${PROJECT_NAME} EXCLUDE Qt6::QFFmpegMediaPlugin)
# On macOS, create an app bundle
elseif(APPLE)
set(MACOSX_BUNDLE_BUNDLE_NAME ${PROJECT_NAME})
@@ -416,10 +517,30 @@ target_link_libraries(${PROJECT_NAME} PRIVATE
Qt6::Multimedia
Qt6::Gui
Qt6::Svg
- Qt6::SerialPort
${OPUS_LIBRARIES}
${HIDAPI_LIBRARIES}
)
+if(NOT IOS AND NOT ANDROID)
+ target_link_libraries(${PROJECT_NAME} PRIVATE Qt6::SerialPort)
+endif()
+
+if(QK4_PSK_TLS_OPENSSL)
+ if(NOT QK4_OPENSSL_ROOT)
+ message(FATAL_ERROR "QK4_PSK_TLS_OPENSSL requires QK4_OPENSSL_ROOT (prefix with include/ and lib/).")
+ endif()
+ foreach(_qk4_ssl_file "include/openssl/ssl.h" "lib/libssl.a" "lib/libcrypto.a")
+ if(NOT EXISTS "${QK4_OPENSSL_ROOT}/${_qk4_ssl_file}")
+ message(FATAL_ERROR "Missing ${QK4_OPENSSL_ROOT}/${_qk4_ssl_file}; see third_party/ios/README.md.")
+ endif()
+ endforeach()
+ unset(_qk4_ssl_file)
+ target_compile_definitions(${PROJECT_NAME} PRIVATE QK4_PSK_TLS_OPENSSL)
+ target_include_directories(${PROJECT_NAME} PRIVATE "${QK4_OPENSSL_ROOT}/include")
+ target_link_libraries(${PROJECT_NAME} PRIVATE
+ "${QK4_OPENSSL_ROOT}/lib/libssl.a"
+ "${QK4_OPENSSL_ROOT}/lib/libcrypto.a"
+ )
+endif()
# Link GuiPrivate if found via CMake, otherwise private headers are included manually
if(QT_GUI_PRIVATE_FOUND)
@@ -427,7 +548,7 @@ if(QT_GUI_PRIVATE_FOUND)
endif()
# macOS frameworks for KPOD hotplug detection (IOKit)
-if(APPLE)
+if(APPLE AND NOT IOS)
target_link_libraries(${PROJECT_NAME} PRIVATE
"-framework IOKit"
"-framework CoreFoundation"
@@ -435,7 +556,17 @@ if(APPLE)
endif()
# RtMidi platform-specific MIDI backend
-if(APPLE)
+if(ANDROID)
+ # No RtMidi backend on Android (HaliKey/KPOD serial+MIDI stubbed).
+elseif(IOS)
+ # iOS uses the CoreMIDI backend (RtMidi guards the bits unavailable on iOS).
+ target_compile_definitions(${PROJECT_NAME} PRIVATE __MACOSX_CORE__)
+ target_link_libraries(${PROJECT_NAME} PRIVATE
+ "-framework CoreMIDI"
+ "-framework CoreAudio"
+ "-framework CoreFoundation"
+ )
+elseif(APPLE)
target_compile_definitions(${PROJECT_NAME} PRIVATE __MACOSX_CORE__)
target_link_libraries(${PROJECT_NAME} PRIVATE
"-framework CoreMIDI"
@@ -444,8 +575,6 @@ if(APPLE)
elseif(WIN32)
target_compile_definitions(${PROJECT_NAME} PRIVATE __WINDOWS_MM__)
target_link_libraries(${PROJECT_NAME} PRIVATE winmm)
-elseif(ANDROID)
- # No RtMidi backend on Android (HaliKey/KPOD features disabled).
else()
target_compile_definitions(${PROJECT_NAME} PRIVATE __LINUX_ALSA__)
target_link_libraries(${PROJECT_NAME} PRIVATE asound)
@@ -528,7 +657,7 @@ endif()
# Deployment / Bundling - Create self-contained distributable app
# =============================================================================
-if(APPLE)
+if(APPLE AND NOT IOS)
# Find macdeployqt
find_program(MACDEPLOYQT_EXECUTABLE macdeployqt HINTS "${Qt6_DIR}/../../../bin")
@@ -618,11 +747,11 @@ elseif(WIN32)
)
endif()
-if(ANDROID)
+if(ANDROID OR IOS)
qt_finalize_executable(${PROJECT_NAME})
endif()
-if(BUILD_TESTING AND NOT ANDROID)
+if(BUILD_TESTING AND NOT ANDROID AND NOT IOS)
find_package(Qt6 REQUIRED COMPONENTS Test)
qt_add_executable(test_frequencyentryparser
tests/test_frequencyentryparser.cpp
diff --git a/docs/BUILD_IOS.md b/docs/BUILD_IOS.md
new file mode 100644
index 0000000..ca1fc6d
--- /dev/null
+++ b/docs/BUILD_IOS.md
@@ -0,0 +1,40 @@
+# Build QK4 Mobile for iOS
+
+The iOS target must be configured and built on macOS with Xcode and a Qt iOS kit. The Windows and Android scripts do not produce an iOS application.
+
+## Requirements
+
+- Xcode with the iOS 16 or newer SDK
+- Qt 6.11.1 for iOS, matching the Qt version used by the project
+- CMake through Qt's `qt-cmake` wrapper
+- The checked-in iOS OpenSSL and Opus headers and static libraries under `third_party/ios`
+
+The K4 remote connection uses TLS 1.2 PSK. Qt's iOS TLS backend does not support PSK, so this target links OpenSSL and uses `PskTlsSocket` directly. QRZ API keys are stored in the iOS Keychain with the `AfterFirstUnlockThisDeviceOnly` accessibility class.
+
+## Configure and build
+
+From the repository root on the Mac:
+
+```bash
+/path/to/Qt/6.11.1/ios/bin/qt-cmake -S . -B build-ios -G Xcode
+cmake --build build-ios --config RelWithDebInfo -- -sdk iphoneos
+```
+
+For an Intel Simulator build:
+
+```bash
+cmake --build build-ios --config RelWithDebInfo -- \
+ -sdk iphonesimulator -arch x86_64 CODE_SIGNING_ALLOWED=NO ONLY_ACTIVE_ARCH=YES
+```
+
+The bundled archives contain device `arm64` and Intel Simulator `x86_64` slices. An Apple Silicon Simulator needs separately built simulator-arm64 dependencies packaged as XCFrameworks.
+
+Set the Apple development team and signing identity in the generated Xcode project before installing on a physical device. The bundle identifier is `com.w9wdx.qk4phone`.
+
+## Screen behavior
+
+The radio console opens in landscape. FT8 and FT4 request portrait. SSTV and a logbook opened from the radio or SSTV allow portrait and landscape, then return to the landscape radio console when closed.
+
+## Validation boundary
+
+Windows tests and an Android build verify shared C++ and the Qt TLS adapter. The iOS target, Keychain, orientation requests, direct OpenSSL PSK handshake, audio routes, and physical-device UI require validation on a Mac and iPhone/iPad before release.
diff --git a/resources/Info.plist.ios.in b/resources/Info.plist.ios.in
new file mode 100644
index 0000000..e8be724
--- /dev/null
+++ b/resources/Info.plist.ios.in
@@ -0,0 +1,58 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleExecutable
+ ${MACOSX_BUNDLE_EXECUTABLE_NAME}
+ CFBundleIdentifier
+ ${MACOSX_BUNDLE_GUI_IDENTIFIER}
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ ${MACOSX_BUNDLE_BUNDLE_NAME}
+ CFBundleDisplayName
+ QK4 Mobile
+ CFBundleIconName
+ AppIcon
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ ${MACOSX_BUNDLE_SHORT_VERSION_STRING}
+ CFBundleVersion
+ ${MACOSX_BUNDLE_BUNDLE_VERSION}
+ LSRequiresIPhoneOS
+
+ UILaunchStoryboardName
+ LaunchScreen
+ UIRequiresFullScreen
+
+ UIStatusBarHidden
+
+ UIViewControllerBasedStatusBarAppearance
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
+
+ UISupportedInterfaceOrientations~ipad
+
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
+
+ UIBackgroundModes
+
+ audio
+
+ NSMicrophoneUsageDescription
+ QK4 needs microphone access for transmit audio.
+ NSLocalNetworkUsageDescription
+ QK4 needs local network access to connect to your Elecraft K4 radio.
+
+
diff --git a/resources/ios/Assets.xcassets/AppIcon.appiconset/Contents.json b/resources/ios/Assets.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 0000000..f27760d
--- /dev/null
+++ b/resources/ios/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,14 @@
+{
+ "images" : [
+ {
+ "filename" : "icon_1024.png",
+ "idiom" : "universal",
+ "platform" : "ios",
+ "size" : "1024x1024"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/resources/ios/Assets.xcassets/AppIcon.appiconset/icon_1024.png b/resources/ios/Assets.xcassets/AppIcon.appiconset/icon_1024.png
new file mode 100644
index 0000000..2511e73
Binary files /dev/null and b/resources/ios/Assets.xcassets/AppIcon.appiconset/icon_1024.png differ
diff --git a/resources/ios/Assets.xcassets/Contents.json b/resources/ios/Assets.xcassets/Contents.json
new file mode 100644
index 0000000..73c0059
--- /dev/null
+++ b/resources/ios/Assets.xcassets/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/src/android/sstvorientation.cpp b/src/android/sstvorientation.cpp
index 79c4965..1fd5162 100644
--- a/src/android/sstvorientation.cpp
+++ b/src/android/sstvorientation.cpp
@@ -3,17 +3,26 @@
#ifdef Q_OS_ANDROID
#include
#include
+#elif defined(Q_OS_IOS)
+#include "ios/iosorientation.h"
+#endif
void setSstvOrientationEnabled(bool enabled) {
+#ifdef Q_OS_ANDROID
const jint requested = enabled ? 10 /* SCREEN_ORIENTATION_FULL_SENSOR */
: 6 /* SCREEN_ORIENTATION_SENSOR_LANDSCAPE */;
const QJniObject activity = QNativeInterface::QAndroidApplication::context();
if (activity.isValid())
activity.callMethod("setRequestedOrientation", "(I)V", requested);
-}
+#elif defined(Q_OS_IOS)
+ if (enabled)
+ IosOrientation::allowPortraitAndLandscape();
+ else
+ IosOrientation::requestLandscape();
#else
-void setSstvOrientationEnabled(bool) {}
+ Q_UNUSED(enabled)
#endif
+}
void setFt8PortraitEnabled(bool enabled) {
#ifdef Q_OS_ANDROID
@@ -21,14 +30,25 @@ void setFt8PortraitEnabled(bool enabled) {
if (activity.isValid())
activity.callMethod("setRequestedOrientation", "(I)V",
jint(enabled ? 1 /* PORTRAIT */ : 6 /* SENSOR_LANDSCAPE */));
+#elif defined(Q_OS_IOS)
+ if (enabled)
+ IosOrientation::requestPortrait();
+ else
+ IosOrientation::requestLandscape();
#else
Q_UNUSED(enabled)
#endif
}
+
void setRadioLogbookOrientationEnabled(bool enabled) {
#ifdef Q_OS_ANDROID
QJniObject::callStaticMethod("com/w9wdx/qk4phone/Qk4Activity",
"setRadioLogbookRotation", "(Z)V", jboolean(enabled));
+#elif defined(Q_OS_IOS)
+ if (enabled)
+ IosOrientation::allowPortraitAndLandscape();
+ else
+ IosOrientation::requestLandscape();
#else
Q_UNUSED(enabled)
#endif
diff --git a/src/audio/audioengine.cpp b/src/audio/audioengine.cpp
index fba9340..fe513ee 100644
--- a/src/audio/audioengine.cpp
+++ b/src/audio/audioengine.cpp
@@ -14,6 +14,9 @@
#include
#include
#endif
+#ifdef Q_OS_IOS
+#include "ios/iosaudiosession.h"
+#endif
#ifdef Q_OS_ANDROID
namespace {
@@ -206,6 +209,12 @@ AudioEngine::~AudioEngine() {
}
bool AudioEngine::start() {
+#ifdef Q_OS_IOS
+ // Put the session in playAndRecord and activate it before any audio object
+ // is created, so RX plays and the mic can later be captured for TX.
+ IosAudioSession::configureForVoice();
+ IosAudioSession::activate();
+#endif
bool outputOk = setupAudioOutput();
if (outputOk) {
@@ -270,6 +279,10 @@ void AudioEngine::stop() {
m_micBuffer.clear();
m_micReadOffset = 0;
+
+#ifdef Q_OS_IOS
+ IosAudioSession::deactivate();
+#endif
}
bool AudioEngine::setupAudioOutput(bool resetPlayback) {
diff --git a/src/ft8/qrzlogbook.cpp b/src/ft8/qrzlogbook.cpp
index 6be84be..14aa678 100644
--- a/src/ft8/qrzlogbook.cpp
+++ b/src/ft8/qrzlogbook.cpp
@@ -15,6 +15,8 @@
#ifdef Q_OS_ANDROID
#include
#include
+#elif defined(Q_OS_IOS)
+#include "ios/iossecurecredentials.h"
#endif
namespace {
@@ -28,6 +30,8 @@ QString readKey(QString *error) {
"com/w9wdx/qk4phone/QrzCredentials", "read", "(Landroid/content/Context;)Ljava/lang/String;",
context.object()).toString();
if (result.startsWith("OK:")) return result.mid(3);
+#elif defined(Q_OS_IOS)
+ return IosSecureCredentials::readQrzApiKey(error);
#endif
fail(error, secureError);
return {};
@@ -38,16 +42,20 @@ bool writeKey(const QString &key, QString *error) {
const auto value = QJniObject::fromString(key);
if (QJniObject::callStaticMethod("com/w9wdx/qk4phone/QrzCredentials", "write",
"(Landroid/content/Context;Ljava/lang/String;)Z", context.object(), value.object())) return true;
+#elif defined(Q_OS_IOS)
+ return IosSecureCredentials::writeQrzApiKey(key, error);
#else
Q_UNUSED(key)
#endif
- return fail(error, "Cannot save the API key securely. Android Keystore is required.");
+ return fail(error, "Cannot save the API key securely on this platform.");
}
bool clearKey(QString *error) {
#ifdef Q_OS_ANDROID
const auto context = QNativeInterface::QAndroidApplication::context();
if (QJniObject::callStaticMethod("com/w9wdx/qk4phone/QrzCredentials", "clear",
"(Landroid/content/Context;)Z", context.object())) return true;
+#elif defined(Q_OS_IOS)
+ return IosSecureCredentials::clearQrzApiKey(error);
#endif
return fail(error, "Cannot remove the encrypted QRZ key.");
}
@@ -57,7 +65,7 @@ int findId(const Ft8Logbook &log, const QString &id) {
return -1;
}
}
-QrzKeyStore QrzKeyStore::android() { return {readKey, writeKey, clearKey}; }
+QrzKeyStore QrzKeyStore::platform() { return {readKey, writeKey, clearKey}; }
QrzLogbook::QrzLogbook(const QString &path, QObject *parent, QNetworkAccessManager *network, QrzKeyStore keys)
: QObject(parent), m_path(path), m_keys(std::move(keys)),
m_network(network ? network : new QNetworkAccessManager(this)) {
diff --git a/src/ft8/qrzlogbook.h b/src/ft8/qrzlogbook.h
index d23684f..766c003 100644
--- a/src/ft8/qrzlogbook.h
+++ b/src/ft8/qrzlogbook.h
@@ -10,13 +10,13 @@ struct QrzKeyStore {
std::function read;
std::function write;
std::function clear;
- static QrzKeyStore android();
+ static QrzKeyStore platform();
};
class QrzLogbook : public QObject {
Q_OBJECT
public:
explicit QrzLogbook(const QString &path, QObject *parent = nullptr,
- QNetworkAccessManager *network = nullptr, QrzKeyStore keys = QrzKeyStore::android());
+ QNetworkAccessManager *network = nullptr, QrzKeyStore keys = QrzKeyStore::platform());
static QrzLogbook *instance();
static void start(const QString &path, QObject *parent);
QString callsign() const { return m_call; }
diff --git a/src/hardware/halikeydevice.cpp b/src/hardware/halikeydevice.cpp
index 5079d2f..fad39a2 100644
--- a/src/hardware/halikeydevice.cpp
+++ b/src/hardware/halikeydevice.cpp
@@ -224,7 +224,9 @@ bool HalikeyDevice::dahPressed() const {
#else
#include "halikeymidiworker.h"
-#include "halikeyv14worker.h"
+#ifndef Q_OS_IOS
+#include "halikeyv14worker.h" // serial/HID V14 keyer — desktop only (no serial on iOS)
+#endif
#include "halikeyworkerbase.h"
#include "../settings/radiosettings.h"
#include
@@ -315,13 +317,19 @@ bool HalikeyDevice::openPort(const QString &portName) {
m_confirmedDahState = false;
m_confirmedPttState = false;
- // Create worker based on configured device type
+ // Create worker based on configured device type.
+#ifdef Q_OS_IOS
+ // iOS keyer is MIDI-only (CoreMIDI via RtMidi); the serial/HID V14 path is
+ // not built on iOS, so always use the MIDI worker regardless of the setting.
+ m_worker = new HaliKeyMidiWorker(portName);
+#else
int deviceType = RadioSettings::instance()->halikeyDeviceType();
if (deviceType == 1) {
m_worker = new HaliKeyMidiWorker(portName);
} else {
m_worker = new HaliKeyV14Worker(portName);
}
+#endif
m_workerThread = new QThread(this);
m_worker->moveToThread(m_workerThread);
@@ -393,15 +401,23 @@ QString HalikeyDevice::portName() const {
}
QStringList HalikeyDevice::availablePorts() {
+#ifdef Q_OS_IOS
+ // No serial ports on iOS; the keyer is MIDI-only (see availableMidiDevices).
+ return {};
+#else
QStringList ports;
const auto portInfos = QSerialPortInfo::availablePorts();
for (const QSerialPortInfo &info : portInfos) {
ports.append(info.portName());
}
return ports;
+#endif
}
QList HalikeyDevice::availablePortsDetailed() {
+#ifdef Q_OS_IOS
+ return {};
+#else
QList ports;
const auto portInfos = QSerialPortInfo::availablePorts();
for (const QSerialPortInfo &info : portInfos) {
@@ -410,6 +426,7 @@ QList HalikeyDevice::availablePortsDetailed() {
ports.append(pi);
}
return ports;
+#endif
}
QStringList HalikeyDevice::availableMidiDevices() {
diff --git a/src/hardware/halikeydevice.h b/src/hardware/halikeydevice.h
index 1cfa5d0..46f508d 100644
--- a/src/hardware/halikeydevice.h
+++ b/src/hardware/halikeydevice.h
@@ -3,7 +3,9 @@
#include
#include
+#if !defined(Q_OS_IOS) && !defined(Q_OS_ANDROID)
#include
+#endif
#include
#include
#include
diff --git a/src/hardware/kpoddevice.cpp b/src/hardware/kpoddevice.cpp
index aa4ffe9..f17a767 100644
--- a/src/hardware/kpoddevice.cpp
+++ b/src/hardware/kpoddevice.cpp
@@ -1,7 +1,7 @@
#include "kpoddevice.h"
#include
-#ifdef Q_OS_ANDROID
+#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
KpodDevice::KpodDevice(QObject *parent)
: QObject(parent), m_hidDevice(nullptr), m_pollTimer(new QTimer(this)), m_lastRockerPosition(RockerCenter) {
diff --git a/src/ios/iosaudiosession.h b/src/ios/iosaudiosession.h
new file mode 100644
index 0000000..b87b0fd
--- /dev/null
+++ b/src/ios/iosaudiosession.h
@@ -0,0 +1,26 @@
+#ifndef IOSAUDIOSESSION_H
+#define IOSAUDIOSESSION_H
+
+// iOS AVAudioSession configuration for the K4 audio path.
+//
+// RX playback works under iOS's default session, but capturing the microphone
+// for TX needs the session in the playAndRecord category and activated, or
+// CoreAudio hands QAudioSource silence. These helpers own that session state;
+// they are no-ops on every other platform (the .mm only builds for iOS).
+namespace IosAudioSession {
+
+// Put the shared session in playAndRecord, routed to the loudspeaker, at
+// 48 kHz to match AudioEngine's input format. Safe to call before any
+// QAudioSource/QAudioSink exists. Registers interruption/route observers on
+// first call. Logs (does not throw) on failure.
+void configureForVoice();
+
+// Activate the session. Returns false and logs the underlying error on failure.
+bool activate();
+
+// Deactivate the session, letting other apps resume.
+void deactivate();
+
+} // namespace IosAudioSession
+
+#endif // IOSAUDIOSESSION_H
diff --git a/src/ios/iosaudiosession.mm b/src/ios/iosaudiosession.mm
new file mode 100644
index 0000000..ff29b70
--- /dev/null
+++ b/src/ios/iosaudiosession.mm
@@ -0,0 +1,126 @@
+#include "iosaudiosession.h"
+
+#import
+#import
+
+#include
+#include
+
+// Observes AVAudioSession interruptions and route changes. Interruption
+// handling is intentionally minimal: on interruption end, if the system says
+// we may resume, re-activate the session so RX playback and mic capture come
+// back. It does not restart QAudioSink/QAudioSource; a long interruption
+// (e.g. a phone call) may still require reconnecting. Route changes are logged
+// only for now.
+@interface Qk4AudioSessionObserver : NSObject
+@end
+
+@implementation Qk4AudioSessionObserver
+
+- (instancetype)init {
+ if ((self = [super init])) {
+ NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
+ [nc addObserver:self
+ selector:@selector(handleInterruption:)
+ name:AVAudioSessionInterruptionNotification
+ object:nil];
+ [nc addObserver:self
+ selector:@selector(handleRouteChange:)
+ name:AVAudioSessionRouteChangeNotification
+ object:nil];
+ }
+ return self;
+}
+
+- (void)handleInterruption:(NSNotification *)note {
+ NSNumber *typeValue = note.userInfo[AVAudioSessionInterruptionTypeKey];
+ if (!typeValue)
+ return;
+ const AVAudioSessionInterruptionType type =
+ static_cast(typeValue.unsignedIntegerValue);
+ if (type == AVAudioSessionInterruptionTypeBegan) {
+ qInfo() << "IosAudioSession: audio interrupted";
+ return;
+ }
+ if (type == AVAudioSessionInterruptionTypeEnded) {
+ NSNumber *optsValue = note.userInfo[AVAudioSessionInterruptionOptionKey];
+ const bool shouldResume =
+ optsValue && (optsValue.unsignedIntegerValue & AVAudioSessionInterruptionOptionShouldResume);
+ if (shouldResume) {
+ NSError *error = nil;
+ if (![[AVAudioSession sharedInstance] setActive:YES error:&error]) {
+ qWarning() << "IosAudioSession: reactivate after interruption failed:"
+ << (error ? QString::fromNSString(error.localizedDescription) : QString());
+ } else {
+ qInfo() << "IosAudioSession: audio resumed after interruption";
+ }
+ }
+ }
+}
+
+- (void)handleRouteChange:(NSNotification *)note {
+ NSNumber *reason = note.userInfo[AVAudioSessionRouteChangeReasonKey];
+ qInfo() << "IosAudioSession: audio route changed, reason" << (reason ? int(reason.unsignedIntegerValue) : -1);
+}
+
+@end
+
+namespace {
+// Held for the process lifetime; the session outlives any AudioEngine.
+Qk4AudioSessionObserver *g_observer = nil;
+
+void ensureObserver() {
+ if (g_observer == nil)
+ g_observer = [[Qk4AudioSessionObserver alloc] init];
+}
+} // namespace
+
+void IosAudioSession::configureForVoice() {
+ ensureObserver();
+ AVAudioSession *session = [AVAudioSession sharedInstance];
+
+ // playAndRecord so the mic can be captured while RX plays. defaultToSpeaker
+ // keeps RX on the loudspeaker (playAndRecord otherwise routes to the
+ // earpiece). Only A2DP is allowed for Bluetooth: it is output-only, so the
+ // built-in mic stays at 48 kHz and matches AudioEngine's input format.
+ // HFP (allowBluetooth) would drop the hardware to 8/16 kHz narrowband and
+ // can make QAudioSource's 48 kHz format check fail; add it later as a
+ // deliberate choice.
+ const AVAudioSessionCategoryOptions options =
+ AVAudioSessionCategoryOptionDefaultToSpeaker | AVAudioSessionCategoryOptionAllowBluetoothA2DP;
+ NSError *error = nil;
+ if (![session setCategory:AVAudioSessionCategoryPlayAndRecord
+ mode:AVAudioSessionModeDefault
+ options:options
+ error:&error]) {
+ qWarning() << "IosAudioSession: setCategory failed:"
+ << (error ? QString::fromNSString(error.localizedDescription) : QString());
+ }
+
+ error = nil;
+ if (![session setPreferredSampleRate:48000.0 error:&error]) {
+ qWarning() << "IosAudioSession: setPreferredSampleRate failed:"
+ << (error ? QString::fromNSString(error.localizedDescription) : QString());
+ }
+}
+
+bool IosAudioSession::activate() {
+ NSError *error = nil;
+ const bool ok = [[AVAudioSession sharedInstance] setActive:YES error:&error];
+ if (!ok) {
+ qWarning() << "IosAudioSession: activate failed:"
+ << (error ? QString::fromNSString(error.localizedDescription) : QString());
+ } else {
+ AVAudioSession *session = [AVAudioSession sharedInstance];
+ qInfo() << "IosAudioSession: active, sampleRate" << session.sampleRate
+ << "inputs" << (session.isInputAvailable ? "available" : "none");
+ }
+ return ok;
+}
+
+void IosAudioSession::deactivate() {
+ NSError *error = nil;
+ [[AVAudioSession sharedInstance] setActive:NO
+ withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation
+ error:&error];
+}
diff --git a/src/ios/iosorientation.h b/src/ios/iosorientation.h
new file mode 100644
index 0000000..6081bc4
--- /dev/null
+++ b/src/ios/iosorientation.h
@@ -0,0 +1,10 @@
+#ifndef IOSORIENTATION_H
+#define IOSORIENTATION_H
+
+namespace IosOrientation {
+void requestLandscape();
+void requestPortrait();
+void allowPortraitAndLandscape();
+}
+
+#endif // IOSORIENTATION_H
diff --git a/src/ios/iosorientation.mm b/src/ios/iosorientation.mm
new file mode 100644
index 0000000..b787e40
--- /dev/null
+++ b/src/ios/iosorientation.mm
@@ -0,0 +1,46 @@
+#include "iosorientation.h"
+
+#import
+
+#include
+#include
+
+namespace {
+UIWindowScene *activeWindowScene() {
+ for (UIScene *scene in UIApplication.sharedApplication.connectedScenes) {
+ if ([scene isKindOfClass:[UIWindowScene class]]
+ && scene.activationState == UISceneActivationStateForegroundActive)
+ return (UIWindowScene *)scene;
+ }
+ return nil;
+}
+
+void requestOrientations(UIInterfaceOrientationMask mask) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ UIWindowScene *scene = activeWindowScene();
+ if (!scene)
+ return;
+ if (@available(iOS 16.0, *)) {
+ UIWindowSceneGeometryPreferencesIOS *preferences =
+ [[UIWindowSceneGeometryPreferencesIOS alloc] initWithInterfaceOrientations:mask];
+ [scene requestGeometryUpdateWithPreferences:preferences errorHandler:^(NSError *error) {
+ qWarning() << "IosOrientation: geometry update failed:"
+ << QString::fromNSString(error.localizedDescription);
+ }];
+ }
+ [UIViewController attemptRotationToDeviceOrientation];
+ });
+}
+}
+
+void IosOrientation::requestLandscape() {
+ requestOrientations(UIInterfaceOrientationMaskLandscape);
+}
+
+void IosOrientation::requestPortrait() {
+ requestOrientations(UIInterfaceOrientationMaskPortrait);
+}
+
+void IosOrientation::allowPortraitAndLandscape() {
+ requestOrientations(UIInterfaceOrientationMaskAll);
+}
diff --git a/src/ios/iossecurecredentials.h b/src/ios/iossecurecredentials.h
new file mode 100644
index 0000000..d458d27
--- /dev/null
+++ b/src/ios/iossecurecredentials.h
@@ -0,0 +1,12 @@
+#ifndef IOSSECURECREDENTIALS_H
+#define IOSSECURECREDENTIALS_H
+
+#include
+
+namespace IosSecureCredentials {
+QString readQrzApiKey(QString *error);
+bool writeQrzApiKey(const QString &key, QString *error);
+bool clearQrzApiKey(QString *error);
+}
+
+#endif // IOSSECURECREDENTIALS_H
diff --git a/src/ios/iossecurecredentials.mm b/src/ios/iossecurecredentials.mm
new file mode 100644
index 0000000..012e070
--- /dev/null
+++ b/src/ios/iossecurecredentials.mm
@@ -0,0 +1,72 @@
+#include "iossecurecredentials.h"
+
+#import
+#import
+
+#include
+
+namespace {
+NSString *const serviceName = @"com.w9wdx.qk4phone.qrz";
+NSString *const accountName = @"api-key";
+
+NSMutableDictionary *baseQuery() {
+ return [@{
+ (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
+ (__bridge id)kSecAttrService: serviceName,
+ (__bridge id)kSecAttrAccount: accountName
+ } mutableCopy];
+}
+
+bool setError(QString *error, OSStatus status, const QString &operation) {
+ if (error) {
+ CFStringRef description = SecCopyErrorMessageString(status, nullptr);
+ const QString detail = description ? QString::fromCFString(description) : QString::number(status);
+ if (description)
+ CFRelease(description);
+ *error = QStringLiteral("%1: %2").arg(operation, detail);
+ }
+ return false;
+}
+}
+
+QString IosSecureCredentials::readQrzApiKey(QString *error) {
+ NSMutableDictionary *query = baseQuery();
+ query[(__bridge id)kSecReturnData] = @YES;
+ query[(__bridge id)kSecMatchLimit] = (__bridge id)kSecMatchLimitOne;
+ CFTypeRef result = nullptr;
+ const OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &result);
+ if (status == errSecItemNotFound)
+ return {};
+ if (status != errSecSuccess) {
+ setError(error, status, QStringLiteral("Cannot read the QRZ API key securely"));
+ return {};
+ }
+ NSData *data = (__bridge_transfer NSData *)result;
+ NSString *value = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
+ if (!value) {
+ if (error)
+ *error = QStringLiteral("The saved QRZ API key is not valid text.");
+ return {};
+ }
+ return QString::fromNSString(value);
+}
+
+bool IosSecureCredentials::writeQrzApiKey(const QString &key, QString *error) {
+ NSData *data = [key.toNSString() dataUsingEncoding:NSUTF8StringEncoding];
+ NSMutableDictionary *query = baseQuery();
+ NSDictionary *update = @{(__bridge id)kSecValueData: data};
+ OSStatus status = SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)update);
+ if (status == errSecItemNotFound) {
+ query[(__bridge id)kSecValueData] = data;
+ query[(__bridge id)kSecAttrAccessible] = (__bridge id)kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly;
+ status = SecItemAdd((__bridge CFDictionaryRef)query, nullptr);
+ }
+ return status == errSecSuccess
+ || setError(error, status, QStringLiteral("Cannot save the QRZ API key securely"));
+}
+
+bool IosSecureCredentials::clearQrzApiKey(QString *error) {
+ const OSStatus status = SecItemDelete((__bridge CFDictionaryRef)baseQuery());
+ return status == errSecSuccess || status == errSecItemNotFound
+ || setError(error, status, QStringLiteral("Cannot remove the QRZ API key"));
+}
diff --git a/src/main.cpp b/src/main.cpp
index 805a097..85c2f2e 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -134,7 +134,11 @@ int main(int argc, char *argv[]) {
setupFonts();
MainWindow window;
+#if defined(Q_OS_IOS)
+ window.showFullScreen();
+#else
window.show();
+#endif
return app.exec();
}
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index 2a6d025..b879991 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -89,6 +89,8 @@
#include
#include
#include
+#include
+#include
#include
#include
#include
@@ -96,7 +98,7 @@
#include
#include
#include
-#ifdef Q_OS_ANDROID
+#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
#include
#endif
@@ -256,6 +258,33 @@ QString temperatureStyle(int celsius) {
// changing over; do not make transmission depend on a CAT state echo.
constexpr int SstvKeyUpGuardMs = 500;
constexpr int SstvDrainMarginMs = 150;
+// Horizontal QSlider that jumps to the tapped position (groove-tap-to-set),
+// so a touch anywhere on the track moves the handle there rather than
+// page-stepping. Used for the RIT/XIT offset slider.
+class TouchSlider final : public QSlider {
+public:
+ using QSlider::QSlider;
+
+protected:
+ void mousePressEvent(QMouseEvent *event) override {
+ setValueFromX(event->pos().x());
+ event->accept();
+ }
+ void mouseMoveEvent(QMouseEvent *event) override {
+ if (event->buttons() & Qt::LeftButton) {
+ setValueFromX(event->pos().x());
+ event->accept();
+ }
+ }
+
+private:
+ void setValueFromX(int x) {
+ const int handleWidth = qMax(12, height() / 2);
+ const int span = qMax(1, width() - handleWidth);
+ const int pos = qBound(0, x - handleWidth / 2, span);
+ setValue(QStyle::sliderValueFromPosition(minimum(), maximum(), pos, span, invertedAppearance()));
+ }
+};
} // namespace
// Convert K4 tuning step index (VT command, 0-5) to Hz
@@ -290,7 +319,7 @@ static int getNextSpanDown(int currentSpan) {
return qMax(newSpan, SPAN_MIN);
}
-#ifdef Q_OS_ANDROID
+#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
static bool ensureMicrophonePermission(QWidget *parent) {
QMicrophonePermission permission;
Qt::PermissionStatus status = qApp->checkPermission(permission);
@@ -483,7 +512,11 @@ MainWindow::MainWindow(QWidget *parent)
// prevents the RHI backing store from being set up correctly, causing
// "QRhiWidget: No QRhi" errors and blank panadapter display.
setupUi();
+ // iOS is a touch app with on-screen controls (Settings via the bottom-bar
+ // gear); the desktop File/Tools/View/Help menu bar only wastes a row.
+#ifndef Q_OS_IOS
setupMenuBar();
+#endif
connect(qApp, &QGuiApplication::applicationStateChanged, this,
[this](Qt::ApplicationState state) {
@@ -1736,6 +1769,12 @@ MainWindow::MainWindow(QWidget *parent)
// Also updates DIV indicator since DIV requires SUB to be on
// Also dims VFO B frequency and mode labels when SUB RX is off
connect(m_radioState, &RadioState::subRxEnabledChanged, this, [this](bool enabled) {
+ // Drive the right-panel SUB / DIVERSITY LEDs (SUB/DIV were removed from
+ // the centre VFO area; the radio shows them as LEDs here).
+ if (m_rightSidePanel) {
+ m_rightSidePanel->setSubActive(enabled);
+ m_rightSidePanel->setDiversityActive(enabled && m_radioState->diversityEnabled());
+ }
if (enabled) {
m_subLabel->setStyleSheet(QString("background-color: %1;"
"color: black;"
@@ -1792,6 +1831,8 @@ MainWindow::MainWindow(QWidget *parent)
connect(m_radioState, &RadioState::diversityChanged, this, [this](bool enabled) {
// DIV only shows green if both diversity is enabled AND sub RX is enabled
bool showActive = enabled && m_radioState->subReceiverEnabled();
+ if (m_rightSidePanel)
+ m_rightSidePanel->setDiversityActive(showActive);
if (showActive) {
m_divLabel->setStyleSheet(QString("background-color: %1;"
"color: black;"
@@ -1860,6 +1901,8 @@ MainWindow::MainWindow(QWidget *parent)
connect(m_radioState, &RadioState::filterBandwidthBChanged, this, updateFilterDisplay);
connect(m_radioState, &RadioState::ifShiftBChanged, this, updateFilterDisplay);
connect(m_radioState, &RadioState::bSetChanged, this, updateFilterDisplay);
+ // Mode and DATA sub-mode change the valid BW/SHFT ranges (e.g. FSK is
+ // 150-800 Hz), so refresh the control ranges when they change too.
connect(m_radioState, &RadioState::modeChanged, this, updateFilterDisplay);
connect(m_radioState, &RadioState::modeBChanged, this, updateFilterDisplay);
connect(m_radioState, &RadioState::dataSubModeChanged, this, updateFilterDisplay);
@@ -1920,11 +1963,17 @@ MainWindow::MainWindow(QWidget *parent)
[this](int bw) { m_filterBWidget->setBandwidth(bw); });
connect(m_radioState, &RadioState::ifShiftChanged, this, [this](int shift) { m_filterAWidget->setShift(shift); });
connect(m_radioState, &RadioState::ifShiftBChanged, this, [this](int shift) { m_filterBWidget->setShift(shift); });
- // Mode affects filter indicator shift center calculation
+ // Mode affects the filter indicator (shift centre, and FSK/AFSK draws two
+ // peaks). Use the full mode string so the DATA sub-mode (FSK/AFSK/PSK) is
+ // reflected, and refresh when the sub-mode alone changes.
connect(m_radioState, &RadioState::modeChanged, this,
- [this](RadioState::Mode mode) { m_filterAWidget->setMode(RadioState::modeToString(mode)); });
+ [this](RadioState::Mode) { m_filterAWidget->setMode(m_radioState->modeStringFull()); });
connect(m_radioState, &RadioState::modeBChanged, this,
- [this](RadioState::Mode mode) { m_filterBWidget->setMode(RadioState::modeToString(mode)); });
+ [this](RadioState::Mode) { m_filterBWidget->setMode(m_radioState->modeStringFullB()); });
+ connect(m_radioState, &RadioState::dataSubModeChanged, this,
+ [this](int) { m_filterAWidget->setMode(m_radioState->modeStringFull()); });
+ connect(m_radioState, &RadioState::dataSubModeBChanged, this,
+ [this](int) { m_filterBWidget->setMode(m_radioState->modeStringFullB()); });
// RadioState signals -> Processing state updates (AGC, PRE, ATT, NB, NR)
connect(m_radioState, &RadioState::processingChanged, this, &MainWindow::onProcessingChanged);
@@ -2651,7 +2700,7 @@ MainWindow::MainWindow(QWidget *parent)
// but always honor PTT-off so a stale gate can be cleared.
if (on && !m_tcpClient->isConnected())
return;
-#ifdef Q_OS_ANDROID
+#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
if (on && !ensureMicrophonePermission(this)) {
m_pttActive = false;
m_bottomMenuBar->setPttActive(false);
@@ -2684,7 +2733,7 @@ MainWindow::MainWindow(QWidget *parent)
m_catServer->start(RadioSettings::instance()->catServerPort());
}
-#ifdef Q_OS_ANDROID
+#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
// Prime Android runtime permission early, before the first TX attempt.
ensureMicrophonePermission(this);
#endif
@@ -2819,15 +2868,19 @@ void MainWindow::showSettings() {
m_radioState->setKeyerSpeed(boundedWpm);
});
}
-#ifdef Q_OS_ANDROID
+ // On touch platforms the dialog is an in-window overlay: fill the console
+ // so its "RETURN TO OPERATE" header button is on-screen and reachable.
+ // Without this the iPad opened it at its default size with the close
+ // button out of reach.
+#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
m_optionsDialog->setGeometry(centralWidget()->rect());
#endif
m_optionsDialog->show();
m_optionsDialog->raise();
-#ifndef Q_OS_ANDROID
- m_optionsDialog->activateWindow();
-#else
+#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
m_optionsDialog->setFocus(Qt::OtherFocusReason);
+#else
+ m_optionsDialog->activateWindow();
#endif
}
@@ -2969,6 +3022,26 @@ void MainWindow::setupUi() {
setStyleSheet(QString("QMainWindow { background-color: %1; }").arg(K4Styles::Colors::Background));
+#if defined(Q_OS_ANDROID)
+ // Android tablet fit: the window (~1007 logical px) can't give each VFO panel
+ // its full 270px column once the side-control panels (107+132) and the centre
+ // panel are placed, so each panel is squeezed to ~246 and the 270/260 column
+ // content (meter +40 scale, frequency, feature-label row) is clipped. Size the
+ // VFO column and meter to what actually fits so the content renders in full
+ // (the S-meter scale is a touch denser than desktop). macOS/iOS keep 270/260.
+ if (!K4Styles::isCompactLayout()) {
+ K4Styles::Dimensions::VfoColumnWidth = 244;
+ K4Styles::Dimensions::VfoMeterWidth = 244;
+ // Restore the desktop meter/content heights: at 120 the meter clipped
+ // the Id row's scale (it lands at ~y129), and the feature row (AGC-S…APF)
+ // sat right under the meter with no gap. 130/150 shows the Id scale and
+ // drops the feature row to match macOS. The spectrum below absorbs the
+ // few extra pixels.
+ K4Styles::Dimensions::VfoMeterHeight = 130;
+ K4Styles::Dimensions::VfoContentHeight = 150;
+ }
+#endif
+
auto *centralWidget = new QWidget(this);
centralWidget->setStyleSheet(QString("background-color: %1;").arg(K4Styles::Colors::Background));
setCentralWidget(centralWidget);
@@ -3042,11 +3115,14 @@ void MainWindow::setupUi() {
// Right Side Panel (mirrors left panel dimensions)
m_rightPanelScroll = new QScrollArea(middleWidget);
m_rightPanelScroll->setFrameShape(QFrame::NoFrame);
- m_rightPanelScroll->setWidgetResizable(false);
+ // iPad: let the panel fill the viewport height so its trailing addStretch
+ // can bottom-anchor the fine-tune pad near the PTT button, while a taller
+ // panel still scrolls (minimumHeight below). Phone keeps manual sizing.
+ m_rightPanelScroll->setWidgetResizable(!K4Styles::isCompactLayout());
m_rightPanelScroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
m_rightPanelScroll->setVerticalScrollBarPolicy(K4Styles::isCompactLayout() ? Qt::ScrollBarAlwaysOn
: Qt::ScrollBarAlwaysOff);
- m_rightPanelScroll->setFixedWidth(K4Styles::Dimensions::SidePanelWidth + sidePanelScrollExtra);
+ m_rightPanelScroll->setFixedWidth(K4Styles::Dimensions::RightSidePanelWidth + sidePanelScrollExtra);
m_rightSidePanel = new RightSidePanel(m_rightPanelScroll);
m_rightPanelScroll->setWidget(m_rightSidePanel);
if (K4Styles::isCompactLayout()) {
@@ -3059,6 +3135,10 @@ void MainWindow::setupUi() {
if (K4Styles::isCompactLayout()) {
m_rightPanelScroll->hide();
} else {
+ // Floor the panel at its natural height: when the viewport is taller,
+ // widgetResizable stretches it and the addStretch anchors the pad to
+ // the bottom; when shorter, it keeps full height and scrolls.
+ m_rightSidePanel->setMinimumHeight(m_rightSidePanel->sizeHint().height());
middleLayout->addWidget(m_rightPanelScroll);
}
@@ -3426,6 +3506,11 @@ void MainWindow::setupUi() {
m_bSetLabel->setVisible(enabled);
m_splitLabel->setVisible(!enabled);
+ // Green highlight on the right-panel B SET button so the mode is easy
+ // to spot (like the SUB button).
+ if (m_rightSidePanel)
+ m_rightSidePanel->setBSetActive(enabled);
+
// Change side panel BW/SHFT indicator color (cyan=MainRx, green=SubRx)
m_sideControlPanel->setActiveReceiver(enabled);
});
@@ -3801,12 +3886,58 @@ void MainWindow::setupUi() {
m_tcpClient->sendCAT("SW157;");
});
- // NORM is placed with BW/SHFT and performs the K4's nominal-passband
- // action. K4 MON is intentionally not exposed in the remote control UI.
+ // NORM performs the K4's nominal-passband action. After the radio settles
+ // to its nominal width, learn that width for the active RX's current mode
+ // so the filter indicator's NORM edge ticks show at the true nominal
+ // rather than a hardcoded guess.
connect(m_sideControlPanel, &SideControlPanel::normalizeFilterRequested, this, [this]() {
queueControlFeedback("FILTER_NORM", "Filter passband normalized");
m_tcpClient->sendCAT("SW129;");
+ QTimer::singleShot(300, this, [this]() {
+ if (m_radioState->bSetEnabled())
+ m_filterBWidget->setNormBandwidth(m_radioState->filterBandwidthB());
+ else
+ m_filterAWidget->setNormBandwidth(m_radioState->filterBandwidth());
+ });
});
+ // MON / BAL toggle their K4 functions; the overlays adjust ML / BL levels.
+ connect(m_sideControlPanel, &SideControlPanel::monClicked, this, [this]() {
+ queueControlFeedback("MON", "Monitor toggled");
+ m_tcpClient->sendCAT("SW128;");
+ });
+ connect(m_sideControlPanel, &SideControlPanel::balClicked, this, [this]() {
+ queueControlFeedback("BAL", "Sub-RX balance toggled");
+ m_tcpClient->sendCAT("SW130;");
+ });
+ connect(m_sideControlPanel, &SideControlPanel::monLevelChangeRequested, this,
+ [this](int mode, int level) {
+ m_tcpClient->sendCAT(QString("ML%1%2;").arg(mode).arg(level, 3, 10, QChar('0')));
+ m_radioState->setMonitorLevel(mode, level);
+ });
+ connect(m_sideControlPanel, &SideControlPanel::balChangeRequested, this,
+ [this](int mode, int offset) {
+ const QString sign = offset >= 0 ? "+" : "-";
+ m_tcpClient->sendCAT(QString("BL%1%2%3;")
+ .arg(mode)
+ .arg(sign)
+ .arg(qAbs(offset), 2, 10, QChar('0')));
+ m_radioState->setBalance(mode, offset);
+ });
+ connect(m_radioState, &RadioState::monitorLevelChanged,
+ m_sideControlPanel, &SideControlPanel::updateMonitorLevel);
+ connect(m_radioState, &RadioState::balanceChanged,
+ m_sideControlPanel, &SideControlPanel::updateBalance);
+ // Keep the MON overlay pointed at the right ML register as the mode changes.
+ auto updateMonitorMode = [this](RadioState::Mode mode) {
+ int monMode = 2; // Voice
+ if (mode == RadioState::CW || mode == RadioState::CW_R)
+ monMode = 0;
+ else if (mode == RadioState::DATA || mode == RadioState::DATA_R)
+ monMode = 1;
+ m_sideControlPanel->updateMonitorMode(monMode);
+ };
+ connect(m_radioState, &RadioState::modeChanged, this, updateMonitorMode);
+ updateMonitorMode(m_radioState->mode()); // seed initial monitor mode
// Forward audio mix routing (MX command) to audio engine
connect(m_radioState, &RadioState::audioMixChanged, this, [this](int left, int right) {
@@ -3999,6 +4130,81 @@ void MainWindow::setupUi() {
connect(m_rightSidePanel, &RightSidePanel::lockBClicked, this,
[this]() { queueControlFeedback("LOCK_B", "VFO B lock changed"); m_tcpClient->sendCAT("SW151;"); });
+ // iPad fine-tune pad. Steps the VFO by the radio's current tuning step,
+ // mirroring the phone's A-/A+/B-/B+ buttons (signals only fire on iPad).
+ // Snap to the current tuning-step grid: from x.957 with a 100 Hz step,
+ // "-" lands on x.900 and "+" on the next x.000, matching the radio. Uses
+ // the same rate source as the panadapter drag/scroll tuning.
+ auto snapStep = [](qint64 cur, int dir, int stepHz) -> qint64 {
+ const qint64 base = (cur / stepHz) * stepHz; // floor to grid (freq > 0)
+ if (dir < 0)
+ return (cur == base) ? base - stepHz : base;
+ return base + stepHz;
+ };
+ connect(m_rightSidePanel, &RightSidePanel::tuneARequested, this, [this, snapStep](int dir) {
+ // While the blue edit field is open, A-/A+ change the selected digit
+ // (with carry) so a frequency can be entered entirely by touch.
+ if (m_vfoA->frequencyDisplay()->isEditing()) {
+ m_vfoA->frequencyDisplay()->nudgeCursorDigit(dir);
+ return;
+ }
+ if (!m_tcpClient->isConnected())
+ return;
+ const int stepHz = m_phoneTuneStepAHz > 0 ? m_phoneTuneStepAHz : tuningStepToHz(m_radioState->tuningStep());
+ const qint64 next = snapStep(static_cast(m_radioState->vfoA()), dir, stepHz);
+ if (next > 0) {
+ const QString command = QString("FA%1;").arg(next, 11, 10, QChar('0'));
+ m_tcpClient->sendCAT(command);
+ m_radioState->parseCATCommand(command);
+ }
+ });
+ connect(m_rightSidePanel, &RightSidePanel::tuneBRequested, this, [this, snapStep](int dir) {
+ if (!m_tcpClient->isConnected())
+ return;
+ const int stepHz = m_phoneTuneStepBHz > 0 ? m_phoneTuneStepBHz : tuningStepToHz(m_radioState->tuningStepB());
+ const qint64 next = snapStep(static_cast(m_radioState->vfoB()), dir, stepHz);
+ if (next > 0) {
+ const QString command = QString("FB%1;").arg(next, 11, 10, QChar('0'));
+ m_tcpClient->sendCAT(command);
+ m_radioState->parseCATCommand(command);
+ }
+ });
+
+ // FREQ ENT switches the main VFO's frequency display into the blue edit
+ // field, matching the radio (a dedicated key enters edit mode rather than
+ // tapping the frequency, which selects the tuning rate).
+ connect(m_rightSidePanel, &RightSidePanel::freqEntClicked, this, [this]() {
+ auto *fd = m_vfoA->frequencyDisplay();
+ // Toggle: FREQ ENT opens the blue field, and pressing it again commits
+ // (sends the entered frequency), so the whole entry is touch-only.
+ if (fd->isEditing())
+ fd->commitEdit();
+ else
+ fd->beginEdit();
+ });
+
+ // iPad: tapping a frequency digit sets the tuning rate at that place
+ // (1 Hz .. 10 kHz, the five rightmost digits), matching the radio. The
+ // compact layout wires this on the bottom bar instead.
+ if (!K4Styles::isCompactLayout()) {
+ connect(m_vfoA, &VFOWidget::tuningDigitSelected, this, [this](int digitFromRight) {
+ const int digit = qBound(0, digitFromRight, 4);
+ if (m_tcpClient->isConnected()) {
+ const QString command = QString("VT%1;").arg(digit);
+ m_tcpClient->sendCAT(command);
+ m_radioState->parseCATCommand(command);
+ }
+ });
+ connect(m_vfoB, &VFOWidget::tuningDigitSelected, this, [this](int digitFromRight) {
+ const int digit = qBound(0, digitFromRight, 4);
+ if (m_tcpClient->isConnected()) {
+ const QString command = QString("VT$%1;").arg(digit);
+ m_tcpClient->sendCAT(command);
+ m_radioState->parseCATCommand(command);
+ }
+ });
+ }
+
// Resolve CTRL-panel actions from the state echoed by the K4. These
// confirmations remain useful after the drawer has closed, particularly
// for controls whose state is not represented in the compact phone view.
@@ -4253,6 +4459,18 @@ void MainWindow::setupVfoSection(QWidget *parent) {
// ===== Center Section =====
auto *centerWidget = new QWidget(parent);
centerWidget->setFixedWidth(K4Styles::Dimensions::CenterPanelWidth);
+#if defined(Q_OS_ANDROID)
+ // Root cause of the old centre/meter overlap: the VFO row is width-bound on
+ // the tablet. The row is ~752px; each VFO panel needs ~246 (VfoColumnWidth
+ // 244 + margins) and the two inter-column gaps are ~4 each, so the fixed
+ // centre panel must be <= 752 - 2*246 - 2*4 = 252 or the HBox can't shrink it
+ // (it's fixed) and it overflows into the right meter panel. Size it to fit
+ // that budget (250) instead of the desktop 330. The VFO cluster and the
+ // narrowed memory strip (~242) still fit. If the window/panel widths change
+ // materially, recompute against this budget.
+ if (!K4Styles::isCompactLayout())
+ centerWidget->setFixedWidth(250);
+#endif
centerWidget->setStyleSheet(QString("background-color: %1;").arg(K4Styles::Colors::Background));
auto *centerLayout = new QVBoxLayout(centerWidget);
centerLayout->setContentsMargins(K4Styles::isCompactLayout() ? 2 : 4,
@@ -4293,8 +4511,9 @@ void MainWindow::setupVfoSection(QWidget *parent) {
m_splitLabel = new QLabel("SPLIT OFF", centerWidget);
m_splitLabel->setAlignment(Qt::AlignCenter);
m_splitLabel->setStyleSheet(QString("color: %1; font-size: 11px;").arg(K4Styles::Colors::AccentAmber));
- if (!K4Styles::isCompactLayout())
- centerLayout->addWidget(m_splitLabel);
+ // In regular layout SPLIT/MSG/RIT are stacked in the VFO row's centre
+ // column (between the filters, like the radio); added after the RIT box is
+ // built below. Compact keeps SPLIT in the shared status row.
// B SET indicator (green rounded rect with black text, hidden by default)
m_bSetLabel = new QLabel("B SET", centerWidget);
@@ -4312,7 +4531,8 @@ void MainWindow::setupVfoSection(QWidget *parent) {
m_bSetLabel->setCursor(Qt::PointingHandCursor);
m_bSetLabel->installEventFilter(this);
m_bSetLabel->setVisible(false);
- centerLayout->addWidget(m_bSetLabel, 0, Qt::AlignHCenter);
+ if (K4Styles::isCompactLayout())
+ centerLayout->addWidget(m_bSetLabel, 0, Qt::AlignHCenter);
// Message Bank indicator
m_msgBankLabel = new QLabel("MSG: I", centerWidget);
@@ -4326,9 +4546,9 @@ void MainWindow::setupVfoSection(QWidget *parent) {
compactStatusRow->setSpacing(6);
compactStatusRow->addWidget(m_splitLabel, 1);
compactStatusRow->addWidget(m_msgBankLabel, 1);
- } else {
- centerLayout->addWidget(m_msgBankLabel);
}
+ // Regular layout adds SPLIT/MSG/RIT to the centre column below (after the
+ // RIT box exists).
// RIT/XIT Box with border - constrained size
// Supports mouse wheel to adjust RIT/XIT offset
@@ -4381,31 +4601,43 @@ void MainWindow::setupVfoSection(QWidget *parent) {
ritXitLayout->addWidget(m_ritXitValueLabel);
// Create filter/RIT/XIT row - filter indicators flanking the RIT/XIT box
- auto *filterRitXitRow = new QHBoxLayout();
- filterRitXitRow->setContentsMargins(0, 0, 0, 0);
- filterRitXitRow->setSpacing(0);
-
- // VFO A filter indicator (left side, cyan #00BFFF to match VFO A square/slider)
- m_filterAWidget = new FilterIndicatorWidget(centerWidget);
+ // Filter indicators now live under each VFO square+mode inside the VFO row
+ // (like the radio), not in a row beside RIT/XIT. Pull them from there and
+ // keep the color/cursor/event-filter setup MainWindow relies on.
+ m_filterAWidget = m_vfoRow->filterAWidget();
m_filterAWidget->setShapeColor(QColor(0x00, 0xBF, 0xFF), QColor(0x00, 0xBF, 0xFF)); // Cyan solid
m_filterAWidget->setCursor(Qt::PointingHandCursor);
m_filterAWidget->installEventFilter(this);
- filterRitXitRow->addWidget(m_filterAWidget);
- filterRitXitRow->addStretch();
-
- // RIT/XIT box (centered)
- filterRitXitRow->addWidget(m_ritXitBox);
- filterRitXitRow->addStretch();
-
- // VFO B filter indicator (right side, green #00FF00 to match VFO B square/slider)
- m_filterBWidget = new FilterIndicatorWidget(centerWidget);
+ m_filterBWidget = m_vfoRow->filterBWidget();
m_filterBWidget->setShapeColor(QColor(0x00, 0xFF, 0x00), QColor(0x00, 0xFF, 0x00)); // Green solid
m_filterBWidget->setCursor(Qt::PointingHandCursor);
m_filterBWidget->installEventFilter(this);
- filterRitXitRow->addWidget(m_filterBWidget);
- centerLayout->addLayout(filterRitXitRow);
+ // Seed a default shape so B renders before its first bandwidth/mode update.
+ m_filterBWidget->setMode(QStringLiteral("USB"));
+ m_filterBWidget->setBandwidth(2400);
+ m_filterAWidget->show();
+ m_filterBWidget->show();
+
+ if (K4Styles::isCompactLayout()) {
+ // Phone: RIT/XIT box centred on its own row.
+ auto *ritXitRow = new QHBoxLayout();
+ ritXitRow->setContentsMargins(0, 0, 0, 0);
+ ritXitRow->setSpacing(0);
+ ritXitRow->addStretch();
+ ritXitRow->addWidget(m_ritXitBox);
+ ritXitRow->addStretch();
+ centerLayout->addLayout(ritXitRow);
+ } else {
+ // Tablet/iPad: stack SPLIT / B SET / MSG / RIT-XIT in the VFO row's
+ // centre column so they sit between the two VFO filters, as on the
+ // radio. This also widens the centre column, pushing A/B outward.
+ m_vfoRow->addToCenterColumn(m_splitLabel);
+ m_vfoRow->addToCenterColumn(m_bSetLabel);
+ m_vfoRow->addToCenterColumn(m_msgBankLabel);
+ m_vfoRow->addToCenterColumn(m_ritXitBox);
+ }
if (compactStatusRow)
centerLayout->addLayout(compactStatusRow);
@@ -4464,22 +4696,38 @@ void MainWindow::setupVfoSection(QWidget *parent) {
// Container: VBox with 2px spacing, button centered, sub-label below
// Button: MemoryButtonWidth x ButtonHeightSmall (42x28)
// Sub-label: FontSizeSmall (8px), AccentAmber color
- auto createMemoryButton = [centerWidget](const QString &label, const QString &subLabel,
+ // On an Android tablet the meter panels leave less room between them, so a
+ // narrower memory button lets the whole strip fit the (also narrower) centre
+ // panel without the meters overlapping STORE/RCL.
+#if defined(Q_OS_ANDROID)
+ const int mbW = K4Styles::isCompactLayout() ? K4Styles::Dimensions::MemoryButtonWidth : 32;
+ // Smaller font so 5-char labels (STORE) fit the narrower button.
+ const QString mbFont =
+ K4Styles::isCompactLayout() ? QString() : QStringLiteral(" QPushButton{font-size:9px;padding:0px;}");
+#else
+ const int mbW = K4Styles::Dimensions::MemoryButtonWidth;
+ const QString mbFont;
+#endif
+ auto createMemoryButton = [centerWidget, mbW, mbFont](const QString &label, const QString &subLabel,
bool isLighter) -> QWidget * {
auto *container = new QWidget(centerWidget);
+ // Cap the container to the button width so wide sub-labels (AF REC,
+ // AF PLAY) don't widen it and push the whole row past the centre panel.
+ container->setFixedWidth(mbW);
auto *layout = new QVBoxLayout(container);
layout->setContentsMargins(0, 0, 0, 0);
layout->setSpacing(2);
auto *btn = new QPushButton(label, container);
- btn->setFixedSize(K4Styles::Dimensions::MemoryButtonWidth, K4Styles::Dimensions::ButtonHeightSmall);
+ btn->setFixedSize(mbW, K4Styles::Dimensions::ButtonHeightSmall);
btn->setCursor(Qt::PointingHandCursor);
- btn->setStyleSheet(isLighter ? K4Styles::sidePanelButtonLight() : K4Styles::sidePanelButton());
+ btn->setStyleSheet((isLighter ? K4Styles::sidePanelButtonLight() : K4Styles::sidePanelButton()) + mbFont);
layout->addWidget(btn, 0, Qt::AlignHCenter);
// Add sub-label if provided
if (!subLabel.isEmpty()) {
auto *sub = new QLabel(subLabel, container);
+ sub->setFixedWidth(mbW);
sub->setStyleSheet(QString("color: %1; font-size: %2px;")
.arg(K4Styles::Colors::AccentAmber)
.arg(K4Styles::Dimensions::FontSizeSmall));
@@ -4493,7 +4741,7 @@ void MainWindow::setupVfoSection(QWidget *parent) {
// Single row: M1-M4 group, REC, STORE, RCL (all centered)
auto *memoryRow = new QHBoxLayout();
memoryRow->setContentsMargins(0, 0, 0, 0);
- memoryRow->setSpacing(4);
+ memoryRow->setSpacing(3);
memoryRow->addStretch();
@@ -4506,15 +4754,15 @@ void MainWindow::setupVfoSection(QWidget *parent) {
// M1-M4 button row
auto *m1m4Row = new QHBoxLayout();
m1m4Row->setContentsMargins(0, 0, 0, 0);
- m1m4Row->setSpacing(4);
+ m1m4Row->setSpacing(3);
// Helper to create just a button (no sub-label container)
// Button: MemoryButtonWidth x ButtonHeightSmall (42x28), dark sidePanelButton style
- auto createSimpleButton = [centerWidget](const QString &label) -> QPushButton * {
+ auto createSimpleButton = [centerWidget, mbW, mbFont](const QString &label) -> QPushButton * {
auto *btn = new QPushButton(label, centerWidget);
- btn->setFixedSize(K4Styles::Dimensions::MemoryButtonWidth, K4Styles::Dimensions::ButtonHeightSmall);
+ btn->setFixedSize(mbW, K4Styles::Dimensions::ButtonHeightSmall);
btn->setCursor(Qt::PointingHandCursor);
- btn->setStyleSheet(K4Styles::sidePanelButton());
+ btn->setStyleSheet(K4Styles::sidePanelButton() + mbFont);
return btn;
};
@@ -4714,7 +4962,17 @@ void MainWindow::setupSpectrumPlaceholder(QWidget *parent) {
m_panadapterA->setSecondaryPassbandColor(vfoBPassbandAlpha);
m_panadapterA->setSecondaryMarkerColor(QColor(K4Styles::Colors::VfoBGreen));
m_panadapterA->setSecondaryVisible(true);
- layout->addWidget(m_panadapterA);
+ // Thin border around each panadapter so both panes are clearly visible in
+ // dual (A+B) mode, matching the radio's outlined panes.
+ m_panAFrame = new QFrame(m_spectrumContainer);
+ m_panAFrame->setObjectName("panFrameA");
+ m_panAFrame->setStyleSheet(QStringLiteral("#panFrameA { border: 1px solid #A0A0A0; }"));
+ {
+ auto *frameLayout = new QVBoxLayout(m_panAFrame);
+ frameLayout->setContentsMargins(1, 1, 1, 1);
+ frameLayout->addWidget(m_panadapterA);
+ }
+ layout->addWidget(m_panAFrame);
// Sub panadapter for VFO B (right side) - QRhiWidget with Metal/DirectX/Vulkan
m_panadapterB = new PanadapterRhiWidget(m_spectrumContainer);
@@ -4731,8 +4989,16 @@ void MainWindow::setupSpectrumPlaceholder(QWidget *parent) {
m_panadapterB->setSecondaryPassbandColor(vfoAPassbandAlpha);
m_panadapterB->setSecondaryMarkerColor(QColor(K4Styles::Colors::VfoACyan));
m_panadapterB->setSecondaryVisible(true);
- layout->addWidget(m_panadapterB);
- m_panadapterB->hide(); // Start hidden (MainOnly mode)
+ m_panBFrame = new QFrame(m_spectrumContainer);
+ m_panBFrame->setObjectName("panFrameB");
+ m_panBFrame->setStyleSheet(QStringLiteral("#panFrameB { border: 1px solid #A0A0A0; }"));
+ {
+ auto *frameLayout = new QVBoxLayout(m_panBFrame);
+ frameLayout->setContentsMargins(1, 1, 1, 1);
+ frameLayout->addWidget(m_panadapterB);
+ }
+ layout->addWidget(m_panBFrame);
+ m_panBFrame->hide(); // Start hidden (MainOnly mode)
// Span control buttons - overlay on panadapter (lower right, above freq labels)
// Note: rgba used intentionally for transparent overlay effect on spectrum
@@ -5606,9 +5872,33 @@ void MainWindow::onBandwidthBChanged(int bw) {
// Could update a bandwidth display if needed
}
+#if defined(Q_OS_ANDROID)
+#include
+// Toggle FLAG_KEEP_SCREEN_ON (WindowManager.LayoutParams = 128) on the activity
+// window so the tablet stays awake while connected to the radio, and may sleep
+// normally once disconnected.
+static void androidSetKeepScreenOn(bool on) {
+ QNativeInterface::QAndroidApplication::runOnAndroidMainThread([on]() {
+ QJniObject activity = QNativeInterface::QAndroidApplication::context();
+ if (!activity.isValid())
+ return;
+ QJniObject win = activity.callObjectMethod("getWindow", "()Landroid/view/Window;");
+ if (!win.isValid())
+ return;
+ if (on)
+ win.callMethod("addFlags", "(I)V", 128);
+ else
+ win.callMethod("clearFlags", "(I)V", 128);
+ });
+}
+#endif
+
void MainWindow::updateConnectionState(TcpClient::ConnectionState state) {
switch (state) {
case TcpClient::Disconnected:
+#if defined(Q_OS_ANDROID)
+ androidSetKeepScreenOn(false); // allow sleep once disconnected
+#endif
// Clear the local TX gate on every disconnect, including unexpected
// radio/network closure. Never leave the next connection latched TX.
m_pttActive = false;
@@ -5733,6 +6023,24 @@ void MainWindow::updateConnectionState(TcpClient::ConnectionState state) {
m_vfoRow->setLockA(false);
m_vfoRow->setLockB(false);
+ // SUB / DIVERSITY indicators back to inactive (they otherwise keep the
+ // green state from the last connection after a disconnect).
+ if (m_rightSidePanel) {
+ m_rightSidePanel->setSubActive(false);
+ m_rightSidePanel->setDiversityActive(false);
+ m_rightSidePanel->setBSetActive(false);
+ }
+ {
+ const QString subDivOffStyle = QString("background-color: %1; color: %2; font-size: 9px;"
+ "font-weight: bold; border-radius: 2px;")
+ .arg(K4Styles::Colors::DisabledBackground,
+ K4Styles::Colors::LightGradientTop);
+ if (m_subLabel)
+ m_subLabel->setStyleSheet(subDivOffStyle);
+ if (m_divLabel)
+ m_divLabel->setStyleSheet(subDivOffStyle);
+ }
+
// Side control panel values
m_sideControlPanel->setBandwidth(0);
m_sideControlPanel->setShift(0);
@@ -5811,6 +6119,9 @@ void MainWindow::updateConnectionState(TcpClient::ConnectionState state) {
m_connectionStatusLabel->setText("K4 OK");
m_connectionStatusLabel->setStyleSheet(
QString("color: %1; font-size: 12px; font-weight: bold;").arg(K4Styles::Colors::StatusGreen));
+#if defined(Q_OS_ANDROID)
+ androidSetKeepScreenOn(true); // stay awake while connected
+#endif
break;
}
}
@@ -5983,7 +6294,7 @@ void MainWindow::onQskEnabledChanged(bool enabled) {
// QSK indicator: white when enabled, grey when disabled
if (enabled) {
m_qskLabel->setStyleSheet(
- QString("color: %1; font-size: 11px; font-weight: bold;").arg(K4Styles::Colors::TextWhite));
+ QString("color: %1; font-size: 11px; font-weight: bold;").arg(K4Styles::Colors::AccentAmber));
} else {
m_qskLabel->setStyleSheet(
QString("color: %1; font-size: 11px; font-weight: bold;").arg(K4Styles::Colors::TextGray));
@@ -6275,10 +6586,19 @@ void MainWindow::showRitXitAdjustment(bool preferXit) {
K4Styles::Colors::InactiveGray));
layout->addWidget(offsetValue);
+ // Slider for coarse offset (drag the handle); the -/+ buttons below give
+ // fine 10 Hz steps. Range is the K4's +/-9.99 kHz RIT/XIT span.
+ auto *offsetSlider = new TouchSlider(Qt::Horizontal, panel);
+ offsetSlider->setRange(-9990, 9990);
+ offsetSlider->setSingleStep(10);
+ offsetSlider->setPageStep(100);
+ offsetSlider->setMinimumHeight(40);
+ layout->addWidget(offsetSlider);
+
auto usesBRegister = [this, &adjustXit]() {
return adjustXit ? m_radioState->splitEnabled() : m_radioState->bSetEnabled();
};
- auto refreshTarget = [this, &adjustXit, ritTarget, xitTarget, targetDescription, offsetValue,
+ auto refreshTarget = [this, &adjustXit, ritTarget, xitTarget, targetDescription, offsetValue, offsetSlider,
&usesBRegister]() {
ritTarget->setChecked(!adjustXit);
xitTarget->setChecked(adjustXit);
@@ -6291,6 +6611,9 @@ void MainWindow::showRitXitAdjustment(bool preferXit) {
offsetValue->setText(QString("%1%2 kHz")
.arg(offset >= 0 ? "+" : "")
.arg(offset / 1000.0, 0, 'f', 2));
+ offsetSlider->blockSignals(true);
+ offsetSlider->setValue(qBound(offsetSlider->minimum(), offset, offsetSlider->maximum()));
+ offsetSlider->blockSignals(false);
};
connect(ritTarget, &QPushButton::clicked, &dialog, [&adjustXit, &refreshTarget]() {
adjustXit = false;
@@ -6348,6 +6671,18 @@ void MainWindow::showRitXitAdjustment(bool preferXit) {
connect(down, &QPushButton::clicked, &dialog, [&sendJog]() { sendJog(false); });
connect(up, &QPushButton::clicked, &dialog, [&sendJog]() { sendJog(true); });
+ // Slider sets the offset absolutely on the selected register (10 Hz grid).
+ connect(offsetSlider, &QSlider::valueChanged, &dialog, [this, &usesBRegister](int value) {
+ const int v = (value / 10) * 10;
+ const bool registerB = usesBRegister();
+ const QString cmd = QString("%1%2%3;")
+ .arg(registerB ? "RO$" : "RO")
+ .arg(v >= 0 ? "+" : "-")
+ .arg(qAbs(v), 4, 10, QChar('0'));
+ m_tcpClient->sendCAT(cmd);
+ m_radioState->parseCATCommand(cmd);
+ });
+
auto querySelectedOffset = [this, &usesBRegister]() {
m_tcpClient->sendCAT(usesBRegister() ? "RO$;" : "RO;");
};
@@ -6732,7 +7067,7 @@ void MainWindow::onPttPressed() {
return;
}
-#ifdef Q_OS_ANDROID
+#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
if (!ensureMicrophonePermission(this)) {
return;
}
@@ -6889,6 +7224,21 @@ bool MainWindow::eventFilter(QObject *watched, QEvent *event) {
// short tap toggles while a long press opens the offset jog control.
if (watched == m_ritXitBox || watched == m_ritLabel || watched == m_xitLabel
|| watched == m_ritXitValueLabel) {
+ // iPad (touch, no wheel): tap the box to open the offset adjuster.
+ // RIT/XIT on/off toggling lives on the right panel's RIT/XIT buttons.
+ if (!K4Styles::isCompactLayout() && event->type() == QEvent::MouseButtonPress) {
+ auto *mouseEvent = static_cast(event);
+ if (mouseEvent->button() == Qt::LeftButton) {
+ const bool ritActive =
+ m_radioState->bSetEnabled() ? m_radioState->ritEnabledB() : m_radioState->ritEnabled();
+ const bool preferXit = (watched == m_xitLabel) || (m_radioState->xitEnabled() && !ritActive);
+ if ((preferXit && m_radioState->xitEnabled()) || (!preferXit && ritActive))
+ showRitXitAdjustment(preferXit);
+ else
+ showControlFeedback("Enable RIT or XIT before adjusting");
+ return true;
+ }
+ }
if (K4Styles::isCompactLayout() && event->type() == QEvent::MouseButtonPress) {
auto *mouseEvent = static_cast(event);
if (mouseEvent->button() == Qt::LeftButton) {
@@ -7014,18 +7364,19 @@ void MainWindow::keyPressEvent(QKeyEvent *event) {
void MainWindow::setPanadapterMode(PanadapterMode mode) {
m_panadapterMode = mode;
+ // Show/hide the bordered frames (the panadapters stay shown inside them).
switch (mode) {
case PanadapterMode::MainOnly:
- m_panadapterA->show();
- m_panadapterB->hide();
+ m_panAFrame->show();
+ m_panBFrame->hide();
break;
case PanadapterMode::Dual:
- m_panadapterA->show();
- m_panadapterB->show();
+ m_panAFrame->show();
+ m_panBFrame->show();
break;
case PanadapterMode::SubOnly:
- m_panadapterA->hide();
- m_panadapterB->show();
+ m_panAFrame->hide();
+ m_panBFrame->show();
break;
}
}
diff --git a/src/mainwindow.h b/src/mainwindow.h
index 0d94e02..26f9006 100644
--- a/src/mainwindow.h
+++ b/src/mainwindow.h
@@ -333,6 +333,8 @@ private slots:
// Spectrum/Waterfall displays (QRhiWidget - Metal/DirectX/Vulkan)
PanadapterRhiWidget *m_panadapterA; // VFO A (Main RX)
PanadapterRhiWidget *m_panadapterB; // VFO B (Sub RX) - for future use
+ QWidget *m_panAFrame = nullptr; // thin bordered wrapper around panadapter A
+ QWidget *m_panBFrame = nullptr; // thin bordered wrapper around panadapter B
QWidget *m_spectrumContainer;
// Span control buttons (overlay on panadapter A)
diff --git a/src/network/psktlssocket.h b/src/network/psktlssocket.h
new file mode 100644
index 0000000..7bc0f32
--- /dev/null
+++ b/src/network/psktlssocket.h
@@ -0,0 +1,97 @@
+#ifndef PSKTLSSOCKET_H
+#define PSKTLSSOCKET_H
+
+#include
+#include
+#include
+#include
+#include
+
+class QTcpSocket;
+class QSslSocket;
+#ifdef QK4_PSK_TLS_OPENSSL
+struct ssl_ctx_st;
+struct ssl_st;
+struct bio_st;
+#endif
+
+// TLS-PSK client socket for the K4 remote link.
+//
+// The K4 authenticates remote clients with TLS 1.2 pre-shared keys. Qt's
+// native TLS backends (Secure Transport on iOS/macOS, Schannel on Windows)
+// have no PSK support, so QSslSocket only works where Qt's OpenSSL backend
+// plus an OpenSSL runtime are available. This class hides that difference:
+//
+// - QK4_PSK_TLS_OPENSSL: drives OpenSSL directly over a QTcpSocket using
+// memory BIOs. Used on iOS, where OpenSSL is linked statically and Qt
+// does not ship its OpenSSL TLS plugin.
+// - otherwise: thin adapter over QSslSocket (Android, Windows, macOS, Linux).
+//
+// Plain (unencrypted) connections pass straight through to the TCP socket.
+class PskTlsSocket : public QIODevice {
+ Q_OBJECT
+
+public:
+ explicit PskTlsSocket(QObject *parent = nullptr);
+ ~PskTlsSocket() override;
+
+ static bool tlsAvailable();
+ static QString tlsLibraryVersion();
+
+ void setPreSharedKey(const QByteArray &identity, const QByteArray &psk);
+
+ void connectToHost(const QString &host, quint16 port);
+ void connectToHostEncrypted(const QString &host, quint16 port);
+ void disconnectFromHost();
+ void abort();
+ bool flush();
+ void setSocketOption(QAbstractSocket::SocketOption option, const QVariant &value);
+
+ QAbstractSocket::SocketState state() const;
+ bool isEncrypted() const;
+ QString sessionCipher() const;
+
+ bool isSequential() const override { return true; }
+ qint64 bytesAvailable() const override;
+ qint64 bytesToWrite() const override;
+
+signals:
+ void connected();
+ void encrypted();
+ void disconnected();
+ void errorOccurred(QAbstractSocket::SocketError error);
+
+protected:
+ qint64 readData(char *data, qint64 maxSize) override;
+ qint64 writeData(const char *data, qint64 size) override;
+
+private:
+ QByteArray m_identity;
+ QByteArray m_psk;
+ bool m_useTls = false;
+
+#ifdef QK4_PSK_TLS_OPENSSL
+ void onTcpConnected();
+ void onTcpReadyRead();
+ void onTcpDisconnected();
+ void onTcpError(QAbstractSocket::SocketError error);
+ bool pumpTls();
+ void flushOutgoing();
+ void failTls(const QString &what);
+ void teardownTls();
+ static unsigned int pskClientCallback(ssl_st *ssl, const char *hint, char *identity, unsigned int maxIdentityLen,
+ unsigned char *psk, unsigned int maxPskLen);
+
+ QTcpSocket *m_tcp = nullptr;
+ ssl_ctx_st *m_ctx = nullptr;
+ ssl_st *m_ssl = nullptr;
+ bio_st *m_readBio = nullptr; // ciphertext from the radio, fed to OpenSSL
+ bio_st *m_writeBio = nullptr; // ciphertext from OpenSSL, sent to the radio
+ bool m_handshakeDone = false;
+ QByteArray m_plaintext; // decrypted bytes not yet read by the caller
+#else
+ QSslSocket *m_qssl = nullptr;
+#endif
+};
+
+#endif // PSKTLSSOCKET_H
diff --git a/src/network/psktlssocket_openssl.cpp b/src/network/psktlssocket_openssl.cpp
new file mode 100644
index 0000000..6e3ef0c
--- /dev/null
+++ b/src/network/psktlssocket_openssl.cpp
@@ -0,0 +1,341 @@
+// PskTlsSocket backend that drives OpenSSL directly over a QTcpSocket.
+//
+// OpenSSL never touches the network here: it reads ciphertext from a memory
+// BIO that we fill from the TCP socket, and writes ciphertext into a second
+// memory BIO that we drain into the TCP socket. All work happens on the
+// socket's thread, so no locking is needed.
+#include "psktlssocket.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace {
+QString drainOpenSslErrors() {
+ QString text;
+ unsigned long code;
+ const char *file = nullptr;
+ const char *func = nullptr;
+ const char *data = nullptr;
+ int line = 0;
+ int flags = 0;
+ while ((code = ERR_get_error_all(&file, &line, &func, &data, &flags)) != 0) {
+ char buf[256];
+ ERR_error_string_n(code, buf, sizeof buf);
+ if (!text.isEmpty())
+ text += QLatin1String("; ");
+ text += QString::fromLatin1(buf);
+ if (file)
+ text += QStringLiteral(" [%1:%2 %3]").arg(QString::fromLatin1(file)).arg(line).arg(QString::fromLatin1(func ? func : ""));
+ if (data && (flags & ERR_TXT_STRING) && *data)
+ text += QStringLiteral(" (%1)").arg(QString::fromLatin1(data));
+ }
+ return text;
+}
+} // namespace
+
+PskTlsSocket::PskTlsSocket(QObject *parent) : QIODevice(parent), m_tcp(new QTcpSocket(this)) {
+ connect(m_tcp, &QTcpSocket::connected, this, &PskTlsSocket::onTcpConnected);
+ connect(m_tcp, &QTcpSocket::readyRead, this, &PskTlsSocket::onTcpReadyRead);
+ connect(m_tcp, &QTcpSocket::disconnected, this, &PskTlsSocket::onTcpDisconnected);
+ connect(m_tcp, &QTcpSocket::errorOccurred, this, &PskTlsSocket::onTcpError);
+}
+
+PskTlsSocket::~PskTlsSocket() {
+ teardownTls();
+}
+
+bool PskTlsSocket::tlsAvailable() {
+ return true;
+}
+
+QString PskTlsSocket::tlsLibraryVersion() {
+ return QString::fromLatin1(OpenSSL_version(OPENSSL_VERSION));
+}
+
+void PskTlsSocket::setPreSharedKey(const QByteArray &identity, const QByteArray &psk) {
+ m_identity = identity;
+ m_psk = psk;
+}
+
+void PskTlsSocket::connectToHost(const QString &host, quint16 port) {
+ teardownTls();
+ m_useTls = false;
+ m_plaintext.clear();
+ m_tcp->connectToHost(host, port);
+}
+
+void PskTlsSocket::connectToHostEncrypted(const QString &host, quint16 port) {
+ teardownTls();
+ m_useTls = true;
+ m_plaintext.clear();
+
+ m_ctx = SSL_CTX_new(TLS_client_method());
+ if (!m_ctx) {
+ failTls(QStringLiteral("SSL_CTX_new"));
+ return;
+ }
+ // The K4 speaks TLS 1.2 with PSK cipher suites. Pin exactly that: with
+ // TLS 1.3 enabled, OpenSSL 3 fails inside tls_construct_ctos_early_data
+ // ("internal error") when the key comes from the legacy
+ // psk_client_callback, so the ClientHello never leaves the device.
+ SSL_CTX_set_min_proto_version(m_ctx, TLS1_2_VERSION);
+ SSL_CTX_set_max_proto_version(m_ctx, TLS1_2_VERSION);
+ SSL_CTX_set_verify(m_ctx, SSL_VERIFY_NONE, nullptr); // PSK: no certificates
+ if (SSL_CTX_set_cipher_list(m_ctx, "PSK") != 1) {
+ failTls(QStringLiteral("no PSK cipher suites available"));
+ return;
+ }
+ SSL_CTX_set_mode(m_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_AUTO_RETRY);
+ SSL_CTX_set_psk_client_callback(m_ctx, &PskTlsSocket::pskClientCallback);
+
+ m_ssl = SSL_new(m_ctx);
+ m_readBio = BIO_new(BIO_s_mem());
+ m_writeBio = BIO_new(BIO_s_mem());
+ if (!m_ssl || !m_readBio || !m_writeBio) {
+ failTls(QStringLiteral("SSL_new"));
+ return;
+ }
+ // An empty memory BIO must report "retry", not end-of-stream, so the
+ // handshake and reads simply wait for more bytes from the socket.
+ BIO_set_mem_eof_return(m_readBio, -1);
+ BIO_set_mem_eof_return(m_writeBio, -1);
+ SSL_set_bio(m_ssl, m_readBio, m_writeBio); // SSL now owns both BIOs
+ SSL_set_app_data(m_ssl, this);
+ SSL_set_connect_state(m_ssl);
+ m_handshakeDone = false;
+
+ m_tcp->connectToHost(host, port);
+}
+
+void PskTlsSocket::disconnectFromHost() {
+ if (m_useTls && m_ssl && m_handshakeDone) {
+ SSL_shutdown(m_ssl); // best-effort close_notify
+ flushOutgoing();
+ }
+ m_tcp->disconnectFromHost();
+}
+
+void PskTlsSocket::abort() {
+ m_tcp->abort();
+ teardownTls();
+}
+
+bool PskTlsSocket::flush() {
+ return m_tcp->flush();
+}
+
+void PskTlsSocket::setSocketOption(QAbstractSocket::SocketOption option, const QVariant &value) {
+ m_tcp->setSocketOption(option, value);
+}
+
+QAbstractSocket::SocketState PskTlsSocket::state() const {
+ return m_tcp->state();
+}
+
+bool PskTlsSocket::isEncrypted() const {
+ return m_useTls && m_handshakeDone;
+}
+
+QString PskTlsSocket::sessionCipher() const {
+ if (!isEncrypted() || !m_ssl)
+ return QString();
+ return QStringLiteral("%1 (%2)").arg(QString::fromLatin1(SSL_get_cipher_name(m_ssl)),
+ QString::fromLatin1(SSL_get_version(m_ssl)));
+}
+
+qint64 PskTlsSocket::bytesAvailable() const {
+ const qint64 pending = m_useTls ? m_plaintext.size() : m_tcp->bytesAvailable();
+ return pending + QIODevice::bytesAvailable();
+}
+
+qint64 PskTlsSocket::bytesToWrite() const {
+ return m_tcp->bytesToWrite();
+}
+
+qint64 PskTlsSocket::readData(char *data, qint64 maxSize) {
+ if (!m_useTls)
+ return m_tcp->read(data, maxSize);
+ const qint64 n = qMin(maxSize, m_plaintext.size());
+ if (n > 0) {
+ std::memcpy(data, m_plaintext.constData(), size_t(n));
+ m_plaintext.remove(0, int(n));
+ }
+ return n;
+}
+
+qint64 PskTlsSocket::writeData(const char *data, qint64 size) {
+ if (!m_useTls)
+ return m_tcp->write(data, size);
+ if (!m_ssl || !m_handshakeDone)
+ return -1;
+ qint64 total = 0;
+ while (total < size) {
+ const int chunk = int(qMin(size - total, INT_MAX));
+ const int n = SSL_write(m_ssl, data + total, chunk);
+ if (n <= 0) {
+ failTls(QStringLiteral("SSL_write"));
+ return -1;
+ }
+ total += n;
+ }
+ flushOutgoing();
+ return total;
+}
+
+void PskTlsSocket::onTcpConnected() {
+ // Plain connections are writable from inside the connected() slot
+ // (TcpClient sends the auth hash there), so open before emitting.
+ if (!m_useTls)
+ open(QIODevice::ReadWrite | QIODevice::Unbuffered);
+ emit connected();
+ if (m_useTls)
+ pumpTls(); // sends ClientHello
+}
+
+void PskTlsSocket::onTcpReadyRead() {
+ if (!m_useTls) {
+ emit readyRead();
+ return;
+ }
+ if (!m_ssl)
+ return;
+ const QByteArray ciphertext = m_tcp->readAll();
+ int offset = 0;
+ while (offset < ciphertext.size()) {
+ const int n = BIO_write(m_readBio, ciphertext.constData() + offset, ciphertext.size() - offset);
+ if (n <= 0) {
+ failTls(QStringLiteral("BIO_write"));
+ return;
+ }
+ offset += n;
+ }
+ pumpTls();
+}
+
+void PskTlsSocket::onTcpDisconnected() {
+ close();
+ teardownTls();
+ m_plaintext.clear();
+ emit disconnected();
+}
+
+void PskTlsSocket::onTcpError(QAbstractSocket::SocketError error) {
+ setErrorString(m_tcp->errorString());
+ emit errorOccurred(error);
+}
+
+// Advance the handshake and/or decrypt whatever the read BIO holds.
+// Returns false when the TLS session failed and has been torn down.
+bool PskTlsSocket::pumpTls() {
+ if (!m_ssl)
+ return false;
+
+ if (!m_handshakeDone) {
+ const int r = SSL_do_handshake(m_ssl);
+ const size_t pendingOut = BIO_ctrl_pending(m_writeBio);
+ flushOutgoing();
+ if (r != 1) {
+ const int err = SSL_get_error(m_ssl, r);
+ qDebug() << "TLS handshake step: rc" << r << "ssl_error" << err << "wrote" << pendingOut
+ << "bytes, state" << SSL_state_string_long(m_ssl);
+ if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE)
+ return true; // need more bytes from the radio
+ failTls(QStringLiteral("handshake"));
+ return false;
+ }
+ m_handshakeDone = true;
+ open(QIODevice::ReadWrite | QIODevice::Unbuffered);
+ emit encrypted();
+ if (!m_ssl)
+ return false; // slot disconnected us
+ }
+
+ bool gotData = false;
+ for (;;) {
+ char buf[16384];
+ const int n = SSL_read(m_ssl, buf, sizeof buf);
+ if (n > 0) {
+ m_plaintext.append(buf, n);
+ gotData = true;
+ continue;
+ }
+ const int err = SSL_get_error(m_ssl, n);
+ if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE)
+ break;
+ if (err == SSL_ERROR_ZERO_RETURN) {
+ // Peer sent close_notify: let the TCP teardown deliver disconnected().
+ m_tcp->disconnectFromHost();
+ break;
+ }
+ failTls(QStringLiteral("SSL_read"));
+ return false;
+ }
+ flushOutgoing();
+ if (gotData)
+ emit readyRead();
+ return true;
+}
+
+void PskTlsSocket::flushOutgoing() {
+ if (!m_writeBio)
+ return;
+ while (BIO_ctrl_pending(m_writeBio) > 0) {
+ char buf[16384];
+ const int n = BIO_read(m_writeBio, buf, sizeof buf);
+ if (n <= 0)
+ break;
+ m_tcp->write(buf, n);
+ }
+}
+
+void PskTlsSocket::failTls(const QString &what) {
+ QString detail = drainOpenSslErrors();
+ if (detail.isEmpty())
+ detail = QStringLiteral("no further detail");
+ const QString message = QStringLiteral("TLS/PSK failure (%1): %2").arg(what, detail);
+ qWarning() << message;
+ setErrorString(message);
+ teardownTls();
+ emit errorOccurred(QAbstractSocket::SslHandshakeFailedError);
+ m_tcp->abort();
+}
+
+void PskTlsSocket::teardownTls() {
+ if (m_ssl) {
+ SSL_free(m_ssl); // frees the BIOs handed over by SSL_set_bio
+ m_ssl = nullptr;
+ m_readBio = nullptr;
+ m_writeBio = nullptr;
+ } else {
+ BIO_free(m_readBio);
+ BIO_free(m_writeBio);
+ m_readBio = nullptr;
+ m_writeBio = nullptr;
+ }
+ if (m_ctx) {
+ SSL_CTX_free(m_ctx);
+ m_ctx = nullptr;
+ }
+ m_handshakeDone = false;
+}
+
+unsigned int PskTlsSocket::pskClientCallback(ssl_st *ssl, const char *hint, char *identity, unsigned int maxIdentityLen,
+ unsigned char *psk, unsigned int maxPskLen) {
+ Q_UNUSED(hint)
+ auto *self = static_cast(SSL_get_app_data(ssl));
+ if (!self || self->m_psk.isEmpty())
+ return 0;
+ const unsigned int identityLen = unsigned(self->m_identity.size());
+ const unsigned int pskLen = unsigned(self->m_psk.size());
+ if (identityLen >= maxIdentityLen || pskLen > maxPskLen)
+ return 0;
+ std::memcpy(identity, self->m_identity.constData(), identityLen);
+ identity[identityLen] = '\0';
+ std::memcpy(psk, self->m_psk.constData(), pskLen);
+ return pskLen;
+}
diff --git a/src/network/psktlssocket_qssl.cpp b/src/network/psktlssocket_qssl.cpp
new file mode 100644
index 0000000..058c554
--- /dev/null
+++ b/src/network/psktlssocket_qssl.cpp
@@ -0,0 +1,137 @@
+// PskTlsSocket backend that adapts QSslSocket. This is the original QK4
+// TLS/PSK path and needs Qt's OpenSSL TLS plugin plus an OpenSSL runtime.
+#include "psktlssocket.h"
+
+#include
+#include
+#include
+#include
+#include
+
+PskTlsSocket::PskTlsSocket(QObject *parent) : QIODevice(parent), m_qssl(new QSslSocket(this)) {
+ connect(m_qssl, &QSslSocket::connected, this, [this]() {
+ if (!m_useTls)
+ open(QIODevice::ReadWrite | QIODevice::Unbuffered);
+ emit connected();
+ });
+ connect(m_qssl, &QSslSocket::encrypted, this, [this]() {
+ open(QIODevice::ReadWrite | QIODevice::Unbuffered);
+ emit encrypted();
+ });
+ connect(m_qssl, &QSslSocket::disconnected, this, [this]() {
+ close();
+ emit disconnected();
+ });
+ connect(m_qssl, &QSslSocket::readyRead, this, &PskTlsSocket::readyRead);
+ connect(m_qssl, &QSslSocket::errorOccurred, this, [this](QAbstractSocket::SocketError error) {
+ setErrorString(m_qssl->errorString());
+ emit errorOccurred(error);
+ });
+ connect(m_qssl, &QSslSocket::sslErrors, this, [this](const QList &errors) {
+ // PSK doesn't use certificates, so certificate errors are expected.
+ for (const QSslError &error : errors)
+ qDebug() << "SSL error (ignored for PSK):" << error.errorString();
+ m_qssl->ignoreSslErrors();
+ });
+ connect(m_qssl, &QSslSocket::preSharedKeyAuthenticationRequired, this,
+ [this](QSslPreSharedKeyAuthenticator *authenticator) {
+ qDebug() << "PSK authentication requested, identity hint:" << authenticator->identityHint();
+ authenticator->setIdentity(m_identity);
+ authenticator->setPreSharedKey(m_psk);
+ });
+}
+
+PskTlsSocket::~PskTlsSocket() = default;
+
+bool PskTlsSocket::tlsAvailable() {
+ return QSslSocket::supportsSsl();
+}
+
+QString PskTlsSocket::tlsLibraryVersion() {
+ return QStringLiteral("%1 (built against %2)")
+ .arg(QSslSocket::sslLibraryVersionString(), QSslSocket::sslLibraryBuildVersionString());
+}
+
+void PskTlsSocket::setPreSharedKey(const QByteArray &identity, const QByteArray &psk) {
+ m_identity = identity;
+ m_psk = psk;
+}
+
+void PskTlsSocket::connectToHost(const QString &host, quint16 port) {
+ m_useTls = false;
+ m_qssl->connectToHost(host, port);
+}
+
+void PskTlsSocket::connectToHostEncrypted(const QString &host, quint16 port) {
+ m_useTls = true;
+
+ // Configure TLS for PSK authentication - require TLS 1.2 minimum
+ QSslConfiguration sslConfig = QSslConfiguration::defaultConfiguration();
+ sslConfig.setProtocol(QSsl::TlsV1_2OrLater);
+ sslConfig.setPeerVerifyMode(QSslSocket::VerifyNone); // PSK doesn't use certificates
+
+ // Filter to only TLS 1.2+ PSK ciphers
+ QList tls12PskCiphers;
+ for (const QSslCipher &cipher : QSslConfiguration::supportedCiphers()) {
+ if (cipher.name().contains("PSK")
+ && (cipher.protocol() == QSsl::TlsV1_2 || cipher.protocol() == QSsl::TlsV1_3)) {
+ tls12PskCiphers.append(cipher);
+ }
+ }
+ qDebug() << "=== Offering" << tls12PskCiphers.size() << "TLS 1.2+ PSK ciphers ===";
+ for (const QSslCipher &cipher : tls12PskCiphers)
+ qDebug() << " " << cipher.name() << "(" << cipher.protocolString() << ")";
+ if (!tls12PskCiphers.isEmpty())
+ sslConfig.setCiphers(tls12PskCiphers);
+
+ m_qssl->setSslConfiguration(sslConfig);
+ m_qssl->connectToHostEncrypted(host, port);
+}
+
+void PskTlsSocket::disconnectFromHost() {
+ m_qssl->disconnectFromHost();
+}
+
+void PskTlsSocket::abort() {
+ m_qssl->abort();
+}
+
+bool PskTlsSocket::flush() {
+ return m_qssl->flush();
+}
+
+void PskTlsSocket::setSocketOption(QAbstractSocket::SocketOption option, const QVariant &value) {
+ m_qssl->setSocketOption(option, value);
+}
+
+QAbstractSocket::SocketState PskTlsSocket::state() const {
+ return m_qssl->state();
+}
+
+bool PskTlsSocket::isEncrypted() const {
+ return m_qssl->isEncrypted();
+}
+
+QString PskTlsSocket::sessionCipher() const {
+ const QSslCipher cipher = m_qssl->sessionCipher();
+ if (cipher.isNull())
+ return QString();
+ return QStringLiteral("%1 (%2, kx %3, enc %4)")
+ .arg(cipher.name(), cipher.protocolString(), cipher.keyExchangeMethod(), cipher.encryptionMethod());
+}
+
+qint64 PskTlsSocket::bytesAvailable() const {
+ return m_qssl->bytesAvailable() + QIODevice::bytesAvailable();
+}
+
+qint64 PskTlsSocket::bytesToWrite() const {
+ return m_qssl->bytesToWrite();
+}
+
+qint64 PskTlsSocket::readData(char *data, qint64 maxSize) {
+ return m_qssl->read(data, maxSize);
+}
+
+qint64 PskTlsSocket::writeData(const char *data, qint64 size) {
+ return m_qssl->write(data, size);
+}
diff --git a/src/network/tcpclient.cpp b/src/network/tcpclient.cpp
index 1c3556c..4cb454a 100644
--- a/src/network/tcpclient.cpp
+++ b/src/network/tcpclient.cpp
@@ -2,29 +2,20 @@
#include
#include
#include
-#include
-#include
-#include
-#include
#include
#include
TcpClient::TcpClient(QObject *parent)
- : QObject(parent), m_socket(new QSslSocket(this)), m_protocol(new Protocol(this)), m_connectTimer(new QTimer(this)),
+ : QObject(parent), m_socket(new PskTlsSocket(this)), m_protocol(new Protocol(this)), m_connectTimer(new QTimer(this)),
m_authTimer(new QTimer(this)),
m_pingTimer(new QTimer(this)), m_port(K4Protocol::DEFAULT_PORT), m_useTls(false), m_encodeMode(3),
m_streamingLatency(3), m_authResponseReceived(false) {
// Socket signals
- connect(m_socket, &QSslSocket::connected, this, &TcpClient::onSocketConnected);
- connect(m_socket, &QSslSocket::encrypted, this, &TcpClient::onSocketEncrypted);
- connect(m_socket, &QSslSocket::disconnected, this, &TcpClient::onSocketDisconnected);
- connect(m_socket, &QSslSocket::readyRead, this, &TcpClient::onReadyRead);
- connect(m_socket, &QSslSocket::errorOccurred, this, &TcpClient::onSocketError);
-
- // SSL-specific signals
- connect(m_socket, &QSslSocket::sslErrors, this, &TcpClient::onSslErrors);
- connect(m_socket, &QSslSocket::preSharedKeyAuthenticationRequired, this,
- &TcpClient::onPreSharedKeyAuthenticationRequired);
+ connect(m_socket, &PskTlsSocket::connected, this, &TcpClient::onSocketConnected);
+ connect(m_socket, &PskTlsSocket::encrypted, this, &TcpClient::onSocketEncrypted);
+ connect(m_socket, &PskTlsSocket::disconnected, this, &TcpClient::onSocketDisconnected);
+ connect(m_socket, &PskTlsSocket::readyRead, this, &TcpClient::onReadyRead);
+ connect(m_socket, &PskTlsSocket::errorOccurred, this, &TcpClient::onSocketError);
// Connect timeout timer (single shot) - covers TCP/TLS handshake phase
m_connectTimer->setSingleShot(true);
@@ -141,51 +132,18 @@ void TcpClient::connectToHost(const QString &host, quint16 port, const QString &
void TcpClient::attemptConnection() {
if (m_useTls) {
- // On Android the TLS backend is present in Qt, but OpenSSL itself is a
- // separately bundled runtime. Fail before opening the K4 socket if
- // that runtime could not be loaded, rather than reporting the opaque
- // TLSInitializationFailedError from QSslSocket.
- if (!QSslSocket::supportsSsl()) {
+ // Fail before opening the K4 socket if no PSK-capable TLS backend is
+ // available, rather than reporting an opaque socket error later.
+ if (!PskTlsSocket::tlsAvailable()) {
m_connectTimer->stop();
emit errorOccurred(QStringLiteral("TLS is unavailable: the OpenSSL runtime could not be loaded."));
setState(Disconnected);
return;
}
-
- // Log OpenSSL version Qt is using
- qDebug() << "=== SSL Library Info ===";
- qDebug() << " Build version:" << QSslSocket::sslLibraryBuildVersionString();
- qDebug() << " Runtime version:" << QSslSocket::sslLibraryVersionString();
- qDebug() << " Supports SSL:" << QSslSocket::supportsSsl();
-
- // Configure TLS for PSK authentication - require TLS 1.2 minimum
- QSslConfiguration sslConfig = QSslConfiguration::defaultConfiguration();
- sslConfig.setProtocol(QSsl::TlsV1_2OrLater);
- sslConfig.setPeerVerifyMode(QSslSocket::VerifyNone); // PSK doesn't use certificates
-
- // Filter to only TLS 1.2+ PSK ciphers
- QList tls12PskCiphers;
- qDebug() << "=== Available PSK Ciphers ===";
- for (const QSslCipher &cipher : QSslConfiguration::supportedCiphers()) {
- if (cipher.name().contains("PSK")) {
- qDebug() << " " << cipher.name() << "(" << cipher.protocolString() << ")";
- // Only include TLS 1.2+ ciphers
- if (cipher.protocol() == QSsl::TlsV1_2 || cipher.protocol() == QSsl::TlsV1_3) {
- tls12PskCiphers.append(cipher);
- }
- }
- }
- qDebug() << "=== Offering" << tls12PskCiphers.size() << "TLS 1.2+ PSK ciphers ===";
- for (const QSslCipher &cipher : tls12PskCiphers) {
- qDebug() << " " << cipher.name();
- }
- if (!tls12PskCiphers.isEmpty()) {
- sslConfig.setCiphers(tls12PskCiphers);
- }
-
- m_socket->setSslConfiguration(sslConfig);
-
- qDebug() << "Connecting with TLS/PSK to" << m_host << ":" << m_port;
+ qDebug() << "TLS library:" << PskTlsSocket::tlsLibraryVersion();
+ m_socket->setPreSharedKey(m_identity.toUtf8(), m_password.toUtf8());
+ qDebug() << "Connecting with TLS/PSK to" << m_host << ":" << m_port
+ << "identity:" << (m_identity.isEmpty() ? QStringLiteral("(empty)") : m_identity);
m_socket->connectToHostEncrypted(m_host, m_port);
} else {
qDebug() << "Connecting (unencrypted) to" << m_host << ":" << m_port;
@@ -469,12 +427,8 @@ void TcpClient::onSocketConnected() {
void TcpClient::onSocketEncrypted() {
// TLS handshake completed successfully
- QSslCipher negotiated = m_socket->sessionCipher();
qDebug() << "=== TLS/PSK Connection Established ===";
- qDebug() << " Negotiated cipher:" << negotiated.name();
- qDebug() << " Protocol:" << negotiated.protocolString();
- qDebug() << " Key exchange:" << negotiated.keyExchangeMethod();
- qDebug() << " Encryption:" << negotiated.encryptionMethod();
+ qDebug() << " Negotiated cipher:" << m_socket->sessionCipher();
m_connectTimer->stop();
setState(Authenticating);
// Start auth timeout - waiting for first packet to confirm connection works
@@ -527,25 +481,6 @@ void TcpClient::onConnectTimeout() {
}
}
-void TcpClient::onSslErrors(const QList &errors) {
- // Log SSL errors but continue - PSK doesn't use certificates so some errors are expected
- for (const QSslError &error : errors) {
- qDebug() << "SSL error (ignored for PSK):" << error.errorString();
- }
- // Ignore all SSL errors for PSK connections (no certificate verification)
- m_socket->ignoreSslErrors();
-}
-
-void TcpClient::onPreSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator *authenticator) {
- qDebug() << "PSK authentication requested, identity hint:" << authenticator->identityHint();
-
- // Set the identity (empty or user-specified) and the pre-shared key (password field)
- authenticator->setIdentity(m_identity.toUtf8());
- authenticator->setPreSharedKey(m_password.toUtf8());
-
- qDebug() << "PSK credentials provided, identity:" << (m_identity.isEmpty() ? "(empty)" : m_identity);
-}
-
void TcpClient::onAuthTimeout() {
if (m_state.load(std::memory_order_acquire) == Authenticating && !m_authResponseReceived) {
qDebug() << "Authentication timeout";
diff --git a/src/network/tcpclient.h b/src/network/tcpclient.h
index 9d2755e..f6d57cd 100644
--- a/src/network/tcpclient.h
+++ b/src/network/tcpclient.h
@@ -2,13 +2,14 @@
#define TCPCLIENT_H
#include
-#include
+#include
#include
#include
#include
#include
#include "protocol.h"
#include "audio/digitaltxguard.h"
+#include "psktlssocket.h"
class TcpClient : public QObject {
Q_OBJECT
@@ -80,8 +81,6 @@ private slots:
void onSocketDisconnected();
void onReadyRead();
void onSocketError(QAbstractSocket::SocketError error);
- void onSslErrors(const QList &errors);
- void onPreSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator *authenticator);
void onConnectTimeout();
void onAuthTimeout();
void onPingTimer();
@@ -98,7 +97,7 @@ private slots:
void finishDigitalCalibration(bool success, const QString &text);
void completeDigitalCalibration();
- QSslSocket *m_socket;
+ PskTlsSocket *m_socket;
Protocol *m_protocol;
QTimer *m_connectTimer;
QTimer *m_authTimer;
diff --git a/src/ui/adjustoverlay.cpp b/src/ui/adjustoverlay.cpp
new file mode 100644
index 0000000..88c6bcd
--- /dev/null
+++ b/src/ui/adjustoverlay.cpp
@@ -0,0 +1,186 @@
+#include "adjustoverlay.h"
+#include "k4styles.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+AdjustOverlay::AdjustOverlay(QWidget *parent) : QWidget(parent, Qt::Popup) {
+ setAttribute(Qt::WA_TranslucentBackground);
+ setFixedWidth(240);
+
+ auto *outer = new QVBoxLayout(this);
+ // Leave room for the indicator bar on the left.
+ outer->setContentsMargins(IndicatorBarWidth + 12, 10, 12, 12);
+ outer->setSpacing(8);
+
+ m_titleLabel = new QLabel(this);
+ m_titleLabel->setStyleSheet(
+ QString("color: %1; font-size: 12px; font-weight: bold;").arg(K4Styles::Colors::TextWhite));
+ outer->addWidget(m_titleLabel);
+
+ m_valueLabel = new QLabel(this);
+ m_valueLabel->setAlignment(Qt::AlignCenter);
+ m_valueLabel->setStyleSheet(
+ QString("color: %1; font-size: 22px; font-weight: bold;").arg(K4Styles::Colors::TextWhite));
+ outer->addWidget(m_valueLabel);
+
+ auto *row = new QHBoxLayout();
+ row->setSpacing(10);
+
+ const QString stepBtnStyle =
+ QString("QPushButton { color: %1; background: %2; border: 1px solid %3; border-radius: 6px; "
+ "font-size: 22px; font-weight: bold; } QPushButton:pressed { background: %3; }")
+ .arg(K4Styles::Colors::TextWhite, K4Styles::Colors::DarkBackground, K4Styles::Colors::BorderNormal);
+
+ m_minusBtn = new QPushButton(QStringLiteral("−"), this); // minus sign
+ m_minusBtn->setFixedSize(44, 44);
+ m_minusBtn->setStyleSheet(stepBtnStyle);
+ row->addWidget(m_minusBtn);
+
+ m_slider = new QSlider(Qt::Horizontal, this);
+ m_slider->setMinimumHeight(40);
+ // A raw QSlider treats a touch that lands on the groove as a page-step and
+ // does not track the drag. Map x->value directly instead (the popup is not
+ // inside a scroll area, so there is no scroll-vs-adjust ambiguity).
+ m_slider->installEventFilter(this);
+ row->addWidget(m_slider, 1);
+
+ m_plusBtn = new QPushButton(QStringLiteral("+"), this);
+ m_plusBtn->setFixedSize(44, 44);
+ m_plusBtn->setStyleSheet(stepBtnStyle);
+ row->addWidget(m_plusBtn);
+
+ outer->addLayout(row);
+
+ connect(m_minusBtn, &QPushButton::clicked, this, [this]() {
+ m_slider->setValue(m_slider->value() - m_slider->singleStep());
+ pokeActivity();
+ });
+ connect(m_plusBtn, &QPushButton::clicked, this, [this]() {
+ m_slider->setValue(m_slider->value() + m_slider->singleStep());
+ pokeActivity();
+ });
+ connect(m_slider, &QSlider::valueChanged, this, [this](int value) {
+ m_valueLabel->setText(formatValue(value));
+ pokeActivity();
+ });
+
+ m_inactivityTimer = new QTimer(this);
+ m_inactivityTimer->setSingleShot(true);
+ m_inactivityTimer->setInterval(InactivityMs);
+ connect(m_inactivityTimer, &QTimer::timeout, this, &QWidget::hide);
+}
+
+void AdjustOverlay::configure(const QString &title, DualControlButton::Context context) {
+ m_context = context;
+ m_titleLabel->setText(title);
+ m_slider->setStyleSheet(
+ K4Styles::sliderHorizontal(K4Styles::Colors::DarkBackground, barColor().name()));
+ update();
+}
+
+void AdjustOverlay::setValueText(const QString &text) {
+ m_valueLabel->setText(text);
+}
+
+void AdjustOverlay::setValueFormatter(std::function formatter) {
+ m_formatter = std::move(formatter);
+ if (m_slider)
+ m_valueLabel->setText(formatValue(m_slider->value()));
+}
+
+QString AdjustOverlay::formatValue(int value) const {
+ return m_formatter ? m_formatter(value) : QString::number(value);
+}
+
+void AdjustOverlay::pokeActivity() {
+ if (m_inactivityTimer)
+ m_inactivityTimer->start();
+}
+
+void AdjustOverlay::showOver(QWidget *anchor) {
+ adjustSize();
+ QPoint pos;
+ if (anchor) {
+ // Sit just to the right of the tile, vertically centred on it.
+ const QPoint tl = anchor->mapToGlobal(QPoint(anchor->width(), 0));
+ pos = QPoint(tl.x() + 8, tl.y() + anchor->height() / 2 - height() / 2);
+ } else {
+ pos = QCursor::pos();
+ }
+ // Keep on screen.
+ if (QScreen *screen = QGuiApplication::screenAt(pos) ? QGuiApplication::screenAt(pos)
+ : QGuiApplication::primaryScreen()) {
+ const QRect avail = screen->availableGeometry();
+ int x = qBound(avail.left() + 4, pos.x(), avail.right() - width() - 4);
+ int y = qBound(avail.top() + 4, pos.y(), avail.bottom() - height() - 4);
+ pos = QPoint(x, y);
+ }
+ move(pos);
+ show();
+ raise();
+ pokeActivity();
+}
+
+QColor AdjustOverlay::barColor() const {
+ switch (m_context) {
+ case DualControlButton::MainRx:
+ return QColor(K4Styles::Colors::VfoACyan);
+ case DualControlButton::SubRx:
+ return QColor(K4Styles::Colors::VfoBGreen);
+ case DualControlButton::Global:
+ default:
+ return QColor(K4Styles::Colors::AccentAmber);
+ }
+}
+
+bool AdjustOverlay::eventFilter(QObject *watched, QEvent *event) {
+ if (watched == m_slider) {
+ if (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseMove) {
+ auto *me = static_cast(event);
+ if (me->buttons() & Qt::LeftButton || event->type() == QEvent::MouseButtonPress) {
+ setSliderFromX(me->pos().x());
+ pokeActivity();
+ return true; // consume: we position absolutely, not by page-step
+ }
+ }
+ }
+ return QWidget::eventFilter(watched, event);
+}
+
+void AdjustOverlay::setSliderFromX(int xPosition) {
+ if (!m_slider)
+ return;
+ const int handleWidth = qMax(12, m_slider->height() / 2);
+ const int span = qMax(1, m_slider->width() - handleWidth);
+ const int position = qBound(0, xPosition - handleWidth / 2, span);
+ m_slider->setValue(QStyle::sliderValueFromPosition(m_slider->minimum(), m_slider->maximum(), position, span,
+ m_slider->invertedAppearance()));
+}
+
+void AdjustOverlay::paintEvent(QPaintEvent *) {
+ QPainter painter(this);
+ painter.setRenderHint(QPainter::Antialiasing);
+ const QRect r = rect();
+
+ painter.setPen(Qt::NoPen);
+ painter.setBrush(QColor(K4Styles::Colors::DarkBackground));
+ painter.drawRoundedRect(r, CornerRadius, CornerRadius);
+
+ QRect barRect(0, 0, IndicatorBarWidth, r.height());
+ painter.setBrush(barColor());
+ painter.drawRoundedRect(barRect, CornerRadius / 2, CornerRadius / 2);
+
+ painter.setPen(QPen(QColor(K4Styles::Colors::BorderNormal), 1));
+ painter.setBrush(Qt::NoBrush);
+ painter.drawRoundedRect(r.adjusted(0, 0, -1, -1), CornerRadius, CornerRadius);
+}
diff --git a/src/ui/adjustoverlay.h b/src/ui/adjustoverlay.h
new file mode 100644
index 0000000..1b06cbb
--- /dev/null
+++ b/src/ui/adjustoverlay.h
@@ -0,0 +1,74 @@
+#ifndef ADJUSTOVERLAY_H
+#define ADJUSTOVERLAY_H
+
+#include
+#include
+#include "dualcontrolbutton.h"
+
+class QSlider;
+class QLabel;
+class QPushButton;
+class QTimer;
+
+/**
+ * @brief Touch adjustment popup for a single left-column control tile.
+ *
+ * Mirrors the macOS SideControlOverlay look (dark rounded panel with a
+ * context-coloured indicator bar) but is driven by a large slider plus fine
+ * -/+ buttons instead of the mouse wheel, so a DualControlButton value can be
+ * set by touch on iPad/iPhone. Opened by a long-press on the tile (the touch
+ * equivalent of the macOS right-click/wheel interaction).
+ *
+ * A Qt::Popup window: tapping anywhere outside dismisses it. It also closes
+ * itself after a short period of inactivity.
+ */
+class AdjustOverlay : public QWidget {
+ Q_OBJECT
+
+public:
+ explicit AdjustOverlay(QWidget *parent = nullptr);
+
+ /// The slider the owner configures (range/value) and connects to.
+ QSlider *slider() const { return m_slider; }
+
+ /// Set the title text and indicator-bar colour for this control.
+ void configure(const QString &title, DualControlButton::Context context);
+
+ /// Update the large value readout shown above the slider.
+ void setValueText(const QString &text);
+
+ /// Set how the slider value is rendered in the readout (e.g. kHz). Pass an
+ /// empty function to fall back to the raw integer.
+ void setValueFormatter(std::function formatter);
+
+ /// Position over @p anchor (global coords) and show. Resets inactivity.
+ void showOver(QWidget *anchor);
+
+ /// Restart the inactivity auto-close timer (call on any interaction).
+ void pokeActivity();
+
+protected:
+ void paintEvent(QPaintEvent *event) override;
+ bool eventFilter(QObject *watched, QEvent *event) override;
+
+private:
+ QColor barColor() const;
+ void setSliderFromX(int xPosition);
+
+ DualControlButton::Context m_context = DualControlButton::Global;
+ QString formatValue(int value) const;
+
+ std::function m_formatter;
+ QLabel *m_titleLabel = nullptr;
+ QLabel *m_valueLabel = nullptr;
+ QSlider *m_slider = nullptr;
+ QPushButton *m_minusBtn = nullptr;
+ QPushButton *m_plusBtn = nullptr;
+ QTimer *m_inactivityTimer = nullptr;
+
+ static constexpr int IndicatorBarWidth = 5;
+ static constexpr int CornerRadius = 8;
+ static constexpr int InactivityMs = 3500;
+};
+
+#endif // ADJUSTOVERLAY_H
diff --git a/src/ui/baloverlay.cpp b/src/ui/baloverlay.cpp
index a119a0a..71fe170 100644
--- a/src/ui/baloverlay.cpp
+++ b/src/ui/baloverlay.cpp
@@ -2,6 +2,7 @@
#include "k4styles.h"
#include
#include
+#include
#include
BalOverlay::BalOverlay(QWidget *parent)
@@ -113,6 +114,38 @@ void BalOverlay::wheelEvent(QWheelEvent *event) {
}
void BalOverlay::mousePressEvent(QMouseEvent *event) {
- // Don't close on click - allow adjustment via wheel
- Q_UNUSED(event)
+ m_dragActive = true;
+ m_dragMoved = false;
+ m_dragStartX = event->position().x();
+ m_dragStartY = event->position().y();
+ event->accept();
+}
+
+void BalOverlay::mouseMoveEvent(QMouseEvent *event) {
+ if (!m_dragActive)
+ return;
+ const qreal x = event->position().x();
+ const qreal y = event->position().y();
+ if (!m_dragMoved && (qAbs(y - m_dragStartY) > 4 || qAbs(x - m_dragStartX) > 4))
+ m_dragMoved = true;
+ if (m_dragMoved) {
+ // Top of the overlay is +50 (toward SUB), bottom is -50 (toward MAIN).
+ const qreal h = qMax(1, height());
+ const qreal frac = 1.0 - qBound(0.0, y, h) / h;
+ const int newOffset = qBound(-50, int(qRound((frac - 0.5) * 100.0)), 50);
+ if (newOffset != m_offset) {
+ m_offset = newOffset;
+ updateDisplay();
+ emit balanceChangeRequested(m_mode, m_offset);
+ }
+ }
+ event->accept();
+}
+
+void BalOverlay::mouseReleaseEvent(QMouseEvent *event) {
+ // A tap (press with no drag) dismisses the overlay; a drag adjusted it.
+ if (m_dragActive && !m_dragMoved)
+ hide();
+ m_dragActive = false;
+ event->accept();
}
diff --git a/src/ui/baloverlay.h b/src/ui/baloverlay.h
index 0730be7..24a98c2 100644
--- a/src/ui/baloverlay.h
+++ b/src/ui/baloverlay.h
@@ -35,6 +35,8 @@ class BalOverlay : public SideControlOverlay {
protected:
void wheelEvent(QWheelEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
+ void mouseMoveEvent(QMouseEvent *event) override;
+ void mouseReleaseEvent(QMouseEvent *event) override;
private:
void setupUi();
@@ -46,6 +48,13 @@ class BalOverlay : public SideControlOverlay {
int m_mode = 0; // 0=NOR, 1=BAL
int m_offset = 0; // -50 to +50
+
+ // Touch drag-to-adjust: a drag maps the finger's vertical position to the
+ // balance offset; a tap (no drag) dismisses the overlay.
+ bool m_dragActive = false;
+ bool m_dragMoved = false;
+ qreal m_dragStartX = 0;
+ qreal m_dragStartY = 0;
};
#endif // BALOVERLAY_H
diff --git a/src/ui/bottommenubar.cpp b/src/ui/bottommenubar.cpp
index 731efd8..10dab03 100644
--- a/src/ui/bottommenubar.cpp
+++ b/src/ui/bottommenubar.cpp
@@ -8,8 +8,35 @@
#include
#include
#include
+#include
#include
+namespace {
+// Draw a monochrome gear onto a settings button so no platform can substitute
+// a colored emoji glyph. Shared by the compact and regular layouts.
+void applyGearIcon(QPushButton *button) {
+ QPixmap gearPixmap(16, 16);
+ gearPixmap.fill(Qt::transparent);
+ QPainter gearPainter(&gearPixmap);
+ gearPainter.setRenderHint(QPainter::Antialiasing);
+ gearPainter.setPen(QPen(Qt::white, 2.0, Qt::SolidLine, Qt::RoundCap));
+ const QPointF center(8.0, 8.0);
+ constexpr qreal Pi = 3.14159265358979323846;
+ for (int i = 0; i < 8; ++i) {
+ const qreal angle = i * Pi / 4.0;
+ gearPainter.drawLine(center + QPointF(std::cos(angle) * 4.0, std::sin(angle) * 4.0),
+ center + QPointF(std::cos(angle) * 6.5, std::sin(angle) * 6.5));
+ }
+ gearPainter.drawEllipse(center, 4.0, 4.0);
+ gearPainter.drawEllipse(center, 1.5, 1.5);
+ gearPainter.end();
+ button->setAccessibleName("QK4 Settings");
+ button->setToolTip("QK4 Settings");
+ button->setIcon(QIcon(gearPixmap));
+ button->setIconSize(QSize(16, 16));
+}
+} // namespace
+
BottomMenuBar::BottomMenuBar(QWidget *parent) : QWidget(parent) {
setupUi();
}
@@ -74,27 +101,8 @@ void BottomMenuBar::setupUi() {
button->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
}
m_settingsBtn = createMenuButton(QString());
- m_settingsBtn->setAccessibleName("QK4 Settings");
- m_settingsBtn->setToolTip("QK4 Settings");
m_settingsBtn->setFixedSize(34, 26);
- // Draw a monochrome gear so Android cannot substitute a colored emoji.
- QPixmap gearPixmap(16, 16);
- gearPixmap.fill(Qt::transparent);
- QPainter gearPainter(&gearPixmap);
- gearPainter.setRenderHint(QPainter::Antialiasing);
- gearPainter.setPen(QPen(Qt::white, 2.0, Qt::SolidLine, Qt::RoundCap));
- const QPointF center(8.0, 8.0);
- constexpr qreal Pi = 3.14159265358979323846;
- for (int i = 0; i < 8; ++i) {
- const qreal angle = i * Pi / 4.0;
- gearPainter.drawLine(center + QPointF(std::cos(angle) * 4.0, std::sin(angle) * 4.0),
- center + QPointF(std::cos(angle) * 6.5, std::sin(angle) * 6.5));
- }
- gearPainter.drawEllipse(center, 4.0, 4.0);
- gearPainter.drawEllipse(center, 1.5, 1.5);
- gearPainter.end();
- m_settingsBtn->setIcon(QIcon(gearPixmap));
- m_settingsBtn->setIconSize(QSize(16, 16));
+ applyGearIcon(m_settingsBtn);
tuneRow->addWidget(m_settingsBtn);
tuneRow->addWidget(m_tuneADownBtn);
tuneRow->addWidget(m_tuneAUpBtn);
@@ -117,7 +125,11 @@ void BottomMenuBar::setupUi() {
m_subVolumeSlider->setStyleSheet(
K4Styles::sliderHorizontal(K4Styles::Colors::DarkBackground, K4Styles::Colors::VfoBGreen));
} else {
+#if defined(Q_OS_ANDROID)
+ setFixedHeight(K4Styles::isCompactLayout() ? K4Styles::Dimensions::MenuBarHeight : 40);
+#else
setFixedHeight(K4Styles::Dimensions::MenuBarHeight);
+#endif
auto *layout = new QHBoxLayout(this);
// Left margin matches side panel/scroll width to align with waterfall above
@@ -126,6 +138,14 @@ void BottomMenuBar::setupUi() {
K4Styles::Dimensions::PaddingSmall);
layout->setSpacing(K4Styles::Dimensions::PopupButtonSpacing);
+ // Connect and Settings at far left (desktop/macOS parity). On iOS these are
+ // the only connect/settings entry points, since the menu bar is hidden.
+ m_connectBtn = createMenuButton("CONN");
+ layout->addWidget(m_connectBtn);
+ m_settingsBtn = createMenuButton(QString());
+ applyGearIcon(m_settingsBtn);
+ layout->addWidget(m_settingsBtn);
+
// Add stretch before buttons to center them
layout->addStretch();
@@ -254,7 +274,14 @@ void BottomMenuBar::setTuneStepB(int hertz) {
QPushButton *BottomMenuBar::createMenuButton(const QString &text) {
auto *btn = new QPushButton(text, this);
- btn->setFixedSize(K4Styles::Dimensions::MenuBarButtonWidth, K4Styles::Dimensions::ButtonHeightMedium);
+#if defined(Q_OS_ANDROID)
+ // Shorter bottom-bar buttons on the tablet free vertical space for the
+ // middle section so the left column's SUB slider isn't clipped.
+ const int h = K4Styles::isCompactLayout() ? K4Styles::Dimensions::ButtonHeightMedium : 28;
+#else
+ const int h = K4Styles::Dimensions::ButtonHeightMedium;
+#endif
+ btn->setFixedSize(K4Styles::Dimensions::MenuBarButtonWidth, h);
btn->setCursor(Qt::PointingHandCursor);
btn->setStyleSheet(K4Styles::menuBarButton());
return btn;
@@ -323,7 +350,9 @@ void BottomMenuBar::setPttActive(bool active) {
} else {
m_pttLocked = false;
m_pttLockTimer->stop();
- m_pttBtn->setText("TX / RX");
+ // Compact keeps the phone's "TX / RX" latch label; the regular/iPad
+ // layout returns to "PTT" to match QK4 on macOS and the radio.
+ m_pttBtn->setText(K4Styles::isCompactLayout() ? "TX / RX" : "PTT");
m_pttBtn->setStyleSheet(K4Styles::menuBarButton());
}
}
diff --git a/src/ui/dualcontrolbutton.cpp b/src/ui/dualcontrolbutton.cpp
index 0777fed..623a855 100644
--- a/src/ui/dualcontrolbutton.cpp
+++ b/src/ui/dualcontrolbutton.cpp
@@ -14,13 +14,20 @@ DualControlButton::DualControlButton(QWidget *parent) : QWidget(parent) {
m_longPressTimer->setSingleShot(true);
m_longPressTimer->setInterval(550);
connect(m_longPressTimer, &QTimer::timeout, this, [this]() {
- if (!K4Styles::isCompactLayout() || m_dragging)
+ if (m_dragging)
return;
- if (!m_showIndicator)
- emit becameActive();
- swapFunctions();
- emit swapped();
m_longPressHandled = true;
+ if (K4Styles::isCompactLayout()) {
+ // Phone: long-press swaps to the amber alternate function.
+ if (!m_showIndicator)
+ emit becameActive();
+ swapFunctions();
+ emit swapped();
+ } else {
+ // iPad (macOS-style column): long-press opens the touch adjust
+ // popup, the touch equivalent of the macOS wheel/right-click.
+ emit adjustRequested();
+ }
});
}
@@ -187,8 +194,9 @@ void DualControlButton::mousePressEvent(QMouseEvent *event) {
m_lastDragY = event->pos().y();
m_dragging = false;
m_longPressHandled = false;
- if (K4Styles::isCompactLayout())
- m_longPressTimer->start();
+ // Compact: long-press swaps to alternate. Regular (iPad): long-press
+ // opens the adjust popup. Either way the timer is armed on press.
+ m_longPressTimer->start();
event->accept();
} else {
QWidget::mousePressEvent(event);
@@ -232,11 +240,19 @@ void DualControlButton::mouseReleaseEvent(QMouseEvent *event) {
if (!m_dragging) {
if (!m_showIndicator) {
emit becameActive();
- } else if (!K4Styles::isCompactLayout()) {
+ emit clicked();
+ } else if (K4Styles::isCompactLayout()) {
+ // Phone: a tap selects the primary function (handled by the
+ // panel's clicked handler); no swap here.
+ emit clicked();
+ } else {
+ // iPad: a tap swaps white<->yellow (active function). Emit
+ // only swapped so the panel does not also run the compact
+ // clicked handler, which would swap a second time and cancel
+ // it out.
swapFunctions();
emit swapped();
}
- emit clicked();
}
event->accept();
return;
diff --git a/src/ui/dualcontrolbutton.h b/src/ui/dualcontrolbutton.h
index a6af828..0517f97 100644
--- a/src/ui/dualcontrolbutton.h
+++ b/src/ui/dualcontrolbutton.h
@@ -73,6 +73,7 @@ class DualControlButton : public QWidget {
void clicked(); // Button was clicked
void swapped(); // Primary/alternate were swapped (only when already active)
void becameActive(); // User clicked to activate this button
+ void adjustRequested(); // Long-press on iPad: open touch adjust popup
protected:
void paintEvent(QPaintEvent *event) override;
diff --git a/src/ui/filterindicatorwidget.cpp b/src/ui/filterindicatorwidget.cpp
index ed7d011..2fd4660 100644
--- a/src/ui/filterindicatorwidget.cpp
+++ b/src/ui/filterindicatorwidget.cpp
@@ -4,6 +4,8 @@
#include
#include
+QHash FilterIndicatorWidget::s_normByMode;
+
FilterIndicatorWidget::FilterIndicatorWidget(QWidget *parent) : QWidget(parent) {
setFixedSize(62, 62); // 50 * 1.25 = 62
}
@@ -51,6 +53,13 @@ void FilterIndicatorWidget::setShapeColor(const QColor &fill, const QColor &outl
update();
}
+void FilterIndicatorWidget::setNormBandwidth(int hz) {
+ if (hz <= 0)
+ return;
+ s_normByMode.insert(m_mode, hz);
+ update();
+}
+
void FilterIndicatorWidget::drawBandwidthShape(QPainter &painter, int lineY, int lineWidth) {
// Shape height
const float shapeHeight = 16.0f;
@@ -140,6 +149,34 @@ void FilterIndicatorWidget::drawBandwidthShape(QPainter &painter, int lineY, int
float bottomY = lineY - gapAboveLine;
float topY = bottomY - shapeHeight;
+ // FSK/AFSK: the K4 draws the same passband trapezoid as other modes but
+ // with a notch in the top edge, so the mark/space tones show as two peaks
+ // at the top corners. At the narrow end it collapses to a single triangle;
+ // as BW widens the top spreads into a plateau with two corner peaks. Drawn
+ // centred (the pair straddles the passband centre), matching the radio.
+ if (m_mode.startsWith(QLatin1String("FSK")) || m_mode.startsWith(QLatin1String("AFSK"))) {
+ const float fcx = width() / 2.0f;
+ // FSK always resolves two tone peaks; their separation scales with the
+ // filter bandwidth. Map the FSK working range (~150-800 Hz) to a peak
+ // spacing that starts clearly apart and grows, capped so the widest
+ // setting still fits the 62px widget instead of clipping.
+ const float bwMin = 150.0f, bwMax = 800.0f;
+ const float t = std::clamp((static_cast(m_bandwidthHz) - bwMin) / (bwMax - bwMin), 0.0f, 1.0f);
+ const float halfTop = 9.0f + t * 12.0f; // peaks: ~18px..42px apart
+ const float halfBase = halfTop + 5.0f; // sides slope outward below the peaks
+ const float tl = fcx - halfTop, tr = fcx + halfTop;
+ const float bl = fcx - halfBase, br = fcx + halfBase;
+ const float valleyY = topY + shapeHeight * 0.30f;
+ painter.setPen(Qt::NoPen);
+ painter.setBrush(m_shapeColor);
+ QPolygonF shape;
+ shape << QPointF(bl, bottomY) << QPointF(tl, topY) << QPointF(fcx, valleyY) << QPointF(tr, topY)
+ << QPointF(br, bottomY);
+ painter.drawPolygon(shape);
+ drawFilterBaseline(painter, bl, br, lineY);
+ return;
+ }
+
float bottomLeft = centerX - baseWidth / 2.0f;
float bottomRight = centerX + baseWidth / 2.0f;
float topLeft = centerX - topWidth / 2.0f;
@@ -160,6 +197,62 @@ void FilterIndicatorWidget::drawBandwidthShape(QPainter &painter, int lineY, int
painter.setPen(Qt::NoPen);
painter.setBrush(m_shapeColor);
painter.drawPolygon(shape);
+
+ drawFilterBaseline(painter, bottomLeft, bottomRight, lineY);
+}
+
+int FilterIndicatorWidget::normBandwidthHz() const {
+ // The nominal width learned when the operator last pressed NORM in this
+ // mode is authoritative; the per-mode guesses below are only a fallback
+ // for a mode NORM has not been pressed in yet this session.
+ auto it = s_normByMode.constFind(m_mode);
+ if (it != s_normByMode.constEnd())
+ return it.value();
+ if (m_mode == "FM" || m_mode.startsWith(QLatin1String("PSK")))
+ return 0; // no NORM marker
+ if (m_mode.startsWith(QLatin1String("FSK")) || m_mode.startsWith(QLatin1String("AFSK")))
+ return 300;
+ if (m_mode == "CW" || m_mode == "CW-R")
+ return 400;
+ if (m_mode == "AM")
+ return 6000;
+ return 2700; // SSB / DATA nominal
+}
+
+void FilterIndicatorWidget::drawFilterBaseline(QPainter &painter, float leftX, float rightX, float lineY) {
+ // The K4 draws a fixed-length yellow reference line, the same for every
+ // mode (the coloured filter shape varies, this line does not). Centre it
+ // under the current shape and give it a constant half-width.
+ const float cx = (leftX + rightX) / 2.0f;
+ const float half = 22.0f; // fixed: CW and LSB lines are identical length
+ const float lx = cx - half;
+ const float rx = cx + half;
+
+ painter.setBrush(Qt::NoBrush);
+ QPen pen(m_lineColor, 2);
+ pen.setJoinStyle(Qt::RoundJoin); // clean corner, no miter spike above the flat
+ painter.setPen(pen);
+
+ // When the passband is at (near) the mode's NORM width, the two ends turn
+ // downward. A tolerance (~10%, min 40 Hz) absorbs small differences between
+ // the radio's actual nominal and our per-mode fallback so both VFOs show
+ // the ends at their default width. Drawn as one polyline so the corners
+ // join cleanly and the legs never rise above the flat line.
+ const int norm = normBandwidthHz();
+ const int tol = qMax(40, norm / 10);
+ if (norm > 0 && qAbs(m_bandwidthHz - norm) <= tol) {
+ const float len = 5.0f;
+ const float out = 2.0f;
+ const QPointF pts[4] = {
+ QPointF(lx - out, lineY + len),
+ QPointF(lx, lineY),
+ QPointF(rx, lineY),
+ QPointF(rx + out, lineY + len),
+ };
+ painter.drawPolyline(pts, 4);
+ } else {
+ painter.drawLine(QPointF(lx, lineY), QPointF(rx, lineY));
+ }
}
void FilterIndicatorWidget::paintEvent(QPaintEvent *) {
@@ -172,19 +265,12 @@ void FilterIndicatorWidget::paintEvent(QPaintEvent *) {
// Line parameters
// Preserve breathing room above the phone's always-visible antenna row.
int lineY = K4Styles::isCompactLayout() ? 36 : 40;
- int lineHeight = 3;
int lineWidth = 58; // 38 + 20 (10px wider on each side)
- int lineX = (w - lineWidth) / 2;
- // Draw bandwidth shape above the line
+ // Draw bandwidth shape; the yellow passband line (and NORM ends) are drawn
+ // with it so the line width matches the current filter.
drawBandwidthShape(painter, lineY, lineWidth);
- // Draw horizontal line
- QRectF lineRect(lineX, lineY, lineWidth, lineHeight);
- painter.setPen(Qt::NoPen);
- painter.setBrush(m_lineColor);
- painter.drawRect(lineRect);
-
// FIL text below line
QFont textFont = font();
textFont.setPixelSize(K4Styles::Dimensions::FontSizeButton);
@@ -193,7 +279,7 @@ void FilterIndicatorWidget::paintEvent(QPaintEvent *) {
painter.setPen(m_textColor);
QString text = QString("FIL%1").arg(m_filterPosition);
- int textY = lineY + lineHeight + 2;
+ int textY = lineY + 3 + 2; // 3 = passband line thickness (see drawFilterBaseline)
QRectF textRect(0, textY, w, h - textY);
painter.drawText(textRect, Qt::AlignHCenter | Qt::AlignTop, text);
}
diff --git a/src/ui/filterindicatorwidget.h b/src/ui/filterindicatorwidget.h
index 21f29a8..00646c6 100644
--- a/src/ui/filterindicatorwidget.h
+++ b/src/ui/filterindicatorwidget.h
@@ -2,6 +2,7 @@
#define FILTERINDICATORWIDGET_H
#include
+#include
#include
// Compact filter indicator widget showing filter position,
@@ -35,11 +36,20 @@ class FilterIndicatorWidget : public QWidget {
// Shape color (for VFO A/B color coding)
void setShapeColor(const QColor &fill, const QColor &outline);
+ // Record the current mode's nominal (NORM) passband width in Hz, learned
+ // when the operator presses NORM. The down-turned edge ticks then show
+ // only when the live bandwidth returns to this learned width.
+ void setNormBandwidth(int hz);
+
protected:
void paintEvent(QPaintEvent *event) override;
private:
void drawBandwidthShape(QPainter &painter, int lineY, int lineWidth);
+ // Mode's nominal (NORM) bandwidth in Hz, or 0 if unknown.
+ int normBandwidthHz() const;
+ // Down-turned yellow ticks at the shape's base edges when at NORM.
+ void drawFilterBaseline(QPainter &painter, float leftX, float rightX, float lineY);
int m_filterPosition = 2;
int m_bandwidthHz = 2400; // Current bandwidth in Hz
@@ -48,6 +58,10 @@ class FilterIndicatorWidget : public QWidget {
int m_minBandwidthHz = 50; // Minimum bandwidth (triangle)
int m_maxBandwidthHz = 5000; // Maximum bandwidth (full trapezoid)
+ // Learned NORM width per mode string, shared across both VFO indicators
+ // (nominal is a property of the mode, not the receiver).
+ static QHash s_normByMode;
+
QColor m_lineColor{0xFF, 0xD0, 0x40}; // Gold #FFD040
QColor m_textColor{0xFF, 0xD0, 0x40}; // Gold #FFD040
QColor m_shapeColor{0xFF, 0xD0, 0x40, 128}; // Gold with 50% alpha
diff --git a/src/ui/frequencydisplaywidget.cpp b/src/ui/frequencydisplaywidget.cpp
index 99f9191..1ae3a39 100644
--- a/src/ui/frequencydisplaywidget.cpp
+++ b/src/ui/frequencydisplaywidget.cpp
@@ -240,7 +240,7 @@ QRect FrequencyDisplayWidget::charRectAt(int charIndex) const {
int FrequencyDisplayWidget::digitPositionFromX(int x) const {
QString display = formatWithDots();
- int currentX = 0;
+ int currentX = drawStartX();
for (int i = 0; i < display.length(); ++i) {
int charW = (display[i] == '.') ? m_dotWidth : m_charWidth;
@@ -280,7 +280,46 @@ void FrequencyDisplayWidget::enterEditMode(int digitPosition) {
m_originalDigits = m_digits;
m_cursorPosition = digitPosition;
setFocus();
- grabMouse(); // Capture all mouse events to detect clicks outside
+#if !defined(Q_OS_IOS) && !defined(Q_OS_ANDROID)
+ grabMouse(); // Desktop: capture mouse to detect clicks outside. On touch this
+ // would steal taps from the +/- controls used to edit digits.
+#endif
+ update();
+}
+
+void FrequencyDisplayWidget::beginEdit() {
+ if (m_cursorPosition < 0)
+ enterEditMode(displayStartIndex()); // start at the leftmost visible digit
+}
+
+void FrequencyDisplayWidget::commitEdit() {
+ if (m_cursorPosition >= 0)
+ exitEditMode(true);
+}
+
+void FrequencyDisplayWidget::cancelEdit() {
+ if (m_cursorPosition >= 0)
+ exitEditMode(false);
+}
+
+void FrequencyDisplayWidget::nudgeCursorDigit(int delta) {
+ if (m_cursorPosition < 0 || delta == 0)
+ return;
+ // Add/subtract the place value of the cursor digit so carries ripple
+ // naturally (e.g. 9->0 bumps the next digit up).
+ const int place = kMaxDigitIndex - m_cursorPosition;
+ quint64 placeValue = 1;
+ for (int i = 0; i < place; ++i)
+ placeValue *= 10;
+ qint64 value = static_cast(m_digits.toULongLong()) + static_cast(delta) * static_cast(placeValue);
+ if (value < 0)
+ value = 0;
+ QString s = QString::number(static_cast(value));
+ while (s.length() < kDigits)
+ s.prepend('0');
+ if (s.length() > kDigits)
+ s = s.right(kDigits);
+ m_digits = s;
update();
}
@@ -289,7 +328,9 @@ void FrequencyDisplayWidget::exitEditMode(bool send) {
return; // Not in edit mode
}
- releaseMouse(); // Release mouse grab
+#if !defined(Q_OS_IOS) && !defined(Q_OS_ANDROID)
+ releaseMouse(); // Release mouse grab (desktop only; see enterEditMode)
+#endif
if (send) {
// Remove leading zeros for the signal (but keep at least one digit)
@@ -309,6 +350,39 @@ void FrequencyDisplayWidget::exitEditMode(bool send) {
update();
}
+void FrequencyDisplayWidget::setRightAligned(bool rightAligned) {
+ if (m_rightAligned != rightAligned) {
+ m_rightAligned = rightAligned;
+ update();
+ }
+}
+
+int FrequencyDisplayWidget::displayPixelWidth() const {
+ QString display = formatWithDots();
+ int w = 0;
+ for (int i = 0; i < display.length(); ++i)
+ w += (display[i] == '.') ? m_dotWidth : m_charWidth;
+ return w;
+}
+
+void FrequencyDisplayWidget::setRightAlignEdge(int edgeX) {
+ if (m_rightAlignEdge != edgeX) {
+ m_rightAlignEdge = edgeX;
+ update();
+ }
+}
+
+int FrequencyDisplayWidget::drawStartX() const {
+ if (!m_rightAligned)
+ return 0;
+ // Digits end just inside m_rightAlignEdge (or the widget's right edge if
+ // unset). The small inset keeps the last digit off the clipped boundary and
+ // matches the radio, where the frequency sits a touch inside the meter edge.
+ constexpr int kRightInset = 16;
+ const int ref = (m_rightAlignEdge >= 0) ? m_rightAlignEdge : width();
+ return qMax(0, ref - kRightInset - displayPixelWidth());
+}
+
void FrequencyDisplayWidget::paintEvent(QPaintEvent *) {
QPainter p(this);
p.setRenderHint(QPainter::Antialiasing);
@@ -317,7 +391,7 @@ void FrequencyDisplayWidget::paintEvent(QPaintEvent *) {
QString display = formatWithDots();
// Draw each character
- int x = 0;
+ int x = drawStartX();
int digitIdx = displayStartIndex();
for (int i = 0; i < display.length(); ++i) {
@@ -333,10 +407,11 @@ void FrequencyDisplayWidget::paintEvent(QPaintEvent *) {
// Dots always in normal color
charColor = m_normalColor;
} else {
- // Normal mode: check if this digit should be grayed (tuning rate indicator)
+ // Normal mode: digits strictly below the tuning rate are grayed.
+ // The active tuning-rate digit itself stays normal and is marked by
+ // the underline below (matching the radio and QK4 on macOS).
const int posFromRight = kMaxDigitIndex - digitIdx;
- if (m_tuningRateDigit >= 0 && posFromRight <= m_tuningRateDigit) {
- // This digit is at or below tuning rate - show in gray
+ if (m_tuningRateDigit >= 0 && posFromRight < m_tuningRateDigit) {
charColor = QColor(K4Styles::Colors::TextGray);
} else {
charColor = m_normalColor;
@@ -355,6 +430,15 @@ void FrequencyDisplayWidget::paintEvent(QPaintEvent *) {
p.fillRect(x + 2, underlineY, charW - 4, 2, m_editColor);
}
+ // Tuning-rate indicator underline under the active digit. Guarded by
+ // m_cursorPosition < 0 so the edit-mode cursor underline takes
+ // precedence and we do not double-draw.
+ if (m_cursorPosition < 0 && c != '.' && m_tuningRateDigit >= 0 &&
+ (kMaxDigitIndex - digitIdx) == m_tuningRateDigit) {
+ int underlineY = height() - 4;
+ p.fillRect(x + 2, underlineY, charW - 4, 2, m_normalColor);
+ }
+
// Advance digit index (only for non-dot characters)
if (c != '.') {
digitIdx++;
diff --git a/src/ui/frequencydisplaywidget.h b/src/ui/frequencydisplaywidget.h
index b68ebb5..3121f51 100644
--- a/src/ui/frequencydisplaywidget.h
+++ b/src/ui/frequencydisplaywidget.h
@@ -56,6 +56,13 @@ class FrequencyDisplayWidget : public QWidget {
// e.g., rate 2 (100Hz) grays out digits 0,1,2 (1s, 10s, 100s places)
void setTuningRateDigit(int digitFromRight);
+ // Right-align the digits within the widget (VFO A, to line the frequency up
+ // with the right edge of the meters like the radio). Default is left.
+ void setRightAligned(bool rightAligned);
+ // X (in widget coords) the right edge of the digits aligns to when
+ // right-aligned. Defaults to the widget's own width when unset (<0).
+ void setRightAlignEdge(int edgeX);
+
// Check if currently in edit mode
bool isEditing() const;
// Opt-in fitting and phone gestures for embedded frequency displays.
@@ -63,6 +70,16 @@ class FrequencyDisplayWidget : public QWidget {
void setTouchTuningEnabled(bool enabled);
void setSelectedTuningDigit(int digitFromRight);
+ // Enter the blue frequency edit field (FREQ ENT button / radio-style),
+ // as opposed to tapping a digit which selects the tuning rate.
+ void beginEdit();
+ // Commit the edit field (send) / cancel it (restore).
+ void commitEdit();
+ void cancelEdit();
+ // Adjust the digit under the cursor by delta (+/-1), carrying across
+ // digits, for touch entry via +/- controls while the field is open.
+ void nudgeCursorDigit(int delta);
+
signals:
// Emitted when user presses Enter to confirm frequency entry
// digits is the frequency as plain digits (e.g., "7024980")
@@ -131,13 +148,21 @@ class FrequencyDisplayWidget : public QWidget {
// Tuning rate indicator: digits from this position to 0 show in gray
int m_tuningRateDigit = -1; // -1 = no indicator, 0-4 = position from right
+ bool m_rightAligned = false; // draw digits against the widget's right edge
+ int m_rightAlignEdge = -1; // right-align target x; <0 = use width()
+
+ // Pixel width of the current display string, and the left x the paint/hit
+ // logic starts from (nonzero when right-aligned).
+ int displayPixelWidth() const;
+ int drawStartX() const;
+
WheelAccumulator m_wheelAccumulator;
// Cached character metrics for click detection
int m_charWidth = 0;
int m_dotWidth = 0;
bool m_autoFit = false;
-#ifdef Q_OS_ANDROID
+#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
bool m_touchTuningEnabled = true;
#else
bool m_touchTuningEnabled = false;
diff --git a/src/ui/k4styles.cpp b/src/ui/k4styles.cpp
index a5849d5..2ebe179 100644
--- a/src/ui/k4styles.cpp
+++ b/src/ui/k4styles.cpp
@@ -51,12 +51,14 @@ void applyDefaultDimensions() {
VfoSquareSize = 45;
NavButtonWidth = 54;
SidePanelWidth = 105;
+ RightSidePanelWidth = 130;
MemoryButtonWidth = 42;
CenterPanelWidth = 330;
VfoColumnWidth = 270;
VfoContentHeight = 150;
VfoMeterWidth = 260;
+ VfoMeterHeight = 130;
SpectrumMinHeight = 300;
VfoIndicatorBadgeWidth = 34;
VfoIndicatorBadgeHeight = 30;
@@ -133,6 +135,7 @@ void applyCompactDimensions() {
// Original QK4 control banks are now presented side-by-side in the
// phone Controls screen, so each needs room for its two-column grid.
SidePanelWidth = 170;
+ RightSidePanelWidth = 170;
MemoryButtonWidth = 34;
// 62 px filter shapes on both sides plus the 80 px RIT/XIT readout.
@@ -195,15 +198,31 @@ void configureForScreen(const QSize &availableSize, qreal devicePixelRatio, qrea
bool forceCompact) {
applyDefaultDimensions();
- // TEMPORARY: Until the tablet layout has been physically validated, use the
- // proven landscape phone layout on every Android screen size. Keep the
- // original size-based selection below for restoration once tablet testing
- // is available.
+ // Large screens (iPad / Android tablet) get the regular desktop-like layout,
+ // closer to QK4 on macOS and the physical radio; phones keep the compact
+ // layout. iOS separates by the landscape short edge (iPad >= ~740 pt,
+ // iPhone <= ~440 pt). Android logical sizes vary a lot, so prefer the
+ // reported physical diagonal there (phones <= ~7", tablets larger), falling
+ // back to the short edge when the physical size is unknown.
+#if defined(Q_OS_IOS) || defined(Q_OS_ANDROID)
+ Q_UNUSED(devicePixelRatio);
+ const int shortEdge = std::min(availableSize.width(), availableSize.height());
+#if defined(Q_OS_ANDROID)
+ const bool regular =
+ (physicalDiagonalInches > 0.0) ? (physicalDiagonalInches >= 7.0) : (shortEdge > 700);
+#else
+ Q_UNUSED(physicalDiagonalInches);
+ const bool regular = (shortEdge > 700);
+#endif
+ const bool useCompact = forceCompact || !regular;
+#else
+ // Desktop dev builds keep the compact layout (unchanged).
Q_UNUSED(availableSize);
Q_UNUSED(devicePixelRatio);
Q_UNUSED(physicalDiagonalInches);
Q_UNUSED(forceCompact);
const bool useCompact = true;
+#endif
/*
bool forceCompactEnvOk = false;
bool forceRegularEnvOk = false;
@@ -226,6 +245,31 @@ void configureForScreen(const QSize &availableSize, qreal devicePixelRatio, qrea
}
*/
+#if defined(Q_OS_ANDROID)
+ // Android tablets are wider and shorter than an iPad (e.g. 1340x800), so
+ // the regular layout's iPad vertical rhythm overflows and clips the bottom
+ // of each column. Tighten the vertical density for the Android tablet
+ // layout (iOS/iPad keep the roomier values).
+ if (!useCompact) {
+ using namespace K4Styles::Dimensions;
+ // The left control column is the tallest. Shrink its DualControlButton
+ // tiles and the group padding to fit. Keep the shared ButtonHeightSmall
+ // at its default so the right panel's two-line function buttons (FREQ
+ // ENT) are not squished; the left MON/NORM/BAL use their own compact
+ // height in SideControlPanel. Shrink the S-meter (and the matching VFO
+ // content height) so the centre's SUB/DIV badges and the B filter
+ // indicator fit; the panadapter absorbs the difference.
+ ButtonHeightLarge = 32; // DualControlButton tiles (left column)
+ ButtonHeightSmall = 22; // right-panel function buttons + left MON/NORM/BAL
+ PaddingLarge = 6;
+ PaddingMedium = 5;
+ PaddingSmall = 4;
+ SpectrumMinHeight = 190;
+ VfoMeterHeight = 120; // was 130; keeps all 5 meter rows, a little tighter
+ VfoContentHeight = 138; // meter + feature labels
+ }
+#endif
+
g_compactLayout = useCompact;
if (useCompact) {
applyCompactDimensions();
diff --git a/src/ui/k4styles.h b/src/ui/k4styles.h
index 74665a4..c59218e 100644
--- a/src/ui/k4styles.h
+++ b/src/ui/k4styles.h
@@ -287,7 +287,8 @@ inline int MenuBarHeight = 52; // Bottom menu bar container height
inline int FormLabelWidth = 80; // Form field labels in dialogs
inline int VfoSquareSize = 45; // VFO A/B indicator squares and mode labels
inline int NavButtonWidth = 54; // Navigation buttons in overlays
-inline int SidePanelWidth = 105; // Left and right side panels
+inline int SidePanelWidth = 105; // Left side panel (and both panels on phone)
+inline int RightSidePanelWidth = 130; // Right side panel; wider on iPad to match macOS
inline int MemoryButtonWidth = 42; // M1-M4, REC, STORE, RCL buttons
// Main layout widths/heights
@@ -295,6 +296,7 @@ inline int CenterPanelWidth = 330; // Center controls column between VFO A/B
inline int VfoColumnWidth = 270; // VFO A/B column width
inline int VfoContentHeight = 150; // VFO normal/mini-pan content height
inline int VfoMeterWidth = 260; // TX meter width inside VFO column
+inline int VfoMeterHeight = 130; // TX/S meter height inside VFO column (regular)
inline int SpectrumMinHeight = 300; // Minimum spectrum/waterfall section height
inline int VfoIndicatorBadgeWidth = 34;
inline int VfoIndicatorBadgeHeight = 30;
diff --git a/src/ui/monoverlay.cpp b/src/ui/monoverlay.cpp
index 60e4394..b7c3801 100644
--- a/src/ui/monoverlay.cpp
+++ b/src/ui/monoverlay.cpp
@@ -2,6 +2,7 @@
#include "k4styles.h"
#include
#include
+#include
#include
MonOverlay::MonOverlay(QWidget *parent) : SideControlOverlay(Global, parent) {
@@ -71,7 +72,38 @@ void MonOverlay::wheelEvent(QWheelEvent *event) {
}
void MonOverlay::mousePressEvent(QMouseEvent *event) {
- // Don't close on click - allow adjustment via wheel
- // Click does nothing, user must click the MON button again to close
- Q_UNUSED(event)
+ m_dragActive = true;
+ m_dragMoved = false;
+ m_dragStartX = event->position().x();
+ m_dragStartY = event->position().y();
+ event->accept();
+}
+
+void MonOverlay::mouseMoveEvent(QMouseEvent *event) {
+ if (!m_dragActive)
+ return;
+ const qreal x = event->position().x();
+ const qreal y = event->position().y();
+ if (!m_dragMoved && (qAbs(y - m_dragStartY) > 4 || qAbs(x - m_dragStartX) > 4))
+ m_dragMoved = true;
+ if (m_dragMoved) {
+ // Top of the overlay is 100, bottom is 0 (vertical slider feel).
+ const qreal h = qMax(1, height());
+ const qreal frac = 1.0 - qBound(0.0, y, h) / h;
+ const int newValue = qBound(0, int(qRound(frac * 100.0)), 100);
+ if (newValue != m_value) {
+ m_value = newValue;
+ updateValueDisplay();
+ emit levelChangeRequested(m_mode, m_value);
+ }
+ }
+ event->accept();
+}
+
+void MonOverlay::mouseReleaseEvent(QMouseEvent *event) {
+ // A tap (press with no drag) dismisses the overlay; a drag adjusted it.
+ if (m_dragActive && !m_dragMoved)
+ hide();
+ m_dragActive = false;
+ event->accept();
}
diff --git a/src/ui/monoverlay.h b/src/ui/monoverlay.h
index e5b3c8b..580ee06 100644
--- a/src/ui/monoverlay.h
+++ b/src/ui/monoverlay.h
@@ -50,6 +50,8 @@ class MonOverlay : public SideControlOverlay {
protected:
void wheelEvent(QWheelEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
+ void mouseMoveEvent(QMouseEvent *event) override;
+ void mouseReleaseEvent(QMouseEvent *event) override;
private:
void setupUi();
@@ -61,6 +63,13 @@ class MonOverlay : public SideControlOverlay {
int m_value = 0;
int m_mode = 0; // 0=CW, 1=Data, 2=Voice
+
+ // Touch drag-to-adjust: a drag maps the finger's vertical position to the
+ // level; a tap (no drag) dismisses the overlay.
+ bool m_dragActive = false;
+ bool m_dragMoved = false;
+ qreal m_dragStartX = 0;
+ qreal m_dragStartY = 0;
};
#endif // MONOVERLAY_H
diff --git a/src/ui/optionsdialog.cpp b/src/ui/optionsdialog.cpp
index bd59492..4e60027 100644
--- a/src/ui/optionsdialog.cpp
+++ b/src/ui/optionsdialog.cpp
@@ -102,7 +102,8 @@ OptionsDialog::~OptionsDialog() {
void OptionsDialog::setupUi() {
new OverlayBackHandler(this, [this] { requestReturnToOperate(); });
setWindowTitle("Options");
-#ifdef Q_OS_ANDROID
+ // Touch platforms show this as an in-window overlay sized to the console.
+#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
setMinimumSize(0, 0);
#else
setMinimumSize(700, 550);
@@ -122,7 +123,10 @@ void OptionsDialog::setupUi() {
.arg(K4Styles::Dimensions::FontSizePopup)
.arg(K4Styles::Colors::GradientBottom));
-#ifdef Q_OS_ANDROID
+ // Touch platforms have no native window chrome, so provide an in-dialog
+ // header with a "RETURN TO OPERATE" button; the desktop uses the window
+ // title bar's close control instead.
+#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
auto *outerLayout = new QVBoxLayout(this);
outerLayout->setContentsMargins(6, 4, 6, 6);
outerLayout->setSpacing(4);
@@ -130,9 +134,13 @@ void OptionsDialog::setupUi() {
auto *title = new QLabel("QK4 SETTINGS", this);
title->setStyleSheet(QString("color: %1; font-size: 16px; font-weight: bold;")
.arg(K4Styles::Colors::AccentAmber));
- auto *close = new QPushButton("RETURN TO OPERATE", this);
- close->setMinimumHeight(30);
- close->setStyleSheet(K4Styles::menuBarButton());
+ // Compact return/enter key on the far right, matching the "↵" button in
+ // the in-window control dialogs (e.g. NR ADJUST) rather than a wide label.
+ auto *close = new QPushButton(QString::fromUtf8("↵"), this);
+ close->setFixedSize(48, 32);
+ close->setStyleSheet(K4Styles::menuBarButton() + "QPushButton { font-size: 20px; font-weight: bold; }");
+ close->setToolTip("Return to operate");
+ close->setAccessibleName("Return to operate");
connect(close, &QPushButton::clicked, this, &OptionsDialog::requestReturnToOperate);
header->addWidget(title);
header->addStretch(1);
@@ -2116,7 +2124,8 @@ QWidget *OptionsDialog::createCwKeyerPage() {
deviceTypeLabel->setStyleSheet(QString("color: %1; font-size: %2px;")
.arg(K4Styles::Colors::TextGray)
.arg(K4Styles::Dimensions::FontSizePopup));
- deviceTypeLabel->setFixedWidth(K4Styles::Dimensions::FormLabelWidth);
+ // Size to the text (a fixed FormLabelWidth clipped "Device Type:").
+ deviceTypeLabel->setMinimumWidth(deviceTypeLabel->sizeHint().width());
m_cwKeyerDeviceTypeCombo = new QComboBox(page);
m_cwKeyerDeviceTypeCombo->setStyleSheet(
@@ -2132,11 +2141,16 @@ QWidget *OptionsDialog::createCwKeyerPage() {
.arg(K4Styles::Dimensions::FontSizePopup)
.arg(K4Styles::Dimensions::PaddingSmall)
.arg(K4Styles::Dimensions::SliderBorderRadius));
+#ifndef Q_OS_IOS
+ // The serial/HID V1.4 keyer is desktop-only; iOS supports MIDI only.
m_cwKeyerDeviceTypeCombo->addItem("HaliKey V1.4", 0);
+#endif
m_cwKeyerDeviceTypeCombo->addItem("HaliKey MIDI", 1);
+ // Select by stored device-type value (index differs once V1.4 is absent).
int savedDeviceType = RadioSettings::instance()->halikeyDeviceType();
- m_cwKeyerDeviceTypeCombo->setCurrentIndex(savedDeviceType);
+ int savedIndex = m_cwKeyerDeviceTypeCombo->findData(savedDeviceType);
+ m_cwKeyerDeviceTypeCombo->setCurrentIndex(savedIndex >= 0 ? savedIndex : 0);
updateCwKeyerDescription();
connect(m_cwKeyerDeviceTypeCombo, QOverload::of(&QComboBox::currentIndexChanged), this, [this](int index) {
diff --git a/src/ui/rightsidepanel.cpp b/src/ui/rightsidepanel.cpp
index 7f2cb26..d6605ba 100644
--- a/src/ui/rightsidepanel.cpp
+++ b/src/ui/rightsidepanel.cpp
@@ -36,8 +36,7 @@ RightSidePanel::RightSidePanel(QWidget *parent)
void RightSidePanel::setupUi() {
const bool compact = K4Styles::isCompactLayout();
- // Match left panel dimensions exactly
- setFixedWidth(K4Styles::Dimensions::SidePanelWidth);
+ setFixedWidth(K4Styles::Dimensions::RightSidePanelWidth);
QPalette panelPalette = palette();
panelPalette.setColor(QPalette::Window, QColor(K4Styles::Colors::PopupBackground));
setPalette(panelPalette);
@@ -52,7 +51,7 @@ void RightSidePanel::setupUi() {
auto *buttonGrid = new QGridLayout();
buttonGrid->setContentsMargins(0, 0, 0, 0);
buttonGrid->setHorizontalSpacing(K4Styles::Dimensions::PopupButtonSpacing);
- buttonGrid->setVerticalSpacing(K4Styles::Dimensions::PopupButtonSpacing);
+ buttonGrid->setVerticalSpacing(K4Styles::isCompactLayout() ? K4Styles::Dimensions::PopupButtonSpacing : 2);
auto *preControl = createFunctionButton("PRE", "ATTN", m_preBtn);
auto *nbControl = createFunctionButton("NB", "LEVEL", m_nbBtn);
@@ -118,7 +117,7 @@ void RightSidePanel::setupUi() {
auto *pfGrid = new QGridLayout();
pfGrid->setContentsMargins(0, 0, 0, 0);
pfGrid->setHorizontalSpacing(K4Styles::Dimensions::PopupButtonSpacing);
- pfGrid->setVerticalSpacing(K4Styles::Dimensions::PopupButtonSpacing);
+ pfGrid->setVerticalSpacing(K4Styles::isCompactLayout() ? K4Styles::Dimensions::PopupButtonSpacing : 2);
auto *bsetControl = createFunctionButton("B SET", "PF 1", m_bsetBtn, true);
auto *clrControl = createFunctionButton("CLR", "PF 2", m_clrBtn, true);
@@ -157,12 +156,16 @@ void RightSidePanel::setupUi() {
auto *bottomGrid = new QGridLayout();
bottomGrid->setContentsMargins(0, 0, 0, 0);
bottomGrid->setHorizontalSpacing(K4Styles::Dimensions::PopupButtonSpacing);
- bottomGrid->setVerticalSpacing(K4Styles::Dimensions::PopupButtonSpacing);
+ bottomGrid->setVerticalSpacing(K4Styles::isCompactLayout() ? K4Styles::Dimensions::PopupButtonSpacing : 2);
- auto *freqControl = createFunctionButton("FREQ\nENT", "SCAN", m_freqEntBtn);
+ auto *freqControl = createFunctionButton("FREQ ENT", "SCAN", m_freqEntBtn);
auto *rateControl = createFunctionButton("RATE", "KHZ", m_rateBtn);
auto *lockControl = createFunctionButton("LOCK A", "LOCK B", m_lockABtn);
auto *subControl = createFunctionButton("SUB", "DIVERSITY", m_subBtn);
+ // The "DIVERSITY" amber sub-label; turned green as the DIV LED (regular only,
+ // where the sub-label is a separate QLabel under the button).
+ if (!compact)
+ m_diversityLabel = subControl->findChild();
if (compact) {
buttonGrid->addWidget(freqControl, 3, 2);
buttonGrid->addWidget(rateControl, 3, 3);
@@ -186,30 +189,84 @@ void RightSidePanel::setupUi() {
m_rateBtn->installEventFilter(this);
m_lockABtn->installEventFilter(this);
m_subBtn->installEventFilter(this);
+
+ // iPad fine-tune pad (A-/A+/B-/B+). Fine tuning is awkward by touch on the
+ // panadapter; these give the phone app's well-liked step buttons on iPad.
+ // These are not controls on the radio, so separate them from the radio
+ // button groups with the same inter-group spacing used above, and style
+ // them like the function buttons above (style guide sidePanelButton).
+ if (!compact) {
+ auto makeTuneBtn = [this](const QString &text) {
+ auto *btn = new QPushButton(text, this);
+ btn->setFixedHeight(K4Styles::Dimensions::ButtonHeightSmall);
+ btn->setCursor(Qt::PointingHandCursor);
+ btn->setStyleSheet(K4Styles::sidePanelButton());
+ // Typematic: one tap = one step; press-and-hold repeats after a short
+ // delay until released (like a keyboard arrow key).
+ btn->setAutoRepeat(true);
+ btn->setAutoRepeatDelay(400);
+ btn->setAutoRepeatInterval(90);
+ return btn;
+ };
+ m_layout->addSpacing(K4Styles::Dimensions::PaddingLarge * 2 + K4Styles::Dimensions::PaddingSmall);
+ auto *tuneGrid = new QGridLayout();
+ tuneGrid->setContentsMargins(0, 0, 0, 0);
+ tuneGrid->setHorizontalSpacing(K4Styles::Dimensions::PopupButtonSpacing);
+ tuneGrid->setVerticalSpacing(K4Styles::isCompactLayout() ? K4Styles::Dimensions::PopupButtonSpacing : 2);
+ m_tuneADownBtn = makeTuneBtn(QStringLiteral("A −"));
+ m_tuneAUpBtn = makeTuneBtn(QStringLiteral("A +"));
+ m_tuneBDownBtn = makeTuneBtn(QStringLiteral("B −"));
+ m_tuneBUpBtn = makeTuneBtn(QStringLiteral("B +"));
+ tuneGrid->addWidget(m_tuneADownBtn, 0, 0);
+ tuneGrid->addWidget(m_tuneAUpBtn, 0, 1);
+ tuneGrid->addWidget(m_tuneBDownBtn, 1, 0);
+ tuneGrid->addWidget(m_tuneBUpBtn, 1, 1);
+ m_layout->addLayout(tuneGrid);
+
+ connect(m_tuneADownBtn, &QPushButton::clicked, this, [this]() { emit tuneARequested(-1); });
+ connect(m_tuneAUpBtn, &QPushButton::clicked, this, [this]() { emit tuneARequested(1); });
+ connect(m_tuneBDownBtn, &QPushButton::clicked, this, [this]() { emit tuneBRequested(-1); });
+ connect(m_tuneBUpBtn, &QPushButton::clicked, this, [this]() { emit tuneBRequested(1); });
+ }
}
QWidget *RightSidePanel::createFunctionButton(const QString &mainText, const QString &subText, QPushButton *&btnOut,
bool isLighter) {
- // The alternate action belongs inside the same touch target as its primary.
+ const bool compact = K4Styles::isCompactLayout();
auto *container = new QWidget(this);
auto *layout = new QVBoxLayout(container);
- layout->setContentsMargins(0, K4Styles::isCompactLayout() ? 0 : K4Styles::Dimensions::SeparatorHeight + 1,
- 0, K4Styles::isCompactLayout() ? 0 : K4Styles::Dimensions::SeparatorHeight + 1);
- layout->setSpacing(K4Styles::isCompactLayout() ? 0 : K4Styles::Dimensions::PaddingSmall);
-
- // Button - scaled down from bottom menu bar style (matching left panel TX buttons)
- auto *btn = new DualLinePanelButton(mainText, subText, container);
- btn->setFixedHeight(42);
- btn->setCursor(Qt::PointingHandCursor);
+ layout->setContentsMargins(0, compact ? 0 : 1, 0, compact ? 0 : 3);
+ // Tight gap above the amber label so it clearly belongs to the button it
+ // sits under, with a larger gap below to the next row (matches macOS).
+ layout->setSpacing(compact ? 0 : 1);
- if (isLighter) {
- btn->setStyleSheet(K4Styles::sidePanelButtonLight());
+ // Phone keeps both labels inside one touch target (DualLinePanelButton).
+ // iPad matches macOS/the radio: white primary on the button, amber
+ // alternate rendered on the case (a QLabel below), so long names like
+ // "DIVERSITY" are not clipped by the button width.
+ QPushButton *btn;
+ if (compact) {
+ btn = new DualLinePanelButton(mainText, subText, container);
+ btn->setFixedHeight(42);
} else {
- btn->setStyleSheet(K4Styles::sidePanelButton());
+ btn = new QPushButton(mainText, container);
+ btn->setFixedHeight(K4Styles::Dimensions::ButtonHeightSmall);
}
+ btn->setCursor(Qt::PointingHandCursor);
+ btn->setStyleSheet(isLighter ? K4Styles::sidePanelButtonLight() : K4Styles::sidePanelButton());
btnOut = btn;
layout->addWidget(btn);
+ if (!compact) {
+ auto *subLabel = new QLabel(subText, container);
+ subLabel->setStyleSheet(QString("color: %1; font-size: %2px;")
+ .arg(K4Styles::Colors::AccentAmber)
+ .arg(K4Styles::Dimensions::FontSizeSmall));
+ subLabel->setAlignment(Qt::AlignCenter);
+ subLabel->setFixedHeight(12);
+ layout->addWidget(subLabel);
+ }
+
return container;
}
@@ -236,6 +293,38 @@ void RightSidePanel::cancelPendingLongPress() {
m_revBtn->setDown(false);
}
+void RightSidePanel::setSubActive(bool on) {
+ // LED only on regular layout (compact packs SUB/DIV into one custom button).
+ if (K4Styles::isCompactLayout() || !m_subBtn)
+ return;
+ if (on)
+ m_subBtn->setStyleSheet(QString("QPushButton { background-color: %1; color: black;"
+ "font-weight: bold; border-radius: 4px; }")
+ .arg(K4Styles::Colors::StatusGreen));
+ else
+ m_subBtn->setStyleSheet(K4Styles::sidePanelButton());
+}
+
+void RightSidePanel::setDiversityActive(bool on) {
+ if (!m_diversityLabel)
+ return;
+ m_diversityLabel->setStyleSheet(QString("color: %1; font-size: %2px; font-weight: %3;")
+ .arg(on ? K4Styles::Colors::StatusGreen : K4Styles::Colors::AccentAmber)
+ .arg(K4Styles::Dimensions::FontSizeSmall)
+ .arg(on ? "bold" : "normal"));
+}
+
+void RightSidePanel::setBSetActive(bool on) {
+ if (K4Styles::isCompactLayout() || !m_bsetBtn)
+ return;
+ if (on)
+ m_bsetBtn->setStyleSheet(QString("QPushButton { background-color: %1; color: black;"
+ "font-weight: bold; border-radius: 4px; }")
+ .arg(K4Styles::Colors::StatusGreen));
+ else
+ m_bsetBtn->setStyleSheet(K4Styles::sidePanelButtonLight());
+}
+
bool RightSidePanel::eventFilter(QObject *watched, QEvent *event) {
if (watched == m_revBtn) {
if (event->type() == QEvent::MouseButtonPress) {
diff --git a/src/ui/rightsidepanel.h b/src/ui/rightsidepanel.h
index d101983..fa02940 100644
--- a/src/ui/rightsidepanel.h
+++ b/src/ui/rightsidepanel.h
@@ -45,6 +45,14 @@ class RightSidePanel : public QWidget {
// Cancel an alternate-action hold when the phone drawer begins scrolling.
void cancelPendingLongPress();
+ // Green "LED" state on the SUB / DIVERSITY button (the radio shows these as
+ // LEDs; they were removed from the centre VFO area). Regular layout only.
+ void setSubActive(bool on);
+ void setDiversityActive(bool on);
+ // Green highlight on the B SET button while B SET (target Sub RX) is active,
+ // so the mode is easy to see. Regular layout only.
+ void setBSetActive(bool on);
+
signals:
// Button click signals (main function - left click)
void preClicked();
@@ -94,6 +102,10 @@ class RightSidePanel : public QWidget {
void lockBClicked(); // LOCK A right-click (LOCK B)
void diversityClicked(); // SUB right-click
+ // iPad fine-tune buttons (A-/A+/B-/B+). steps = +/-1 tuning increment.
+ void tuneARequested(int steps);
+ void tuneBRequested(int steps);
+
protected:
bool eventFilter(QObject *watched, QEvent *event) override;
@@ -128,6 +140,13 @@ class RightSidePanel : public QWidget {
QPushButton *m_rateBtn;
QPushButton *m_lockABtn;
QPushButton *m_subBtn;
+ QLabel *m_diversityLabel = nullptr; // amber "DIVERSITY" sub-label; green when active
+
+ // iPad fine-tune buttons (regular layout only; null on phone)
+ QPushButton *m_tuneADownBtn = nullptr;
+ QPushButton *m_tuneAUpBtn = nullptr;
+ QPushButton *m_tuneBDownBtn = nullptr;
+ QPushButton *m_tuneBUpBtn = nullptr;
// Qt maps a desktop secondary action to a right click. Android has no
// such gesture, so a held touch triggers the same alternate action.
diff --git a/src/ui/sidecontrolpanel.cpp b/src/ui/sidecontrolpanel.cpp
index 3eed68b..3c8b62d 100644
--- a/src/ui/sidecontrolpanel.cpp
+++ b/src/ui/sidecontrolpanel.cpp
@@ -1,5 +1,8 @@
#include "sidecontrolpanel.h"
#include "dualcontrolbutton.h"
+#include "adjustoverlay.h"
+#include "monoverlay.h"
+#include "baloverlay.h"
#include "duallinepanelbutton.h"
#include "k4styles.h"
#include "../settings/radiosettings.h"
@@ -14,6 +17,8 @@
#include
#include
#include
+#include
+#include
SideControlPanel::SideControlPanel(QWidget *parent) : QWidget(parent) {
m_longPressTimer = new QTimer(this);
@@ -110,7 +115,13 @@ void SideControlPanel::setupUi() {
auto *layout = new QVBoxLayout(this);
layout->setContentsMargins(K4Styles::Dimensions::PaddingSmall, K4Styles::Dimensions::PopupButtonSpacing,
K4Styles::Dimensions::PaddingSmall, K4Styles::Dimensions::PopupButtonSpacing);
+ // Tighter inter-row spacing on the Android tablet reclaims the vertical
+ // room needed to keep the bottom MAIN/SUB sliders on-screen.
+#if defined(Q_OS_ANDROID)
+ layout->setSpacing(K4Styles::isCompactLayout() ? 4 : 2);
+#else
layout->setSpacing(4); // Default spacing between buttons in a group
+#endif
auto addAdjustmentRow = [this, layout](DualControlButton *button, QSlider *&slider, const QString &color) {
auto *row = new QWidget(this);
@@ -124,67 +135,92 @@ void SideControlPanel::setupUi() {
slider->setStyleSheet(K4Styles::sliderHorizontal(K4Styles::Colors::DarkBackground, color));
slider->installEventFilter(this);
rowLayout->addWidget(slider, 1);
+ // iPad (macOS-style column): the thin per-tile rail is replaced by the
+ // long-press adjust popup, matching QK4 on macOS which has no rail.
+ // The slider stays wired (radio echoes keep it in sync) but hidden.
+ if (!K4Styles::isCompactLayout()) {
+ slider->hide();
+ rowLayout->addStretch(1);
+ rowLayout->setAlignment(button, Qt::AlignHCenter);
+ }
layout->addWidget(row);
};
- // ===== Receiver AF controls: always first in the phone CTRL bank =====
- m_volumeLabel = new QLabel("A AF", this);
+ // ===== Receiver AF + local mic controls =====
+ // Compact (phone CTRL bank): these lead the scrollable page. Regular
+ // (iPad): they move to the bottom of the always-visible column and the
+ // volumes are labelled MAIN/SUB, matching QK4 on macOS and the radio.
+ const bool afAtTop = K4Styles::isCompactLayout();
+ auto *afGroup = new QWidget(this);
+ auto *afLayout = new QVBoxLayout(afGroup);
+ afLayout->setContentsMargins(0, 0, 0, 0);
+ afLayout->setSpacing(4);
+
+ m_volumeLabel = new QLabel(afAtTop ? "A AF" : "MAIN", afGroup);
m_volumeLabel->setStyleSheet(
QString("color: %1; font-size: 10px; font-weight: bold;").arg(K4Styles::Colors::VfoACyan));
m_volumeLabel->setAlignment(Qt::AlignCenter);
- layout->addWidget(m_volumeLabel);
+ afLayout->addWidget(m_volumeLabel);
- m_volumeSlider = new QSlider(Qt::Horizontal, this);
+ m_volumeSlider = new QSlider(Qt::Horizontal, afGroup);
m_volumeSlider->setRange(0, 100);
m_volumeSlider->setValue(RadioSettings::instance()->volume());
m_volumeSlider->setMinimumHeight(K4Styles::isCompactLayout() ? 32 : 24);
m_volumeSlider->setStyleSheet(
K4Styles::sliderHorizontal(K4Styles::Colors::DarkBackground, K4Styles::Colors::VfoACyan));
m_volumeSlider->installEventFilter(this);
- layout->addWidget(m_volumeSlider);
+ afLayout->addWidget(m_volumeSlider);
connect(m_volumeSlider, &QSlider::valueChanged, this, &SideControlPanel::volumeChanged);
- m_subVolumeLabel = new QLabel("B AF", this);
+ m_subVolumeLabel = new QLabel(afAtTop ? "B AF" : "SUB", afGroup);
m_subVolumeLabel->setStyleSheet(
QString("color: %1; font-size: 10px; font-weight: bold;").arg(K4Styles::Colors::VfoBGreen));
m_subVolumeLabel->setAlignment(Qt::AlignCenter);
- layout->addWidget(m_subVolumeLabel);
+ afLayout->addWidget(m_subVolumeLabel);
- m_subVolumeSlider = new QSlider(Qt::Horizontal, this);
+ m_subVolumeSlider = new QSlider(Qt::Horizontal, afGroup);
m_subVolumeSlider->setRange(0, 100);
m_subVolumeSlider->setValue(RadioSettings::instance()->subVolume());
m_subVolumeSlider->setMinimumHeight(K4Styles::isCompactLayout() ? 32 : 24);
m_subVolumeSlider->setStyleSheet(
K4Styles::sliderHorizontal(K4Styles::Colors::DarkBackground, K4Styles::Colors::VfoBGreen));
m_subVolumeSlider->installEventFilter(this);
- layout->addWidget(m_subVolumeSlider);
+ afLayout->addWidget(m_subVolumeSlider);
connect(m_subVolumeSlider, &QSlider::valueChanged, this, &SideControlPanel::subVolumeChanged);
// Local input gain is intentionally separate from the K4 MIC control.
// It scales the phone/headset microphone stream before Opus encoding.
- m_phoneMicGainLabel = new QLabel("PHONE MIC", this);
- m_phoneMicGainLabel->setStyleSheet(
- QString("color: %1; font-size: 10px; font-weight: bold;").arg(K4Styles::Colors::AccentAmber));
- m_phoneMicGainLabel->setAlignment(Qt::AlignCenter);
- layout->addWidget(m_phoneMicGainLabel);
-
- m_phoneMicGainSlider = new QSlider(Qt::Horizontal, this);
- m_phoneMicGainSlider->setRange(0, 100);
- m_phoneMicGainSlider->setValue(RadioSettings::instance()->micGain());
- m_phoneMicGainSlider->setMinimumHeight(K4Styles::isCompactLayout() ? 32 : 24);
- m_phoneMicGainSlider->setStyleSheet(
- K4Styles::sliderHorizontal(K4Styles::Colors::DarkBackground, K4Styles::Colors::AccentAmber));
- m_phoneMicGainSlider->installEventFilter(this);
- layout->addWidget(m_phoneMicGainSlider);
- connect(m_phoneMicGainSlider, &QSlider::valueChanged, this, &SideControlPanel::phoneMicGainChanged);
-
- layout->addSpacing(K4Styles::Dimensions::PaddingMedium);
+ // On iPad the K4 MIC gain is adjusted from the MIC/CMP tile, so this
+ // duplicate-looking PHONE MIC rail is omitted there; it stays on the
+ // phone layout where the tiles are less prominent.
+ if (K4Styles::isCompactLayout()) {
+ m_phoneMicGainLabel = new QLabel("PHONE MIC", afGroup);
+ m_phoneMicGainLabel->setStyleSheet(
+ QString("color: %1; font-size: 10px; font-weight: bold;").arg(K4Styles::Colors::AccentAmber));
+ m_phoneMicGainLabel->setAlignment(Qt::AlignCenter);
+ afLayout->addWidget(m_phoneMicGainLabel);
+
+ m_phoneMicGainSlider = new QSlider(Qt::Horizontal, afGroup);
+ m_phoneMicGainSlider->setRange(0, 100);
+ m_phoneMicGainSlider->setValue(RadioSettings::instance()->micGain());
+ m_phoneMicGainSlider->setMinimumHeight(32);
+ m_phoneMicGainSlider->setStyleSheet(
+ K4Styles::sliderHorizontal(K4Styles::Colors::DarkBackground, K4Styles::Colors::AccentAmber));
+ m_phoneMicGainSlider->installEventFilter(this);
+ afLayout->addWidget(m_phoneMicGainSlider);
+ connect(m_phoneMicGainSlider, &QSlider::valueChanged, this, &SideControlPanel::phoneMicGainChanged);
+ }
+
+ if (afAtTop) {
+ layout->addWidget(afGroup);
+ layout->addSpacing(K4Styles::Dimensions::PaddingMedium);
+ }
// ===== TX Function Buttons (2x3 grid) =====
auto *txGrid = new QGridLayout();
txGrid->setContentsMargins(0, 0, 0, 0);
txGrid->setHorizontalSpacing(K4Styles::Dimensions::PopupButtonSpacing);
- txGrid->setVerticalSpacing(K4Styles::Dimensions::PopupButtonSpacing);
+ txGrid->setVerticalSpacing(K4Styles::isCompactLayout() ? K4Styles::Dimensions::PopupButtonSpacing : 2);
// Row 0: TUNE, XMIT
txGrid->addWidget(createTxFunctionButton("TUNE", "TUNE LP", m_tuneBtn), 0, 0);
@@ -220,6 +256,43 @@ void SideControlPanel::setupUi() {
// ===== Spacing after TX buttons =====
layout->addSpacing(K4Styles::Dimensions::PaddingLarge);
+ // MON / NORM / BAL each sit under the control pair they act on, matching
+ // the K4 front panel. Full-width so they never crowd each other; taller on
+ // the iPad for touch, compact-mini on the phone.
+#if defined(Q_OS_ANDROID)
+ // Android tablet: a compact MON/NORM/BAL height (independent of the shared
+ // ButtonHeightSmall, which the right panel needs at full size) so the left
+ // column fits.
+ const int swBtnHeight = K4Styles::isCompactLayout() ? K4Styles::Dimensions::ButtonHeightMini : 22;
+#else
+ const int swBtnHeight = K4Styles::isCompactLayout() ? K4Styles::Dimensions::ButtonHeightMini
+ : K4Styles::Dimensions::ButtonHeightSmall;
+#endif
+ auto addSwButton = [this, layout, swBtnHeight](QPushButton *&btn, const QString &text) {
+ btn = new QPushButton(text, this);
+ btn->setFixedHeight(swBtnHeight);
+ btn->setStyleSheet(K4Styles::compactButton());
+ if (K4Styles::isCompactLayout()) {
+ layout->addWidget(btn);
+ } else {
+ // Align the button's visible box with the DualControlButton tiles
+ // above. Their painted box is inset inside the 90px widget by
+ // barWidth(5)+margin(1)+2 on the left and margin(1) on the right
+ // (see DualControlButton::paintEvent); a plain button paints to its
+ // own edge, so inset it by the same amounts to line the boxes up.
+ constexpr int tileBoxLeft = 5 + 1 + 2;
+ const int tileBoxWidth = K4Styles::Dimensions::MenuBarButtonWidth - tileBoxLeft - 1;
+ btn->setFixedWidth(tileBoxWidth);
+ auto *row = new QWidget(this);
+ auto *rowLayout = new QHBoxLayout(row);
+ rowLayout->setContentsMargins(tileBoxLeft, 0, 0, 0);
+ rowLayout->setSpacing(0);
+ rowLayout->addWidget(btn);
+ rowLayout->addStretch(1);
+ layout->addWidget(row);
+ }
+ };
+
// ===== Group 1: Global (CW/Power) - Orange bar =====
m_wpmBtn = new DualControlButton(this);
m_wpmBtn->setPrimaryLabel("WPM");
@@ -239,6 +312,10 @@ void SideControlPanel::setupUi() {
m_pwrBtn->setShowIndicator(false); // Second button starts inactive
addAdjustmentRow(m_pwrBtn, m_pwrSlider, K4Styles::Colors::AccentAmber);
+ // MON: monitor level, under the WPM/PWR (MIC/PWR/CMP/DLY) group.
+ addSwButton(m_monBtn, QStringLiteral("MON"));
+ m_monBtn->setToolTip(QStringLiteral("Monitor (sidetone / TX audio) level"));
+
// ===== Spacing between groups =====
layout->addSpacing(K4Styles::Dimensions::PaddingLarge);
@@ -261,15 +338,10 @@ void SideControlPanel::setupUi() {
m_shiftBtn->setShowIndicator(false); // Second button starts inactive
addAdjustmentRow(m_shiftBtn, m_shiftSlider, K4Styles::Colors::VfoACyan);
- // NORM affects only the filter passband, so keep it in the filter group.
- m_normBtn = new QPushButton(QStringLiteral("NORM"), this);
- m_normBtn->setFixedHeight(32);
- m_normBtn->setStyleSheet(K4Styles::compactButton());
+ // NORM: normalize the filter passband, under the BW/SHFT (HI/LO) group.
+ addSwButton(m_normBtn, QStringLiteral("NORM"));
m_normBtn->setAccessibleName(QStringLiteral("Normalize receive filter passband"));
m_normBtn->setToolTip(QStringLiteral("Restore the current mode's nominal filter passband"));
- m_normBtn->installEventFilter(this);
- layout->addWidget(m_normBtn);
- connect(m_normBtn, &QPushButton::clicked, this, &SideControlPanel::normalizeFilterRequested);
// ===== Spacing between groups =====
layout->addSpacing(K4Styles::Dimensions::PaddingLarge);
@@ -293,6 +365,42 @@ void SideControlPanel::setupUi() {
m_subSqlBtn->setShowIndicator(false); // Second button starts inactive
addAdjustmentRow(m_subSqlBtn, m_subSqlSlider, K4Styles::Colors::VfoBGreen);
+ // BAL: sub-RX audio balance, under the M.RF/S.SQL (M.SQL/S.RF) group.
+ addSwButton(m_balBtn, QStringLiteral("BAL"));
+ m_balBtn->setToolTip(QStringLiteral("Sub-RX audio balance"));
+
+ // Overlays cover their control groups; construct after all groups exist so
+ // raise() in showOverGroup lands them on top.
+ m_monOverlay = new MonOverlay(this);
+ m_balOverlay = new BalOverlay(this);
+
+ connect(m_normBtn, &QPushButton::clicked, this, &SideControlPanel::normalizeFilterRequested);
+ connect(m_monBtn, &QPushButton::clicked, this, [this]() {
+ emit monClicked();
+ if (m_monOverlay->isVisible())
+ m_monOverlay->hide();
+ else
+ m_monOverlay->showOverGroup(m_wpmBtn, m_pwrBtn);
+ });
+ connect(m_balBtn, &QPushButton::clicked, this, [this]() {
+ emit balClicked();
+ if (m_balOverlay->isVisible())
+ m_balOverlay->hide();
+ else
+ m_balOverlay->showOverGroup(m_mainRfBtn, m_subSqlBtn);
+ });
+ connect(m_monOverlay, &MonOverlay::levelChangeRequested,
+ this, &SideControlPanel::monLevelChangeRequested);
+ connect(m_balOverlay, &BalOverlay::balanceChangeRequested,
+ this, &SideControlPanel::balChangeRequested);
+
+ // Regular (iPad): MAIN/SUB volumes and PHONE MIC sit at the bottom of the
+ // column, as on QK4 for macOS, instead of leading it.
+ if (!afAtTop) {
+ layout->addSpacing(K4Styles::Dimensions::PaddingMedium);
+ layout->addWidget(afGroup);
+ }
+
// ===== Stretch to push status/icons to bottom =====
layout->addStretch();
@@ -310,6 +418,23 @@ void SideControlPanel::setupUi() {
m_voltageCurrentLabel->setStyleSheet(QString("color: %1; font-size: 11px;").arg(K4Styles::Colors::TextWhite));
layout->addWidget(m_voltageCurrentLabel);
+#if defined(Q_OS_ANDROID)
+ // On the Android tablet the top status bar already shows time / power-SWR /
+ // voltage-current, so hide these duplicates here (kept as members so the
+ // radio-state setters still update them harmlessly). The version line below
+ // stays — it isn't in the top bar. Compact phone keeps all of them.
+ if (!K4Styles::isCompactLayout()) {
+ m_timeLabel->hide();
+ m_powerSwrLabel->hide();
+ m_voltageCurrentLabel->hide();
+ }
+#endif
+
+ // App version, lower-left, matching QK4 on macOS.
+ auto *versionLabel = new QLabel(QString("v%1").arg(QCoreApplication::applicationVersion()), this);
+ versionLabel->setStyleSheet(QString("color: %1; font-size: 10px;").arg(K4Styles::Colors::InactiveGray));
+ layout->addWidget(versionLabel);
+
layout->addSpacing(K4Styles::Dimensions::PopupButtonSpacing);
// ===== Connect Group 1 signals (WPM/PWR) =====
@@ -429,6 +554,60 @@ void SideControlPanel::setupUi() {
configureAdjustmentSlider(m_shiftBtn, m_shiftSlider);
configureAdjustmentSlider(m_mainRfBtn, m_mainRfSlider);
configureAdjustmentSlider(m_subSqlBtn, m_subSqlSlider);
+
+ // iPad: a long-press on any value tile opens the touch adjust popup.
+ for (DualControlButton *btn : {m_wpmBtn, m_pwrBtn, m_bwBtn, m_shiftBtn, m_mainRfBtn, m_subSqlBtn}) {
+ connect(btn, &DualControlButton::adjustRequested, this, [this, btn]() { openAdjustOverlay(btn); });
+ }
+}
+
+void SideControlPanel::openAdjustOverlay(DualControlButton *button) {
+ if (!button)
+ return;
+
+ if (!m_adjustOverlay) {
+ m_adjustOverlay = new AdjustOverlay(window());
+ connect(m_adjustOverlay->slider(), &QSlider::valueChanged, this, [this](int value) {
+ QSlider *s = m_adjustOverlay->slider();
+ const int previous = s->property("lastRadioValue").toInt();
+ s->setProperty("lastRadioValue", value);
+ const int delta = value - previous;
+ if (delta == 0 || !m_adjustButton)
+ return;
+ // Route through the same per-control handlers the tiles/rail use.
+ if (m_adjustButton == m_wpmBtn)
+ onWpmScrolled(delta);
+ else if (m_adjustButton == m_pwrBtn)
+ onPwrScrolled(delta);
+ else if (m_adjustButton == m_bwBtn)
+ onBwScrolled(delta);
+ else if (m_adjustButton == m_shiftBtn)
+ onShiftScrolled(delta);
+ else if (m_adjustButton == m_mainRfBtn)
+ onMainRfScrolled(delta);
+ else if (m_adjustButton == m_subSqlBtn)
+ onSubSqlScrolled(delta);
+ });
+ }
+
+ m_adjustButton = button;
+ configureAdjustmentSlider(button, m_adjustOverlay->slider());
+ m_adjustOverlay->configure(button->primaryLabel(), button->context());
+
+ // Show the readout in the control's real units (kHz for the filter
+ // controls, seconds for DLY) instead of the raw slider integer.
+ const auto kHzFromHz = [](double hz) { return QString::number(hz / 1000.0, 'f', 2); };
+ std::function fmt; // empty => raw integer
+ if (button == m_bwBtn)
+ fmt = m_bwIsPrimary ? std::function([kHzFromHz](int v) { return kHzFromHz(v * 50.0); }) // BW
+ : std::function([kHzFromHz](int v) { return kHzFromHz(v * 10.0); }); // HI
+ else if (button == m_shiftBtn)
+ fmt = [kHzFromHz](int v) { return kHzFromHz(v * 10.0); }; // SHFT / LO (10 Hz units)
+ else if (button == m_pwrBtn && !m_pwrIsPrimary)
+ fmt = [](int v) { return QString::number(v / 100.0, 'f', 2); }; // DLY seconds
+ m_adjustOverlay->setValueFormatter(fmt);
+
+ m_adjustOverlay->showOver(button);
}
void SideControlPanel::configureAdjustmentSlider(DualControlButton *button, QSlider *slider) {
@@ -881,20 +1060,47 @@ void SideControlPanel::setCurrent(double amps) {
QWidget *SideControlPanel::createTxFunctionButton(const QString &mainText, const QString &subText,
QPushButton *&btnOut) {
+ const bool compact = K4Styles::isCompactLayout();
// Container widget for button + sub-text label
auto *container = new QWidget(this);
auto *layout = new QVBoxLayout(container);
- layout->setContentsMargins(0, K4Styles::Dimensions::SeparatorHeight + 1, 0, K4Styles::Dimensions::SeparatorHeight + 1);
- layout->setSpacing(K4Styles::Dimensions::PaddingSmall);
-
- // Keep both the primary and amber alternate action inside one touch target.
- auto *btn = new DualLinePanelButton(mainText, subText, container);
- btn->setFixedHeight(42);
+ layout->setContentsMargins(0, compact ? 0 : 1, 0, compact ? 0 : 3);
+ // Tight gap above the amber label so it clearly belongs to the button it
+ // sits under, with a larger gap below to the next row (matches macOS).
+ layout->setSpacing(compact ? 0 : 1);
+
+ // Phone keeps both labels inside one touch target. iPad matches the radio
+ // and macOS: white primary on the button, amber alternate on the case
+ // (a QLabel below the button).
+ QPushButton *btn;
+ if (compact) {
+ btn = new DualLinePanelButton(mainText, subText, container);
+ btn->setFixedHeight(42);
+ } else {
+ btn = new QPushButton(mainText, container);
+ btn->setFixedHeight(K4Styles::Dimensions::ButtonHeightSmall);
+ }
btn->setCursor(Qt::PointingHandCursor);
- btn->setStyleSheet(K4Styles::sidePanelButtonLight());
+ // A two-line label (e.g. "ATU\nTUNE") clips inside the single-line tile
+ // height; drop its font a touch and remove padding so both lines fit and
+ // read clearly without growing the (already tight) left column.
+ QString btnStyle = K4Styles::sidePanelButtonLight();
+ if (!compact && mainText.contains('\n'))
+ btnStyle += QStringLiteral(" QPushButton { font-size: 10px; padding: 0px; }");
+ btn->setStyleSheet(btnStyle);
btnOut = btn;
layout->addWidget(btn);
+ if (!compact) {
+ auto *subLabel = new QLabel(subText, container);
+ subLabel->setStyleSheet(QString("color: %1; font-size: %2px;")
+ .arg(K4Styles::Colors::AccentAmber)
+ .arg(K4Styles::Dimensions::FontSizeSmall));
+ subLabel->setAlignment(Qt::AlignCenter);
+ subLabel->setFixedHeight(12);
+ layout->addWidget(subLabel);
+ }
+
return container;
}
@@ -1070,3 +1276,18 @@ void SideControlPanel::triggerSecondary(QObject *watched) {
else if (watched == m_antBtn) emit remAntClicked();
else if (watched == m_rxAntBtn) emit subAntClicked();
}
+
+void SideControlPanel::updateMonitorLevel(int mode, int level) {
+ if (m_monOverlay && m_monOverlay->mode() == mode)
+ m_monOverlay->setValue(level);
+}
+
+void SideControlPanel::updateMonitorMode(int mode) {
+ if (m_monOverlay)
+ m_monOverlay->setMode(mode);
+}
+
+void SideControlPanel::updateBalance(int mode, int offset) {
+ if (m_balOverlay)
+ m_balOverlay->setBalance(mode, offset);
+}
diff --git a/src/ui/sidecontrolpanel.h b/src/ui/sidecontrolpanel.h
index f76bc91..1d27cb0 100644
--- a/src/ui/sidecontrolpanel.h
+++ b/src/ui/sidecontrolpanel.h
@@ -8,6 +8,9 @@
#include
class DualControlButton;
+class AdjustOverlay;
+class MonOverlay;
+class BalOverlay;
class QGridLayout;
class QScrollArea;
@@ -95,6 +98,14 @@ class SideControlPanel : public QWidget {
// Cancel an alternate-action hold when a containing phone panel begins scrolling.
void cancelPendingLongPress();
+public slots:
+ // Monitor level from radio (mode 0=CW/1=Data/2=Voice); updates MON overlay.
+ void updateMonitorLevel(int mode, int level);
+ // Track current monitor mode so ML commands target the right register.
+ void updateMonitorMode(int mode);
+ // Sub-AF balance from radio (mode 0=NOR/1=BAL, offset -50..+50).
+ void updateBalance(int mode, int offset);
+
signals:
// TX Function button signals (left-click = primary, right-click = secondary)
void tuneClicked(); // TUNE - SW16;
@@ -109,6 +120,8 @@ class SideControlPanel : public QWidget {
void remAntClicked(); // REM ANT - TBD
void rxAntClicked(); // RX ANT - SW70;
void subAntClicked(); // SUB ANT - SW157;
+ void monClicked(); // MON - SW128;
+ void balClicked(); // BAL - SW130;
// Value changed signals (emitted when user scrolls to change value)
// CW mode signals
@@ -137,6 +150,11 @@ class SideControlPanel : public QWidget {
// Restore the current mode's nominal filter passband.
void normalizeFilterRequested();
+ // Monitor level edited on the MON overlay (mode 0/1/2, level 0-100).
+ void monLevelChangeRequested(int mode, int level);
+ // Sub-AF balance edited on the BAL overlay (mode 0/1, offset -50..+50).
+ void balChangeRequested(int mode, int offset);
+
private slots:
// Group 1: WPM/PWR - handle activation and scrolling
void onWpmBecameActive();
@@ -166,6 +184,7 @@ private slots:
void setupUi();
void triggerSecondary(QObject *watched);
void configureAdjustmentSlider(DualControlButton *button, QSlider *slider);
+ void openAdjustOverlay(DualControlButton *button);
void setSliderValueFromTouchPosition(QSlider *slider, int xPosition);
QScrollArea *containingScrollArea() const;
void setGroup1Active(DualControlButton *activeBtn);
@@ -204,6 +223,11 @@ private slots:
QSlider *m_mainRfSlider = nullptr;
QSlider *m_subSqlSlider = nullptr;
+ // iPad touch adjust popup (shared, one at a time). m_adjustButton is the
+ // control whose value the popup slider currently drives.
+ AdjustOverlay *m_adjustOverlay = nullptr;
+ DualControlButton *m_adjustButton = nullptr;
+
int m_wpmValue = 20;
int m_pitchValue = 600;
int m_micValue = 0;
@@ -257,12 +281,15 @@ private slots:
QLabel *m_volumeLabel;
QSlider *m_subVolumeSlider;
QLabel *m_subVolumeLabel;
- QSlider *m_phoneMicGainSlider;
- QLabel *m_phoneMicGainLabel;
+ QSlider *m_phoneMicGainSlider = nullptr;
+ QLabel *m_phoneMicGainLabel = nullptr;
- // NORM stays with filter controls. K4 MON and BAL are intentionally
- // omitted from the remote UI; A AF and B AF provide independent levels.
+ // MON / NORM / BAL row, grouped as on the K4 and QK4 for macOS.
+ QPushButton *m_monBtn = nullptr;
QPushButton *m_normBtn = nullptr;
+ QPushButton *m_balBtn = nullptr;
+ MonOverlay *m_monOverlay = nullptr;
+ BalOverlay *m_balOverlay = nullptr;
};
#endif // SIDECONTROLPANEL_H
diff --git a/src/ui/txmeterwidget.cpp b/src/ui/txmeterwidget.cpp
index 5f9931b..84b231b 100644
--- a/src/ui/txmeterwidget.cpp
+++ b/src/ui/txmeterwidget.cpp
@@ -8,7 +8,7 @@ TxMeterWidget::TxMeterWidget(QWidget *parent) : QWidget(parent) {
// phone it is a compact status meter; leaving the desktop 130px minimum
// here forces the entire operating dock below the visible viewport.
const bool compact = K4Styles::isCompactLayout();
- setFixedHeight(compact ? 56 : 130);
+ setFixedHeight(compact ? 56 : K4Styles::Dimensions::VfoMeterHeight);
setMinimumWidth(compact ? 130 : 200);
setMaximumWidth(compact ? 150 : 380);
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
@@ -151,6 +151,14 @@ void TxMeterWidget::setSMeter(double sValue) {
update();
}
+void TxMeterWidget::setSMeterColor(const QColor &color) {
+ if (m_sMeterColor != color) {
+ m_sMeterColor = color;
+ if (!m_isTransmitting)
+ update();
+ }
+}
+
void TxMeterWidget::setTransmitting(bool isTx) {
if (m_isTransmitting != isTx) {
m_isTransmitting = isTx;
@@ -259,8 +267,10 @@ void TxMeterWidget::paintEvent(QPaintEvent *event) {
peakValue = m_powerPeak;
}
+ // RX S-meter uses the VFO colour (A cyan, B green); TX Po uses the
+ // standard power gradient.
drawMeterRow(painter, y, rowHeight, compact ? "S" : "S/Po", displayValue, peakValue, labels, scaleFont, barStartX, barWidth,
- barHeight, MeterType::Gradient);
+ barHeight, m_isTransmitting ? MeterType::Gradient : MeterType::SMeter);
y += rowHeight + spacing;
}
@@ -324,18 +334,23 @@ void TxMeterWidget::drawMeterRow(QPainter &painter, int y, int rowHeight, const
// Filled meter bar
if (fillRatio > 0.001) {
int fillWidth = static_cast(barWidth * fillRatio);
- QLinearGradient gradient(barStartX, 0, barStartX + barWidth, 0);
- if (type == MeterType::Gradient) {
- // Standard meter gradient: green → yellow → orange → red
- gradient = K4Styles::meterGradient(barStartX, 0, barStartX + barWidth, 0);
+ if (type == MeterType::SMeter) {
+ // RX S-meter: solid VFO colour (A cyan, B green), matching the radio.
+ painter.fillRect(barStartX + 1, barY + 1, fillWidth - 2, barHeight - 2, m_sMeterColor);
} else {
- // Red style for Id meter (PA drain current)
- gradient.setColorAt(0.0, QColor(K4Styles::Colors::MeterIdDark));
- gradient.setColorAt(0.7, QColor(K4Styles::Colors::MeterIdDark));
- gradient.setColorAt(1.0, QColor(K4Styles::Colors::MeterIdLight));
+ QLinearGradient gradient(barStartX, 0, barStartX + barWidth, 0);
+ if (type == MeterType::Gradient) {
+ // Standard meter gradient: green → yellow → orange → red
+ gradient = K4Styles::meterGradient(barStartX, 0, barStartX + barWidth, 0);
+ } else {
+ // Red style for Id meter (PA drain current)
+ gradient.setColorAt(0.0, QColor(K4Styles::Colors::MeterIdDark));
+ gradient.setColorAt(0.7, QColor(K4Styles::Colors::MeterIdDark));
+ gradient.setColorAt(1.0, QColor(K4Styles::Colors::MeterIdLight));
+ }
+ painter.fillRect(barStartX + 1, barY + 1, fillWidth - 2, barHeight - 2, gradient);
}
- painter.fillRect(barStartX + 1, barY + 1, fillWidth - 2, barHeight - 2, gradient);
}
// Draw peak indicator
diff --git a/src/ui/txmeterwidget.h b/src/ui/txmeterwidget.h
index bebd072..a3bb54b 100644
--- a/src/ui/txmeterwidget.h
+++ b/src/ui/txmeterwidget.h
@@ -3,6 +3,8 @@
#include
#include
+#include
+#include "k4styles.h"
/**
* TxMeterWidget - Multi-function TX meter display (IC-7760 style)
@@ -38,6 +40,9 @@ class TxMeterWidget : public QWidget {
void setSMeter(double sValue); // S-units (0-9 for S1-S9, 9+ for +dB over S9)
void setTransmitting(bool isTx); // Switch between RX (S-meter) and TX (Po) mode
+ // Fill colour for the RX S-meter bar (per VFO: A cyan, B green).
+ void setSMeterColor(const QColor &color);
+
protected:
void paintEvent(QPaintEvent *event) override;
@@ -90,7 +95,10 @@ private slots:
static constexpr int PeakHoldTicks = 10; // 500ms hold time (10 × 50ms)
// Meter types for color selection
- enum class MeterType { Gradient, Red };
+ enum class MeterType { Gradient, Red, SMeter };
+
+ // RX S-meter fill colour (VFO A cyan, VFO B green). Default green.
+ QColor m_sMeterColor = QColor(K4Styles::Colors::VfoBGreen);
// Drawing helpers
void drawMeterRow(QPainter &painter, int y, int rowHeight, const QString &label, double fillRatio, double peakRatio,
diff --git a/src/ui/vforowwidget.cpp b/src/ui/vforowwidget.cpp
index 72d34fb..1a00014 100644
--- a/src/ui/vforowwidget.cpp
+++ b/src/ui/vforowwidget.cpp
@@ -1,4 +1,5 @@
#include "vforowwidget.h"
+#include "filterindicatorwidget.h"
#include "k4styles.h"
#include
#include
@@ -61,7 +62,27 @@ void VfoSquareWidget::paintEvent(QPaintEvent *) {
VfoRowWidget::VfoRowWidget(QWidget *parent) : QWidget(parent) {
setupWidgets();
- setFixedHeight(K4Styles::Dimensions::VfoRowHeight);
+ recomputeHeight();
+}
+
+void VfoRowWidget::recomputeHeight() {
+ // Tall enough for the tallest of the three columns: the A/B square + mode +
+ // filter stacks, and the centre column (TX glyph + any SPLIT/MSG/RIT stack).
+ m_vfoAContainer->adjustSize();
+ m_vfoBContainer->adjustSize();
+ m_txContainer->adjustSize();
+ const int stacked = qMax(m_txContainer->sizeHint().height(),
+ qMax(m_vfoAContainer->sizeHint().height(),
+ m_vfoBContainer->sizeHint().height()));
+ setFixedHeight(qMax(K4Styles::Dimensions::VfoRowHeight, stacked));
+}
+
+void VfoRowWidget::addToCenterColumn(QWidget *w) {
+ if (!m_txColumn)
+ return;
+ m_txColumn->addWidget(w, 0, Qt::AlignHCenter);
+ recomputeHeight();
+ positionWidgets();
}
void VfoRowWidget::setLockA(bool locked) {
@@ -76,17 +97,19 @@ void VfoRowWidget::setupWidgets() {
// No layout manager - we use absolute positioning
// All containers are children of this widget
// === VFO A Container (square + mode label) ===
+ // The VFO column is as wide as the filter indicator that sits under it.
+ const int filterW = 62;
m_vfoAContainer = new QWidget(this);
- m_vfoAContainer->setFixedWidth(K4Styles::Dimensions::VfoSquareSize);
+ m_vfoAContainer->setFixedWidth(filterW);
auto *vfoAColumn = new QVBoxLayout(m_vfoAContainer);
vfoAColumn->setContentsMargins(0, 0, 0, 0);
- vfoAColumn->setSpacing(2);
+ vfoAColumn->setSpacing(1);
m_vfoASquare = new VfoSquareWidget("A", QColor(K4Styles::Colors::VfoACyan), m_vfoAContainer);
vfoAColumn->addWidget(m_vfoASquare, 0, Qt::AlignHCenter);
m_modeALabel = new QLabel("USB", m_vfoAContainer);
- m_modeALabel->setFixedWidth(K4Styles::Dimensions::VfoSquareSize);
+ m_modeALabel->setFixedWidth(filterW);
m_modeALabel->setAlignment(Qt::AlignCenter);
m_modeALabel->setCursor(Qt::PointingHandCursor);
m_modeALabel->setStyleSheet(QString("color: %1; font-size: %2px; font-weight: bold;")
@@ -94,11 +117,16 @@ void VfoRowWidget::setupWidgets() {
.arg(K4Styles::Dimensions::FontSizeLarge));
vfoAColumn->addWidget(m_modeALabel, 0, Qt::AlignHCenter);
+ // VFO A filter indicator, directly under the square+mode (like the radio).
+ m_filterAWidget = new FilterIndicatorWidget(m_vfoAContainer);
+ vfoAColumn->addWidget(m_filterAWidget, 0, Qt::AlignHCenter);
+
// === TX Container (TEST label + triangles + TX) ===
m_txContainer = new QWidget(this);
auto *txVLayout = new QVBoxLayout(m_txContainer);
txVLayout->setContentsMargins(0, 0, 0, 0);
txVLayout->setSpacing(0);
+ m_txColumn = txVLayout; // widgets stacked here sit under the TX glyph
// TEST indicator - hidden by default
// TEST is positioned independently from the TX container below. Keeping it
@@ -111,10 +139,13 @@ void VfoRowWidget::setupWidgets() {
m_testLabel->setVisible(false);
// TX row (triangles + TX label)
+ // Stretches keep the TX glyph centred when the column widens to hold the
+ // SPLIT/MSG/RIT stack beneath it.
auto *txIndicatorRow = new QHBoxLayout();
txIndicatorRow->setSpacing(0);
+ txIndicatorRow->addStretch();
- m_txTriangle = new QLabel(QString::fromUtf8("\u25C0"), m_txContainer); // ◀
+ m_txTriangle = new QLabel(QString::fromUtf8("\u25C0"), m_txContainer); //◀
m_txTriangle->setFixedSize(K4Styles::Dimensions::ButtonHeightMini, K4Styles::Dimensions::ButtonHeightMini);
m_txTriangle->setAlignment(Qt::AlignCenter);
m_txTriangle->setStyleSheet(QString("color: %1; font-size: 18px;").arg(K4Styles::Colors::AccentAmber));
@@ -130,6 +161,7 @@ void VfoRowWidget::setupWidgets() {
m_txTriangleB->setAlignment(Qt::AlignCenter);
m_txTriangleB->setStyleSheet(QString("color: %1; font-size: 18px;").arg(K4Styles::Colors::AccentAmber));
txIndicatorRow->addWidget(m_txTriangleB);
+ txIndicatorRow->addStretch();
txVLayout->addLayout(txIndicatorRow);
@@ -138,16 +170,16 @@ void VfoRowWidget::setupWidgets() {
// === VFO B Container (square + mode label) ===
m_vfoBContainer = new QWidget(this);
- m_vfoBContainer->setFixedWidth(K4Styles::Dimensions::VfoSquareSize);
+ m_vfoBContainer->setFixedWidth(filterW);
auto *vfoBColumn = new QVBoxLayout(m_vfoBContainer);
vfoBColumn->setContentsMargins(0, 0, 0, 0);
- vfoBColumn->setSpacing(2);
+ vfoBColumn->setSpacing(1);
m_vfoBSquare = new VfoSquareWidget("B", QColor(K4Styles::Colors::VfoBGreen), m_vfoBContainer);
vfoBColumn->addWidget(m_vfoBSquare, 0, Qt::AlignHCenter);
m_modeBLabel = new QLabel("USB", m_vfoBContainer);
- m_modeBLabel->setFixedWidth(K4Styles::Dimensions::VfoSquareSize);
+ m_modeBLabel->setFixedWidth(filterW);
m_modeBLabel->setAlignment(Qt::AlignCenter);
m_modeBLabel->setCursor(Qt::PointingHandCursor);
m_modeBLabel->setStyleSheet(QString("color: %1; font-size: %2px; font-weight: bold;")
@@ -155,6 +187,10 @@ void VfoRowWidget::setupWidgets() {
.arg(K4Styles::Dimensions::FontSizeLarge));
vfoBColumn->addWidget(m_modeBLabel, 0, Qt::AlignHCenter);
+ // VFO B filter indicator, directly under the square+mode.
+ m_filterBWidget = new FilterIndicatorWidget(m_vfoBContainer);
+ vfoBColumn->addWidget(m_filterBWidget, 0, Qt::AlignHCenter);
+
// === SUB/DIV Container ===
m_subDivContainer = new QWidget(this);
auto *subDivStack = new QVBoxLayout(m_subDivContainer);
@@ -188,6 +224,9 @@ void VfoRowWidget::setupWidgets() {
subDivStack->addWidget(m_divLabel);
m_subDivContainer->adjustSize();
+ // SUB/DIV are not shown in the centre VFO area (the radio shows them as LEDs
+ // elsewhere). State is reflected on the right panel's SUB/DIVERSITY button.
+ m_subDivContainer->hide();
}
void VfoRowWidget::resizeEvent(QResizeEvent *event) {
diff --git a/src/ui/vforowwidget.h b/src/ui/vforowwidget.h
index ec7b4b7..e567ba3 100644
--- a/src/ui/vforowwidget.h
+++ b/src/ui/vforowwidget.h
@@ -6,6 +6,8 @@
#include
#include
+class FilterIndicatorWidget;
+
/**
* VfoSquareWidget - Custom painted VFO A/B indicator with lock arc
*
@@ -58,6 +60,14 @@ class VfoRowWidget : public QWidget {
QLabel *testLabel() const { return m_testLabel; }
QLabel *subLabel() const { return m_subLabel; }
QLabel *divLabel() const { return m_divLabel; }
+ // Filter indicators live under each VFO square+mode (like the radio).
+ FilterIndicatorWidget *filterAWidget() const { return m_filterAWidget; }
+ FilterIndicatorWidget *filterBWidget() const { return m_filterBWidget; }
+
+ // Stack a widget in the centre (TX) column, beneath the TX glyph. Used to
+ // pull SPLIT / MSG / RIT-XIT up between the two VFO filters, as on the
+ // radio. Reparents w and regrows the row to fit.
+ void addToCenterColumn(QWidget *w);
protected:
void resizeEvent(QResizeEvent *event) override;
@@ -65,6 +75,10 @@ class VfoRowWidget : public QWidget {
private:
void setupWidgets();
void positionWidgets();
+ void recomputeHeight();
+
+ // TX (centre) column layout, so extra widgets can be stacked under TX.
+ QVBoxLayout *m_txColumn = nullptr;
// Containers (absolute positioned within this widget)
QWidget *m_vfoAContainer;
@@ -84,6 +98,8 @@ class VfoRowWidget : public QWidget {
QLabel *m_testLabel;
QLabel *m_subLabel;
QLabel *m_divLabel;
+ FilterIndicatorWidget *m_filterAWidget = nullptr;
+ FilterIndicatorWidget *m_filterBWidget = nullptr;
};
#endif // VFOROWWIDGET_H
diff --git a/src/ui/vfowidget.cpp b/src/ui/vfowidget.cpp
index 9e39286..3fcbf0c 100644
--- a/src/ui/vfowidget.cpp
+++ b/src/ui/vfowidget.cpp
@@ -48,6 +48,14 @@ void VFOWidget::setupUi() {
freqContainerLayout->addWidget(m_frequencyDisplay);
freqContainerLayout->addStretch();
+ // Match the radio: the A frequency is right-aligned so its right edge lines
+ // up with the right edge of the A meter block, not the left. Right-align the
+ // digits within the display (whose right edge already coincides with the
+ // meter's, both filling the column). Regular layout only; the phone console
+ // keeps its own left-aligned placement.
+ if (m_type == VFO_A && !K4Styles::isCompactLayout())
+ m_frequencyDisplay->setRightAligned(true);
+
if (m_type == VFO_A) {
freqRow->addWidget(freqContainer);
freqRow->addStretch();
@@ -78,6 +86,8 @@ void VFOWidget::setupUi() {
// Meter fills full width of normal content (both are 200px)
m_txMeter = new TxMeterWidget(m_normalContent);
m_txMeter->setFixedWidth(K4Styles::Dimensions::VfoMeterWidth);
+ m_txMeter->setSMeterColor(
+ QColor(m_type == VFO_A ? K4Styles::Colors::VfoACyan : K4Styles::Colors::VfoBGreen));
normalLayout->addWidget(m_txMeter);
// Row 3: AGC, PRE, ATT, NB, NR labels (aligned with meter)
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 57e89de..554d196 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -54,6 +54,8 @@ qt_add_executable(test_logbook test_logbook.cpp
../src/ui/inwindowdialog.cpp ../src/ui/k4styles.cpp)
target_link_libraries(test_logbook PRIVATE qk4_ft8 Qt6::Test)
add_test(NAME logbook COMMAND test_logbook -o logbook-results.txt,txt -o -,txt)
+# This test asserts native focus restoration; parallel Qt GUI tests can steal OS focus.
+set_tests_properties(logbook PROPERTIES RUN_SERIAL TRUE)
qt_add_executable(test_qrzlogbook test_qrzlogbook.cpp)
target_link_libraries(test_qrzlogbook PRIVATE qk4_ft8 Qt6::Test Qt6::Network)
add_test(NAME qrzlogbook COMMAND test_qrzlogbook -o qrzlogbook-results.txt,txt -o -,txt)
@@ -72,6 +74,7 @@ endif()
qt_add_executable(test_digitaltx test_digitaltx.cpp
../src/audio/digitaltxguard.cpp ../src/audio/digitaltxguard.h
../src/network/tcpclient.cpp ../src/network/tcpclient.h
+ ../src/network/psktlssocket_qssl.cpp ../src/network/psktlssocket.h
../src/network/protocol.cpp ../src/network/protocol.h)
target_include_directories(test_digitaltx PRIVATE ../src)
target_link_libraries(test_digitaltx PRIVATE Qt6::Core Qt6::Network Qt6::Test)
@@ -99,6 +102,7 @@ add_test(NAME radiostate COMMAND test_radiostate)
qt_add_executable(test_macros test_macros.cpp
../src/network/tcpclient.cpp ../src/network/tcpclient.h
+ ../src/network/psktlssocket_qssl.cpp ../src/network/psktlssocket.h
../src/network/protocol.cpp ../src/network/protocol.h
../src/audio/digitaltxguard.cpp ../src/audio/digitaltxguard.h
../src/models/radiostate.cpp ../src/models/radiostate.h
diff --git a/third_party/ios/README.md b/third_party/ios/README.md
new file mode 100644
index 0000000..3fe0e5b
--- /dev/null
+++ b/third_party/ios/README.md
@@ -0,0 +1,62 @@
+# iOS third-party dependencies
+
+Static libraries for the iOS build. Each `lib/*.a` is a fat archive holding
+an `x86_64` slice (iOS Simulator on Intel Macs) and an `arm64` slice (iPhone /
+iPad devices). Apple Silicon simulators need an additional `arm64` simulator
+slice, which cannot share a fat file with the device slice; build an
+`.xcframework` instead if that becomes a target.
+
+Expected layout:
+
+```text
+openssl/include/openssl/*.h
+openssl/lib/libssl.a
+openssl/lib/libcrypto.a
+opus/include/opus/*.h
+opus/lib/libopus.a
+```
+
+`CMakeLists.txt` points at these paths when `IOS` is set. Override with
+`-DQK4_OPENSSL_ROOT=` and `-DQK4_OPUS_INCLUDE_DIR=... -DQK4_OPUS_LIBRARY=...`.
+
+## Why OpenSSL
+
+The K4 remote link uses TLS 1.2 with pre-shared keys. Qt's iOS kit only ships
+the Secure Transport TLS plugin, which has no PSK support, so
+`src/network/psktlssocket_openssl.cpp` drives OpenSSL directly over a
+`QTcpSocket`. The Qt OpenSSL TLS plugin is not used on iOS.
+
+## Building OpenSSL (3.6.3)
+
+```bash
+curl -sSLO https://github.com/openssl/openssl/releases/download/openssl-3.6.3/openssl-3.6.3.tar.gz
+tar xzf openssl-3.6.3.tar.gz
+
+build() { # $1=Configure target $2=min-version flag $3=prefix
+ cp -R openssl-3.6.3 "build-$1" && cd "build-$1"
+ ./Configure "$1" no-shared no-dso no-tests no-apps no-docs no-engine "$2" --prefix="$3"
+ make -j"$(sysctl -n hw.ncpu)" build_libs && make install_dev
+ cd ..
+}
+build iossimulator-x86_64-xcrun -mios-simulator-version-min=16.0 "$PWD/out/sim"
+build ios64-xcrun -miphoneos-version-min=16.0 "$PWD/out/dev"
+
+lipo -create out/sim/lib/libssl.a out/dev/lib/libssl.a -output openssl/lib/libssl.a
+lipo -create out/sim/lib/libcrypto.a out/dev/lib/libcrypto.a -output openssl/lib/libcrypto.a
+cp -R out/sim/include openssl/include
+```
+
+`include/openssl/configuration.h` is generated per target; the copy here
+merges the two with `__x86_64__` / `__aarch64__` guards where they differ.
+
+## Building Opus
+
+See `opus/README.md` once populated. Same recipe: configure Opus with CMake
+for `iphonesimulator` and `iphoneos`, `BUILD_SHARED_LIBS=OFF`, then `lipo`.
+
+## QRhi debug builds
+
+The shared RHI renderers batch dynamic resource updates before `beginPass()`, so
+the Qt Metal backend no longer encounters mid-pass resource updates. Debug and
+RelWithDebInfo configurations can both be used; RelWithDebInfo remains useful
+for device testing with symbols and release-like optimization.
diff --git a/third_party/ios/openssl/include/openssl/aes.h b/third_party/ios/openssl/include/openssl/aes.h
new file mode 100644
index 0000000..2b6c683
--- /dev/null
+++ b/third_party/ios/openssl/include/openssl/aes.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2002-2020 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#ifndef OPENSSL_AES_H
+#define OPENSSL_AES_H
+#pragma once
+
+#include
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+#define HEADER_AES_H
+#endif
+
+#include
+
+#include
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define AES_BLOCK_SIZE 16
+
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+
+#define AES_ENCRYPT 1
+#define AES_DECRYPT 0
+
+#define AES_MAXNR 14
+
+/* This should be a hidden type, but EVP requires that the size be known */
+struct aes_key_st {
+#ifdef AES_LONG
+ unsigned long rd_key[4 * (AES_MAXNR + 1)];
+#else
+ unsigned int rd_key[4 * (AES_MAXNR + 1)];
+#endif
+ int rounds;
+};
+typedef struct aes_key_st AES_KEY;
+
+#endif
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+OSSL_DEPRECATEDIN_3_0 const char *AES_options(void);
+OSSL_DEPRECATEDIN_3_0
+int AES_set_encrypt_key(const unsigned char *userKey, const int bits,
+ AES_KEY *key);
+OSSL_DEPRECATEDIN_3_0
+int AES_set_decrypt_key(const unsigned char *userKey, const int bits,
+ AES_KEY *key);
+OSSL_DEPRECATEDIN_3_0
+void AES_encrypt(const unsigned char *in, unsigned char *out,
+ const AES_KEY *key);
+OSSL_DEPRECATEDIN_3_0
+void AES_decrypt(const unsigned char *in, unsigned char *out,
+ const AES_KEY *key);
+OSSL_DEPRECATEDIN_3_0
+void AES_ecb_encrypt(const unsigned char *in, unsigned char *out,
+ const AES_KEY *key, const int enc);
+OSSL_DEPRECATEDIN_3_0
+void AES_cbc_encrypt(const unsigned char *in, unsigned char *out,
+ size_t length, const AES_KEY *key,
+ unsigned char *ivec, const int enc);
+OSSL_DEPRECATEDIN_3_0
+void AES_cfb128_encrypt(const unsigned char *in, unsigned char *out,
+ size_t length, const AES_KEY *key,
+ unsigned char *ivec, int *num, const int enc);
+OSSL_DEPRECATEDIN_3_0
+void AES_cfb1_encrypt(const unsigned char *in, unsigned char *out,
+ size_t length, const AES_KEY *key,
+ unsigned char *ivec, int *num, const int enc);
+OSSL_DEPRECATEDIN_3_0
+void AES_cfb8_encrypt(const unsigned char *in, unsigned char *out,
+ size_t length, const AES_KEY *key,
+ unsigned char *ivec, int *num, const int enc);
+OSSL_DEPRECATEDIN_3_0
+void AES_ofb128_encrypt(const unsigned char *in, unsigned char *out,
+ size_t length, const AES_KEY *key,
+ unsigned char *ivec, int *num);
+
+/* NB: the IV is _two_ blocks long */
+OSSL_DEPRECATEDIN_3_0
+void AES_ige_encrypt(const unsigned char *in, unsigned char *out,
+ size_t length, const AES_KEY *key,
+ unsigned char *ivec, const int enc);
+/* NB: the IV is _four_ blocks long */
+OSSL_DEPRECATEDIN_3_0
+void AES_bi_ige_encrypt(const unsigned char *in, unsigned char *out,
+ size_t length, const AES_KEY *key, const AES_KEY *key2,
+ const unsigned char *ivec, const int enc);
+OSSL_DEPRECATEDIN_3_0
+int AES_wrap_key(AES_KEY *key, const unsigned char *iv,
+ unsigned char *out, const unsigned char *in,
+ unsigned int inlen);
+OSSL_DEPRECATEDIN_3_0
+int AES_unwrap_key(AES_KEY *key, const unsigned char *iv,
+ unsigned char *out, const unsigned char *in,
+ unsigned int inlen);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/third_party/ios/openssl/include/openssl/asn1.h b/third_party/ios/openssl/include/openssl/asn1.h
new file mode 100644
index 0000000..4cbd8e2
--- /dev/null
+++ b/third_party/ios/openssl/include/openssl/asn1.h
@@ -0,0 +1,1125 @@
+/*
+ * WARNING: do not edit!
+ * Generated by Makefile from include/openssl/asn1.h.in
+ *
+ * Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+/* clang-format off */
+
+/* clang-format on */
+
+#ifndef OPENSSL_ASN1_H
+#define OPENSSL_ASN1_H
+#pragma once
+
+#include
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+#define HEADER_ASN1_H
+#endif
+
+#ifndef OPENSSL_NO_STDIO
+#include
+#endif
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#ifdef OPENSSL_BUILD_SHLIBCRYPTO
+#undef OPENSSL_EXTERN
+#define OPENSSL_EXTERN OPENSSL_EXPORT
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define V_ASN1_UNIVERSAL 0x00
+#define V_ASN1_APPLICATION 0x40
+#define V_ASN1_CONTEXT_SPECIFIC 0x80
+#define V_ASN1_PRIVATE 0xc0
+
+#define V_ASN1_CONSTRUCTED 0x20
+#define V_ASN1_PRIMITIVE_TAG 0x1f
+#define V_ASN1_PRIMATIVE_TAG /*compat*/ V_ASN1_PRIMITIVE_TAG
+
+#define V_ASN1_APP_CHOOSE -2 /* let the recipient choose */
+#define V_ASN1_OTHER -3 /* used in ASN1_TYPE */
+#define V_ASN1_ANY -4 /* used in ASN1 template code */
+
+#define V_ASN1_UNDEF -1
+/* ASN.1 tag values */
+#define V_ASN1_EOC 0
+#define V_ASN1_BOOLEAN 1
+#define V_ASN1_INTEGER 2
+#define V_ASN1_BIT_STRING 3
+#define V_ASN1_OCTET_STRING 4
+#define V_ASN1_NULL 5
+#define V_ASN1_OBJECT 6
+#define V_ASN1_OBJECT_DESCRIPTOR 7
+#define V_ASN1_EXTERNAL 8
+#define V_ASN1_REAL 9
+#define V_ASN1_ENUMERATED 10
+#define V_ASN1_UTF8STRING 12
+#define V_ASN1_SEQUENCE 16
+#define V_ASN1_SET 17
+#define V_ASN1_NUMERICSTRING 18
+#define V_ASN1_PRINTABLESTRING 19
+#define V_ASN1_T61STRING 20
+#define V_ASN1_TELETEXSTRING 20 /* alias */
+#define V_ASN1_VIDEOTEXSTRING 21
+#define V_ASN1_IA5STRING 22
+#define V_ASN1_UTCTIME 23
+#define V_ASN1_GENERALIZEDTIME 24
+#define V_ASN1_GRAPHICSTRING 25
+#define V_ASN1_ISO64STRING 26
+#define V_ASN1_VISIBLESTRING 26 /* alias */
+#define V_ASN1_GENERALSTRING 27
+#define V_ASN1_UNIVERSALSTRING 28
+#define V_ASN1_BMPSTRING 30
+
+/*
+ * NB the constants below are used internally by ASN1_INTEGER
+ * and ASN1_ENUMERATED to indicate the sign. They are *not* on
+ * the wire tag values.
+ */
+
+#define V_ASN1_NEG 0x100
+#define V_ASN1_NEG_INTEGER (2 | V_ASN1_NEG)
+#define V_ASN1_NEG_ENUMERATED (10 | V_ASN1_NEG)
+
+/* For use with d2i_ASN1_type_bytes() */
+#define B_ASN1_NUMERICSTRING 0x0001
+#define B_ASN1_PRINTABLESTRING 0x0002
+#define B_ASN1_T61STRING 0x0004
+#define B_ASN1_TELETEXSTRING 0x0004
+#define B_ASN1_VIDEOTEXSTRING 0x0008
+#define B_ASN1_IA5STRING 0x0010
+#define B_ASN1_GRAPHICSTRING 0x0020
+#define B_ASN1_ISO64STRING 0x0040
+#define B_ASN1_VISIBLESTRING 0x0040
+#define B_ASN1_GENERALSTRING 0x0080
+#define B_ASN1_UNIVERSALSTRING 0x0100
+#define B_ASN1_OCTET_STRING 0x0200
+#define B_ASN1_BIT_STRING 0x0400
+#define B_ASN1_BMPSTRING 0x0800
+#define B_ASN1_UNKNOWN 0x1000
+#define B_ASN1_UTF8STRING 0x2000
+#define B_ASN1_UTCTIME 0x4000
+#define B_ASN1_GENERALIZEDTIME 0x8000
+#define B_ASN1_SEQUENCE 0x10000
+/* For use with ASN1_mbstring_copy() */
+#define MBSTRING_FLAG 0x1000
+#define MBSTRING_UTF8 (MBSTRING_FLAG)
+#define MBSTRING_ASC (MBSTRING_FLAG | 1)
+#define MBSTRING_BMP (MBSTRING_FLAG | 2)
+#define MBSTRING_UNIV (MBSTRING_FLAG | 4)
+#define SMIME_OLDMIME 0x400
+#define SMIME_CRLFEOL 0x800
+#define SMIME_STREAM 0x1000
+
+/* Stacks for types not otherwise defined in this header */
+/* clang-format off */
+SKM_DEFINE_STACK_OF_INTERNAL(X509_ALGOR, X509_ALGOR, X509_ALGOR)
+#define sk_X509_ALGOR_num(sk) OPENSSL_sk_num(ossl_check_const_X509_ALGOR_sk_type(sk))
+#define sk_X509_ALGOR_value(sk, idx) ((X509_ALGOR *)OPENSSL_sk_value(ossl_check_const_X509_ALGOR_sk_type(sk), (idx)))
+#define sk_X509_ALGOR_new(cmp) ((STACK_OF(X509_ALGOR) *)OPENSSL_sk_new(ossl_check_X509_ALGOR_compfunc_type(cmp)))
+#define sk_X509_ALGOR_new_null() ((STACK_OF(X509_ALGOR) *)OPENSSL_sk_new_null())
+#define sk_X509_ALGOR_new_reserve(cmp, n) ((STACK_OF(X509_ALGOR) *)OPENSSL_sk_new_reserve(ossl_check_X509_ALGOR_compfunc_type(cmp), (n)))
+#define sk_X509_ALGOR_reserve(sk, n) OPENSSL_sk_reserve(ossl_check_X509_ALGOR_sk_type(sk), (n))
+#define sk_X509_ALGOR_free(sk) OPENSSL_sk_free(ossl_check_X509_ALGOR_sk_type(sk))
+#define sk_X509_ALGOR_zero(sk) OPENSSL_sk_zero(ossl_check_X509_ALGOR_sk_type(sk))
+#define sk_X509_ALGOR_delete(sk, i) ((X509_ALGOR *)OPENSSL_sk_delete(ossl_check_X509_ALGOR_sk_type(sk), (i)))
+#define sk_X509_ALGOR_delete_ptr(sk, ptr) ((X509_ALGOR *)OPENSSL_sk_delete_ptr(ossl_check_X509_ALGOR_sk_type(sk), ossl_check_X509_ALGOR_type(ptr)))
+#define sk_X509_ALGOR_push(sk, ptr) OPENSSL_sk_push(ossl_check_X509_ALGOR_sk_type(sk), ossl_check_X509_ALGOR_type(ptr))
+#define sk_X509_ALGOR_unshift(sk, ptr) OPENSSL_sk_unshift(ossl_check_X509_ALGOR_sk_type(sk), ossl_check_X509_ALGOR_type(ptr))
+#define sk_X509_ALGOR_pop(sk) ((X509_ALGOR *)OPENSSL_sk_pop(ossl_check_X509_ALGOR_sk_type(sk)))
+#define sk_X509_ALGOR_shift(sk) ((X509_ALGOR *)OPENSSL_sk_shift(ossl_check_X509_ALGOR_sk_type(sk)))
+#define sk_X509_ALGOR_pop_free(sk, freefunc) OPENSSL_sk_pop_free(ossl_check_X509_ALGOR_sk_type(sk), ossl_check_X509_ALGOR_freefunc_type(freefunc))
+#define sk_X509_ALGOR_insert(sk, ptr, idx) OPENSSL_sk_insert(ossl_check_X509_ALGOR_sk_type(sk), ossl_check_X509_ALGOR_type(ptr), (idx))
+#define sk_X509_ALGOR_set(sk, idx, ptr) ((X509_ALGOR *)OPENSSL_sk_set(ossl_check_X509_ALGOR_sk_type(sk), (idx), ossl_check_X509_ALGOR_type(ptr)))
+#define sk_X509_ALGOR_find(sk, ptr) OPENSSL_sk_find(ossl_check_X509_ALGOR_sk_type(sk), ossl_check_X509_ALGOR_type(ptr))
+#define sk_X509_ALGOR_find_ex(sk, ptr) OPENSSL_sk_find_ex(ossl_check_X509_ALGOR_sk_type(sk), ossl_check_X509_ALGOR_type(ptr))
+#define sk_X509_ALGOR_find_all(sk, ptr, pnum) OPENSSL_sk_find_all(ossl_check_X509_ALGOR_sk_type(sk), ossl_check_X509_ALGOR_type(ptr), pnum)
+#define sk_X509_ALGOR_sort(sk) OPENSSL_sk_sort(ossl_check_X509_ALGOR_sk_type(sk))
+#define sk_X509_ALGOR_is_sorted(sk) OPENSSL_sk_is_sorted(ossl_check_const_X509_ALGOR_sk_type(sk))
+#define sk_X509_ALGOR_dup(sk) ((STACK_OF(X509_ALGOR) *)OPENSSL_sk_dup(ossl_check_const_X509_ALGOR_sk_type(sk)))
+#define sk_X509_ALGOR_deep_copy(sk, copyfunc, freefunc) ((STACK_OF(X509_ALGOR) *)OPENSSL_sk_deep_copy(ossl_check_const_X509_ALGOR_sk_type(sk), ossl_check_X509_ALGOR_copyfunc_type(copyfunc), ossl_check_X509_ALGOR_freefunc_type(freefunc)))
+#define sk_X509_ALGOR_set_cmp_func(sk, cmp) ((sk_X509_ALGOR_compfunc)OPENSSL_sk_set_cmp_func(ossl_check_X509_ALGOR_sk_type(sk), ossl_check_X509_ALGOR_compfunc_type(cmp)))
+
+/* clang-format on */
+
+#define ASN1_STRING_FLAG_BITS_LEFT 0x08 /* Set if 0x07 has bits left value */
+/*
+ * This indicates that the ASN1_STRING is not a real value but just a place
+ * holder for the location where indefinite length constructed data should be
+ * inserted in the memory buffer
+ */
+#define ASN1_STRING_FLAG_NDEF 0x010
+
+/*
+ * This flag is used by the CMS code to indicate that a string is not
+ * complete and is a place holder for content when it had all been accessed.
+ * The flag will be reset when content has been written to it.
+ */
+
+#define ASN1_STRING_FLAG_CONT 0x020
+/*
+ * This flag is used by ASN1 code to indicate an ASN1_STRING is an MSTRING
+ * type.
+ */
+#define ASN1_STRING_FLAG_MSTRING 0x040
+/* String is embedded and only content should be freed */
+#define ASN1_STRING_FLAG_EMBED 0x080
+/* String should be parsed in RFC 5280's time format */
+#define ASN1_STRING_FLAG_X509_TIME 0x100
+/* This is the base type that holds just about everything :-) */
+struct asn1_string_st {
+ int length;
+ int type;
+ unsigned char *data;
+ /*
+ * The value of the following field depends on the type being held. It
+ * is mostly being used for BIT_STRING so if the input data has a
+ * non-zero 'unused bits' value, it will be handled correctly
+ */
+ long flags;
+};
+
+/*
+ * ASN1_ENCODING structure: this is used to save the received encoding of an
+ * ASN1 type. This is useful to get round problems with invalid encodings
+ * which can break signatures.
+ */
+
+typedef struct ASN1_ENCODING_st {
+ unsigned char *enc; /* DER encoding */
+ long len; /* Length of encoding */
+ int modified; /* set to 1 if 'enc' is invalid */
+} ASN1_ENCODING;
+
+/* Used with ASN1 LONG type: if a long is set to this it is omitted */
+#define ASN1_LONG_UNDEF 0x7fffffffL
+
+#define STABLE_FLAGS_MALLOC 0x01
+/*
+ * A zero passed to ASN1_STRING_TABLE_new_add for the flags is interpreted
+ * as "don't change" and STABLE_FLAGS_MALLOC is always set. By setting
+ * STABLE_FLAGS_MALLOC only we can clear the existing value. Use the alias
+ * STABLE_FLAGS_CLEAR to reflect this.
+ */
+#define STABLE_FLAGS_CLEAR STABLE_FLAGS_MALLOC
+#define STABLE_NO_MASK 0x02
+#define DIRSTRING_TYPE \
+ (B_ASN1_PRINTABLESTRING | B_ASN1_T61STRING | B_ASN1_BMPSTRING | B_ASN1_UTF8STRING)
+#define PKCS9STRING_TYPE (DIRSTRING_TYPE | B_ASN1_IA5STRING)
+
+struct asn1_string_table_st {
+ int nid;
+ long minsize;
+ long maxsize;
+ unsigned long mask;
+ unsigned long flags;
+};
+
+/* clang-format off */
+SKM_DEFINE_STACK_OF_INTERNAL(ASN1_STRING_TABLE, ASN1_STRING_TABLE, ASN1_STRING_TABLE)
+#define sk_ASN1_STRING_TABLE_num(sk) OPENSSL_sk_num(ossl_check_const_ASN1_STRING_TABLE_sk_type(sk))
+#define sk_ASN1_STRING_TABLE_value(sk, idx) ((ASN1_STRING_TABLE *)OPENSSL_sk_value(ossl_check_const_ASN1_STRING_TABLE_sk_type(sk), (idx)))
+#define sk_ASN1_STRING_TABLE_new(cmp) ((STACK_OF(ASN1_STRING_TABLE) *)OPENSSL_sk_new(ossl_check_ASN1_STRING_TABLE_compfunc_type(cmp)))
+#define sk_ASN1_STRING_TABLE_new_null() ((STACK_OF(ASN1_STRING_TABLE) *)OPENSSL_sk_new_null())
+#define sk_ASN1_STRING_TABLE_new_reserve(cmp, n) ((STACK_OF(ASN1_STRING_TABLE) *)OPENSSL_sk_new_reserve(ossl_check_ASN1_STRING_TABLE_compfunc_type(cmp), (n)))
+#define sk_ASN1_STRING_TABLE_reserve(sk, n) OPENSSL_sk_reserve(ossl_check_ASN1_STRING_TABLE_sk_type(sk), (n))
+#define sk_ASN1_STRING_TABLE_free(sk) OPENSSL_sk_free(ossl_check_ASN1_STRING_TABLE_sk_type(sk))
+#define sk_ASN1_STRING_TABLE_zero(sk) OPENSSL_sk_zero(ossl_check_ASN1_STRING_TABLE_sk_type(sk))
+#define sk_ASN1_STRING_TABLE_delete(sk, i) ((ASN1_STRING_TABLE *)OPENSSL_sk_delete(ossl_check_ASN1_STRING_TABLE_sk_type(sk), (i)))
+#define sk_ASN1_STRING_TABLE_delete_ptr(sk, ptr) ((ASN1_STRING_TABLE *)OPENSSL_sk_delete_ptr(ossl_check_ASN1_STRING_TABLE_sk_type(sk), ossl_check_ASN1_STRING_TABLE_type(ptr)))
+#define sk_ASN1_STRING_TABLE_push(sk, ptr) OPENSSL_sk_push(ossl_check_ASN1_STRING_TABLE_sk_type(sk), ossl_check_ASN1_STRING_TABLE_type(ptr))
+#define sk_ASN1_STRING_TABLE_unshift(sk, ptr) OPENSSL_sk_unshift(ossl_check_ASN1_STRING_TABLE_sk_type(sk), ossl_check_ASN1_STRING_TABLE_type(ptr))
+#define sk_ASN1_STRING_TABLE_pop(sk) ((ASN1_STRING_TABLE *)OPENSSL_sk_pop(ossl_check_ASN1_STRING_TABLE_sk_type(sk)))
+#define sk_ASN1_STRING_TABLE_shift(sk) ((ASN1_STRING_TABLE *)OPENSSL_sk_shift(ossl_check_ASN1_STRING_TABLE_sk_type(sk)))
+#define sk_ASN1_STRING_TABLE_pop_free(sk, freefunc) OPENSSL_sk_pop_free(ossl_check_ASN1_STRING_TABLE_sk_type(sk), ossl_check_ASN1_STRING_TABLE_freefunc_type(freefunc))
+#define sk_ASN1_STRING_TABLE_insert(sk, ptr, idx) OPENSSL_sk_insert(ossl_check_ASN1_STRING_TABLE_sk_type(sk), ossl_check_ASN1_STRING_TABLE_type(ptr), (idx))
+#define sk_ASN1_STRING_TABLE_set(sk, idx, ptr) ((ASN1_STRING_TABLE *)OPENSSL_sk_set(ossl_check_ASN1_STRING_TABLE_sk_type(sk), (idx), ossl_check_ASN1_STRING_TABLE_type(ptr)))
+#define sk_ASN1_STRING_TABLE_find(sk, ptr) OPENSSL_sk_find(ossl_check_ASN1_STRING_TABLE_sk_type(sk), ossl_check_ASN1_STRING_TABLE_type(ptr))
+#define sk_ASN1_STRING_TABLE_find_ex(sk, ptr) OPENSSL_sk_find_ex(ossl_check_ASN1_STRING_TABLE_sk_type(sk), ossl_check_ASN1_STRING_TABLE_type(ptr))
+#define sk_ASN1_STRING_TABLE_find_all(sk, ptr, pnum) OPENSSL_sk_find_all(ossl_check_ASN1_STRING_TABLE_sk_type(sk), ossl_check_ASN1_STRING_TABLE_type(ptr), pnum)
+#define sk_ASN1_STRING_TABLE_sort(sk) OPENSSL_sk_sort(ossl_check_ASN1_STRING_TABLE_sk_type(sk))
+#define sk_ASN1_STRING_TABLE_is_sorted(sk) OPENSSL_sk_is_sorted(ossl_check_const_ASN1_STRING_TABLE_sk_type(sk))
+#define sk_ASN1_STRING_TABLE_dup(sk) ((STACK_OF(ASN1_STRING_TABLE) *)OPENSSL_sk_dup(ossl_check_const_ASN1_STRING_TABLE_sk_type(sk)))
+#define sk_ASN1_STRING_TABLE_deep_copy(sk, copyfunc, freefunc) ((STACK_OF(ASN1_STRING_TABLE) *)OPENSSL_sk_deep_copy(ossl_check_const_ASN1_STRING_TABLE_sk_type(sk), ossl_check_ASN1_STRING_TABLE_copyfunc_type(copyfunc), ossl_check_ASN1_STRING_TABLE_freefunc_type(freefunc)))
+#define sk_ASN1_STRING_TABLE_set_cmp_func(sk, cmp) ((sk_ASN1_STRING_TABLE_compfunc)OPENSSL_sk_set_cmp_func(ossl_check_ASN1_STRING_TABLE_sk_type(sk), ossl_check_ASN1_STRING_TABLE_compfunc_type(cmp)))
+
+/* clang-format on */
+
+/* size limits: this stuff is taken straight from RFC 5280 */
+
+#define ub_name 32768
+#define ub_common_name 64
+#define ub_locality_name 128
+#define ub_state_name 128
+#define ub_organization_name 64
+#define ub_organization_unit_name 64
+#define ub_title 64
+#define ub_email_address 128
+
+/*
+ * Declarations for template structures: for full definitions see asn1t.h
+ */
+typedef struct ASN1_TEMPLATE_st ASN1_TEMPLATE;
+typedef struct ASN1_TLC_st ASN1_TLC;
+/* This is just an opaque pointer */
+typedef struct ASN1_VALUE_st ASN1_VALUE;
+
+/* Declare ASN1 functions: the implement macro is in asn1t.h */
+
+/*
+ * The mysterious 'extern' that's passed to some macros is innocuous,
+ * and is there to quiet pre-C99 compilers that may complain about empty
+ * arguments in macro calls.
+ */
+
+#define DECLARE_ASN1_FUNCTIONS_attr(attr, type) \
+ DECLARE_ASN1_FUNCTIONS_name_attr(attr, type, type)
+#define DECLARE_ASN1_FUNCTIONS(type) \
+ DECLARE_ASN1_FUNCTIONS_attr(extern, type)
+
+#define DECLARE_ASN1_ALLOC_FUNCTIONS_attr(attr, type) \
+ DECLARE_ASN1_ALLOC_FUNCTIONS_name_attr(attr, type, type)
+#define DECLARE_ASN1_ALLOC_FUNCTIONS(type) \
+ DECLARE_ASN1_ALLOC_FUNCTIONS_attr(extern, type)
+
+#define DECLARE_ASN1_FUNCTIONS_name_attr(attr, type, name) \
+ DECLARE_ASN1_ALLOC_FUNCTIONS_name_attr(attr, type, name) \
+ DECLARE_ASN1_ENCODE_FUNCTIONS_name_attr(attr, type, name)
+#define DECLARE_ASN1_FUNCTIONS_name(type, name) \
+ DECLARE_ASN1_FUNCTIONS_name_attr(extern, type, name)
+
+#define DECLARE_ASN1_ENCODE_FUNCTIONS_attr(attr, type, itname, name) \
+ DECLARE_ASN1_ENCODE_FUNCTIONS_only_attr(attr, type, name) \
+ DECLARE_ASN1_ITEM_attr(attr, itname)
+#define DECLARE_ASN1_ENCODE_FUNCTIONS(type, itname, name) \
+ DECLARE_ASN1_ENCODE_FUNCTIONS_attr(extern, type, itname, name)
+
+#define DECLARE_ASN1_ENCODE_FUNCTIONS_name_attr(attr, type, name) \
+ DECLARE_ASN1_ENCODE_FUNCTIONS_attr(attr, type, name, name)
+#define DECLARE_ASN1_ENCODE_FUNCTIONS_name(type, name) \
+ DECLARE_ASN1_ENCODE_FUNCTIONS_name_attr(extern, type, name)
+
+#define DECLARE_ASN1_ENCODE_FUNCTIONS_only_attr(attr, type, name) \
+ attr type *d2i_##name(type **a, const unsigned char **in, long len); \
+ attr int i2d_##name(const type *a, unsigned char **out);
+#define DECLARE_ASN1_ENCODE_FUNCTIONS_only(type, name) \
+ DECLARE_ASN1_ENCODE_FUNCTIONS_only_attr(extern, type, name)
+
+#define DECLARE_ASN1_NDEF_FUNCTION_attr(attr, name) \
+ attr int i2d_##name##_NDEF(const name *a, unsigned char **out);
+#define DECLARE_ASN1_NDEF_FUNCTION(name) \
+ DECLARE_ASN1_NDEF_FUNCTION_attr(extern, name)
+
+#define DECLARE_ASN1_ALLOC_FUNCTIONS_name_attr(attr, type, name) \
+ attr type *name##_new(void); \
+ attr void name##_free(type *a);
+#define DECLARE_ASN1_ALLOC_FUNCTIONS_name(type, name) \
+ DECLARE_ASN1_ALLOC_FUNCTIONS_name_attr(extern, type, name)
+
+#define DECLARE_ASN1_DUP_FUNCTION_attr(attr, type) \
+ DECLARE_ASN1_DUP_FUNCTION_name_attr(attr, type, type)
+#define DECLARE_ASN1_DUP_FUNCTION(type) \
+ DECLARE_ASN1_DUP_FUNCTION_attr(extern, type)
+
+#define DECLARE_ASN1_DUP_FUNCTION_name_attr(attr, type, name) \
+ attr type *name##_dup(const type *a);
+#define DECLARE_ASN1_DUP_FUNCTION_name(type, name) \
+ DECLARE_ASN1_DUP_FUNCTION_name_attr(extern, type, name)
+
+#define DECLARE_ASN1_PRINT_FUNCTION_attr(attr, stname) \
+ DECLARE_ASN1_PRINT_FUNCTION_fname_attr(attr, stname, stname)
+#define DECLARE_ASN1_PRINT_FUNCTION(stname) \
+ DECLARE_ASN1_PRINT_FUNCTION_attr(extern, stname)
+
+#define DECLARE_ASN1_PRINT_FUNCTION_fname_attr(attr, stname, fname) \
+ attr int fname##_print_ctx(BIO *out, const stname *x, int indent, \
+ const ASN1_PCTX *pctx);
+#define DECLARE_ASN1_PRINT_FUNCTION_fname(stname, fname) \
+ DECLARE_ASN1_PRINT_FUNCTION_fname_attr(extern, stname, fname)
+
+#define D2I_OF(type) type *(*)(type **, const unsigned char **, long)
+#define I2D_OF(type) int (*)(const type *, unsigned char **)
+
+#define CHECKED_D2I_OF(type, d2i) \
+ ((d2i_of_void *)(1 ? d2i : ((D2I_OF(type))0)))
+#define CHECKED_I2D_OF(type, i2d) \
+ ((i2d_of_void *)(1 ? i2d : ((I2D_OF(type))0)))
+#define CHECKED_NEW_OF(type, xnew) \
+ ((void *(*)(void))(1 ? xnew : ((type * (*)(void))0)))
+#define CHECKED_PTR_OF(type, p) \
+ ((void *)(1 ? p : (type *)0))
+#define CHECKED_PPTR_OF(type, p) \
+ ((void **)(1 ? p : (type **)0))
+
+#define TYPEDEF_D2I_OF(type) typedef type *d2i_of_##type(type **, const unsigned char **, long)
+#define TYPEDEF_I2D_OF(type) typedef int i2d_of_##type(const type *, unsigned char **)
+#define TYPEDEF_D2I2D_OF(type) \
+ TYPEDEF_D2I_OF(type); \
+ TYPEDEF_I2D_OF(type)
+
+typedef void *d2i_of_void(void **, const unsigned char **, long);
+typedef int i2d_of_void(const void *, unsigned char **);
+typedef int OSSL_i2d_of_void_ctx(const void *, unsigned char **, void *vctx);
+
+/*-
+ * The following macros and typedefs allow an ASN1_ITEM
+ * to be embedded in a structure and referenced. Since
+ * the ASN1_ITEM pointers need to be globally accessible
+ * (possibly from shared libraries) they may exist in
+ * different forms. On platforms that support it the
+ * ASN1_ITEM structure itself will be globally exported.
+ * Other platforms will export a function that returns
+ * an ASN1_ITEM pointer.
+ *
+ * To handle both cases transparently the macros below
+ * should be used instead of hard coding an ASN1_ITEM
+ * pointer in a structure.
+ *
+ * The structure will look like this:
+ *
+ * typedef struct SOMETHING_st {
+ * ...
+ * ASN1_ITEM_EXP *iptr;
+ * ...
+ * } SOMETHING;
+ *
+ * It would be initialised as e.g.:
+ *
+ * SOMETHING somevar = {...,ASN1_ITEM_ref(X509),...};
+ *
+ * and the actual pointer extracted with:
+ *
+ * const ASN1_ITEM *it = ASN1_ITEM_ptr(somevar.iptr);
+ *
+ * Finally an ASN1_ITEM pointer can be extracted from an
+ * appropriate reference with: ASN1_ITEM_rptr(X509). This
+ * would be used when a function takes an ASN1_ITEM * argument.
+ *
+ */
+
+/*
+ * Platforms that can't easily handle shared global variables are declared as
+ * functions returning ASN1_ITEM pointers.
+ */
+
+/* ASN1_ITEM pointer exported type */
+typedef const ASN1_ITEM *ASN1_ITEM_EXP(void);
+
+/* Macro to obtain ASN1_ITEM pointer from exported type */
+#define ASN1_ITEM_ptr(iptr) (iptr())
+
+/* Macro to include ASN1_ITEM pointer from base type */
+#define ASN1_ITEM_ref(iptr) (iptr##_it)
+
+#define ASN1_ITEM_rptr(ref) (ref##_it())
+
+#define DECLARE_ASN1_ITEM_attr(attr, name) \
+ attr const ASN1_ITEM *name##_it(void);
+#define DECLARE_ASN1_ITEM(name) \
+ DECLARE_ASN1_ITEM_attr(extern, name)
+
+/* Parameters used by ASN1_STRING_print_ex() */
+
+/*
+ * These determine which characters to escape: RFC2253 special characters,
+ * control characters and MSB set characters
+ */
+
+#define ASN1_STRFLGS_ESC_2253 1
+#define ASN1_STRFLGS_ESC_CTRL 2
+#define ASN1_STRFLGS_ESC_MSB 4
+
+/* Lower 8 bits are reserved as an output type specifier */
+#define ASN1_DTFLGS_TYPE_MASK 0x0FUL
+#define ASN1_DTFLGS_RFC822 0x00UL
+#define ASN1_DTFLGS_ISO8601 0x01UL
+
+/*
+ * This flag determines how we do escaping: normally RC2253 backslash only,
+ * set this to use backslash and quote.
+ */
+
+#define ASN1_STRFLGS_ESC_QUOTE 8
+
+/* These three flags are internal use only. */
+
+/* Character is a valid PrintableString character */
+#define CHARTYPE_PRINTABLESTRING 0x10
+/* Character needs escaping if it is the first character */
+#define CHARTYPE_FIRST_ESC_2253 0x20
+/* Character needs escaping if it is the last character */
+#define CHARTYPE_LAST_ESC_2253 0x40
+
+/*
+ * NB the internal flags are safely reused below by flags handled at the top
+ * level.
+ */
+
+/*
+ * If this is set we convert all character strings to UTF8 first
+ */
+
+#define ASN1_STRFLGS_UTF8_CONVERT 0x10
+
+/*
+ * If this is set we don't attempt to interpret content: just assume all
+ * strings are 1 byte per character. This will produce some pretty odd
+ * looking output!
+ */
+
+#define ASN1_STRFLGS_IGNORE_TYPE 0x20
+
+/* If this is set we include the string type in the output */
+#define ASN1_STRFLGS_SHOW_TYPE 0x40
+
+/*
+ * This determines which strings to display and which to 'dump' (hex dump of
+ * content octets or DER encoding). We can only dump non character strings or
+ * everything. If we don't dump 'unknown' they are interpreted as character
+ * strings with 1 octet per character and are subject to the usual escaping
+ * options.
+ */
+
+#define ASN1_STRFLGS_DUMP_ALL 0x80
+#define ASN1_STRFLGS_DUMP_UNKNOWN 0x100
+
+/*
+ * These determine what 'dumping' does, we can dump the content octets or the
+ * DER encoding: both use the RFC2253 #XXXXX notation.
+ */
+
+#define ASN1_STRFLGS_DUMP_DER 0x200
+
+/*
+ * This flag specifies that RC2254 escaping shall be performed.
+ */
+#define ASN1_STRFLGS_ESC_2254 0x400
+
+/*
+ * All the string flags consistent with RFC2253, escaping control characters
+ * isn't essential in RFC2253 but it is advisable anyway.
+ */
+
+#define ASN1_STRFLGS_RFC2253 (ASN1_STRFLGS_ESC_2253 | ASN1_STRFLGS_ESC_CTRL | ASN1_STRFLGS_ESC_MSB | ASN1_STRFLGS_UTF8_CONVERT | ASN1_STRFLGS_DUMP_UNKNOWN | ASN1_STRFLGS_DUMP_DER)
+
+struct asn1_type_st {
+ int type;
+ union {
+ char *ptr;
+ ASN1_BOOLEAN boolean;
+ ASN1_STRING *asn1_string;
+ ASN1_OBJECT *object;
+ ASN1_INTEGER *integer;
+ ASN1_ENUMERATED *enumerated;
+ ASN1_BIT_STRING *bit_string;
+ ASN1_OCTET_STRING *octet_string;
+ ASN1_PRINTABLESTRING *printablestring;
+ ASN1_T61STRING *t61string;
+ ASN1_IA5STRING *ia5string;
+ ASN1_GENERALSTRING *generalstring;
+ ASN1_BMPSTRING *bmpstring;
+ ASN1_UNIVERSALSTRING *universalstring;
+ ASN1_UTCTIME *utctime;
+ ASN1_GENERALIZEDTIME *generalizedtime;
+ ASN1_VISIBLESTRING *visiblestring;
+ ASN1_UTF8STRING *utf8string;
+ /*
+ * set and sequence are left complete and still contain the set or
+ * sequence bytes
+ */
+ ASN1_STRING *set;
+ ASN1_STRING *sequence;
+ ASN1_VALUE *asn1_value;
+ } value;
+};
+
+/* clang-format off */
+SKM_DEFINE_STACK_OF_INTERNAL(ASN1_TYPE, ASN1_TYPE, ASN1_TYPE)
+#define sk_ASN1_TYPE_num(sk) OPENSSL_sk_num(ossl_check_const_ASN1_TYPE_sk_type(sk))
+#define sk_ASN1_TYPE_value(sk, idx) ((ASN1_TYPE *)OPENSSL_sk_value(ossl_check_const_ASN1_TYPE_sk_type(sk), (idx)))
+#define sk_ASN1_TYPE_new(cmp) ((STACK_OF(ASN1_TYPE) *)OPENSSL_sk_new(ossl_check_ASN1_TYPE_compfunc_type(cmp)))
+#define sk_ASN1_TYPE_new_null() ((STACK_OF(ASN1_TYPE) *)OPENSSL_sk_new_null())
+#define sk_ASN1_TYPE_new_reserve(cmp, n) ((STACK_OF(ASN1_TYPE) *)OPENSSL_sk_new_reserve(ossl_check_ASN1_TYPE_compfunc_type(cmp), (n)))
+#define sk_ASN1_TYPE_reserve(sk, n) OPENSSL_sk_reserve(ossl_check_ASN1_TYPE_sk_type(sk), (n))
+#define sk_ASN1_TYPE_free(sk) OPENSSL_sk_free(ossl_check_ASN1_TYPE_sk_type(sk))
+#define sk_ASN1_TYPE_zero(sk) OPENSSL_sk_zero(ossl_check_ASN1_TYPE_sk_type(sk))
+#define sk_ASN1_TYPE_delete(sk, i) ((ASN1_TYPE *)OPENSSL_sk_delete(ossl_check_ASN1_TYPE_sk_type(sk), (i)))
+#define sk_ASN1_TYPE_delete_ptr(sk, ptr) ((ASN1_TYPE *)OPENSSL_sk_delete_ptr(ossl_check_ASN1_TYPE_sk_type(sk), ossl_check_ASN1_TYPE_type(ptr)))
+#define sk_ASN1_TYPE_push(sk, ptr) OPENSSL_sk_push(ossl_check_ASN1_TYPE_sk_type(sk), ossl_check_ASN1_TYPE_type(ptr))
+#define sk_ASN1_TYPE_unshift(sk, ptr) OPENSSL_sk_unshift(ossl_check_ASN1_TYPE_sk_type(sk), ossl_check_ASN1_TYPE_type(ptr))
+#define sk_ASN1_TYPE_pop(sk) ((ASN1_TYPE *)OPENSSL_sk_pop(ossl_check_ASN1_TYPE_sk_type(sk)))
+#define sk_ASN1_TYPE_shift(sk) ((ASN1_TYPE *)OPENSSL_sk_shift(ossl_check_ASN1_TYPE_sk_type(sk)))
+#define sk_ASN1_TYPE_pop_free(sk, freefunc) OPENSSL_sk_pop_free(ossl_check_ASN1_TYPE_sk_type(sk), ossl_check_ASN1_TYPE_freefunc_type(freefunc))
+#define sk_ASN1_TYPE_insert(sk, ptr, idx) OPENSSL_sk_insert(ossl_check_ASN1_TYPE_sk_type(sk), ossl_check_ASN1_TYPE_type(ptr), (idx))
+#define sk_ASN1_TYPE_set(sk, idx, ptr) ((ASN1_TYPE *)OPENSSL_sk_set(ossl_check_ASN1_TYPE_sk_type(sk), (idx), ossl_check_ASN1_TYPE_type(ptr)))
+#define sk_ASN1_TYPE_find(sk, ptr) OPENSSL_sk_find(ossl_check_ASN1_TYPE_sk_type(sk), ossl_check_ASN1_TYPE_type(ptr))
+#define sk_ASN1_TYPE_find_ex(sk, ptr) OPENSSL_sk_find_ex(ossl_check_ASN1_TYPE_sk_type(sk), ossl_check_ASN1_TYPE_type(ptr))
+#define sk_ASN1_TYPE_find_all(sk, ptr, pnum) OPENSSL_sk_find_all(ossl_check_ASN1_TYPE_sk_type(sk), ossl_check_ASN1_TYPE_type(ptr), pnum)
+#define sk_ASN1_TYPE_sort(sk) OPENSSL_sk_sort(ossl_check_ASN1_TYPE_sk_type(sk))
+#define sk_ASN1_TYPE_is_sorted(sk) OPENSSL_sk_is_sorted(ossl_check_const_ASN1_TYPE_sk_type(sk))
+#define sk_ASN1_TYPE_dup(sk) ((STACK_OF(ASN1_TYPE) *)OPENSSL_sk_dup(ossl_check_const_ASN1_TYPE_sk_type(sk)))
+#define sk_ASN1_TYPE_deep_copy(sk, copyfunc, freefunc) ((STACK_OF(ASN1_TYPE) *)OPENSSL_sk_deep_copy(ossl_check_const_ASN1_TYPE_sk_type(sk), ossl_check_ASN1_TYPE_copyfunc_type(copyfunc), ossl_check_ASN1_TYPE_freefunc_type(freefunc)))
+#define sk_ASN1_TYPE_set_cmp_func(sk, cmp) ((sk_ASN1_TYPE_compfunc)OPENSSL_sk_set_cmp_func(ossl_check_ASN1_TYPE_sk_type(sk), ossl_check_ASN1_TYPE_compfunc_type(cmp)))
+
+/* clang-format on */
+
+typedef STACK_OF(ASN1_TYPE) ASN1_SEQUENCE_ANY;
+
+DECLARE_ASN1_ENCODE_FUNCTIONS_name(ASN1_SEQUENCE_ANY, ASN1_SEQUENCE_ANY)
+DECLARE_ASN1_ENCODE_FUNCTIONS_name(ASN1_SEQUENCE_ANY, ASN1_SET_ANY)
+
+/* This is used to contain a list of bit names */
+typedef struct BIT_STRING_BITNAME_st {
+ int bitnum;
+ const char *lname;
+ const char *sname;
+} BIT_STRING_BITNAME;
+
+#define B_ASN1_TIME \
+ B_ASN1_UTCTIME | B_ASN1_GENERALIZEDTIME
+
+#define B_ASN1_PRINTABLE \
+ B_ASN1_NUMERICSTRING | B_ASN1_PRINTABLESTRING | B_ASN1_T61STRING | B_ASN1_IA5STRING | B_ASN1_BIT_STRING | B_ASN1_UNIVERSALSTRING | B_ASN1_BMPSTRING | B_ASN1_UTF8STRING | B_ASN1_SEQUENCE | B_ASN1_UNKNOWN
+
+#define B_ASN1_DIRECTORYSTRING \
+ B_ASN1_PRINTABLESTRING | B_ASN1_TELETEXSTRING | B_ASN1_BMPSTRING | B_ASN1_UNIVERSALSTRING | B_ASN1_UTF8STRING
+
+#define B_ASN1_DISPLAYTEXT \
+ B_ASN1_IA5STRING | B_ASN1_VISIBLESTRING | B_ASN1_BMPSTRING | B_ASN1_UTF8STRING
+
+DECLARE_ASN1_ALLOC_FUNCTIONS_name(ASN1_TYPE, ASN1_TYPE)
+DECLARE_ASN1_ENCODE_FUNCTIONS(ASN1_TYPE, ASN1_ANY, ASN1_TYPE)
+
+int ASN1_TYPE_get(const ASN1_TYPE *a);
+void ASN1_TYPE_set(ASN1_TYPE *a, int type, void *value);
+int ASN1_TYPE_set1(ASN1_TYPE *a, int type, const void *value);
+int ASN1_TYPE_cmp(const ASN1_TYPE *a, const ASN1_TYPE *b);
+
+ASN1_TYPE *ASN1_TYPE_pack_sequence(const ASN1_ITEM *it, void *s, ASN1_TYPE **t);
+void *ASN1_TYPE_unpack_sequence(const ASN1_ITEM *it, const ASN1_TYPE *t);
+
+/* clang-format off */
+SKM_DEFINE_STACK_OF_INTERNAL(ASN1_OBJECT, ASN1_OBJECT, ASN1_OBJECT)
+#define sk_ASN1_OBJECT_num(sk) OPENSSL_sk_num(ossl_check_const_ASN1_OBJECT_sk_type(sk))
+#define sk_ASN1_OBJECT_value(sk, idx) ((ASN1_OBJECT *)OPENSSL_sk_value(ossl_check_const_ASN1_OBJECT_sk_type(sk), (idx)))
+#define sk_ASN1_OBJECT_new(cmp) ((STACK_OF(ASN1_OBJECT) *)OPENSSL_sk_new(ossl_check_ASN1_OBJECT_compfunc_type(cmp)))
+#define sk_ASN1_OBJECT_new_null() ((STACK_OF(ASN1_OBJECT) *)OPENSSL_sk_new_null())
+#define sk_ASN1_OBJECT_new_reserve(cmp, n) ((STACK_OF(ASN1_OBJECT) *)OPENSSL_sk_new_reserve(ossl_check_ASN1_OBJECT_compfunc_type(cmp), (n)))
+#define sk_ASN1_OBJECT_reserve(sk, n) OPENSSL_sk_reserve(ossl_check_ASN1_OBJECT_sk_type(sk), (n))
+#define sk_ASN1_OBJECT_free(sk) OPENSSL_sk_free(ossl_check_ASN1_OBJECT_sk_type(sk))
+#define sk_ASN1_OBJECT_zero(sk) OPENSSL_sk_zero(ossl_check_ASN1_OBJECT_sk_type(sk))
+#define sk_ASN1_OBJECT_delete(sk, i) ((ASN1_OBJECT *)OPENSSL_sk_delete(ossl_check_ASN1_OBJECT_sk_type(sk), (i)))
+#define sk_ASN1_OBJECT_delete_ptr(sk, ptr) ((ASN1_OBJECT *)OPENSSL_sk_delete_ptr(ossl_check_ASN1_OBJECT_sk_type(sk), ossl_check_ASN1_OBJECT_type(ptr)))
+#define sk_ASN1_OBJECT_push(sk, ptr) OPENSSL_sk_push(ossl_check_ASN1_OBJECT_sk_type(sk), ossl_check_ASN1_OBJECT_type(ptr))
+#define sk_ASN1_OBJECT_unshift(sk, ptr) OPENSSL_sk_unshift(ossl_check_ASN1_OBJECT_sk_type(sk), ossl_check_ASN1_OBJECT_type(ptr))
+#define sk_ASN1_OBJECT_pop(sk) ((ASN1_OBJECT *)OPENSSL_sk_pop(ossl_check_ASN1_OBJECT_sk_type(sk)))
+#define sk_ASN1_OBJECT_shift(sk) ((ASN1_OBJECT *)OPENSSL_sk_shift(ossl_check_ASN1_OBJECT_sk_type(sk)))
+#define sk_ASN1_OBJECT_pop_free(sk, freefunc) OPENSSL_sk_pop_free(ossl_check_ASN1_OBJECT_sk_type(sk), ossl_check_ASN1_OBJECT_freefunc_type(freefunc))
+#define sk_ASN1_OBJECT_insert(sk, ptr, idx) OPENSSL_sk_insert(ossl_check_ASN1_OBJECT_sk_type(sk), ossl_check_ASN1_OBJECT_type(ptr), (idx))
+#define sk_ASN1_OBJECT_set(sk, idx, ptr) ((ASN1_OBJECT *)OPENSSL_sk_set(ossl_check_ASN1_OBJECT_sk_type(sk), (idx), ossl_check_ASN1_OBJECT_type(ptr)))
+#define sk_ASN1_OBJECT_find(sk, ptr) OPENSSL_sk_find(ossl_check_ASN1_OBJECT_sk_type(sk), ossl_check_ASN1_OBJECT_type(ptr))
+#define sk_ASN1_OBJECT_find_ex(sk, ptr) OPENSSL_sk_find_ex(ossl_check_ASN1_OBJECT_sk_type(sk), ossl_check_ASN1_OBJECT_type(ptr))
+#define sk_ASN1_OBJECT_find_all(sk, ptr, pnum) OPENSSL_sk_find_all(ossl_check_ASN1_OBJECT_sk_type(sk), ossl_check_ASN1_OBJECT_type(ptr), pnum)
+#define sk_ASN1_OBJECT_sort(sk) OPENSSL_sk_sort(ossl_check_ASN1_OBJECT_sk_type(sk))
+#define sk_ASN1_OBJECT_is_sorted(sk) OPENSSL_sk_is_sorted(ossl_check_const_ASN1_OBJECT_sk_type(sk))
+#define sk_ASN1_OBJECT_dup(sk) ((STACK_OF(ASN1_OBJECT) *)OPENSSL_sk_dup(ossl_check_const_ASN1_OBJECT_sk_type(sk)))
+#define sk_ASN1_OBJECT_deep_copy(sk, copyfunc, freefunc) ((STACK_OF(ASN1_OBJECT) *)OPENSSL_sk_deep_copy(ossl_check_const_ASN1_OBJECT_sk_type(sk), ossl_check_ASN1_OBJECT_copyfunc_type(copyfunc), ossl_check_ASN1_OBJECT_freefunc_type(freefunc)))
+#define sk_ASN1_OBJECT_set_cmp_func(sk, cmp) ((sk_ASN1_OBJECT_compfunc)OPENSSL_sk_set_cmp_func(ossl_check_ASN1_OBJECT_sk_type(sk), ossl_check_ASN1_OBJECT_compfunc_type(cmp)))
+
+/* clang-format on */
+
+DECLARE_ASN1_FUNCTIONS(ASN1_OBJECT)
+
+ASN1_STRING *ASN1_STRING_new(void);
+void ASN1_STRING_free(ASN1_STRING *a);
+void ASN1_STRING_clear_free(ASN1_STRING *a);
+int ASN1_STRING_copy(ASN1_STRING *dst, const ASN1_STRING *str);
+DECLARE_ASN1_DUP_FUNCTION(ASN1_STRING)
+ASN1_STRING *ASN1_STRING_type_new(int type);
+int ASN1_STRING_cmp(const ASN1_STRING *a, const ASN1_STRING *b);
+/*
+ * Since this is used to store all sorts of things, via macros, for now,
+ * make its data void *
+ */
+int ASN1_STRING_set(ASN1_STRING *str, const void *data, int len);
+void ASN1_STRING_set0(ASN1_STRING *str, void *data, int len);
+int ASN1_STRING_length(const ASN1_STRING *x);
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+OSSL_DEPRECATEDIN_3_0 void ASN1_STRING_length_set(ASN1_STRING *x, int n);
+#endif
+int ASN1_STRING_type(const ASN1_STRING *x);
+#ifndef OPENSSL_NO_DEPRECATED_1_1_0
+OSSL_DEPRECATEDIN_1_1_0 unsigned char *ASN1_STRING_data(ASN1_STRING *x);
+#endif
+const unsigned char *ASN1_STRING_get0_data(const ASN1_STRING *x);
+
+DECLARE_ASN1_FUNCTIONS(ASN1_BIT_STRING)
+int ASN1_BIT_STRING_set(ASN1_BIT_STRING *a, unsigned char *d, int length);
+int ASN1_BIT_STRING_set_bit(ASN1_BIT_STRING *a, int n, int value);
+int ASN1_BIT_STRING_get_bit(const ASN1_BIT_STRING *a, int n);
+int ASN1_BIT_STRING_check(const ASN1_BIT_STRING *a,
+ const unsigned char *flags, int flags_len);
+
+int ASN1_BIT_STRING_name_print(BIO *out, ASN1_BIT_STRING *bs,
+ BIT_STRING_BITNAME *tbl, int indent);
+int ASN1_BIT_STRING_num_asc(const char *name, BIT_STRING_BITNAME *tbl);
+int ASN1_BIT_STRING_set_asc(ASN1_BIT_STRING *bs, const char *name, int value,
+ BIT_STRING_BITNAME *tbl);
+
+/* clang-format off */
+SKM_DEFINE_STACK_OF_INTERNAL(ASN1_INTEGER, ASN1_INTEGER, ASN1_INTEGER)
+#define sk_ASN1_INTEGER_num(sk) OPENSSL_sk_num(ossl_check_const_ASN1_INTEGER_sk_type(sk))
+#define sk_ASN1_INTEGER_value(sk, idx) ((ASN1_INTEGER *)OPENSSL_sk_value(ossl_check_const_ASN1_INTEGER_sk_type(sk), (idx)))
+#define sk_ASN1_INTEGER_new(cmp) ((STACK_OF(ASN1_INTEGER) *)OPENSSL_sk_new(ossl_check_ASN1_INTEGER_compfunc_type(cmp)))
+#define sk_ASN1_INTEGER_new_null() ((STACK_OF(ASN1_INTEGER) *)OPENSSL_sk_new_null())
+#define sk_ASN1_INTEGER_new_reserve(cmp, n) ((STACK_OF(ASN1_INTEGER) *)OPENSSL_sk_new_reserve(ossl_check_ASN1_INTEGER_compfunc_type(cmp), (n)))
+#define sk_ASN1_INTEGER_reserve(sk, n) OPENSSL_sk_reserve(ossl_check_ASN1_INTEGER_sk_type(sk), (n))
+#define sk_ASN1_INTEGER_free(sk) OPENSSL_sk_free(ossl_check_ASN1_INTEGER_sk_type(sk))
+#define sk_ASN1_INTEGER_zero(sk) OPENSSL_sk_zero(ossl_check_ASN1_INTEGER_sk_type(sk))
+#define sk_ASN1_INTEGER_delete(sk, i) ((ASN1_INTEGER *)OPENSSL_sk_delete(ossl_check_ASN1_INTEGER_sk_type(sk), (i)))
+#define sk_ASN1_INTEGER_delete_ptr(sk, ptr) ((ASN1_INTEGER *)OPENSSL_sk_delete_ptr(ossl_check_ASN1_INTEGER_sk_type(sk), ossl_check_ASN1_INTEGER_type(ptr)))
+#define sk_ASN1_INTEGER_push(sk, ptr) OPENSSL_sk_push(ossl_check_ASN1_INTEGER_sk_type(sk), ossl_check_ASN1_INTEGER_type(ptr))
+#define sk_ASN1_INTEGER_unshift(sk, ptr) OPENSSL_sk_unshift(ossl_check_ASN1_INTEGER_sk_type(sk), ossl_check_ASN1_INTEGER_type(ptr))
+#define sk_ASN1_INTEGER_pop(sk) ((ASN1_INTEGER *)OPENSSL_sk_pop(ossl_check_ASN1_INTEGER_sk_type(sk)))
+#define sk_ASN1_INTEGER_shift(sk) ((ASN1_INTEGER *)OPENSSL_sk_shift(ossl_check_ASN1_INTEGER_sk_type(sk)))
+#define sk_ASN1_INTEGER_pop_free(sk, freefunc) OPENSSL_sk_pop_free(ossl_check_ASN1_INTEGER_sk_type(sk), ossl_check_ASN1_INTEGER_freefunc_type(freefunc))
+#define sk_ASN1_INTEGER_insert(sk, ptr, idx) OPENSSL_sk_insert(ossl_check_ASN1_INTEGER_sk_type(sk), ossl_check_ASN1_INTEGER_type(ptr), (idx))
+#define sk_ASN1_INTEGER_set(sk, idx, ptr) ((ASN1_INTEGER *)OPENSSL_sk_set(ossl_check_ASN1_INTEGER_sk_type(sk), (idx), ossl_check_ASN1_INTEGER_type(ptr)))
+#define sk_ASN1_INTEGER_find(sk, ptr) OPENSSL_sk_find(ossl_check_ASN1_INTEGER_sk_type(sk), ossl_check_ASN1_INTEGER_type(ptr))
+#define sk_ASN1_INTEGER_find_ex(sk, ptr) OPENSSL_sk_find_ex(ossl_check_ASN1_INTEGER_sk_type(sk), ossl_check_ASN1_INTEGER_type(ptr))
+#define sk_ASN1_INTEGER_find_all(sk, ptr, pnum) OPENSSL_sk_find_all(ossl_check_ASN1_INTEGER_sk_type(sk), ossl_check_ASN1_INTEGER_type(ptr), pnum)
+#define sk_ASN1_INTEGER_sort(sk) OPENSSL_sk_sort(ossl_check_ASN1_INTEGER_sk_type(sk))
+#define sk_ASN1_INTEGER_is_sorted(sk) OPENSSL_sk_is_sorted(ossl_check_const_ASN1_INTEGER_sk_type(sk))
+#define sk_ASN1_INTEGER_dup(sk) ((STACK_OF(ASN1_INTEGER) *)OPENSSL_sk_dup(ossl_check_const_ASN1_INTEGER_sk_type(sk)))
+#define sk_ASN1_INTEGER_deep_copy(sk, copyfunc, freefunc) ((STACK_OF(ASN1_INTEGER) *)OPENSSL_sk_deep_copy(ossl_check_const_ASN1_INTEGER_sk_type(sk), ossl_check_ASN1_INTEGER_copyfunc_type(copyfunc), ossl_check_ASN1_INTEGER_freefunc_type(freefunc)))
+#define sk_ASN1_INTEGER_set_cmp_func(sk, cmp) ((sk_ASN1_INTEGER_compfunc)OPENSSL_sk_set_cmp_func(ossl_check_ASN1_INTEGER_sk_type(sk), ossl_check_ASN1_INTEGER_compfunc_type(cmp)))
+
+/* clang-format on */
+
+DECLARE_ASN1_FUNCTIONS(ASN1_INTEGER)
+ASN1_INTEGER *d2i_ASN1_UINTEGER(ASN1_INTEGER **a, const unsigned char **pp,
+ long length);
+DECLARE_ASN1_DUP_FUNCTION(ASN1_INTEGER)
+int ASN1_INTEGER_cmp(const ASN1_INTEGER *x, const ASN1_INTEGER *y);
+
+DECLARE_ASN1_FUNCTIONS(ASN1_ENUMERATED)
+
+int ASN1_UTCTIME_check(const ASN1_UTCTIME *a);
+ASN1_UTCTIME *ASN1_UTCTIME_set(ASN1_UTCTIME *s, time_t t);
+ASN1_UTCTIME *ASN1_UTCTIME_adj(ASN1_UTCTIME *s, time_t t,
+ int offset_day, long offset_sec);
+int ASN1_UTCTIME_set_string(ASN1_UTCTIME *s, const char *str);
+int ASN1_UTCTIME_cmp_time_t(const ASN1_UTCTIME *s, time_t t);
+
+int ASN1_GENERALIZEDTIME_check(const ASN1_GENERALIZEDTIME *a);
+ASN1_GENERALIZEDTIME *ASN1_GENERALIZEDTIME_set(ASN1_GENERALIZEDTIME *s,
+ time_t t);
+ASN1_GENERALIZEDTIME *ASN1_GENERALIZEDTIME_adj(ASN1_GENERALIZEDTIME *s,
+ time_t t, int offset_day,
+ long offset_sec);
+int ASN1_GENERALIZEDTIME_set_string(ASN1_GENERALIZEDTIME *s, const char *str);
+
+int ASN1_TIME_diff(int *pday, int *psec,
+ const ASN1_TIME *from, const ASN1_TIME *to);
+
+DECLARE_ASN1_FUNCTIONS(ASN1_OCTET_STRING)
+DECLARE_ASN1_DUP_FUNCTION(ASN1_OCTET_STRING)
+int ASN1_OCTET_STRING_cmp(const ASN1_OCTET_STRING *a,
+ const ASN1_OCTET_STRING *b);
+int ASN1_OCTET_STRING_set(ASN1_OCTET_STRING *str, const unsigned char *data,
+ int len);
+
+/* clang-format off */
+SKM_DEFINE_STACK_OF_INTERNAL(ASN1_UTF8STRING, ASN1_UTF8STRING, ASN1_UTF8STRING)
+#define sk_ASN1_UTF8STRING_num(sk) OPENSSL_sk_num(ossl_check_const_ASN1_UTF8STRING_sk_type(sk))
+#define sk_ASN1_UTF8STRING_value(sk, idx) ((ASN1_UTF8STRING *)OPENSSL_sk_value(ossl_check_const_ASN1_UTF8STRING_sk_type(sk), (idx)))
+#define sk_ASN1_UTF8STRING_new(cmp) ((STACK_OF(ASN1_UTF8STRING) *)OPENSSL_sk_new(ossl_check_ASN1_UTF8STRING_compfunc_type(cmp)))
+#define sk_ASN1_UTF8STRING_new_null() ((STACK_OF(ASN1_UTF8STRING) *)OPENSSL_sk_new_null())
+#define sk_ASN1_UTF8STRING_new_reserve(cmp, n) ((STACK_OF(ASN1_UTF8STRING) *)OPENSSL_sk_new_reserve(ossl_check_ASN1_UTF8STRING_compfunc_type(cmp), (n)))
+#define sk_ASN1_UTF8STRING_reserve(sk, n) OPENSSL_sk_reserve(ossl_check_ASN1_UTF8STRING_sk_type(sk), (n))
+#define sk_ASN1_UTF8STRING_free(sk) OPENSSL_sk_free(ossl_check_ASN1_UTF8STRING_sk_type(sk))
+#define sk_ASN1_UTF8STRING_zero(sk) OPENSSL_sk_zero(ossl_check_ASN1_UTF8STRING_sk_type(sk))
+#define sk_ASN1_UTF8STRING_delete(sk, i) ((ASN1_UTF8STRING *)OPENSSL_sk_delete(ossl_check_ASN1_UTF8STRING_sk_type(sk), (i)))
+#define sk_ASN1_UTF8STRING_delete_ptr(sk, ptr) ((ASN1_UTF8STRING *)OPENSSL_sk_delete_ptr(ossl_check_ASN1_UTF8STRING_sk_type(sk), ossl_check_ASN1_UTF8STRING_type(ptr)))
+#define sk_ASN1_UTF8STRING_push(sk, ptr) OPENSSL_sk_push(ossl_check_ASN1_UTF8STRING_sk_type(sk), ossl_check_ASN1_UTF8STRING_type(ptr))
+#define sk_ASN1_UTF8STRING_unshift(sk, ptr) OPENSSL_sk_unshift(ossl_check_ASN1_UTF8STRING_sk_type(sk), ossl_check_ASN1_UTF8STRING_type(ptr))
+#define sk_ASN1_UTF8STRING_pop(sk) ((ASN1_UTF8STRING *)OPENSSL_sk_pop(ossl_check_ASN1_UTF8STRING_sk_type(sk)))
+#define sk_ASN1_UTF8STRING_shift(sk) ((ASN1_UTF8STRING *)OPENSSL_sk_shift(ossl_check_ASN1_UTF8STRING_sk_type(sk)))
+#define sk_ASN1_UTF8STRING_pop_free(sk, freefunc) OPENSSL_sk_pop_free(ossl_check_ASN1_UTF8STRING_sk_type(sk), ossl_check_ASN1_UTF8STRING_freefunc_type(freefunc))
+#define sk_ASN1_UTF8STRING_insert(sk, ptr, idx) OPENSSL_sk_insert(ossl_check_ASN1_UTF8STRING_sk_type(sk), ossl_check_ASN1_UTF8STRING_type(ptr), (idx))
+#define sk_ASN1_UTF8STRING_set(sk, idx, ptr) ((ASN1_UTF8STRING *)OPENSSL_sk_set(ossl_check_ASN1_UTF8STRING_sk_type(sk), (idx), ossl_check_ASN1_UTF8STRING_type(ptr)))
+#define sk_ASN1_UTF8STRING_find(sk, ptr) OPENSSL_sk_find(ossl_check_ASN1_UTF8STRING_sk_type(sk), ossl_check_ASN1_UTF8STRING_type(ptr))
+#define sk_ASN1_UTF8STRING_find_ex(sk, ptr) OPENSSL_sk_find_ex(ossl_check_ASN1_UTF8STRING_sk_type(sk), ossl_check_ASN1_UTF8STRING_type(ptr))
+#define sk_ASN1_UTF8STRING_find_all(sk, ptr, pnum) OPENSSL_sk_find_all(ossl_check_ASN1_UTF8STRING_sk_type(sk), ossl_check_ASN1_UTF8STRING_type(ptr), pnum)
+#define sk_ASN1_UTF8STRING_sort(sk) OPENSSL_sk_sort(ossl_check_ASN1_UTF8STRING_sk_type(sk))
+#define sk_ASN1_UTF8STRING_is_sorted(sk) OPENSSL_sk_is_sorted(ossl_check_const_ASN1_UTF8STRING_sk_type(sk))
+#define sk_ASN1_UTF8STRING_dup(sk) ((STACK_OF(ASN1_UTF8STRING) *)OPENSSL_sk_dup(ossl_check_const_ASN1_UTF8STRING_sk_type(sk)))
+#define sk_ASN1_UTF8STRING_deep_copy(sk, copyfunc, freefunc) ((STACK_OF(ASN1_UTF8STRING) *)OPENSSL_sk_deep_copy(ossl_check_const_ASN1_UTF8STRING_sk_type(sk), ossl_check_ASN1_UTF8STRING_copyfunc_type(copyfunc), ossl_check_ASN1_UTF8STRING_freefunc_type(freefunc)))
+#define sk_ASN1_UTF8STRING_set_cmp_func(sk, cmp) ((sk_ASN1_UTF8STRING_compfunc)OPENSSL_sk_set_cmp_func(ossl_check_ASN1_UTF8STRING_sk_type(sk), ossl_check_ASN1_UTF8STRING_compfunc_type(cmp)))
+
+/* clang-format on */
+
+DECLARE_ASN1_FUNCTIONS(ASN1_VISIBLESTRING)
+DECLARE_ASN1_FUNCTIONS(ASN1_UNIVERSALSTRING)
+DECLARE_ASN1_FUNCTIONS(ASN1_UTF8STRING)
+DECLARE_ASN1_FUNCTIONS(ASN1_NULL)
+DECLARE_ASN1_FUNCTIONS(ASN1_BMPSTRING)
+
+int UTF8_getc(const unsigned char *str, int len, unsigned long *val);
+int UTF8_putc(unsigned char *str, int len, unsigned long value);
+
+/* clang-format off */
+SKM_DEFINE_STACK_OF_INTERNAL(ASN1_GENERALSTRING, ASN1_GENERALSTRING, ASN1_GENERALSTRING)
+#define sk_ASN1_GENERALSTRING_num(sk) OPENSSL_sk_num(ossl_check_const_ASN1_GENERALSTRING_sk_type(sk))
+#define sk_ASN1_GENERALSTRING_value(sk, idx) ((ASN1_GENERALSTRING *)OPENSSL_sk_value(ossl_check_const_ASN1_GENERALSTRING_sk_type(sk), (idx)))
+#define sk_ASN1_GENERALSTRING_new(cmp) ((STACK_OF(ASN1_GENERALSTRING) *)OPENSSL_sk_new(ossl_check_ASN1_GENERALSTRING_compfunc_type(cmp)))
+#define sk_ASN1_GENERALSTRING_new_null() ((STACK_OF(ASN1_GENERALSTRING) *)OPENSSL_sk_new_null())
+#define sk_ASN1_GENERALSTRING_new_reserve(cmp, n) ((STACK_OF(ASN1_GENERALSTRING) *)OPENSSL_sk_new_reserve(ossl_check_ASN1_GENERALSTRING_compfunc_type(cmp), (n)))
+#define sk_ASN1_GENERALSTRING_reserve(sk, n) OPENSSL_sk_reserve(ossl_check_ASN1_GENERALSTRING_sk_type(sk), (n))
+#define sk_ASN1_GENERALSTRING_free(sk) OPENSSL_sk_free(ossl_check_ASN1_GENERALSTRING_sk_type(sk))
+#define sk_ASN1_GENERALSTRING_zero(sk) OPENSSL_sk_zero(ossl_check_ASN1_GENERALSTRING_sk_type(sk))
+#define sk_ASN1_GENERALSTRING_delete(sk, i) ((ASN1_GENERALSTRING *)OPENSSL_sk_delete(ossl_check_ASN1_GENERALSTRING_sk_type(sk), (i)))
+#define sk_ASN1_GENERALSTRING_delete_ptr(sk, ptr) ((ASN1_GENERALSTRING *)OPENSSL_sk_delete_ptr(ossl_check_ASN1_GENERALSTRING_sk_type(sk), ossl_check_ASN1_GENERALSTRING_type(ptr)))
+#define sk_ASN1_GENERALSTRING_push(sk, ptr) OPENSSL_sk_push(ossl_check_ASN1_GENERALSTRING_sk_type(sk), ossl_check_ASN1_GENERALSTRING_type(ptr))
+#define sk_ASN1_GENERALSTRING_unshift(sk, ptr) OPENSSL_sk_unshift(ossl_check_ASN1_GENERALSTRING_sk_type(sk), ossl_check_ASN1_GENERALSTRING_type(ptr))
+#define sk_ASN1_GENERALSTRING_pop(sk) ((ASN1_GENERALSTRING *)OPENSSL_sk_pop(ossl_check_ASN1_GENERALSTRING_sk_type(sk)))
+#define sk_ASN1_GENERALSTRING_shift(sk) ((ASN1_GENERALSTRING *)OPENSSL_sk_shift(ossl_check_ASN1_GENERALSTRING_sk_type(sk)))
+#define sk_ASN1_GENERALSTRING_pop_free(sk, freefunc) OPENSSL_sk_pop_free(ossl_check_ASN1_GENERALSTRING_sk_type(sk), ossl_check_ASN1_GENERALSTRING_freefunc_type(freefunc))
+#define sk_ASN1_GENERALSTRING_insert(sk, ptr, idx) OPENSSL_sk_insert(ossl_check_ASN1_GENERALSTRING_sk_type(sk), ossl_check_ASN1_GENERALSTRING_type(ptr), (idx))
+#define sk_ASN1_GENERALSTRING_set(sk, idx, ptr) ((ASN1_GENERALSTRING *)OPENSSL_sk_set(ossl_check_ASN1_GENERALSTRING_sk_type(sk), (idx), ossl_check_ASN1_GENERALSTRING_type(ptr)))
+#define sk_ASN1_GENERALSTRING_find(sk, ptr) OPENSSL_sk_find(ossl_check_ASN1_GENERALSTRING_sk_type(sk), ossl_check_ASN1_GENERALSTRING_type(ptr))
+#define sk_ASN1_GENERALSTRING_find_ex(sk, ptr) OPENSSL_sk_find_ex(ossl_check_ASN1_GENERALSTRING_sk_type(sk), ossl_check_ASN1_GENERALSTRING_type(ptr))
+#define sk_ASN1_GENERALSTRING_find_all(sk, ptr, pnum) OPENSSL_sk_find_all(ossl_check_ASN1_GENERALSTRING_sk_type(sk), ossl_check_ASN1_GENERALSTRING_type(ptr), pnum)
+#define sk_ASN1_GENERALSTRING_sort(sk) OPENSSL_sk_sort(ossl_check_ASN1_GENERALSTRING_sk_type(sk))
+#define sk_ASN1_GENERALSTRING_is_sorted(sk) OPENSSL_sk_is_sorted(ossl_check_const_ASN1_GENERALSTRING_sk_type(sk))
+#define sk_ASN1_GENERALSTRING_dup(sk) ((STACK_OF(ASN1_GENERALSTRING) *)OPENSSL_sk_dup(ossl_check_const_ASN1_GENERALSTRING_sk_type(sk)))
+#define sk_ASN1_GENERALSTRING_deep_copy(sk, copyfunc, freefunc) ((STACK_OF(ASN1_GENERALSTRING) *)OPENSSL_sk_deep_copy(ossl_check_const_ASN1_GENERALSTRING_sk_type(sk), ossl_check_ASN1_GENERALSTRING_copyfunc_type(copyfunc), ossl_check_ASN1_GENERALSTRING_freefunc_type(freefunc)))
+#define sk_ASN1_GENERALSTRING_set_cmp_func(sk, cmp) ((sk_ASN1_GENERALSTRING_compfunc)OPENSSL_sk_set_cmp_func(ossl_check_ASN1_GENERALSTRING_sk_type(sk), ossl_check_ASN1_GENERALSTRING_compfunc_type(cmp)))
+
+/* clang-format on */
+
+DECLARE_ASN1_FUNCTIONS_name(ASN1_STRING, ASN1_PRINTABLE)
+
+DECLARE_ASN1_FUNCTIONS_name(ASN1_STRING, DIRECTORYSTRING)
+DECLARE_ASN1_FUNCTIONS_name(ASN1_STRING, DISPLAYTEXT)
+DECLARE_ASN1_FUNCTIONS(ASN1_PRINTABLESTRING)
+DECLARE_ASN1_FUNCTIONS(ASN1_T61STRING)
+DECLARE_ASN1_FUNCTIONS(ASN1_IA5STRING)
+DECLARE_ASN1_FUNCTIONS(ASN1_GENERALSTRING)
+DECLARE_ASN1_FUNCTIONS(ASN1_UTCTIME)
+DECLARE_ASN1_FUNCTIONS(ASN1_GENERALIZEDTIME)
+DECLARE_ASN1_FUNCTIONS(ASN1_TIME)
+
+DECLARE_ASN1_DUP_FUNCTION(ASN1_TIME)
+DECLARE_ASN1_DUP_FUNCTION(ASN1_UTCTIME)
+DECLARE_ASN1_DUP_FUNCTION(ASN1_GENERALIZEDTIME)
+
+DECLARE_ASN1_ITEM(ASN1_OCTET_STRING_NDEF)
+
+ASN1_TIME *ASN1_TIME_set(ASN1_TIME *s, time_t t);
+ASN1_TIME *ASN1_TIME_adj(ASN1_TIME *s, time_t t,
+ int offset_day, long offset_sec);
+int ASN1_TIME_check(const ASN1_TIME *t);
+ASN1_GENERALIZEDTIME *ASN1_TIME_to_generalizedtime(const ASN1_TIME *t,
+ ASN1_GENERALIZEDTIME **out);
+int ASN1_TIME_set_string(ASN1_TIME *s, const char *str);
+int ASN1_TIME_set_string_X509(ASN1_TIME *s, const char *str);
+int ASN1_TIME_to_tm(const ASN1_TIME *s, struct tm *tm);
+int ASN1_TIME_normalize(ASN1_TIME *s);
+int ASN1_TIME_cmp_time_t(const ASN1_TIME *s, time_t t);
+int ASN1_TIME_compare(const ASN1_TIME *a, const ASN1_TIME *b);
+
+int i2a_ASN1_INTEGER(BIO *bp, const ASN1_INTEGER *a);
+int a2i_ASN1_INTEGER(BIO *bp, ASN1_INTEGER *bs, char *buf, int size);
+int i2a_ASN1_ENUMERATED(BIO *bp, const ASN1_ENUMERATED *a);
+int a2i_ASN1_ENUMERATED(BIO *bp, ASN1_ENUMERATED *bs, char *buf, int size);
+int i2a_ASN1_OBJECT(BIO *bp, const ASN1_OBJECT *a);
+int a2i_ASN1_STRING(BIO *bp, ASN1_STRING *bs, char *buf, int size);
+int i2a_ASN1_STRING(BIO *bp, const ASN1_STRING *a, int type);
+int i2t_ASN1_OBJECT(char *buf, int buf_len, const ASN1_OBJECT *a);
+
+int a2d_ASN1_OBJECT(unsigned char *out, int olen, const char *buf, int num);
+ASN1_OBJECT *ASN1_OBJECT_create(int nid, unsigned char *data, int len,
+ const char *sn, const char *ln);
+
+int ASN1_INTEGER_get_int64(int64_t *pr, const ASN1_INTEGER *a);
+int ASN1_INTEGER_set_int64(ASN1_INTEGER *a, int64_t r);
+int ASN1_INTEGER_get_uint64(uint64_t *pr, const ASN1_INTEGER *a);
+int ASN1_INTEGER_set_uint64(ASN1_INTEGER *a, uint64_t r);
+
+int ASN1_INTEGER_set(ASN1_INTEGER *a, long v);
+long ASN1_INTEGER_get(const ASN1_INTEGER *a);
+ASN1_INTEGER *BN_to_ASN1_INTEGER(const BIGNUM *bn, ASN1_INTEGER *ai);
+BIGNUM *ASN1_INTEGER_to_BN(const ASN1_INTEGER *ai, BIGNUM *bn);
+
+int ASN1_ENUMERATED_get_int64(int64_t *pr, const ASN1_ENUMERATED *a);
+int ASN1_ENUMERATED_set_int64(ASN1_ENUMERATED *a, int64_t r);
+
+int ASN1_ENUMERATED_set(ASN1_ENUMERATED *a, long v);
+long ASN1_ENUMERATED_get(const ASN1_ENUMERATED *a);
+ASN1_ENUMERATED *BN_to_ASN1_ENUMERATED(const BIGNUM *bn, ASN1_ENUMERATED *ai);
+BIGNUM *ASN1_ENUMERATED_to_BN(const ASN1_ENUMERATED *ai, BIGNUM *bn);
+
+/* General */
+/* given a string, return the correct type, max is the maximum length */
+int ASN1_PRINTABLE_type(const unsigned char *s, int max);
+
+unsigned long ASN1_tag2bit(int tag);
+
+/* SPECIALS */
+int ASN1_get_object(const unsigned char **pp, long *plength, int *ptag,
+ int *pclass, long omax);
+int ASN1_check_infinite_end(unsigned char **p, long len);
+int ASN1_const_check_infinite_end(const unsigned char **p, long len);
+void ASN1_put_object(unsigned char **pp, int constructed, int length,
+ int tag, int xclass);
+int ASN1_put_eoc(unsigned char **pp);
+int ASN1_object_size(int constructed, int length, int tag);
+
+/* Used to implement other functions */
+void *ASN1_dup(i2d_of_void *i2d, d2i_of_void *d2i, const void *x);
+
+#define ASN1_dup_of(type, i2d, d2i, x) \
+ ((type *)ASN1_dup(CHECKED_I2D_OF(type, i2d), \
+ CHECKED_D2I_OF(type, d2i), \
+ CHECKED_PTR_OF(const type, x)))
+
+void *ASN1_item_dup(const ASN1_ITEM *it, const void *x);
+int ASN1_item_sign_ex(const ASN1_ITEM *it, X509_ALGOR *algor1,
+ X509_ALGOR *algor2, ASN1_BIT_STRING *signature,
+ const void *data, const ASN1_OCTET_STRING *id,
+ EVP_PKEY *pkey, const EVP_MD *md, OSSL_LIB_CTX *libctx,
+ const char *propq);
+int ASN1_item_verify_ex(const ASN1_ITEM *it, const X509_ALGOR *alg,
+ const ASN1_BIT_STRING *signature, const void *data,
+ const ASN1_OCTET_STRING *id, EVP_PKEY *pkey,
+ OSSL_LIB_CTX *libctx, const char *propq);
+
+/* ASN1 alloc/free macros for when a type is only used internally */
+
+#define M_ASN1_new_of(type) (type *)ASN1_item_new(ASN1_ITEM_rptr(type))
+#define M_ASN1_free_of(x, type) \
+ ASN1_item_free(CHECKED_PTR_OF(type, x), ASN1_ITEM_rptr(type))
+
+#ifndef OPENSSL_NO_STDIO
+void *ASN1_d2i_fp(void *(*xnew)(void), d2i_of_void *d2i, FILE *in, void **x);
+
+#define ASN1_d2i_fp_of(type, xnew, d2i, in, x) \
+ ((type *)ASN1_d2i_fp(CHECKED_NEW_OF(type, xnew), \
+ CHECKED_D2I_OF(type, d2i), \
+ in, \
+ CHECKED_PPTR_OF(type, x)))
+
+void *ASN1_item_d2i_fp_ex(const ASN1_ITEM *it, FILE *in, void *x,
+ OSSL_LIB_CTX *libctx, const char *propq);
+void *ASN1_item_d2i_fp(const ASN1_ITEM *it, FILE *in, void *x);
+int ASN1_i2d_fp(i2d_of_void *i2d, FILE *out, const void *x);
+
+#define ASN1_i2d_fp_of(type, i2d, out, x) \
+ (ASN1_i2d_fp(CHECKED_I2D_OF(type, i2d), \
+ out, \
+ CHECKED_PTR_OF(const type, x)))
+
+int ASN1_item_i2d_fp(const ASN1_ITEM *it, FILE *out, const void *x);
+int ASN1_STRING_print_ex_fp(FILE *fp, const ASN1_STRING *str, unsigned long flags);
+#endif
+
+int ASN1_STRING_to_UTF8(unsigned char **out, const ASN1_STRING *in);
+
+void *ASN1_d2i_bio(void *(*xnew)(void), d2i_of_void *d2i, BIO *in, void **x);
+
+#define ASN1_d2i_bio_of(type, xnew, d2i, in, x) \
+ ((type *)ASN1_d2i_bio(CHECKED_NEW_OF(type, xnew), \
+ CHECKED_D2I_OF(type, d2i), \
+ in, \
+ CHECKED_PPTR_OF(type, x)))
+
+void *ASN1_item_d2i_bio_ex(const ASN1_ITEM *it, BIO *in, void *pval,
+ OSSL_LIB_CTX *libctx, const char *propq);
+void *ASN1_item_d2i_bio(const ASN1_ITEM *it, BIO *in, void *pval);
+int ASN1_i2d_bio(i2d_of_void *i2d, BIO *out, const void *x);
+
+#define ASN1_i2d_bio_of(type, i2d, out, x) \
+ (ASN1_i2d_bio(CHECKED_I2D_OF(type, i2d), \
+ out, \
+ CHECKED_PTR_OF(const type, x)))
+
+int ASN1_item_i2d_bio(const ASN1_ITEM *it, BIO *out, const void *x);
+BIO *ASN1_item_i2d_mem_bio(const ASN1_ITEM *it, const ASN1_VALUE *val);
+int ASN1_UTCTIME_print(BIO *fp, const ASN1_UTCTIME *a);
+int ASN1_GENERALIZEDTIME_print(BIO *fp, const ASN1_GENERALIZEDTIME *a);
+int ASN1_TIME_print(BIO *bp, const ASN1_TIME *tm);
+int ASN1_TIME_print_ex(BIO *bp, const ASN1_TIME *tm, unsigned long flags);
+int ASN1_STRING_print(BIO *bp, const ASN1_STRING *v);
+int ASN1_STRING_print_ex(BIO *out, const ASN1_STRING *str, unsigned long flags);
+int ASN1_buf_print(BIO *bp, const unsigned char *buf, size_t buflen, int off);
+int ASN1_bn_print(BIO *bp, const char *number, const BIGNUM *num,
+ unsigned char *buf, int off);
+int ASN1_parse(BIO *bp, const unsigned char *pp, long len, int indent);
+int ASN1_parse_dump(BIO *bp, const unsigned char *pp, long len, int indent,
+ int dump);
+const char *ASN1_tag2str(int tag);
+
+/* Used to load and write Netscape format cert */
+
+int ASN1_UNIVERSALSTRING_to_string(ASN1_UNIVERSALSTRING *s);
+
+int ASN1_TYPE_set_octetstring(ASN1_TYPE *a, unsigned char *data, int len);
+int ASN1_TYPE_get_octetstring(const ASN1_TYPE *a, unsigned char *data, int max_len);
+int ASN1_TYPE_set_int_octetstring(ASN1_TYPE *a, long num,
+ unsigned char *data, int len);
+int ASN1_TYPE_get_int_octetstring(const ASN1_TYPE *a, long *num,
+ unsigned char *data, int max_len);
+
+void *ASN1_item_unpack(const ASN1_STRING *oct, const ASN1_ITEM *it);
+void *ASN1_item_unpack_ex(const ASN1_STRING *oct, const ASN1_ITEM *it,
+ OSSL_LIB_CTX *libctx, const char *propq);
+
+ASN1_STRING *ASN1_item_pack(void *obj, const ASN1_ITEM *it,
+ ASN1_OCTET_STRING **oct);
+
+void ASN1_STRING_set_default_mask(unsigned long mask);
+int ASN1_STRING_set_default_mask_asc(const char *p);
+unsigned long ASN1_STRING_get_default_mask(void);
+int ASN1_mbstring_copy(ASN1_STRING **out, const unsigned char *in, int len,
+ int inform, unsigned long mask);
+int ASN1_mbstring_ncopy(ASN1_STRING **out, const unsigned char *in, int len,
+ int inform, unsigned long mask,
+ long minsize, long maxsize);
+
+ASN1_STRING *ASN1_STRING_set_by_NID(ASN1_STRING **out,
+ const unsigned char *in, int inlen,
+ int inform, int nid);
+ASN1_STRING_TABLE *ASN1_STRING_TABLE_get(int nid);
+int ASN1_STRING_TABLE_add(int, long, long, unsigned long, unsigned long);
+void ASN1_STRING_TABLE_cleanup(void);
+
+/* ASN1 template functions */
+
+/* Old API compatible functions */
+ASN1_VALUE *ASN1_item_new(const ASN1_ITEM *it);
+ASN1_VALUE *ASN1_item_new_ex(const ASN1_ITEM *it, OSSL_LIB_CTX *libctx,
+ const char *propq);
+void ASN1_item_free(ASN1_VALUE *val, const ASN1_ITEM *it);
+ASN1_VALUE *ASN1_item_d2i_ex(ASN1_VALUE **val, const unsigned char **in,
+ long len, const ASN1_ITEM *it,
+ OSSL_LIB_CTX *libctx, const char *propq);
+ASN1_VALUE *ASN1_item_d2i(ASN1_VALUE **val, const unsigned char **in,
+ long len, const ASN1_ITEM *it);
+int ASN1_item_i2d(const ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it);
+int ASN1_item_ndef_i2d(const ASN1_VALUE *val, unsigned char **out,
+ const ASN1_ITEM *it);
+
+void ASN1_add_oid_module(void);
+void ASN1_add_stable_module(void);
+
+ASN1_TYPE *ASN1_generate_nconf(const char *str, CONF *nconf);
+ASN1_TYPE *ASN1_generate_v3(const char *str, X509V3_CTX *cnf);
+int ASN1_str2mask(const char *str, unsigned long *pmask);
+
+/* ASN1 Print flags */
+
+/* Indicate missing OPTIONAL fields */
+#define ASN1_PCTX_FLAGS_SHOW_ABSENT 0x001
+/* Mark start and end of SEQUENCE */
+#define ASN1_PCTX_FLAGS_SHOW_SEQUENCE 0x002
+/* Mark start and end of SEQUENCE/SET OF */
+#define ASN1_PCTX_FLAGS_SHOW_SSOF 0x004
+/* Show the ASN1 type of primitives */
+#define ASN1_PCTX_FLAGS_SHOW_TYPE 0x008
+/* Don't show ASN1 type of ANY */
+#define ASN1_PCTX_FLAGS_NO_ANY_TYPE 0x010
+/* Don't show ASN1 type of MSTRINGs */
+#define ASN1_PCTX_FLAGS_NO_MSTRING_TYPE 0x020
+/* Don't show field names in SEQUENCE */
+#define ASN1_PCTX_FLAGS_NO_FIELD_NAME 0x040
+/* Show structure names of each SEQUENCE field */
+#define ASN1_PCTX_FLAGS_SHOW_FIELD_STRUCT_NAME 0x080
+/* Don't show structure name even at top level */
+#define ASN1_PCTX_FLAGS_NO_STRUCT_NAME 0x100
+
+int ASN1_item_print(BIO *out, const ASN1_VALUE *ifld, int indent,
+ const ASN1_ITEM *it, const ASN1_PCTX *pctx);
+ASN1_PCTX *ASN1_PCTX_new(void);
+void ASN1_PCTX_free(ASN1_PCTX *p);
+unsigned long ASN1_PCTX_get_flags(const ASN1_PCTX *p);
+void ASN1_PCTX_set_flags(ASN1_PCTX *p, unsigned long flags);
+unsigned long ASN1_PCTX_get_nm_flags(const ASN1_PCTX *p);
+void ASN1_PCTX_set_nm_flags(ASN1_PCTX *p, unsigned long flags);
+unsigned long ASN1_PCTX_get_cert_flags(const ASN1_PCTX *p);
+void ASN1_PCTX_set_cert_flags(ASN1_PCTX *p, unsigned long flags);
+unsigned long ASN1_PCTX_get_oid_flags(const ASN1_PCTX *p);
+void ASN1_PCTX_set_oid_flags(ASN1_PCTX *p, unsigned long flags);
+unsigned long ASN1_PCTX_get_str_flags(const ASN1_PCTX *p);
+void ASN1_PCTX_set_str_flags(ASN1_PCTX *p, unsigned long flags);
+
+ASN1_SCTX *ASN1_SCTX_new(int (*scan_cb)(ASN1_SCTX *ctx));
+void ASN1_SCTX_free(ASN1_SCTX *p);
+const ASN1_ITEM *ASN1_SCTX_get_item(ASN1_SCTX *p);
+const ASN1_TEMPLATE *ASN1_SCTX_get_template(ASN1_SCTX *p);
+unsigned long ASN1_SCTX_get_flags(ASN1_SCTX *p);
+void ASN1_SCTX_set_app_data(ASN1_SCTX *p, void *data);
+void *ASN1_SCTX_get_app_data(ASN1_SCTX *p);
+
+const BIO_METHOD *BIO_f_asn1(void);
+
+/* cannot constify val because of CMS_stream() */
+BIO *BIO_new_NDEF(BIO *out, ASN1_VALUE *val, const ASN1_ITEM *it);
+
+int i2d_ASN1_bio_stream(BIO *out, ASN1_VALUE *val, BIO *in, int flags,
+ const ASN1_ITEM *it);
+int PEM_write_bio_ASN1_stream(BIO *out, ASN1_VALUE *val, BIO *in, int flags,
+ const char *hdr, const ASN1_ITEM *it);
+/* cannot constify val because of CMS_dataFinal() */
+int SMIME_write_ASN1(BIO *bio, ASN1_VALUE *val, BIO *data, int flags,
+ int ctype_nid, int econt_nid,
+ STACK_OF(X509_ALGOR) *mdalgs, const ASN1_ITEM *it);
+int SMIME_write_ASN1_ex(BIO *bio, ASN1_VALUE *val, BIO *data, int flags,
+ int ctype_nid, int econt_nid,
+ STACK_OF(X509_ALGOR) *mdalgs, const ASN1_ITEM *it,
+ OSSL_LIB_CTX *libctx, const char *propq);
+ASN1_VALUE *SMIME_read_ASN1(BIO *bio, BIO **bcont, const ASN1_ITEM *it);
+ASN1_VALUE *SMIME_read_ASN1_ex(BIO *bio, int flags, BIO **bcont,
+ const ASN1_ITEM *it, ASN1_VALUE **x,
+ OSSL_LIB_CTX *libctx, const char *propq);
+int SMIME_crlf_copy(BIO *in, BIO *out, int flags);
+int SMIME_text(BIO *in, BIO *out);
+
+const ASN1_ITEM *ASN1_ITEM_lookup(const char *name);
+const ASN1_ITEM *ASN1_ITEM_get(size_t i);
+
+/* Legacy compatibility */
+#define DECLARE_ASN1_FUNCTIONS_fname(type, itname, name) \
+ DECLARE_ASN1_ALLOC_FUNCTIONS_name(type, name) \
+ DECLARE_ASN1_ENCODE_FUNCTIONS(type, itname, name)
+#define DECLARE_ASN1_FUNCTIONS_const(type) DECLARE_ASN1_FUNCTIONS(type)
+#define DECLARE_ASN1_ENCODE_FUNCTIONS_const(type, name) \
+ DECLARE_ASN1_ENCODE_FUNCTIONS(type, name)
+#define I2D_OF_const(type) I2D_OF(type)
+#define ASN1_dup_of_const(type, i2d, d2i, x) ASN1_dup_of(type, i2d, d2i, x)
+#define ASN1_i2d_fp_of_const(type, i2d, out, x) ASN1_i2d_fp_of(type, i2d, out, x)
+#define ASN1_i2d_bio_of_const(type, i2d, out, x) ASN1_i2d_bio_of(type, i2d, out, x)
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/third_party/ios/openssl/include/openssl/asn1err.h b/third_party/ios/openssl/include/openssl/asn1err.h
new file mode 100644
index 0000000..9175614
--- /dev/null
+++ b/third_party/ios/openssl/include/openssl/asn1err.h
@@ -0,0 +1,140 @@
+/*
+ * Generated by util/mkerr.pl DO NOT EDIT
+ * Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#ifndef OPENSSL_ASN1ERR_H
+#define OPENSSL_ASN1ERR_H
+#pragma once
+
+#include
+#include
+#include
+
+/*
+ * ASN1 reason codes.
+ */
+#define ASN1_R_ADDING_OBJECT 171
+#define ASN1_R_ASN1_PARSE_ERROR 203
+#define ASN1_R_ASN1_SIG_PARSE_ERROR 204
+#define ASN1_R_AUX_ERROR 100
+#define ASN1_R_BAD_OBJECT_HEADER 102
+#define ASN1_R_BAD_TEMPLATE 230
+#define ASN1_R_BMPSTRING_IS_WRONG_LENGTH 214
+#define ASN1_R_BN_LIB 105
+#define ASN1_R_BOOLEAN_IS_WRONG_LENGTH 106
+#define ASN1_R_BUFFER_TOO_SMALL 107
+#define ASN1_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER 108
+#define ASN1_R_CONTEXT_NOT_INITIALISED 217
+#define ASN1_R_DATA_IS_WRONG 109
+#define ASN1_R_DECODE_ERROR 110
+#define ASN1_R_DEPTH_EXCEEDED 174
+#define ASN1_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED 198
+#define ASN1_R_ENCODE_ERROR 112
+#define ASN1_R_ERROR_GETTING_TIME 173
+#define ASN1_R_ERROR_LOADING_SECTION 172
+#define ASN1_R_ERROR_SETTING_CIPHER_PARAMS 114
+#define ASN1_R_EXPECTING_AN_INTEGER 115
+#define ASN1_R_EXPECTING_AN_OBJECT 116
+#define ASN1_R_EXPLICIT_LENGTH_MISMATCH 119
+#define ASN1_R_EXPLICIT_TAG_NOT_CONSTRUCTED 120
+#define ASN1_R_FIELD_MISSING 121
+#define ASN1_R_FIRST_NUM_TOO_LARGE 122
+#define ASN1_R_GENERALIZEDTIME_IS_TOO_SHORT 232
+#define ASN1_R_HEADER_TOO_LONG 123
+#define ASN1_R_ILLEGAL_BITSTRING_FORMAT 175
+#define ASN1_R_ILLEGAL_BOOLEAN 176
+#define ASN1_R_ILLEGAL_CHARACTERS 124
+#define ASN1_R_ILLEGAL_FORMAT 177
+#define ASN1_R_ILLEGAL_HEX 178
+#define ASN1_R_ILLEGAL_IMPLICIT_TAG 179
+#define ASN1_R_ILLEGAL_INTEGER 180
+#define ASN1_R_ILLEGAL_NEGATIVE_VALUE 226
+#define ASN1_R_ILLEGAL_NESTED_TAGGING 181
+#define ASN1_R_ILLEGAL_NULL 125
+#define ASN1_R_ILLEGAL_NULL_VALUE 182
+#define ASN1_R_ILLEGAL_OBJECT 183
+#define ASN1_R_ILLEGAL_OPTIONAL_ANY 126
+#define ASN1_R_ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE 170
+#define ASN1_R_ILLEGAL_PADDING 221
+#define ASN1_R_ILLEGAL_TAGGED_ANY 127
+#define ASN1_R_ILLEGAL_TIME_VALUE 184
+#define ASN1_R_ILLEGAL_ZERO_CONTENT 222
+#define ASN1_R_INTEGER_NOT_ASCII_FORMAT 185
+#define ASN1_R_INTEGER_TOO_LARGE_FOR_LONG 128
+#define ASN1_R_INVALID_BIT_STRING_BITS_LEFT 220
+#define ASN1_R_INVALID_BMPSTRING_LENGTH 129
+#define ASN1_R_INVALID_DIGIT 130
+#define ASN1_R_INVALID_MIME_TYPE 205
+#define ASN1_R_INVALID_MODIFIER 186
+#define ASN1_R_INVALID_NUMBER 187
+#define ASN1_R_INVALID_OBJECT_ENCODING 216
+#define ASN1_R_INVALID_SCRYPT_PARAMETERS 227
+#define ASN1_R_INVALID_SEPARATOR 131
+#define ASN1_R_INVALID_STRING_TABLE_VALUE 218
+#define ASN1_R_INVALID_UNIVERSALSTRING_LENGTH 133
+#define ASN1_R_INVALID_UTF8STRING 134
+#define ASN1_R_INVALID_VALUE 219
+#define ASN1_R_LENGTH_TOO_LONG 231
+#define ASN1_R_LIST_ERROR 188
+#define ASN1_R_MIME_NO_CONTENT_TYPE 206
+#define ASN1_R_MIME_PARSE_ERROR 207
+#define ASN1_R_MIME_SIG_PARSE_ERROR 208
+#define ASN1_R_MISSING_EOC 137
+#define ASN1_R_MISSING_SECOND_NUMBER 138
+#define ASN1_R_MISSING_VALUE 189
+#define ASN1_R_MSTRING_NOT_UNIVERSAL 139
+#define ASN1_R_MSTRING_WRONG_TAG 140
+#define ASN1_R_NESTED_ASN1_STRING 197
+#define ASN1_R_NESTED_TOO_DEEP 201
+#define ASN1_R_NON_HEX_CHARACTERS 141
+#define ASN1_R_NOT_ASCII_FORMAT 190
+#define ASN1_R_NOT_ENOUGH_DATA 142
+#define ASN1_R_NO_CONTENT_TYPE 209
+#define ASN1_R_NO_MATCHING_CHOICE_TYPE 143
+#define ASN1_R_NO_MULTIPART_BODY_FAILURE 210
+#define ASN1_R_NO_MULTIPART_BOUNDARY 211
+#define ASN1_R_NO_SIG_CONTENT_TYPE 212
+#define ASN1_R_NULL_IS_WRONG_LENGTH 144
+#define ASN1_R_OBJECT_NOT_ASCII_FORMAT 191
+#define ASN1_R_ODD_NUMBER_OF_CHARS 145
+#define ASN1_R_SECOND_NUMBER_TOO_LARGE 147
+#define ASN1_R_SEQUENCE_LENGTH_MISMATCH 148
+#define ASN1_R_SEQUENCE_NOT_CONSTRUCTED 149
+#define ASN1_R_SEQUENCE_OR_SET_NEEDS_CONFIG 192
+#define ASN1_R_SHORT_LINE 150
+#define ASN1_R_SIG_INVALID_MIME_TYPE 213
+#define ASN1_R_STREAMING_NOT_SUPPORTED 202
+#define ASN1_R_STRING_TOO_LONG 151
+#define ASN1_R_STRING_TOO_SHORT 152
+#define ASN1_R_THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD 154
+#define ASN1_R_TIME_NOT_ASCII_FORMAT 193
+#define ASN1_R_TOO_LARGE 223
+#define ASN1_R_TOO_LONG 155
+#define ASN1_R_TOO_SMALL 224
+#define ASN1_R_TYPE_NOT_CONSTRUCTED 156
+#define ASN1_R_TYPE_NOT_PRIMITIVE 195
+#define ASN1_R_UNEXPECTED_EOC 159
+#define ASN1_R_UNIVERSALSTRING_IS_WRONG_LENGTH 215
+#define ASN1_R_UNKNOWN_DIGEST 229
+#define ASN1_R_UNKNOWN_FORMAT 160
+#define ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM 161
+#define ASN1_R_UNKNOWN_OBJECT_TYPE 162
+#define ASN1_R_UNKNOWN_PUBLIC_KEY_TYPE 163
+#define ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM 199
+#define ASN1_R_UNKNOWN_TAG 194
+#define ASN1_R_UNSUPPORTED_ANY_DEFINED_BY_TYPE 164
+#define ASN1_R_UNSUPPORTED_CIPHER 228
+#define ASN1_R_UNSUPPORTED_PUBLIC_KEY_TYPE 167
+#define ASN1_R_UNSUPPORTED_TYPE 196
+#define ASN1_R_UTCTIME_IS_TOO_SHORT 233
+#define ASN1_R_WRONG_INTEGER_TYPE 225
+#define ASN1_R_WRONG_PUBLIC_KEY_TYPE 200
+#define ASN1_R_WRONG_TAG 168
+
+#endif
diff --git a/third_party/ios/openssl/include/openssl/asn1t.h b/third_party/ios/openssl/include/openssl/asn1t.h
new file mode 100644
index 0000000..60de177
--- /dev/null
+++ b/third_party/ios/openssl/include/openssl/asn1t.h
@@ -0,0 +1,935 @@
+/*
+ * WARNING: do not edit!
+ * Generated by Makefile from include/openssl/asn1t.h.in
+ *
+ * Copyright 2000-2021 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+/* clang-format off */
+
+/* clang-format on */
+
+#ifndef OPENSSL_ASN1T_H
+#define OPENSSL_ASN1T_H
+#pragma once
+
+#include
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+#define HEADER_ASN1T_H
+#endif
+
+#include
+#include
+#include
+
+#ifdef OPENSSL_BUILD_SHLIBCRYPTO
+#undef OPENSSL_EXTERN
+#define OPENSSL_EXTERN OPENSSL_EXPORT
+#endif
+
+/* ASN1 template defines, structures and functions */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*-
+ * These are the possible values for the itype field of the
+ * ASN1_ITEM structure and determine how it is interpreted.
+ *
+ * For PRIMITIVE types the underlying type
+ * determines the behaviour if items is NULL.
+ *
+ * Otherwise templates must contain a single
+ * template and the type is treated in the
+ * same way as the type specified in the template.
+ *
+ * For SEQUENCE types the templates field points
+ * to the members, the size field is the
+ * structure size.
+ *
+ * For CHOICE types the templates field points
+ * to each possible member (typically a union)
+ * and the 'size' field is the offset of the
+ * selector.
+ *
+ * The 'funcs' field is used for application-specific
+ * data and functions.
+ *
+ * The EXTERN type uses a new style d2i/i2d.
+ * The new style should be used where possible
+ * because it avoids things like the d2i IMPLICIT
+ * hack.
+ *
+ * MSTRING is a multiple string type, it is used
+ * for a CHOICE of character strings where the
+ * actual strings all occupy an ASN1_STRING
+ * structure. In this case the 'utype' field
+ * has a special meaning, it is used as a mask
+ * of acceptable types using the B_ASN1 constants.
+ *
+ * NDEF_SEQUENCE is the same as SEQUENCE except
+ * that it will use indefinite length constructed
+ * encoding if requested.
+ *
+ */
+
+#define ASN1_ITYPE_PRIMITIVE 0x0
+#define ASN1_ITYPE_SEQUENCE 0x1
+#define ASN1_ITYPE_CHOICE 0x2
+/* unused value 0x3 */
+#define ASN1_ITYPE_EXTERN 0x4
+#define ASN1_ITYPE_MSTRING 0x5
+#define ASN1_ITYPE_NDEF_SEQUENCE 0x6
+
+/* Macro to obtain ASN1_ADB pointer from a type (only used internally) */
+#define ASN1_ADB_ptr(iptr) ((const ASN1_ADB *)((iptr)()))
+
+/* Macros for start and end of ASN1_ITEM definition */
+
+#define ASN1_ITEM_start(itname) \
+ const ASN1_ITEM *itname##_it(void) \
+ { \
+ static const ASN1_ITEM local_it = {
+
+#define static_ASN1_ITEM_start(itname) \
+ static ASN1_ITEM_start(itname)
+
+#define ASN1_ITEM_end(itname) \
+ } \
+ ; \
+ return &local_it; \
+ }
+
+/* Macros to aid ASN1 template writing */
+
+#define ASN1_ITEM_TEMPLATE(tname) \
+ static const ASN1_TEMPLATE tname##_item_tt
+
+#define ASN1_ITEM_TEMPLATE_END(tname) \
+ ; \
+ ASN1_ITEM_start(tname) \
+ ASN1_ITYPE_PRIMITIVE, \
+ -1, \
+ &tname##_item_tt, \
+ 0, \
+ NULL, \
+ 0, \
+ #tname ASN1_ITEM_end(tname)
+#define static_ASN1_ITEM_TEMPLATE_END(tname) \
+ ; \
+ static_ASN1_ITEM_start(tname) \
+ ASN1_ITYPE_PRIMITIVE, \
+ -1, \
+ &tname##_item_tt, \
+ 0, \
+ NULL, \
+ 0, \
+ #tname ASN1_ITEM_end(tname)
+
+/* This is a ASN1 type which just embeds a template */
+
+/*-
+ * This pair helps declare a SEQUENCE. We can do:
+ *
+ * ASN1_SEQUENCE(stname) = {
+ * ... SEQUENCE components ...
+ * } ASN1_SEQUENCE_END(stname)
+ *
+ * This will produce an ASN1_ITEM called stname_it
+ * for a structure called stname.
+ *
+ * If you want the same structure but a different
+ * name then use:
+ *
+ * ASN1_SEQUENCE(itname) = {
+ * ... SEQUENCE components ...
+ * } ASN1_SEQUENCE_END_name(stname, itname)
+ *
+ * This will create an item called itname_it using
+ * a structure called stname.
+ */
+
+#define ASN1_SEQUENCE(tname) \
+ static const ASN1_TEMPLATE tname##_seq_tt[]
+
+#define ASN1_SEQUENCE_END(stname) ASN1_SEQUENCE_END_name(stname, stname)
+
+#define static_ASN1_SEQUENCE_END(stname) static_ASN1_SEQUENCE_END_name(stname, stname)
+
+#define ASN1_SEQUENCE_END_name(stname, tname) \
+ ; \
+ ASN1_ITEM_start(tname) \
+ ASN1_ITYPE_SEQUENCE, \
+ V_ASN1_SEQUENCE, \
+ tname##_seq_tt, \
+ sizeof(tname##_seq_tt) / sizeof(ASN1_TEMPLATE), \
+ NULL, \
+ sizeof(stname), \
+ #tname ASN1_ITEM_end(tname)
+
+#define static_ASN1_SEQUENCE_END_name(stname, tname) \
+ ; \
+ static_ASN1_ITEM_start(tname) \
+ ASN1_ITYPE_SEQUENCE, \
+ V_ASN1_SEQUENCE, \
+ tname##_seq_tt, \
+ sizeof(tname##_seq_tt) / sizeof(ASN1_TEMPLATE), \
+ NULL, \
+ sizeof(stname), \
+ #stname ASN1_ITEM_end(tname)
+
+#define ASN1_NDEF_SEQUENCE(tname) \
+ ASN1_SEQUENCE(tname)
+
+#define ASN1_NDEF_SEQUENCE_cb(tname, cb) \
+ ASN1_SEQUENCE_cb(tname, cb)
+
+#define ASN1_SEQUENCE_cb(tname, cb) \
+ static const ASN1_AUX tname##_aux = { NULL, 0, 0, 0, cb, 0, NULL }; \
+ ASN1_SEQUENCE(tname)
+
+#define ASN1_SEQUENCE_const_cb(tname, const_cb) \
+ static const ASN1_AUX tname##_aux = { NULL, ASN1_AFLG_CONST_CB, 0, 0, NULL, 0, const_cb }; \
+ ASN1_SEQUENCE(tname)
+
+#define ASN1_SEQUENCE_cb_const_cb(tname, cb, const_cb) \
+ static const ASN1_AUX tname##_aux = { NULL, ASN1_AFLG_CONST_CB, 0, 0, cb, 0, const_cb }; \
+ ASN1_SEQUENCE(tname)
+
+#define ASN1_SEQUENCE_ref(tname, cb) \
+ static const ASN1_AUX tname##_aux = { NULL, ASN1_AFLG_REFCOUNT, offsetof(tname, references), offsetof(tname, lock), cb, 0, NULL }; \
+ ASN1_SEQUENCE(tname)
+
+#define ASN1_SEQUENCE_enc(tname, enc, cb) \
+ static const ASN1_AUX tname##_aux = { NULL, ASN1_AFLG_ENCODING, 0, 0, cb, offsetof(tname, enc), NULL }; \
+ ASN1_SEQUENCE(tname)
+
+#define ASN1_NDEF_SEQUENCE_END(tname) \
+ ; \
+ ASN1_ITEM_start(tname) \
+ ASN1_ITYPE_NDEF_SEQUENCE, \
+ V_ASN1_SEQUENCE, \
+ tname##_seq_tt, \
+ sizeof(tname##_seq_tt) / sizeof(ASN1_TEMPLATE), \
+ NULL, \
+ sizeof(tname), \
+ #tname ASN1_ITEM_end(tname)
+#define static_ASN1_NDEF_SEQUENCE_END(tname) \
+ ; \
+ static_ASN1_ITEM_start(tname) \
+ ASN1_ITYPE_NDEF_SEQUENCE, \
+ V_ASN1_SEQUENCE, \
+ tname##_seq_tt, \
+ sizeof(tname##_seq_tt) / sizeof(ASN1_TEMPLATE), \
+ NULL, \
+ sizeof(tname), \
+ #tname ASN1_ITEM_end(tname)
+
+#define ASN1_SEQUENCE_END_enc(stname, tname) ASN1_SEQUENCE_END_ref(stname, tname)
+
+#define ASN1_SEQUENCE_END_cb(stname, tname) ASN1_SEQUENCE_END_ref(stname, tname)
+#define static_ASN1_SEQUENCE_END_cb(stname, tname) static_ASN1_SEQUENCE_END_ref(stname, tname)
+
+#define ASN1_SEQUENCE_END_ref(stname, tname) \
+ ; \
+ ASN1_ITEM_start(tname) \
+ ASN1_ITYPE_SEQUENCE, \
+ V_ASN1_SEQUENCE, \
+ tname##_seq_tt, \
+ sizeof(tname##_seq_tt) / sizeof(ASN1_TEMPLATE), \
+ &tname##_aux, \
+ sizeof(stname), \
+ #tname ASN1_ITEM_end(tname)
+#define static_ASN1_SEQUENCE_END_ref(stname, tname) \
+ ; \
+ static_ASN1_ITEM_start(tname) \
+ ASN1_ITYPE_SEQUENCE, \
+ V_ASN1_SEQUENCE, \
+ tname##_seq_tt, \
+ sizeof(tname##_seq_tt) / sizeof(ASN1_TEMPLATE), \
+ &tname##_aux, \
+ sizeof(stname), \
+ #stname ASN1_ITEM_end(tname)
+
+#define ASN1_NDEF_SEQUENCE_END_cb(stname, tname) \
+ ; \
+ ASN1_ITEM_start(tname) \
+ ASN1_ITYPE_NDEF_SEQUENCE, \
+ V_ASN1_SEQUENCE, \
+ tname##_seq_tt, \
+ sizeof(tname##_seq_tt) / sizeof(ASN1_TEMPLATE), \
+ &tname##_aux, \
+ sizeof(stname), \
+ #stname ASN1_ITEM_end(tname)
+
+/*-
+ * This pair helps declare a CHOICE type. We can do:
+ *
+ * ASN1_CHOICE(chname) = {
+ * ... CHOICE options ...
+ * ASN1_CHOICE_END(chname)
+ *
+ * This will produce an ASN1_ITEM called chname_it
+ * for a structure called chname. The structure
+ * definition must look like this:
+ * typedef struct {
+ * int type;
+ * union {
+ * ASN1_SOMETHING *opt1;
+ * ASN1_SOMEOTHER *opt2;
+ * } value;
+ * } chname;
+ *
+ * the name of the selector must be 'type'.
+ * to use an alternative selector name use the
+ * ASN1_CHOICE_END_selector() version.
+ */
+
+#define ASN1_CHOICE(tname) \
+ static const ASN1_TEMPLATE tname##_ch_tt[]
+
+#define ASN1_CHOICE_cb(tname, cb) \
+ static const ASN1_AUX tname##_aux = { NULL, 0, 0, 0, cb, 0, NULL }; \
+ ASN1_CHOICE(tname)
+
+#define ASN1_CHOICE_END(stname) ASN1_CHOICE_END_name(stname, stname)
+
+#define static_ASN1_CHOICE_END(stname) static_ASN1_CHOICE_END_name(stname, stname)
+
+#define ASN1_CHOICE_END_name(stname, tname) ASN1_CHOICE_END_selector(stname, tname, type)
+
+#define static_ASN1_CHOICE_END_name(stname, tname) static_ASN1_CHOICE_END_selector(stname, tname, type)
+
+#define ASN1_CHOICE_END_selector(stname, tname, selname) \
+ ; \
+ ASN1_ITEM_start(tname) \
+ ASN1_ITYPE_CHOICE, \
+ offsetof(stname, selname), \
+ tname##_ch_tt, \
+ sizeof(tname##_ch_tt) / sizeof(ASN1_TEMPLATE), \
+ NULL, \
+ sizeof(stname), \
+ #stname ASN1_ITEM_end(tname)
+
+#define static_ASN1_CHOICE_END_selector(stname, tname, selname) \
+ ; \
+ static_ASN1_ITEM_start(tname) \
+ ASN1_ITYPE_CHOICE, \
+ offsetof(stname, selname), \
+ tname##_ch_tt, \
+ sizeof(tname##_ch_tt) / sizeof(ASN1_TEMPLATE), \
+ NULL, \
+ sizeof(stname), \
+ #stname ASN1_ITEM_end(tname)
+
+#define ASN1_CHOICE_END_cb(stname, tname, selname) \
+ ; \
+ ASN1_ITEM_start(tname) \
+ ASN1_ITYPE_CHOICE, \
+ offsetof(stname, selname), \
+ tname##_ch_tt, \
+ sizeof(tname##_ch_tt) / sizeof(ASN1_TEMPLATE), \
+ &tname##_aux, \
+ sizeof(stname), \
+ #stname ASN1_ITEM_end(tname)
+
+/* This helps with the template wrapper form of ASN1_ITEM */
+
+#define ASN1_EX_TEMPLATE_TYPE(flags, tag, name, type) { \
+ (flags), (tag), 0, \
+ #name, ASN1_ITEM_ref(type) \
+}
+
+/* These help with SEQUENCE or CHOICE components */
+
+/* used to declare other types */
+
+#define ASN1_EX_TYPE(flags, tag, stname, field, type) { \
+ (flags), (tag), offsetof(stname, field), \
+ #field, ASN1_ITEM_ref(type) \
+}
+
+/* implicit and explicit helper macros */
+
+#define ASN1_IMP_EX(stname, field, type, tag, ex) \
+ ASN1_EX_TYPE(ASN1_TFLG_IMPLICIT | (ex), tag, stname, field, type)
+
+#define ASN1_EXP_EX(stname, field, type, tag, ex) \
+ ASN1_EX_TYPE(ASN1_TFLG_EXPLICIT | (ex), tag, stname, field, type)
+
+/* Any defined by macros: the field used is in the table itself */
+
+#define ASN1_ADB_OBJECT(tblname) { ASN1_TFLG_ADB_OID, -1, 0, #tblname, tblname##_adb }
+#define ASN1_ADB_INTEGER(tblname) { ASN1_TFLG_ADB_INT, -1, 0, #tblname, tblname##_adb }
+
+/* Plain simple type */
+#define ASN1_SIMPLE(stname, field, type) ASN1_EX_TYPE(0, 0, stname, field, type)
+/* Embedded simple type */
+#define ASN1_EMBED(stname, field, type) ASN1_EX_TYPE(ASN1_TFLG_EMBED, 0, stname, field, type)
+
+/* OPTIONAL simple type */
+#define ASN1_OPT(stname, field, type) ASN1_EX_TYPE(ASN1_TFLG_OPTIONAL, 0, stname, field, type)
+#define ASN1_OPT_EMBED(stname, field, type) ASN1_EX_TYPE(ASN1_TFLG_OPTIONAL | ASN1_TFLG_EMBED, 0, stname, field, type)
+
+/* IMPLICIT tagged simple type */
+#define ASN1_IMP(stname, field, type, tag) ASN1_IMP_EX(stname, field, type, tag, 0)
+#define ASN1_IMP_EMBED(stname, field, type, tag) ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_EMBED)
+
+/* IMPLICIT tagged OPTIONAL simple type */
+#define ASN1_IMP_OPT(stname, field, type, tag) ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_OPTIONAL)
+#define ASN1_IMP_OPT_EMBED(stname, field, type, tag) ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_OPTIONAL | ASN1_TFLG_EMBED)
+
+/* Same as above but EXPLICIT */
+
+#define ASN1_EXP(stname, field, type, tag) ASN1_EXP_EX(stname, field, type, tag, 0)
+#define ASN1_EXP_EMBED(stname, field, type, tag) ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_EMBED)
+#define ASN1_EXP_OPT(stname, field, type, tag) ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_OPTIONAL)
+#define ASN1_EXP_OPT_EMBED(stname, field, type, tag) ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_OPTIONAL | ASN1_TFLG_EMBED)
+
+/* SEQUENCE OF type */
+#define ASN1_SEQUENCE_OF(stname, field, type) \
+ ASN1_EX_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, stname, field, type)
+
+/* OPTIONAL SEQUENCE OF */
+#define ASN1_SEQUENCE_OF_OPT(stname, field, type) \
+ ASN1_EX_TYPE(ASN1_TFLG_SEQUENCE_OF | ASN1_TFLG_OPTIONAL, 0, stname, field, type)
+
+/* Same as above but for SET OF */
+
+#define ASN1_SET_OF(stname, field, type) \
+ ASN1_EX_TYPE(ASN1_TFLG_SET_OF, 0, stname, field, type)
+
+#define ASN1_SET_OF_OPT(stname, field, type) \
+ ASN1_EX_TYPE(ASN1_TFLG_SET_OF | ASN1_TFLG_OPTIONAL, 0, stname, field, type)
+
+/* Finally compound types of SEQUENCE, SET, IMPLICIT, EXPLICIT and OPTIONAL */
+
+#define ASN1_IMP_SET_OF(stname, field, type, tag) \
+ ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_SET_OF)
+
+#define ASN1_EXP_SET_OF(stname, field, type, tag) \
+ ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_SET_OF)
+
+#define ASN1_IMP_SET_OF_OPT(stname, field, type, tag) \
+ ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_SET_OF | ASN1_TFLG_OPTIONAL)
+
+#define ASN1_EXP_SET_OF_OPT(stname, field, type, tag) \
+ ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_SET_OF | ASN1_TFLG_OPTIONAL)
+
+#define ASN1_IMP_SEQUENCE_OF(stname, field, type, tag) \
+ ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_SEQUENCE_OF)
+
+#define ASN1_IMP_SEQUENCE_OF_OPT(stname, field, type, tag) \
+ ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_SEQUENCE_OF | ASN1_TFLG_OPTIONAL)
+
+#define ASN1_EXP_SEQUENCE_OF(stname, field, type, tag) \
+ ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_SEQUENCE_OF)
+
+#define ASN1_EXP_SEQUENCE_OF_OPT(stname, field, type, tag) \
+ ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_SEQUENCE_OF | ASN1_TFLG_OPTIONAL)
+
+/* EXPLICIT using indefinite length constructed form */
+#define ASN1_NDEF_EXP(stname, field, type, tag) \
+ ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_NDEF)
+
+/* EXPLICIT OPTIONAL using indefinite length constructed form */
+#define ASN1_NDEF_EXP_OPT(stname, field, type, tag) \
+ ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_OPTIONAL | ASN1_TFLG_NDEF)
+
+/* Macros for the ASN1_ADB structure */
+
+#define ASN1_ADB(name) \
+ static const ASN1_ADB_TABLE name##_adbtbl[]
+
+#define ASN1_ADB_END(name, flags, field, adb_cb, def, none) \
+ ; \
+ static const ASN1_ITEM *name##_adb(void) \
+ { \
+ static const ASN1_ADB internal_adb = { \
+ flags, \
+ offsetof(name, field), \
+ adb_cb, \
+ name##_adbtbl, \
+ sizeof(name##_adbtbl) / sizeof(ASN1_ADB_TABLE), \
+ def, \
+ none \
+ }; \
+ return (const ASN1_ITEM *)&internal_adb; \
+ } \
+ void dummy_function(void)
+
+#define ADB_ENTRY(val, template) { val, template }
+
+#define ASN1_ADB_TEMPLATE(name) \
+ static const ASN1_TEMPLATE name##_tt
+
+/*
+ * This is the ASN1 template structure that defines a wrapper round the
+ * actual type. It determines the actual position of the field in the value
+ * structure, various flags such as OPTIONAL and the field name.
+ */
+
+struct ASN1_TEMPLATE_st {
+ unsigned long flags; /* Various flags */
+ long tag; /* tag, not used if no tagging */
+ unsigned long offset; /* Offset of this field in structure */
+ const char *field_name; /* Field name */
+ ASN1_ITEM_EXP *item; /* Relevant ASN1_ITEM or ASN1_ADB */
+};
+
+/* Macro to extract ASN1_ITEM and ASN1_ADB pointer from ASN1_TEMPLATE */
+
+#define ASN1_TEMPLATE_item(t) (t->item_ptr)
+#define ASN1_TEMPLATE_adb(t) (t->item_ptr)
+
+typedef struct ASN1_ADB_TABLE_st ASN1_ADB_TABLE;
+typedef struct ASN1_ADB_st ASN1_ADB;
+
+struct ASN1_ADB_st {
+ unsigned long flags; /* Various flags */
+ unsigned long offset; /* Offset of selector field */
+ int (*adb_cb)(long *psel); /* Application callback */
+ const ASN1_ADB_TABLE *tbl; /* Table of possible types */
+ long tblcount; /* Number of entries in tbl */
+ const ASN1_TEMPLATE *default_tt; /* Type to use if no match */
+ const ASN1_TEMPLATE *null_tt; /* Type to use if selector is NULL */
+};
+
+struct ASN1_ADB_TABLE_st {
+ long value; /* NID for an object or value for an int */
+ const ASN1_TEMPLATE tt; /* item for this value */
+};
+
+/* template flags */
+
+/* Field is optional */
+#define ASN1_TFLG_OPTIONAL (0x1)
+
+/* Field is a SET OF */
+#define ASN1_TFLG_SET_OF (0x1 << 1)
+
+/* Field is a SEQUENCE OF */
+#define ASN1_TFLG_SEQUENCE_OF (0x2 << 1)
+
+/*
+ * Special case: this refers to a SET OF that will be sorted into DER order
+ * when encoded *and* the corresponding STACK will be modified to match the
+ * new order.
+ */
+#define ASN1_TFLG_SET_ORDER (0x3 << 1)
+
+/* Mask for SET OF or SEQUENCE OF */
+#define ASN1_TFLG_SK_MASK (0x3 << 1)
+
+/*
+ * These flags mean the tag should be taken from the tag field. If EXPLICIT
+ * then the underlying type is used for the inner tag.
+ */
+
+/* IMPLICIT tagging */
+#define ASN1_TFLG_IMPTAG (0x1 << 3)
+
+/* EXPLICIT tagging, inner tag from underlying type */
+#define ASN1_TFLG_EXPTAG (0x2 << 3)
+
+#define ASN1_TFLG_TAG_MASK (0x3 << 3)
+
+/* context specific IMPLICIT */
+#define ASN1_TFLG_IMPLICIT (ASN1_TFLG_IMPTAG | ASN1_TFLG_CONTEXT)
+
+/* context specific EXPLICIT */
+#define ASN1_TFLG_EXPLICIT (ASN1_TFLG_EXPTAG | ASN1_TFLG_CONTEXT)
+
+/*
+ * If tagging is in force these determine the type of tag to use. Otherwise
+ * the tag is determined by the underlying type. These values reflect the
+ * actual octet format.
+ */
+
+/* Universal tag */
+#define ASN1_TFLG_UNIVERSAL (0x0 << 6)
+/* Application tag */
+#define ASN1_TFLG_APPLICATION (0x1 << 6)
+/* Context specific tag */
+#define ASN1_TFLG_CONTEXT (0x2 << 6)
+/* Private tag */
+#define ASN1_TFLG_PRIVATE (0x3 << 6)
+
+#define ASN1_TFLG_TAG_CLASS (0x3 << 6)
+
+/*
+ * These are for ANY DEFINED BY type. In this case the 'item' field points to
+ * an ASN1_ADB structure which contains a table of values to decode the
+ * relevant type
+ */
+
+#define ASN1_TFLG_ADB_MASK (0x3 << 8)
+
+#define ASN1_TFLG_ADB_OID (0x1 << 8)
+
+#define ASN1_TFLG_ADB_INT (0x1 << 9)
+
+/*
+ * This flag when present in a SEQUENCE OF, SET OF or EXPLICIT causes
+ * indefinite length constructed encoding to be used if required.
+ */
+
+#define ASN1_TFLG_NDEF (0x1 << 11)
+
+/* Field is embedded and not a pointer */
+#define ASN1_TFLG_EMBED (0x1 << 12)
+
+/* This is the actual ASN1 item itself */
+
+struct ASN1_ITEM_st {
+ char itype; /* The item type, primitive, SEQUENCE, CHOICE
+ * or extern */
+ long utype; /* underlying type */
+ const ASN1_TEMPLATE *templates; /* If SEQUENCE or CHOICE this contains
+ * the contents */
+ long tcount; /* Number of templates if SEQUENCE or CHOICE */
+ const void *funcs; /* further data and type-specific functions */
+ /* funcs can be ASN1_PRIMITIVE_FUNCS*, ASN1_EXTERN_FUNCS*, or ASN1_AUX* */
+ long size; /* Structure size (usually) */
+ const char *sname; /* Structure name */
+};
+
+/*
+ * Cache for ASN1 tag and length, so we don't keep re-reading it for things
+ * like CHOICE
+ */
+
+struct ASN1_TLC_st {
+ char valid; /* Values below are valid */
+ int ret; /* return value */
+ long plen; /* length */
+ int ptag; /* class value */
+ int pclass; /* class value */
+ int hdrlen; /* header length */
+};
+
+/* Typedefs for ASN1 function pointers */
+typedef int ASN1_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len,
+ const ASN1_ITEM *it, int tag, int aclass, char opt,
+ ASN1_TLC *ctx);
+
+typedef int ASN1_ex_d2i_ex(ASN1_VALUE **pval, const unsigned char **in, long len,
+ const ASN1_ITEM *it, int tag, int aclass, char opt,
+ ASN1_TLC *ctx, OSSL_LIB_CTX *libctx,
+ const char *propq);
+typedef int ASN1_ex_i2d(const ASN1_VALUE **pval, unsigned char **out,
+ const ASN1_ITEM *it, int tag, int aclass);
+typedef int ASN1_ex_new_func(ASN1_VALUE **pval, const ASN1_ITEM *it);
+typedef int ASN1_ex_new_ex_func(ASN1_VALUE **pval, const ASN1_ITEM *it,
+ OSSL_LIB_CTX *libctx, const char *propq);
+typedef void ASN1_ex_free_func(ASN1_VALUE **pval, const ASN1_ITEM *it);
+
+typedef int ASN1_ex_print_func(BIO *out, const ASN1_VALUE **pval,
+ int indent, const char *fname,
+ const ASN1_PCTX *pctx);
+
+typedef int ASN1_primitive_i2c(const ASN1_VALUE **pval, unsigned char *cont,
+ int *putype, const ASN1_ITEM *it);
+typedef int ASN1_primitive_c2i(ASN1_VALUE **pval, const unsigned char *cont,
+ int len, int utype, char *free_cont,
+ const ASN1_ITEM *it);
+typedef int ASN1_primitive_print(BIO *out, const ASN1_VALUE **pval,
+ const ASN1_ITEM *it, int indent,
+ const ASN1_PCTX *pctx);
+
+typedef struct ASN1_EXTERN_FUNCS_st {
+ void *app_data;
+ ASN1_ex_new_func *asn1_ex_new;
+ ASN1_ex_free_func *asn1_ex_free;
+ ASN1_ex_free_func *asn1_ex_clear;
+ ASN1_ex_d2i *asn1_ex_d2i;
+ ASN1_ex_i2d *asn1_ex_i2d;
+ ASN1_ex_print_func *asn1_ex_print;
+ ASN1_ex_new_ex_func *asn1_ex_new_ex;
+ ASN1_ex_d2i_ex *asn1_ex_d2i_ex;
+} ASN1_EXTERN_FUNCS;
+
+typedef struct ASN1_PRIMITIVE_FUNCS_st {
+ void *app_data;
+ unsigned long flags;
+ ASN1_ex_new_func *prim_new;
+ ASN1_ex_free_func *prim_free;
+ ASN1_ex_free_func *prim_clear;
+ ASN1_primitive_c2i *prim_c2i;
+ ASN1_primitive_i2c *prim_i2c;
+ ASN1_primitive_print *prim_print;
+} ASN1_PRIMITIVE_FUNCS;
+
+/*
+ * This is the ASN1_AUX structure: it handles various miscellaneous
+ * requirements. For example the use of reference counts and an informational
+ * callback. The "informational callback" is called at various points during
+ * the ASN1 encoding and decoding. It can be used to provide minor
+ * customisation of the structures used. This is most useful where the
+ * supplied routines *almost* do the right thing but need some extra help at
+ * a few points. If the callback returns zero then it is assumed a fatal
+ * error has occurred and the main operation should be abandoned. If major
+ * changes in the default behaviour are required then an external type is
+ * more appropriate.
+ * For the operations ASN1_OP_I2D_PRE, ASN1_OP_I2D_POST, ASN1_OP_PRINT_PRE, and
+ * ASN1_OP_PRINT_POST, meanwhile a variant of the callback with const parameter
+ * 'in' is provided to make clear statically that its input is not modified. If
+ * and only if this variant is in use the flag ASN1_AFLG_CONST_CB must be set.
+ */
+
+typedef int ASN1_aux_cb(int operation, ASN1_VALUE **in, const ASN1_ITEM *it,
+ void *exarg);
+typedef int ASN1_aux_const_cb(int operation, const ASN1_VALUE **in,
+ const ASN1_ITEM *it, void *exarg);
+
+typedef struct ASN1_AUX_st {
+ void *app_data;
+ int flags;
+ int ref_offset; /* Offset of reference value */
+ int ref_lock; /* Offset of lock value */
+ ASN1_aux_cb *asn1_cb;
+ int enc_offset; /* Offset of ASN1_ENCODING structure */
+ ASN1_aux_const_cb *asn1_const_cb; /* for ASN1_OP_I2D_ and ASN1_OP_PRINT_ */
+} ASN1_AUX;
+
+/* For print related callbacks exarg points to this structure */
+typedef struct ASN1_PRINT_ARG_st {
+ BIO *out;
+ int indent;
+ const ASN1_PCTX *pctx;
+} ASN1_PRINT_ARG;
+
+/* For streaming related callbacks exarg points to this structure */
+typedef struct ASN1_STREAM_ARG_st {
+ /* BIO to stream through */
+ BIO *out;
+ /* BIO with filters appended */
+ BIO *ndef_bio;
+ /* Streaming I/O boundary */
+ unsigned char **boundary;
+} ASN1_STREAM_ARG;
+
+/* Flags in ASN1_AUX */
+
+/* Use a reference count */
+#define ASN1_AFLG_REFCOUNT 1
+/* Save the encoding of structure (useful for signatures) */
+#define ASN1_AFLG_ENCODING 2
+/* The Sequence length is invalid */
+#define ASN1_AFLG_BROKEN 4
+/* Use the new asn1_const_cb */
+#define ASN1_AFLG_CONST_CB 8
+
+/* operation values for asn1_cb */
+
+#define ASN1_OP_NEW_PRE 0
+#define ASN1_OP_NEW_POST 1
+#define ASN1_OP_FREE_PRE 2
+#define ASN1_OP_FREE_POST 3
+#define ASN1_OP_D2I_PRE 4
+#define ASN1_OP_D2I_POST 5
+#define ASN1_OP_I2D_PRE 6
+#define ASN1_OP_I2D_POST 7
+#define ASN1_OP_PRINT_PRE 8
+#define ASN1_OP_PRINT_POST 9
+#define ASN1_OP_STREAM_PRE 10
+#define ASN1_OP_STREAM_POST 11
+#define ASN1_OP_DETACHED_PRE 12
+#define ASN1_OP_DETACHED_POST 13
+#define ASN1_OP_DUP_PRE 14
+#define ASN1_OP_DUP_POST 15
+#define ASN1_OP_GET0_LIBCTX 16
+#define ASN1_OP_GET0_PROPQ 17
+
+/* Macro to implement a primitive type */
+#define IMPLEMENT_ASN1_TYPE(stname) IMPLEMENT_ASN1_TYPE_ex(stname, stname, 0)
+#define IMPLEMENT_ASN1_TYPE_ex(itname, vname, ex) \
+ ASN1_ITEM_start(itname) \
+ ASN1_ITYPE_PRIMITIVE, \
+ V_##vname, NULL, 0, NULL, ex, #itname ASN1_ITEM_end(itname)
+
+/* Macro to implement a multi string type */
+#define IMPLEMENT_ASN1_MSTRING(itname, mask) \
+ ASN1_ITEM_start(itname) \
+ ASN1_ITYPE_MSTRING, \
+ mask, NULL, 0, NULL, sizeof(ASN1_STRING), #itname ASN1_ITEM_end(itname)
+
+#define IMPLEMENT_EXTERN_ASN1(sname, tag, fptrs) \
+ ASN1_ITEM_start(sname) \
+ ASN1_ITYPE_EXTERN, \
+ tag, \
+ NULL, \
+ 0, \
+ &fptrs, \
+ 0, \
+ #sname ASN1_ITEM_end(sname)
+
+/* Macro to implement standard functions in terms of ASN1_ITEM structures */
+
+#define IMPLEMENT_ASN1_FUNCTIONS(stname) IMPLEMENT_ASN1_FUNCTIONS_fname(stname, stname, stname)
+
+#define IMPLEMENT_ASN1_FUNCTIONS_name(stname, itname) IMPLEMENT_ASN1_FUNCTIONS_fname(stname, itname, itname)
+
+#define IMPLEMENT_ASN1_FUNCTIONS_ENCODE_name(stname, itname) \
+ IMPLEMENT_ASN1_FUNCTIONS_ENCODE_fname(stname, itname, itname)
+
+#define IMPLEMENT_STATIC_ASN1_ALLOC_FUNCTIONS(stname) \
+ IMPLEMENT_ASN1_ALLOC_FUNCTIONS_pfname(static, stname, stname, stname)
+
+#define IMPLEMENT_ASN1_ALLOC_FUNCTIONS(stname) \
+ IMPLEMENT_ASN1_ALLOC_FUNCTIONS_fname(stname, stname, stname)
+
+#define IMPLEMENT_ASN1_ALLOC_FUNCTIONS_pfname(pre, stname, itname, fname) \
+ pre stname *fname##_new(void) \
+ { \
+ return (stname *)ASN1_item_new(ASN1_ITEM_rptr(itname)); \
+ } \
+ pre void fname##_free(stname *a) \
+ { \
+ ASN1_item_free((ASN1_VALUE *)a, ASN1_ITEM_rptr(itname)); \
+ }
+
+#define IMPLEMENT_ASN1_ALLOC_FUNCTIONS_fname(stname, itname, fname) \
+ stname *fname##_new(void) \
+ { \
+ return (stname *)ASN1_item_new(ASN1_ITEM_rptr(itname)); \
+ } \
+ void fname##_free(stname *a) \
+ { \
+ ASN1_item_free((ASN1_VALUE *)a, ASN1_ITEM_rptr(itname)); \
+ }
+
+#define IMPLEMENT_ASN1_FUNCTIONS_fname(stname, itname, fname) \
+ IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(stname, itname, fname) \
+ IMPLEMENT_ASN1_ALLOC_FUNCTIONS_fname(stname, itname, fname)
+
+#define IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(stname, itname, fname) \
+ stname *d2i_##fname(stname **a, const unsigned char **in, long len) \
+ { \
+ return (stname *)ASN1_item_d2i((ASN1_VALUE **)a, in, len, ASN1_ITEM_rptr(itname)); \
+ } \
+ int i2d_##fname(const stname *a, unsigned char **out) \
+ { \
+ return ASN1_item_i2d((const ASN1_VALUE *)a, out, ASN1_ITEM_rptr(itname)); \
+ }
+
+#define IMPLEMENT_ASN1_NDEF_FUNCTION(stname) \
+ int i2d_##stname##_NDEF(const stname *a, unsigned char **out) \
+ { \
+ return ASN1_item_ndef_i2d((const ASN1_VALUE *)a, out, ASN1_ITEM_rptr(stname)); \
+ }
+
+#define IMPLEMENT_STATIC_ASN1_ENCODE_FUNCTIONS(stname) \
+ static stname *d2i_##stname(stname **a, \
+ const unsigned char **in, long len) \
+ { \
+ return (stname *)ASN1_item_d2i((ASN1_VALUE **)a, in, len, \
+ ASN1_ITEM_rptr(stname)); \
+ } \
+ static int i2d_##stname(const stname *a, unsigned char **out) \
+ { \
+ return ASN1_item_i2d((const ASN1_VALUE *)a, out, \
+ ASN1_ITEM_rptr(stname)); \
+ }
+
+#define IMPLEMENT_ASN1_DUP_FUNCTION(stname) \
+ stname *stname##_dup(const stname *x) \
+ { \
+ return ASN1_item_dup(ASN1_ITEM_rptr(stname), x); \
+ }
+
+#define IMPLEMENT_ASN1_PRINT_FUNCTION(stname) \
+ IMPLEMENT_ASN1_PRINT_FUNCTION_fname(stname, stname, stname)
+
+#define IMPLEMENT_ASN1_PRINT_FUNCTION_fname(stname, itname, fname) \
+ int fname##_print_ctx(BIO *out, const stname *x, int indent, \
+ const ASN1_PCTX *pctx) \
+ { \
+ return ASN1_item_print(out, (const ASN1_VALUE *)x, indent, \
+ ASN1_ITEM_rptr(itname), pctx); \
+ }
+
+/* external definitions for primitive types */
+
+DECLARE_ASN1_ITEM(ASN1_BOOLEAN)
+DECLARE_ASN1_ITEM(ASN1_TBOOLEAN)
+DECLARE_ASN1_ITEM(ASN1_FBOOLEAN)
+DECLARE_ASN1_ITEM(ASN1_SEQUENCE)
+DECLARE_ASN1_ITEM(CBIGNUM)
+DECLARE_ASN1_ITEM(BIGNUM)
+DECLARE_ASN1_ITEM(INT32)
+DECLARE_ASN1_ITEM(ZINT32)
+DECLARE_ASN1_ITEM(UINT32)
+DECLARE_ASN1_ITEM(ZUINT32)
+DECLARE_ASN1_ITEM(INT64)
+DECLARE_ASN1_ITEM(ZINT64)
+DECLARE_ASN1_ITEM(UINT64)
+DECLARE_ASN1_ITEM(ZUINT64)
+
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+/*
+ * LONG and ZLONG are strongly discouraged for use as stored data, as the
+ * underlying C type (long) differs in size depending on the architecture.
+ * They are designed with 32-bit longs in mind.
+ */
+DECLARE_ASN1_ITEM(LONG)
+DECLARE_ASN1_ITEM(ZLONG)
+#endif
+
+/* clang-format off */
+SKM_DEFINE_STACK_OF_INTERNAL(ASN1_VALUE, ASN1_VALUE, ASN1_VALUE)
+#define sk_ASN1_VALUE_num(sk) OPENSSL_sk_num(ossl_check_const_ASN1_VALUE_sk_type(sk))
+#define sk_ASN1_VALUE_value(sk, idx) ((ASN1_VALUE *)OPENSSL_sk_value(ossl_check_const_ASN1_VALUE_sk_type(sk), (idx)))
+#define sk_ASN1_VALUE_new(cmp) ((STACK_OF(ASN1_VALUE) *)OPENSSL_sk_new(ossl_check_ASN1_VALUE_compfunc_type(cmp)))
+#define sk_ASN1_VALUE_new_null() ((STACK_OF(ASN1_VALUE) *)OPENSSL_sk_new_null())
+#define sk_ASN1_VALUE_new_reserve(cmp, n) ((STACK_OF(ASN1_VALUE) *)OPENSSL_sk_new_reserve(ossl_check_ASN1_VALUE_compfunc_type(cmp), (n)))
+#define sk_ASN1_VALUE_reserve(sk, n) OPENSSL_sk_reserve(ossl_check_ASN1_VALUE_sk_type(sk), (n))
+#define sk_ASN1_VALUE_free(sk) OPENSSL_sk_free(ossl_check_ASN1_VALUE_sk_type(sk))
+#define sk_ASN1_VALUE_zero(sk) OPENSSL_sk_zero(ossl_check_ASN1_VALUE_sk_type(sk))
+#define sk_ASN1_VALUE_delete(sk, i) ((ASN1_VALUE *)OPENSSL_sk_delete(ossl_check_ASN1_VALUE_sk_type(sk), (i)))
+#define sk_ASN1_VALUE_delete_ptr(sk, ptr) ((ASN1_VALUE *)OPENSSL_sk_delete_ptr(ossl_check_ASN1_VALUE_sk_type(sk), ossl_check_ASN1_VALUE_type(ptr)))
+#define sk_ASN1_VALUE_push(sk, ptr) OPENSSL_sk_push(ossl_check_ASN1_VALUE_sk_type(sk), ossl_check_ASN1_VALUE_type(ptr))
+#define sk_ASN1_VALUE_unshift(sk, ptr) OPENSSL_sk_unshift(ossl_check_ASN1_VALUE_sk_type(sk), ossl_check_ASN1_VALUE_type(ptr))
+#define sk_ASN1_VALUE_pop(sk) ((ASN1_VALUE *)OPENSSL_sk_pop(ossl_check_ASN1_VALUE_sk_type(sk)))
+#define sk_ASN1_VALUE_shift(sk) ((ASN1_VALUE *)OPENSSL_sk_shift(ossl_check_ASN1_VALUE_sk_type(sk)))
+#define sk_ASN1_VALUE_pop_free(sk, freefunc) OPENSSL_sk_pop_free(ossl_check_ASN1_VALUE_sk_type(sk), ossl_check_ASN1_VALUE_freefunc_type(freefunc))
+#define sk_ASN1_VALUE_insert(sk, ptr, idx) OPENSSL_sk_insert(ossl_check_ASN1_VALUE_sk_type(sk), ossl_check_ASN1_VALUE_type(ptr), (idx))
+#define sk_ASN1_VALUE_set(sk, idx, ptr) ((ASN1_VALUE *)OPENSSL_sk_set(ossl_check_ASN1_VALUE_sk_type(sk), (idx), ossl_check_ASN1_VALUE_type(ptr)))
+#define sk_ASN1_VALUE_find(sk, ptr) OPENSSL_sk_find(ossl_check_ASN1_VALUE_sk_type(sk), ossl_check_ASN1_VALUE_type(ptr))
+#define sk_ASN1_VALUE_find_ex(sk, ptr) OPENSSL_sk_find_ex(ossl_check_ASN1_VALUE_sk_type(sk), ossl_check_ASN1_VALUE_type(ptr))
+#define sk_ASN1_VALUE_find_all(sk, ptr, pnum) OPENSSL_sk_find_all(ossl_check_ASN1_VALUE_sk_type(sk), ossl_check_ASN1_VALUE_type(ptr), pnum)
+#define sk_ASN1_VALUE_sort(sk) OPENSSL_sk_sort(ossl_check_ASN1_VALUE_sk_type(sk))
+#define sk_ASN1_VALUE_is_sorted(sk) OPENSSL_sk_is_sorted(ossl_check_const_ASN1_VALUE_sk_type(sk))
+#define sk_ASN1_VALUE_dup(sk) ((STACK_OF(ASN1_VALUE) *)OPENSSL_sk_dup(ossl_check_const_ASN1_VALUE_sk_type(sk)))
+#define sk_ASN1_VALUE_deep_copy(sk, copyfunc, freefunc) ((STACK_OF(ASN1_VALUE) *)OPENSSL_sk_deep_copy(ossl_check_const_ASN1_VALUE_sk_type(sk), ossl_check_ASN1_VALUE_copyfunc_type(copyfunc), ossl_check_ASN1_VALUE_freefunc_type(freefunc)))
+#define sk_ASN1_VALUE_set_cmp_func(sk, cmp) ((sk_ASN1_VALUE_compfunc)OPENSSL_sk_set_cmp_func(ossl_check_ASN1_VALUE_sk_type(sk), ossl_check_ASN1_VALUE_compfunc_type(cmp)))
+
+/* clang-format on */
+
+/* Functions used internally by the ASN1 code */
+
+int ASN1_item_ex_new(ASN1_VALUE **pval, const ASN1_ITEM *it);
+void ASN1_item_ex_free(ASN1_VALUE **pval, const ASN1_ITEM *it);
+
+int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len,
+ const ASN1_ITEM *it, int tag, int aclass, char opt,
+ ASN1_TLC *ctx);
+
+int ASN1_item_ex_i2d(const ASN1_VALUE **pval, unsigned char **out,
+ const ASN1_ITEM *it, int tag, int aclass);
+
+/* Legacy compatibility */
+#define IMPLEMENT_ASN1_FUNCTIONS_const(name) IMPLEMENT_ASN1_FUNCTIONS(name)
+#define IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(stname, itname, fname) \
+ IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(stname, itname, fname)
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/third_party/ios/openssl/include/openssl/async.h b/third_party/ios/openssl/include/openssl/async.h
new file mode 100644
index 0000000..9044385
--- /dev/null
+++ b/third_party/ios/openssl/include/openssl/async.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2015-2022 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include
+
+#ifndef OPENSSL_ASYNC_H
+#define OPENSSL_ASYNC_H
+#pragma once
+
+#include
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+#define HEADER_ASYNC_H
+#endif
+
+#if defined(_WIN32)
+#if defined(BASETYPES) || defined(_WINDEF_H)
+/* application has to include to use this */
+#define OSSL_ASYNC_FD HANDLE
+#define OSSL_BAD_ASYNC_FD INVALID_HANDLE_VALUE
+#endif
+#else
+#define OSSL_ASYNC_FD int
+#define OSSL_BAD_ASYNC_FD -1
+#endif
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct async_job_st ASYNC_JOB;
+typedef struct async_wait_ctx_st ASYNC_WAIT_CTX;
+typedef int (*ASYNC_callback_fn)(void *arg);
+
+#define ASYNC_ERR 0
+#define ASYNC_NO_JOBS 1
+#define ASYNC_PAUSE 2
+#define ASYNC_FINISH 3
+
+#define ASYNC_STATUS_UNSUPPORTED 0
+#define ASYNC_STATUS_ERR 1
+#define ASYNC_STATUS_OK 2
+#define ASYNC_STATUS_EAGAIN 3
+
+int ASYNC_init_thread(size_t max_size, size_t init_size);
+void ASYNC_cleanup_thread(void);
+
+#ifdef OSSL_ASYNC_FD
+ASYNC_WAIT_CTX *ASYNC_WAIT_CTX_new(void);
+void ASYNC_WAIT_CTX_free(ASYNC_WAIT_CTX *ctx);
+int ASYNC_WAIT_CTX_set_wait_fd(ASYNC_WAIT_CTX *ctx, const void *key,
+ OSSL_ASYNC_FD fd,
+ void *custom_data,
+ void (*cleanup)(ASYNC_WAIT_CTX *, const void *,
+ OSSL_ASYNC_FD, void *));
+int ASYNC_WAIT_CTX_get_fd(ASYNC_WAIT_CTX *ctx, const void *key,
+ OSSL_ASYNC_FD *fd, void **custom_data);
+int ASYNC_WAIT_CTX_get_all_fds(ASYNC_WAIT_CTX *ctx, OSSL_ASYNC_FD *fd,
+ size_t *numfds);
+int ASYNC_WAIT_CTX_get_callback(ASYNC_WAIT_CTX *ctx,
+ ASYNC_callback_fn *callback,
+ void **callback_arg);
+int ASYNC_WAIT_CTX_set_callback(ASYNC_WAIT_CTX *ctx,
+ ASYNC_callback_fn callback,
+ void *callback_arg);
+int ASYNC_WAIT_CTX_set_status(ASYNC_WAIT_CTX *ctx, int status);
+int ASYNC_WAIT_CTX_get_status(ASYNC_WAIT_CTX *ctx);
+int ASYNC_WAIT_CTX_get_changed_fds(ASYNC_WAIT_CTX *ctx, OSSL_ASYNC_FD *addfd,
+ size_t *numaddfds, OSSL_ASYNC_FD *delfd,
+ size_t *numdelfds);
+int ASYNC_WAIT_CTX_clear_fd(ASYNC_WAIT_CTX *ctx, const void *key);
+#endif
+
+int ASYNC_is_capable(void);
+
+typedef void *(*ASYNC_stack_alloc_fn)(size_t *num);
+typedef void (*ASYNC_stack_free_fn)(void *addr);
+
+int ASYNC_set_mem_functions(ASYNC_stack_alloc_fn alloc_fn,
+ ASYNC_stack_free_fn free_fn);
+void ASYNC_get_mem_functions(ASYNC_stack_alloc_fn *alloc_fn,
+ ASYNC_stack_free_fn *free_fn);
+
+int ASYNC_start_job(ASYNC_JOB **job, ASYNC_WAIT_CTX *ctx, int *ret,
+ int (*func)(void *), void *args, size_t size);
+int ASYNC_pause_job(void);
+
+ASYNC_JOB *ASYNC_get_current_job(void);
+ASYNC_WAIT_CTX *ASYNC_get_wait_ctx(ASYNC_JOB *job);
+void ASYNC_block_pause(void);
+void ASYNC_unblock_pause(void);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/third_party/ios/openssl/include/openssl/asyncerr.h b/third_party/ios/openssl/include/openssl/asyncerr.h
new file mode 100644
index 0000000..41bd4a0
--- /dev/null
+++ b/third_party/ios/openssl/include/openssl/asyncerr.h
@@ -0,0 +1,27 @@
+/*
+ * Generated by util/mkerr.pl DO NOT EDIT
+ * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#ifndef OPENSSL_ASYNCERR_H
+#define OPENSSL_ASYNCERR_H
+#pragma once
+
+#include
+#include
+#include
+
+/*
+ * ASYNC reason codes.
+ */
+#define ASYNC_R_FAILED_TO_SET_POOL 101
+#define ASYNC_R_FAILED_TO_SWAP_CONTEXT 102
+#define ASYNC_R_INIT_FAILED 105
+#define ASYNC_R_INVALID_POOL_SIZE 103
+
+#endif
diff --git a/third_party/ios/openssl/include/openssl/bio.h b/third_party/ios/openssl/include/openssl/bio.h
new file mode 100644
index 0000000..c47f774
--- /dev/null
+++ b/third_party/ios/openssl/include/openssl/bio.h
@@ -0,0 +1,1028 @@
+/*
+ * WARNING: do not edit!
+ * Generated by Makefile from include/openssl/bio.h.in
+ *
+ * Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+/* clang-format off */
+
+/* clang-format on */
+
+#ifndef OPENSSL_BIO_H
+#define OPENSSL_BIO_H
+#pragma once
+
+#include
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+#define HEADER_BIO_H
+#endif
+
+#include
+
+#ifndef OPENSSL_NO_STDIO
+#include
+#endif
+#include
+
+#include
+#include
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* There are the classes of BIOs */
+#define BIO_TYPE_DESCRIPTOR 0x0100 /* socket, fd, connect or accept */
+#define BIO_TYPE_FILTER 0x0200
+#define BIO_TYPE_SOURCE_SINK 0x0400
+
+/* These are the 'types' of BIOs */
+#define BIO_TYPE_NONE 0
+#define BIO_TYPE_MEM (1 | BIO_TYPE_SOURCE_SINK)
+#define BIO_TYPE_FILE (2 | BIO_TYPE_SOURCE_SINK)
+
+#define BIO_TYPE_FD (4 | BIO_TYPE_SOURCE_SINK | BIO_TYPE_DESCRIPTOR)
+#define BIO_TYPE_SOCKET (5 | BIO_TYPE_SOURCE_SINK | BIO_TYPE_DESCRIPTOR)
+#define BIO_TYPE_NULL (6 | BIO_TYPE_SOURCE_SINK)
+#define BIO_TYPE_SSL (7 | BIO_TYPE_FILTER)
+#define BIO_TYPE_MD (8 | BIO_TYPE_FILTER)
+#define BIO_TYPE_BUFFER (9 | BIO_TYPE_FILTER)
+#define BIO_TYPE_CIPHER (10 | BIO_TYPE_FILTER)
+#define BIO_TYPE_BASE64 (11 | BIO_TYPE_FILTER)
+#define BIO_TYPE_CONNECT (12 | BIO_TYPE_SOURCE_SINK | BIO_TYPE_DESCRIPTOR)
+#define BIO_TYPE_ACCEPT (13 | BIO_TYPE_SOURCE_SINK | BIO_TYPE_DESCRIPTOR)
+
+#define BIO_TYPE_NBIO_TEST (16 | BIO_TYPE_FILTER) /* server proxy BIO */
+#define BIO_TYPE_NULL_FILTER (17 | BIO_TYPE_FILTER)
+#define BIO_TYPE_BIO (19 | BIO_TYPE_SOURCE_SINK) /* half a BIO pair */
+#define BIO_TYPE_LINEBUFFER (20 | BIO_TYPE_FILTER)
+#define BIO_TYPE_DGRAM (21 | BIO_TYPE_SOURCE_SINK | BIO_TYPE_DESCRIPTOR)
+#define BIO_TYPE_ASN1 (22 | BIO_TYPE_FILTER)
+#define BIO_TYPE_COMP (23 | BIO_TYPE_FILTER)
+#ifndef OPENSSL_NO_SCTP
+#define BIO_TYPE_DGRAM_SCTP (24 | BIO_TYPE_SOURCE_SINK | BIO_TYPE_DESCRIPTOR)
+#endif
+#define BIO_TYPE_CORE_TO_PROV (25 | BIO_TYPE_SOURCE_SINK)
+#define BIO_TYPE_DGRAM_PAIR (26 | BIO_TYPE_SOURCE_SINK)
+#define BIO_TYPE_DGRAM_MEM (27 | BIO_TYPE_SOURCE_SINK)
+
+/* Custom type starting index returned by BIO_get_new_index() */
+#define BIO_TYPE_START 128
+/* Custom type maximum index that can be returned by BIO_get_new_index() */
+#define BIO_TYPE_MASK 0xFF
+
+/*
+ * BIO_FILENAME_READ|BIO_CLOSE to open or close on free.
+ * BIO_set_fp(in,stdin,BIO_NOCLOSE);
+ */
+#define BIO_NOCLOSE 0x00
+#define BIO_CLOSE 0x01
+
+/*
+ * These are used in the following macros and are passed to BIO_ctrl()
+ */
+#define BIO_CTRL_RESET 1 /* opt - rewind/zero etc */
+#define BIO_CTRL_EOF 2 /* opt - are we at the eof */
+#define BIO_CTRL_INFO 3 /* opt - extra tit-bits */
+#define BIO_CTRL_SET 4 /* man - set the 'IO' type */
+#define BIO_CTRL_GET 5 /* man - get the 'IO' type */
+#define BIO_CTRL_PUSH 6 /* opt - internal, used to signify change */
+#define BIO_CTRL_POP 7 /* opt - internal, used to signify change */
+#define BIO_CTRL_GET_CLOSE 8 /* man - set the 'close' on free */
+#define BIO_CTRL_SET_CLOSE 9 /* man - set the 'close' on free */
+#define BIO_CTRL_PENDING 10 /* opt - is their more data buffered */
+#define BIO_CTRL_FLUSH 11 /* opt - 'flush' buffered output */
+#define BIO_CTRL_DUP 12 /* man - extra stuff for 'duped' BIO */
+#define BIO_CTRL_WPENDING 13 /* opt - number of bytes still to write */
+#define BIO_CTRL_SET_CALLBACK 14 /* opt - set callback function */
+#define BIO_CTRL_GET_CALLBACK 15 /* opt - set callback function */
+
+#define BIO_CTRL_PEEK 29 /* BIO_f_buffer special */
+#define BIO_CTRL_SET_FILENAME 30 /* BIO_s_file special */
+
+/* dgram BIO stuff */
+#define BIO_CTRL_DGRAM_CONNECT 31 /* BIO dgram special */
+#define BIO_CTRL_DGRAM_SET_CONNECTED 32 /* allow for an externally connected \
+ * socket to be passed in */
+#define BIO_CTRL_DGRAM_SET_RECV_TIMEOUT 33 /* setsockopt, essentially */
+#define BIO_CTRL_DGRAM_GET_RECV_TIMEOUT 34 /* getsockopt, essentially */
+#define BIO_CTRL_DGRAM_SET_SEND_TIMEOUT 35 /* setsockopt, essentially */
+#define BIO_CTRL_DGRAM_GET_SEND_TIMEOUT 36 /* getsockopt, essentially */
+
+#define BIO_CTRL_DGRAM_GET_RECV_TIMER_EXP 37 /* flag whether the last */
+#define BIO_CTRL_DGRAM_GET_SEND_TIMER_EXP 38 /* I/O operation timed out */
+
+/* #ifdef IP_MTU_DISCOVER */
+#define BIO_CTRL_DGRAM_MTU_DISCOVER 39 /* set DF bit on egress packets */
+/* #endif */
+
+#define BIO_CTRL_DGRAM_QUERY_MTU 40 /* as kernel for current MTU */
+#define BIO_CTRL_DGRAM_GET_FALLBACK_MTU 47
+#define BIO_CTRL_DGRAM_GET_MTU 41 /* get cached value for MTU */
+#define BIO_CTRL_DGRAM_SET_MTU 42 /* set cached value for MTU. \
+ * want to use this if asking \
+ * the kernel fails */
+
+#define BIO_CTRL_DGRAM_MTU_EXCEEDED 43 /* check whether the MTU was \
+ * exceed in the previous write \
+ * operation */
+
+#define BIO_CTRL_DGRAM_GET_PEER 46
+#define BIO_CTRL_DGRAM_SET_PEER 44 /* Destination for the data */
+
+#define BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT 45 /* Next DTLS handshake timeout \
+ * to adjust socket timeouts */
+#define BIO_CTRL_DGRAM_SET_DONT_FRAG 48
+
+#define BIO_CTRL_DGRAM_GET_MTU_OVERHEAD 49
+
+/* Deliberately outside of OPENSSL_NO_SCTP - used in bss_dgram.c */
+#define BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE 50
+#ifndef OPENSSL_NO_SCTP
+/* SCTP stuff */
+#define BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY 51
+#define BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY 52
+#define BIO_CTRL_DGRAM_SCTP_AUTH_CCS_RCVD 53
+#define BIO_CTRL_DGRAM_SCTP_GET_SNDINFO 60
+#define BIO_CTRL_DGRAM_SCTP_SET_SNDINFO 61
+#define BIO_CTRL_DGRAM_SCTP_GET_RCVINFO 62
+#define BIO_CTRL_DGRAM_SCTP_SET_RCVINFO 63
+#define BIO_CTRL_DGRAM_SCTP_GET_PRINFO 64
+#define BIO_CTRL_DGRAM_SCTP_SET_PRINFO 65
+#define BIO_CTRL_DGRAM_SCTP_SAVE_SHUTDOWN 70
+#endif
+
+#define BIO_CTRL_DGRAM_SET_PEEK_MODE 71
+
+/*
+ * internal BIO:
+ * # define BIO_CTRL_SET_KTLS_SEND 72
+ * # define BIO_CTRL_SET_KTLS_SEND_CTRL_MSG 74
+ * # define BIO_CTRL_CLEAR_KTLS_CTRL_MSG 75
+ */
+
+#define BIO_CTRL_GET_KTLS_SEND 73
+#define BIO_CTRL_GET_KTLS_RECV 76
+
+#define BIO_CTRL_DGRAM_SCTP_WAIT_FOR_DRY 77
+#define BIO_CTRL_DGRAM_SCTP_MSG_WAITING 78
+
+/* BIO_f_prefix controls */
+#define BIO_CTRL_SET_PREFIX 79
+#define BIO_CTRL_SET_INDENT 80
+#define BIO_CTRL_GET_INDENT 81
+
+#define BIO_CTRL_DGRAM_GET_LOCAL_ADDR_CAP 82
+#define BIO_CTRL_DGRAM_GET_LOCAL_ADDR_ENABLE 83
+#define BIO_CTRL_DGRAM_SET_LOCAL_ADDR_ENABLE 84
+#define BIO_CTRL_DGRAM_GET_EFFECTIVE_CAPS 85
+#define BIO_CTRL_DGRAM_GET_CAPS 86
+#define BIO_CTRL_DGRAM_SET_CAPS 87
+#define BIO_CTRL_DGRAM_GET_NO_TRUNC 88
+#define BIO_CTRL_DGRAM_SET_NO_TRUNC 89
+
+/*
+ * internal BIO:
+ * # define BIO_CTRL_SET_KTLS_TX_ZEROCOPY_SENDFILE 90
+ */
+
+#define BIO_CTRL_GET_RPOLL_DESCRIPTOR 91
+#define BIO_CTRL_GET_WPOLL_DESCRIPTOR 92
+#define BIO_CTRL_DGRAM_DETECT_PEER_ADDR 93
+#define BIO_CTRL_DGRAM_SET0_LOCAL_ADDR 94
+
+#define BIO_DGRAM_CAP_NONE 0U
+#define BIO_DGRAM_CAP_HANDLES_SRC_ADDR (1U << 0)
+#define BIO_DGRAM_CAP_HANDLES_DST_ADDR (1U << 1)
+#define BIO_DGRAM_CAP_PROVIDES_SRC_ADDR (1U << 2)
+#define BIO_DGRAM_CAP_PROVIDES_DST_ADDR (1U << 3)
+
+#ifndef OPENSSL_NO_KTLS
+#define BIO_get_ktls_send(b) \
+ (BIO_ctrl(b, BIO_CTRL_GET_KTLS_SEND, 0, NULL) > 0)
+#define BIO_get_ktls_recv(b) \
+ (BIO_ctrl(b, BIO_CTRL_GET_KTLS_RECV, 0, NULL) > 0)
+#else
+#define BIO_get_ktls_send(b) (0)
+#define BIO_get_ktls_recv(b) (0)
+#endif
+
+/* modifiers */
+#define BIO_FP_READ 0x02
+#define BIO_FP_WRITE 0x04
+#define BIO_FP_APPEND 0x08
+#define BIO_FP_TEXT 0x10
+
+#define BIO_FLAGS_READ 0x01
+#define BIO_FLAGS_WRITE 0x02
+#define BIO_FLAGS_IO_SPECIAL 0x04
+#define BIO_FLAGS_RWS (BIO_FLAGS_READ | BIO_FLAGS_WRITE | BIO_FLAGS_IO_SPECIAL)
+#define BIO_FLAGS_SHOULD_RETRY 0x08
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+/* This #define was replaced by an internal constant and should not be used. */
+#define BIO_FLAGS_UPLINK 0
+#endif
+
+#define BIO_FLAGS_BASE64_NO_NL 0x100
+
+/*
+ * This is used with memory BIOs:
+ * BIO_FLAGS_MEM_RDONLY means we shouldn't free up or change the data in any way;
+ * BIO_FLAGS_NONCLEAR_RST means we shouldn't clear data on reset.
+ */
+#define BIO_FLAGS_MEM_RDONLY 0x200
+#define BIO_FLAGS_NONCLEAR_RST 0x400
+#define BIO_FLAGS_IN_EOF 0x800
+
+/* the BIO FLAGS values 0x1000 to 0x8000 are reserved for internal KTLS flags */
+
+typedef union bio_addr_st BIO_ADDR;
+typedef struct bio_addrinfo_st BIO_ADDRINFO;
+
+int BIO_get_new_index(void);
+void BIO_set_flags(BIO *b, int flags);
+int BIO_test_flags(const BIO *b, int flags);
+void BIO_clear_flags(BIO *b, int flags);
+
+#define BIO_get_flags(b) BIO_test_flags(b, ~(0x0))
+#define BIO_set_retry_special(b) \
+ BIO_set_flags(b, (BIO_FLAGS_IO_SPECIAL | BIO_FLAGS_SHOULD_RETRY))
+#define BIO_set_retry_read(b) \
+ BIO_set_flags(b, (BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY))
+#define BIO_set_retry_write(b) \
+ BIO_set_flags(b, (BIO_FLAGS_WRITE | BIO_FLAGS_SHOULD_RETRY))
+
+/* These are normally used internally in BIOs */
+#define BIO_clear_retry_flags(b) \
+ BIO_clear_flags(b, (BIO_FLAGS_RWS | BIO_FLAGS_SHOULD_RETRY))
+#define BIO_get_retry_flags(b) \
+ BIO_test_flags(b, (BIO_FLAGS_RWS | BIO_FLAGS_SHOULD_RETRY))
+
+/* These should be used by the application to tell why we should retry */
+#define BIO_should_read(a) BIO_test_flags(a, BIO_FLAGS_READ)
+#define BIO_should_write(a) BIO_test_flags(a, BIO_FLAGS_WRITE)
+#define BIO_should_io_special(a) BIO_test_flags(a, BIO_FLAGS_IO_SPECIAL)
+#define BIO_retry_type(a) BIO_test_flags(a, BIO_FLAGS_RWS)
+#define BIO_should_retry(a) BIO_test_flags(a, BIO_FLAGS_SHOULD_RETRY)
+
+/*
+ * The next three are used in conjunction with the BIO_should_io_special()
+ * condition. After this returns true, BIO *BIO_get_retry_BIO(BIO *bio, int
+ * *reason); will walk the BIO stack and return the 'reason' for the special
+ * and the offending BIO. Given a BIO, BIO_get_retry_reason(bio) will return
+ * the code.
+ */
+/*
+ * Returned from the SSL bio when the certificate retrieval code had an error
+ */
+#define BIO_RR_SSL_X509_LOOKUP 0x01
+/* Returned from the connect BIO when a connect would have blocked */
+#define BIO_RR_CONNECT 0x02
+/* Returned from the accept BIO when an accept would have blocked */
+#define BIO_RR_ACCEPT 0x03
+
+/* These are passed by the BIO callback */
+#define BIO_CB_FREE 0x01
+#define BIO_CB_READ 0x02
+#define BIO_CB_WRITE 0x03
+#define BIO_CB_PUTS 0x04
+#define BIO_CB_GETS 0x05
+#define BIO_CB_CTRL 0x06
+#define BIO_CB_RECVMMSG 0x07
+#define BIO_CB_SENDMMSG 0x08
+
+/*
+ * The callback is called before and after the underling operation, The
+ * BIO_CB_RETURN flag indicates if it is after the call
+ */
+#define BIO_CB_RETURN 0x80
+#define BIO_CB_return(a) ((a) | BIO_CB_RETURN)
+#define BIO_cb_pre(a) (!((a) & BIO_CB_RETURN))
+#define BIO_cb_post(a) ((a) & BIO_CB_RETURN)
+
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+typedef long (*BIO_callback_fn)(BIO *b, int oper, const char *argp, int argi,
+ long argl, long ret);
+OSSL_DEPRECATEDIN_3_0 BIO_callback_fn BIO_get_callback(const BIO *b);
+OSSL_DEPRECATEDIN_3_0 void BIO_set_callback(BIO *b, BIO_callback_fn callback);
+OSSL_DEPRECATEDIN_3_0 long BIO_debug_callback(BIO *bio, int cmd,
+ const char *argp, int argi,
+ long argl, long ret);
+#endif
+
+typedef long (*BIO_callback_fn_ex)(BIO *b, int oper, const char *argp,
+ size_t len, int argi,
+ long argl, int ret, size_t *processed);
+BIO_callback_fn_ex BIO_get_callback_ex(const BIO *b);
+void BIO_set_callback_ex(BIO *b, BIO_callback_fn_ex callback);
+long BIO_debug_callback_ex(BIO *bio, int oper, const char *argp, size_t len,
+ int argi, long argl, int ret, size_t *processed);
+
+char *BIO_get_callback_arg(const BIO *b);
+void BIO_set_callback_arg(BIO *b, char *arg);
+
+typedef struct bio_method_st BIO_METHOD;
+
+const char *BIO_method_name(const BIO *b);
+int BIO_method_type(const BIO *b);
+
+typedef int BIO_info_cb(BIO *, int, int);
+typedef BIO_info_cb bio_info_cb; /* backward compatibility */
+
+/* clang-format off */
+SKM_DEFINE_STACK_OF_INTERNAL(BIO, BIO, BIO)
+#define sk_BIO_num(sk) OPENSSL_sk_num(ossl_check_const_BIO_sk_type(sk))
+#define sk_BIO_value(sk, idx) ((BIO *)OPENSSL_sk_value(ossl_check_const_BIO_sk_type(sk), (idx)))
+#define sk_BIO_new(cmp) ((STACK_OF(BIO) *)OPENSSL_sk_new(ossl_check_BIO_compfunc_type(cmp)))
+#define sk_BIO_new_null() ((STACK_OF(BIO) *)OPENSSL_sk_new_null())
+#define sk_BIO_new_reserve(cmp, n) ((STACK_OF(BIO) *)OPENSSL_sk_new_reserve(ossl_check_BIO_compfunc_type(cmp), (n)))
+#define sk_BIO_reserve(sk, n) OPENSSL_sk_reserve(ossl_check_BIO_sk_type(sk), (n))
+#define sk_BIO_free(sk) OPENSSL_sk_free(ossl_check_BIO_sk_type(sk))
+#define sk_BIO_zero(sk) OPENSSL_sk_zero(ossl_check_BIO_sk_type(sk))
+#define sk_BIO_delete(sk, i) ((BIO *)OPENSSL_sk_delete(ossl_check_BIO_sk_type(sk), (i)))
+#define sk_BIO_delete_ptr(sk, ptr) ((BIO *)OPENSSL_sk_delete_ptr(ossl_check_BIO_sk_type(sk), ossl_check_BIO_type(ptr)))
+#define sk_BIO_push(sk, ptr) OPENSSL_sk_push(ossl_check_BIO_sk_type(sk), ossl_check_BIO_type(ptr))
+#define sk_BIO_unshift(sk, ptr) OPENSSL_sk_unshift(ossl_check_BIO_sk_type(sk), ossl_check_BIO_type(ptr))
+#define sk_BIO_pop(sk) ((BIO *)OPENSSL_sk_pop(ossl_check_BIO_sk_type(sk)))
+#define sk_BIO_shift(sk) ((BIO *)OPENSSL_sk_shift(ossl_check_BIO_sk_type(sk)))
+#define sk_BIO_pop_free(sk, freefunc) OPENSSL_sk_pop_free(ossl_check_BIO_sk_type(sk), ossl_check_BIO_freefunc_type(freefunc))
+#define sk_BIO_insert(sk, ptr, idx) OPENSSL_sk_insert(ossl_check_BIO_sk_type(sk), ossl_check_BIO_type(ptr), (idx))
+#define sk_BIO_set(sk, idx, ptr) ((BIO *)OPENSSL_sk_set(ossl_check_BIO_sk_type(sk), (idx), ossl_check_BIO_type(ptr)))
+#define sk_BIO_find(sk, ptr) OPENSSL_sk_find(ossl_check_BIO_sk_type(sk), ossl_check_BIO_type(ptr))
+#define sk_BIO_find_ex(sk, ptr) OPENSSL_sk_find_ex(ossl_check_BIO_sk_type(sk), ossl_check_BIO_type(ptr))
+#define sk_BIO_find_all(sk, ptr, pnum) OPENSSL_sk_find_all(ossl_check_BIO_sk_type(sk), ossl_check_BIO_type(ptr), pnum)
+#define sk_BIO_sort(sk) OPENSSL_sk_sort(ossl_check_BIO_sk_type(sk))
+#define sk_BIO_is_sorted(sk) OPENSSL_sk_is_sorted(ossl_check_const_BIO_sk_type(sk))
+#define sk_BIO_dup(sk) ((STACK_OF(BIO) *)OPENSSL_sk_dup(ossl_check_const_BIO_sk_type(sk)))
+#define sk_BIO_deep_copy(sk, copyfunc, freefunc) ((STACK_OF(BIO) *)OPENSSL_sk_deep_copy(ossl_check_const_BIO_sk_type(sk), ossl_check_BIO_copyfunc_type(copyfunc), ossl_check_BIO_freefunc_type(freefunc)))
+#define sk_BIO_set_cmp_func(sk, cmp) ((sk_BIO_compfunc)OPENSSL_sk_set_cmp_func(ossl_check_BIO_sk_type(sk), ossl_check_BIO_compfunc_type(cmp)))
+
+/* clang-format on */
+
+/* Prefix and suffix callback in ASN1 BIO */
+typedef int asn1_ps_func(BIO *b, unsigned char **pbuf, int *plen,
+ void *parg);
+
+typedef void (*BIO_dgram_sctp_notification_handler_fn)(BIO *b,
+ void *context,
+ void *buf);
+#ifndef OPENSSL_NO_SCTP
+/* SCTP parameter structs */
+struct bio_dgram_sctp_sndinfo {
+ uint16_t snd_sid;
+ uint16_t snd_flags;
+ uint32_t snd_ppid;
+ uint32_t snd_context;
+};
+
+struct bio_dgram_sctp_rcvinfo {
+ uint16_t rcv_sid;
+ uint16_t rcv_ssn;
+ uint16_t rcv_flags;
+ uint32_t rcv_ppid;
+ uint32_t rcv_tsn;
+ uint32_t rcv_cumtsn;
+ uint32_t rcv_context;
+};
+
+struct bio_dgram_sctp_prinfo {
+ uint16_t pr_policy;
+ uint32_t pr_value;
+};
+#endif
+
+/* BIO_sendmmsg/BIO_recvmmsg-related definitions */
+typedef struct bio_msg_st {
+ void *data;
+ size_t data_len;
+ BIO_ADDR *peer, *local;
+ uint64_t flags;
+} BIO_MSG;
+
+typedef struct bio_mmsg_cb_args_st {
+ BIO_MSG *msg;
+ size_t stride, num_msg;
+ uint64_t flags;
+ size_t *msgs_processed;
+} BIO_MMSG_CB_ARGS;
+
+#define BIO_POLL_DESCRIPTOR_TYPE_NONE 0
+#define BIO_POLL_DESCRIPTOR_TYPE_SOCK_FD 1
+#define BIO_POLL_DESCRIPTOR_TYPE_SSL 2
+#define BIO_POLL_DESCRIPTOR_CUSTOM_START 8192
+
+typedef struct bio_poll_descriptor_st {
+ uint32_t type;
+ union {
+ int fd;
+ void *custom;
+ uintptr_t custom_ui;
+ SSL *ssl;
+ } value;
+} BIO_POLL_DESCRIPTOR;
+
+/*
+ * #define BIO_CONN_get_param_hostname BIO_ctrl
+ */
+
+#define BIO_C_SET_CONNECT 100
+#define BIO_C_DO_STATE_MACHINE 101
+#define BIO_C_SET_NBIO 102
+/* # define BIO_C_SET_PROXY_PARAM 103 */
+#define BIO_C_SET_FD 104
+#define BIO_C_GET_FD 105
+#define BIO_C_SET_FILE_PTR 106
+#define BIO_C_GET_FILE_PTR 107
+#define BIO_C_SET_FILENAME 108
+#define BIO_C_SET_SSL 109
+#define BIO_C_GET_SSL 110
+#define BIO_C_SET_MD 111
+#define BIO_C_GET_MD 112
+#define BIO_C_GET_CIPHER_STATUS 113
+#define BIO_C_SET_BUF_MEM 114
+#define BIO_C_GET_BUF_MEM_PTR 115
+#define BIO_C_GET_BUFF_NUM_LINES 116
+#define BIO_C_SET_BUFF_SIZE 117
+#define BIO_C_SET_ACCEPT 118
+#define BIO_C_SSL_MODE 119
+#define BIO_C_GET_MD_CTX 120
+/* # define BIO_C_GET_PROXY_PARAM 121 */
+#define BIO_C_SET_BUFF_READ_DATA 122 /* data to read first */
+#define BIO_C_GET_CONNECT 123
+#define BIO_C_GET_ACCEPT 124
+#define BIO_C_SET_SSL_RENEGOTIATE_BYTES 125
+#define BIO_C_GET_SSL_NUM_RENEGOTIATES 126
+#define BIO_C_SET_SSL_RENEGOTIATE_TIMEOUT 127
+#define BIO_C_FILE_SEEK 128
+#define BIO_C_GET_CIPHER_CTX 129
+#define BIO_C_SET_BUF_MEM_EOF_RETURN 130 /* return end of input \
+ * value */
+#define BIO_C_SET_BIND_MODE 131
+#define BIO_C_GET_BIND_MODE 132
+#define BIO_C_FILE_TELL 133
+#define BIO_C_GET_SOCKS 134
+#define BIO_C_SET_SOCKS 135
+
+#define BIO_C_SET_WRITE_BUF_SIZE 136 /* for BIO_s_bio */
+#define BIO_C_GET_WRITE_BUF_SIZE 137
+#define BIO_C_MAKE_BIO_PAIR 138
+#define BIO_C_DESTROY_BIO_PAIR 139
+#define BIO_C_GET_WRITE_GUARANTEE 140
+#define BIO_C_GET_READ_REQUEST 141
+#define BIO_C_SHUTDOWN_WR 142
+#define BIO_C_NREAD0 143
+#define BIO_C_NREAD 144
+#define BIO_C_NWRITE0 145
+#define BIO_C_NWRITE 146
+#define BIO_C_RESET_READ_REQUEST 147
+#define BIO_C_SET_MD_CTX 148
+
+#define BIO_C_SET_PREFIX 149
+#define BIO_C_GET_PREFIX 150
+#define BIO_C_SET_SUFFIX 151
+#define BIO_C_GET_SUFFIX 152
+
+#define BIO_C_SET_EX_ARG 153
+#define BIO_C_GET_EX_ARG 154
+
+#define BIO_C_SET_CONNECT_MODE 155
+
+#define BIO_C_SET_TFO 156 /* like BIO_C_SET_NBIO */
+
+#define BIO_C_SET_SOCK_TYPE 157
+#define BIO_C_GET_SOCK_TYPE 158
+#define BIO_C_GET_DGRAM_BIO 159
+
+#define BIO_set_app_data(s, arg) BIO_set_ex_data(s, 0, arg)
+#define BIO_get_app_data(s) BIO_get_ex_data(s, 0)
+
+#define BIO_set_nbio(b, n) BIO_ctrl(b, BIO_C_SET_NBIO, (n), NULL)
+#define BIO_set_tfo(b, n) BIO_ctrl(b, BIO_C_SET_TFO, (n), NULL)
+
+#ifndef OPENSSL_NO_SOCK
+/* IP families we support, for BIO_s_connect() and BIO_s_accept() */
+/* Note: the underlying operating system may not support some of them */
+#define BIO_FAMILY_IPV4 4
+#define BIO_FAMILY_IPV6 6
+#define BIO_FAMILY_IPANY 256
+
+/* BIO_s_connect() */
+#define BIO_set_conn_hostname(b, name) BIO_ctrl(b, BIO_C_SET_CONNECT, 0, \
+ (char *)(name))
+#define BIO_set_conn_port(b, port) BIO_ctrl(b, BIO_C_SET_CONNECT, 1, \
+ (char *)(port))
+#define BIO_set_conn_address(b, addr) BIO_ctrl(b, BIO_C_SET_CONNECT, 2, \
+ (char *)(addr))
+#define BIO_set_conn_ip_family(b, f) BIO_int_ctrl(b, BIO_C_SET_CONNECT, 3, f)
+#define BIO_get_conn_hostname(b) ((const char *)BIO_ptr_ctrl(b, BIO_C_GET_CONNECT, 0))
+#define BIO_get_conn_port(b) ((const char *)BIO_ptr_ctrl(b, BIO_C_GET_CONNECT, 1))
+#define BIO_get_conn_address(b) ((const BIO_ADDR *)BIO_ptr_ctrl(b, BIO_C_GET_CONNECT, 2))
+#define BIO_get_conn_ip_family(b) BIO_ctrl(b, BIO_C_GET_CONNECT, 3, NULL)
+#define BIO_get_conn_mode(b) BIO_ctrl(b, BIO_C_GET_CONNECT, 4, NULL)
+#define BIO_set_conn_mode(b, n) BIO_ctrl(b, BIO_C_SET_CONNECT_MODE, (n), NULL)
+#define BIO_set_sock_type(b, t) BIO_ctrl(b, BIO_C_SET_SOCK_TYPE, (t), NULL)
+#define BIO_get_sock_type(b) BIO_ctrl(b, BIO_C_GET_SOCK_TYPE, 0, NULL)
+#define BIO_get0_dgram_bio(b, p) BIO_ctrl(b, BIO_C_GET_DGRAM_BIO, 0, (void *)(BIO **)(p))
+
+/* BIO_s_accept() */
+#define BIO_set_accept_name(b, name) BIO_ctrl(b, BIO_C_SET_ACCEPT, 0, \
+ (char *)(name))
+#define BIO_set_accept_port(b, port) BIO_ctrl(b, BIO_C_SET_ACCEPT, 1, \
+ (char *)(port))
+#define BIO_get_accept_name(b) ((const char *)BIO_ptr_ctrl(b, BIO_C_GET_ACCEPT, 0))
+#define BIO_get_accept_port(b) ((const char *)BIO_ptr_ctrl(b, BIO_C_GET_ACCEPT, 1))
+#define BIO_get_peer_name(b) ((const char *)BIO_ptr_ctrl(b, BIO_C_GET_ACCEPT, 2))
+#define BIO_get_peer_port(b) ((const char *)BIO_ptr_ctrl(b, BIO_C_GET_ACCEPT, 3))
+/* #define BIO_set_nbio(b,n) BIO_ctrl(b,BIO_C_SET_NBIO,(n),NULL) */
+#define BIO_set_nbio_accept(b, n) BIO_ctrl(b, BIO_C_SET_ACCEPT, 2, (n) ? (void *)"a" : NULL)
+#define BIO_set_accept_bios(b, bio) BIO_ctrl(b, BIO_C_SET_ACCEPT, 3, \
+ (char *)(bio))
+#define BIO_set_accept_ip_family(b, f) BIO_int_ctrl(b, BIO_C_SET_ACCEPT, 4, f)
+#define BIO_get_accept_ip_family(b) BIO_ctrl(b, BIO_C_GET_ACCEPT, 4, NULL)
+#define BIO_set_tfo_accept(b, n) BIO_ctrl(b, BIO_C_SET_ACCEPT, 5, (n) ? (void *)"a" : NULL)
+
+/* Aliases kept for backward compatibility */
+#define BIO_BIND_NORMAL 0
+#define BIO_BIND_REUSEADDR BIO_SOCK_REUSEADDR
+#define BIO_BIND_REUSEADDR_IF_UNUSED BIO_SOCK_REUSEADDR
+#define BIO_set_bind_mode(b, mode) BIO_ctrl(b, BIO_C_SET_BIND_MODE, mode, NULL)
+#define BIO_get_bind_mode(b) BIO_ctrl(b, BIO_C_GET_BIND_MODE, 0, NULL)
+#endif /* OPENSSL_NO_SOCK */
+
+#define BIO_do_connect(b) BIO_do_handshake(b)
+#define BIO_do_accept(b) BIO_do_handshake(b)
+
+#define BIO_do_handshake(b) BIO_ctrl(b, BIO_C_DO_STATE_MACHINE, 0, NULL)
+
+/* BIO_s_datagram(), BIO_s_fd(), BIO_s_socket(), BIO_s_accept() and BIO_s_connect() */
+#define BIO_set_fd(b, fd, c) BIO_int_ctrl(b, BIO_C_SET_FD, c, fd)
+#define BIO_get_fd(b, c) BIO_ctrl(b, BIO_C_GET_FD, 0, (char *)(c))
+
+/* BIO_s_file() */
+#define BIO_set_fp(b, fp, c) BIO_ctrl(b, BIO_C_SET_FILE_PTR, c, (char *)(fp))
+#define BIO_get_fp(b, fpp) BIO_ctrl(b, BIO_C_GET_FILE_PTR, 0, (char *)(fpp))
+
+/* BIO_s_fd() and BIO_s_file() */
+#define BIO_seek(b, ofs) (int)BIO_ctrl(b, BIO_C_FILE_SEEK, ofs, NULL)
+#define BIO_tell(b) (int)BIO_ctrl(b, BIO_C_FILE_TELL, 0, NULL)
+
+/*
+ * name is cast to lose const, but might be better to route through a
+ * function so we can do it safely
+ */
+#ifdef CONST_STRICT
+/*
+ * If you are wondering why this isn't defined, its because CONST_STRICT is
+ * purely a compile-time kludge to allow const to be checked.
+ */
+int BIO_read_filename(BIO *b, const char *name);
+#else
+#define BIO_read_filename(b, name) (int)BIO_ctrl(b, BIO_C_SET_FILENAME, \
+ BIO_CLOSE | BIO_FP_READ, (char *)(name))
+#endif
+#define BIO_write_filename(b, name) (int)BIO_ctrl(b, BIO_C_SET_FILENAME, \
+ BIO_CLOSE | BIO_FP_WRITE, name)
+#define BIO_append_filename(b, name) (int)BIO_ctrl(b, BIO_C_SET_FILENAME, \
+ BIO_CLOSE | BIO_FP_APPEND, name)
+#define BIO_rw_filename(b, name) (int)BIO_ctrl(b, BIO_C_SET_FILENAME, \
+ BIO_CLOSE | BIO_FP_READ | BIO_FP_WRITE, name)
+
+/*
+ * WARNING WARNING, this ups the reference count on the read bio of the SSL
+ * structure. This is because the ssl read BIO is now pointed to by the
+ * next_bio field in the bio. So when you free the BIO, make sure you are
+ * doing a BIO_free_all() to catch the underlying BIO.
+ */
+#define BIO_set_ssl(b, ssl, c) BIO_ctrl(b, BIO_C_SET_SSL, c, (char *)(ssl))
+#define BIO_get_ssl(b, sslp) BIO_ctrl(b, BIO_C_GET_SSL, 0, (char *)(sslp))
+#define BIO_set_ssl_mode(b, client) BIO_ctrl(b, BIO_C_SSL_MODE, client, NULL)
+#define BIO_set_ssl_renegotiate_bytes(b, num) \
+ BIO_ctrl(b, BIO_C_SET_SSL_RENEGOTIATE_BYTES, num, NULL)
+#define BIO_get_num_renegotiates(b) \
+ BIO_ctrl(b, BIO_C_GET_SSL_NUM_RENEGOTIATES, 0, NULL)
+#define BIO_set_ssl_renegotiate_timeout(b, seconds) \
+ BIO_ctrl(b, BIO_C_SET_SSL_RENEGOTIATE_TIMEOUT, seconds, NULL)
+
+/* defined in evp.h */
+/* #define BIO_set_md(b,md) BIO_ctrl(b,BIO_C_SET_MD,1,(char *)(md)) */
+
+#define BIO_get_mem_data(b, pp) BIO_ctrl(b, BIO_CTRL_INFO, 0, (char *)(pp))
+#define BIO_set_mem_buf(b, bm, c) BIO_ctrl(b, BIO_C_SET_BUF_MEM, c, (char *)(bm))
+#define BIO_get_mem_ptr(b, pp) BIO_ctrl(b, BIO_C_GET_BUF_MEM_PTR, 0, \
+ (char *)(pp))
+#define BIO_set_mem_eof_return(b, v) \
+ BIO_ctrl(b, BIO_C_SET_BUF_MEM_EOF_RETURN, v, NULL)
+
+/* For the BIO_f_buffer() type */
+#define BIO_get_buffer_num_lines(b) BIO_ctrl(b, BIO_C_GET_BUFF_NUM_LINES, 0, NULL)
+#define BIO_set_buffer_size(b, size) BIO_ctrl(b, BIO_C_SET_BUFF_SIZE, size, NULL)
+#define BIO_set_read_buffer_size(b, size) BIO_int_ctrl(b, BIO_C_SET_BUFF_SIZE, size, 0)
+#define BIO_set_write_buffer_size(b, size) BIO_int_ctrl(b, BIO_C_SET_BUFF_SIZE, size, 1)
+#define BIO_set_buffer_read_data(b, buf, num) BIO_ctrl(b, BIO_C_SET_BUFF_READ_DATA, num, buf)
+
+/* Don't use the next one unless you know what you are doing :-) */
+#define BIO_dup_state(b, ret) BIO_ctrl(b, BIO_CTRL_DUP, 0, (char *)(ret))
+
+#define BIO_reset(b) (int)BIO_ctrl(b, BIO_CTRL_RESET, 0, NULL)
+#define BIO_eof(b) (int)BIO_ctrl(b, BIO_CTRL_EOF, 0, NULL)
+#define BIO_set_close(b, c) (int)BIO_ctrl(b, BIO_CTRL_SET_CLOSE, (c), NULL)
+#define BIO_get_close(b) (int)BIO_ctrl(b, BIO_CTRL_GET_CLOSE, 0, NULL)
+#define BIO_pending(b) (int)BIO_ctrl(b, BIO_CTRL_PENDING, 0, NULL)
+#define BIO_wpending(b) (int)BIO_ctrl(b, BIO_CTRL_WPENDING, 0, NULL)
+/* ...pending macros have inappropriate return type */
+size_t BIO_ctrl_pending(BIO *b);
+size_t BIO_ctrl_wpending(BIO *b);
+#define BIO_flush(b) (int)BIO_ctrl(b, BIO_CTRL_FLUSH, 0, NULL)
+#define BIO_get_info_callback(b, cbp) (int)BIO_ctrl(b, BIO_CTRL_GET_CALLBACK, 0, \
+ cbp)
+#define BIO_set_info_callback(b, cb) (int)BIO_callback_ctrl(b, BIO_CTRL_SET_CALLBACK, cb)
+
+/* For the BIO_f_buffer() type */
+#define BIO_buffer_get_num_lines(b) BIO_ctrl(b, BIO_CTRL_GET, 0, NULL)
+#define BIO_buffer_peek(b, s, l) BIO_ctrl(b, BIO_CTRL_PEEK, (l), (s))
+
+/* For BIO_s_bio() */
+#define BIO_set_write_buf_size(b, size) (int)BIO_ctrl(b, BIO_C_SET_WRITE_BUF_SIZE, size, NULL)
+#define BIO_get_write_buf_size(b, size) (size_t)BIO_ctrl(b, BIO_C_GET_WRITE_BUF_SIZE, size, NULL)
+#define BIO_make_bio_pair(b1, b2) (int)BIO_ctrl(b1, BIO_C_MAKE_BIO_PAIR, 0, b2)
+#define BIO_destroy_bio_pair(b) (int)BIO_ctrl(b, BIO_C_DESTROY_BIO_PAIR, 0, NULL)
+#define BIO_shutdown_wr(b) (int)BIO_ctrl(b, BIO_C_SHUTDOWN_WR, 0, NULL)
+/* macros with inappropriate type -- but ...pending macros use int too: */
+#define BIO_get_write_guarantee(b) (int)BIO_ctrl(b, BIO_C_GET_WRITE_GUARANTEE, 0, NULL)
+#define BIO_get_read_request(b) (int)BIO_ctrl(b, BIO_C_GET_READ_REQUEST, 0, NULL)
+size_t BIO_ctrl_get_write_guarantee(BIO *b);
+size_t BIO_ctrl_get_read_request(BIO *b);
+int BIO_ctrl_reset_read_request(BIO *b);
+
+/* ctrl macros for dgram */
+#define BIO_ctrl_dgram_connect(b, peer) \
+ (int)BIO_ctrl(b, BIO_CTRL_DGRAM_CONNECT, 0, (char *)(peer))
+#define BIO_ctrl_set_connected(b, peer) \
+ (int)BIO_ctrl(b, BIO_CTRL_DGRAM_SET_CONNECTED, 0, (char *)(peer))
+#define BIO_dgram_recv_timedout(b) \
+ (int)BIO_ctrl(b, BIO_CTRL_DGRAM_GET_RECV_TIMER_EXP, 0, NULL)
+#define BIO_dgram_send_timedout(b) \
+ (int)BIO_ctrl(b, BIO_CTRL_DGRAM_GET_SEND_TIMER_EXP, 0, NULL)
+#define BIO_dgram_get_peer(b, peer) \
+ (int)BIO_ctrl(b, BIO_CTRL_DGRAM_GET_PEER, 0, (char *)(peer))
+#define BIO_dgram_set_peer(b, peer) \
+ (int)BIO_ctrl(b, BIO_CTRL_DGRAM_SET_PEER, 0, (char *)(peer))
+#define BIO_dgram_detect_peer_addr(b, peer) \
+ (int)BIO_ctrl(b, BIO_CTRL_DGRAM_DETECT_PEER_ADDR, 0, (char *)(peer))
+#define BIO_dgram_get_mtu_overhead(b) \
+ (unsigned int)BIO_ctrl((b), BIO_CTRL_DGRAM_GET_MTU_OVERHEAD, 0, NULL)
+#define BIO_dgram_get_local_addr_cap(b) \
+ (int)BIO_ctrl((b), BIO_CTRL_DGRAM_GET_LOCAL_ADDR_CAP, 0, NULL)
+#define BIO_dgram_get_local_addr_enable(b, penable) \
+ (int)BIO_ctrl((b), BIO_CTRL_DGRAM_GET_LOCAL_ADDR_ENABLE, 0, (char *)(penable))
+#define BIO_dgram_set_local_addr_enable(b, enable) \
+ (int)BIO_ctrl((b), BIO_CTRL_DGRAM_SET_LOCAL_ADDR_ENABLE, (enable), NULL)
+#define BIO_dgram_get_effective_caps(b) \
+ (uint32_t)BIO_ctrl((b), BIO_CTRL_DGRAM_GET_EFFECTIVE_CAPS, 0, NULL)
+#define BIO_dgram_get_caps(b) \
+ (uint32_t)BIO_ctrl((b), BIO_CTRL_DGRAM_GET_CAPS, 0, NULL)
+#define BIO_dgram_set_caps(b, caps) \
+ (int)BIO_ctrl((b), BIO_CTRL_DGRAM_SET_CAPS, (long)(caps), NULL)
+#define BIO_dgram_get_no_trunc(b) \
+ (unsigned int)BIO_ctrl((b), BIO_CTRL_DGRAM_GET_NO_TRUNC, 0, NULL)
+#define BIO_dgram_set_no_trunc(b, enable) \
+ (int)BIO_ctrl((b), BIO_CTRL_DGRAM_SET_NO_TRUNC, (enable), NULL)
+#define BIO_dgram_get_mtu(b) \
+ (unsigned int)BIO_ctrl((b), BIO_CTRL_DGRAM_GET_MTU, 0, NULL)
+#define BIO_dgram_set_mtu(b, mtu) \
+ (int)BIO_ctrl((b), BIO_CTRL_DGRAM_SET_MTU, (mtu), NULL)
+#define BIO_dgram_set0_local_addr(b, addr) \
+ (int)BIO_ctrl((b), BIO_CTRL_DGRAM_SET0_LOCAL_ADDR, 0, (addr))
+
+/* ctrl macros for BIO_f_prefix */
+#define BIO_set_prefix(b, p) BIO_ctrl((b), BIO_CTRL_SET_PREFIX, 0, (void *)(p))
+#define BIO_set_indent(b, i) BIO_ctrl((b), BIO_CTRL_SET_INDENT, (i), NULL)
+#define BIO_get_indent(b) BIO_ctrl((b), BIO_CTRL_GET_INDENT, 0, NULL)
+
+#define BIO_get_ex_new_index(l, p, newf, dupf, freef) \
+ CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_BIO, l, p, newf, dupf, freef)
+int BIO_set_ex_data(BIO *bio, int idx, void *data);
+void *BIO_get_ex_data(const BIO *bio, int idx);
+uint64_t BIO_number_read(BIO *bio);
+uint64_t BIO_number_written(BIO *bio);
+
+/* For BIO_f_asn1() */
+int BIO_asn1_set_prefix(BIO *b, asn1_ps_func *prefix,
+ asn1_ps_func *prefix_free);
+int BIO_asn1_get_prefix(BIO *b, asn1_ps_func **pprefix,
+ asn1_ps_func **pprefix_free);
+int BIO_asn1_set_suffix(BIO *b, asn1_ps_func *suffix,
+ asn1_ps_func *suffix_free);
+int BIO_asn1_get_suffix(BIO *b, asn1_ps_func **psuffix,
+ asn1_ps_func **psuffix_free);
+
+const BIO_METHOD *BIO_s_file(void);
+BIO *BIO_new_file(const char *filename, const char *mode);
+BIO *BIO_new_from_core_bio(OSSL_LIB_CTX *libctx, OSSL_CORE_BIO *corebio);
+#ifndef OPENSSL_NO_STDIO
+BIO *BIO_new_fp(FILE *stream, int close_flag);
+#endif
+BIO *BIO_new_ex(OSSL_LIB_CTX *libctx, const BIO_METHOD *method);
+BIO *BIO_new(const BIO_METHOD *type);
+int BIO_free(BIO *a);
+void BIO_set_data(BIO *a, void *ptr);
+void *BIO_get_data(BIO *a);
+void BIO_set_init(BIO *a, int init);
+int BIO_get_init(BIO *a);
+void BIO_set_shutdown(BIO *a, int shut);
+int BIO_get_shutdown(BIO *a);
+void BIO_vfree(BIO *a);
+int BIO_up_ref(BIO *a);
+int BIO_read(BIO *b, void *data, int dlen);
+int BIO_read_ex(BIO *b, void *data, size_t dlen, size_t *readbytes);
+__owur int BIO_recvmmsg(BIO *b, BIO_MSG *msg,
+ size_t stride, size_t num_msg, uint64_t flags,
+ size_t *msgs_processed);
+int BIO_gets(BIO *bp, char *buf, int size);
+int BIO_get_line(BIO *bio, char *buf, int size);
+int BIO_write(BIO *b, const void *data, int dlen);
+int BIO_write_ex(BIO *b, const void *data, size_t dlen, size_t *written);
+__owur int BIO_sendmmsg(BIO *b, BIO_MSG *msg,
+ size_t stride, size_t num_msg, uint64_t flags,
+ size_t *msgs_processed);
+__owur int BIO_get_rpoll_descriptor(BIO *b, BIO_POLL_DESCRIPTOR *desc);
+__owur int BIO_get_wpoll_descriptor(BIO *b, BIO_POLL_DESCRIPTOR *desc);
+int BIO_puts(BIO *bp, const char *buf);
+int BIO_indent(BIO *b, int indent, int max);
+long BIO_ctrl(BIO *bp, int cmd, long larg, void *parg);
+long BIO_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp);
+void *BIO_ptr_ctrl(BIO *bp, int cmd, long larg);
+long BIO_int_ctrl(BIO *bp, int cmd, long larg, int iarg);
+BIO *BIO_push(BIO *b, BIO *append);
+BIO *BIO_pop(BIO *b);
+void BIO_free_all(BIO *a);
+BIO *BIO_find_type(BIO *b, int bio_type);
+BIO *BIO_next(BIO *b);
+void BIO_set_next(BIO *b, BIO *next);
+BIO *BIO_get_retry_BIO(BIO *bio, int *reason);
+int BIO_get_retry_reason(BIO *bio);
+void BIO_set_retry_reason(BIO *bio, int reason);
+BIO *BIO_dup_chain(BIO *in);
+
+int BIO_nread0(BIO *bio, char **buf);
+int BIO_nread(BIO *bio, char **buf, int num);
+int BIO_nwrite0(BIO *bio, char **buf);
+int BIO_nwrite(BIO *bio, char **buf, int num);
+
+const BIO_METHOD *BIO_s_mem(void);
+#ifndef OPENSSL_NO_DGRAM
+const BIO_METHOD *BIO_s_dgram_mem(void);
+#endif
+const BIO_METHOD *BIO_s_secmem(void);
+BIO *BIO_new_mem_buf(const void *buf, int len);
+#ifndef OPENSSL_NO_SOCK
+const BIO_METHOD *BIO_s_socket(void);
+const BIO_METHOD *BIO_s_connect(void);
+const BIO_METHOD *BIO_s_accept(void);
+#endif
+const BIO_METHOD *BIO_s_fd(void);
+const BIO_METHOD *BIO_s_log(void);
+const BIO_METHOD *BIO_s_bio(void);
+const BIO_METHOD *BIO_s_null(void);
+const BIO_METHOD *BIO_f_null(void);
+const BIO_METHOD *BIO_f_buffer(void);
+const BIO_METHOD *BIO_f_readbuffer(void);
+const BIO_METHOD *BIO_f_linebuffer(void);
+const BIO_METHOD *BIO_f_nbio_test(void);
+const BIO_METHOD *BIO_f_prefix(void);
+const BIO_METHOD *BIO_s_core(void);
+#ifndef OPENSSL_NO_DGRAM
+const BIO_METHOD *BIO_s_dgram_pair(void);
+const BIO_METHOD *BIO_s_datagram(void);
+int BIO_dgram_non_fatal_error(int error);
+BIO *BIO_new_dgram(int fd, int close_flag);
+#ifndef OPENSSL_NO_SCTP
+const BIO_METHOD *BIO_s_datagram_sctp(void);
+BIO *BIO_new_dgram_sctp(int fd, int close_flag);
+int BIO_dgram_is_sctp(BIO *bio);
+int BIO_dgram_sctp_notification_cb(BIO *b,
+ BIO_dgram_sctp_notification_handler_fn handle_notifications,
+ void *context);
+int BIO_dgram_sctp_wait_for_dry(BIO *b);
+int BIO_dgram_sctp_msg_waiting(BIO *b);
+#endif
+#endif
+
+#ifndef OPENSSL_NO_SOCK
+int BIO_sock_should_retry(int i);
+int BIO_sock_non_fatal_error(int error);
+int BIO_err_is_non_fatal(unsigned int errcode);
+int BIO_socket_wait(int fd, int for_read, time_t max_time);
+#endif
+int BIO_wait(BIO *bio, time_t max_time, unsigned int nap_milliseconds);
+int BIO_do_connect_retry(BIO *bio, int timeout, int nap_milliseconds);
+
+int BIO_fd_should_retry(int i);
+int BIO_fd_non_fatal_error(int error);
+int BIO_dump_cb(int (*cb)(const void *data, size_t len, void *u),
+ void *u, const void *s, int len);
+int BIO_dump_indent_cb(int (*cb)(const void *data, size_t len, void *u),
+ void *u, const void *s, int len, int indent);
+int BIO_dump(BIO *b, const void *bytes, int len);
+int BIO_dump_indent(BIO *b, const void *bytes, int len, int indent);
+#ifndef OPENSSL_NO_STDIO
+int BIO_dump_fp(FILE *fp, const void *s, int len);
+int BIO_dump_indent_fp(FILE *fp, const void *s, int len, int indent);
+#endif
+int BIO_hex_string(BIO *out, int indent, int width, const void *data,
+ int datalen);
+
+#ifndef OPENSSL_NO_SOCK
+BIO_ADDR *BIO_ADDR_new(void);
+int BIO_ADDR_copy(BIO_ADDR *dst, const BIO_ADDR *src);
+BIO_ADDR *BIO_ADDR_dup(const BIO_ADDR *ap);
+int BIO_ADDR_rawmake(BIO_ADDR *ap, int family,
+ const void *where, size_t wherelen, unsigned short port);
+void BIO_ADDR_free(BIO_ADDR *);
+void BIO_ADDR_clear(BIO_ADDR *ap);
+int BIO_ADDR_family(const BIO_ADDR *ap);
+int BIO_ADDR_rawaddress(const BIO_ADDR *ap, void *p, size_t *l);
+unsigned short BIO_ADDR_rawport(const BIO_ADDR *ap);
+char *BIO_ADDR_hostname_string(const BIO_ADDR *ap, int numeric);
+char *BIO_ADDR_service_string(const BIO_ADDR *ap, int numeric);
+char *BIO_ADDR_path_string(const BIO_ADDR *ap);
+
+const BIO_ADDRINFO *BIO_ADDRINFO_next(const BIO_ADDRINFO *bai);
+int BIO_ADDRINFO_family(const BIO_ADDRINFO *bai);
+int BIO_ADDRINFO_socktype(const BIO_ADDRINFO *bai);
+int BIO_ADDRINFO_protocol(const BIO_ADDRINFO *bai);
+const BIO_ADDR *BIO_ADDRINFO_address(const BIO_ADDRINFO *bai);
+void BIO_ADDRINFO_free(BIO_ADDRINFO *bai);
+
+enum BIO_hostserv_priorities {
+ BIO_PARSE_PRIO_HOST,
+ BIO_PARSE_PRIO_SERV
+};
+int BIO_parse_hostserv(const char *hostserv, char **host, char **service,
+ enum BIO_hostserv_priorities hostserv_prio);
+enum BIO_lookup_type {
+ BIO_LOOKUP_CLIENT,
+ BIO_LOOKUP_SERVER
+};
+int BIO_lookup(const char *host, const char *service,
+ enum BIO_lookup_type lookup_type,
+ int family, int socktype, BIO_ADDRINFO **res);
+int BIO_lookup_ex(const char *host, const char *service,
+ int lookup_type, int family, int socktype, int protocol,
+ BIO_ADDRINFO **res);
+int BIO_sock_error(int sock);
+int BIO_socket_ioctl(int fd, long type, void *arg);
+int BIO_socket_nbio(int fd, int mode);
+int BIO_sock_init(void);
+#ifndef OPENSSL_NO_DEPRECATED_1_1_0
+#define BIO_sock_cleanup() \
+ while (0) \
+ continue
+#endif
+int BIO_set_tcp_ndelay(int sock, int turn_on);
+#ifndef OPENSSL_NO_DEPRECATED_1_1_0
+OSSL_DEPRECATEDIN_1_1_0 struct hostent *BIO_gethostbyname(const char *name);
+OSSL_DEPRECATEDIN_1_1_0 int BIO_get_port(const char *str, unsigned short *port_ptr);
+OSSL_DEPRECATEDIN_1_1_0 int BIO_get_host_ip(const char *str, unsigned char *ip);
+OSSL_DEPRECATEDIN_1_1_0 int BIO_get_accept_socket(char *host_port, int mode);
+OSSL_DEPRECATEDIN_1_1_0 int BIO_accept(int sock, char **ip_port);
+#endif
+
+union BIO_sock_info_u {
+ BIO_ADDR *addr;
+};
+enum BIO_sock_info_type {
+ BIO_SOCK_INFO_ADDRESS
+};
+int BIO_sock_info(int sock,
+ enum BIO_sock_info_type type, union BIO_sock_info_u *info);
+
+#define BIO_SOCK_REUSEADDR 0x01
+#define BIO_SOCK_V6_ONLY 0x02
+#define BIO_SOCK_KEEPALIVE 0x04
+#define BIO_SOCK_NONBLOCK 0x08
+#define BIO_SOCK_NODELAY 0x10
+#define BIO_SOCK_TFO 0x20
+
+int BIO_socket(int domain, int socktype, int protocol, int options);
+int BIO_connect(int sock, const BIO_ADDR *addr, int options);
+int BIO_bind(int sock, const BIO_ADDR *addr, int options);
+int BIO_listen(int sock, const BIO_ADDR *addr, int options);
+int BIO_accept_ex(int accept_sock, BIO_ADDR *addr, int options);
+int BIO_closesocket(int sock);
+
+BIO *BIO_new_socket(int sock, int close_flag);
+BIO *BIO_new_connect(const char *host_port);
+BIO *BIO_new_accept(const char *host_port);
+#endif /* OPENSSL_NO_SOCK*/
+
+BIO *BIO_new_fd(int fd, int close_flag);
+
+int BIO_new_bio_pair(BIO **bio1, size_t writebuf1,
+ BIO **bio2, size_t writebuf2);
+#ifndef OPENSSL_NO_DGRAM
+int BIO_new_bio_dgram_pair(BIO **bio1, size_t writebuf1,
+ BIO **bio2, size_t writebuf2);
+#endif
+
+/*
+ * If successful, returns 1 and in *bio1, *bio2 two BIO pair endpoints.
+ * Otherwise returns 0 and sets *bio1 and *bio2 to NULL. Size 0 uses default
+ * value.
+ */
+
+void BIO_copy_next_retry(BIO *b);
+
+/*
+ * long BIO_ghbn_ctrl(int cmd,int iarg,char *parg);
+ */
+
+#define ossl_bio__attr__(x)
+#if defined(__GNUC__) && defined(__STDC_VERSION__) \
+ && !defined(__MINGW32__) && !defined(__MINGW64__) \
+ && !defined(__APPLE__)
+/*
+ * Because we support the 'z' modifier, which made its appearance in C99,
+ * we can't use __attribute__ with pre C99 dialects.
+ */
+#if __STDC_VERSION__ >= 199901L
+#undef ossl_bio__attr__
+#define ossl_bio__attr__ __attribute__
+#if __GNUC__ * 10 + __GNUC_MINOR__ >= 44
+#define ossl_bio__printf__ __gnu_printf__
+#else
+#define ossl_bio__printf__ __printf__
+#endif
+#endif
+#endif
+int BIO_printf(BIO *bio, const char *format, ...)
+ ossl_bio__attr__((__format__(ossl_bio__printf__, 2, 3)));
+int BIO_vprintf(BIO *bio, const char *format, va_list args)
+ ossl_bio__attr__((__format__(ossl_bio__printf__, 2, 0)));
+int BIO_snprintf(char *buf, size_t n, const char *format, ...)
+ ossl_bio__attr__((__format__(ossl_bio__printf__, 3, 4)));
+int BIO_vsnprintf(char *buf, size_t n, const char *format, va_list args)
+ ossl_bio__attr__((__format__(ossl_bio__printf__, 3, 0)));
+#undef ossl_bio__attr__
+#undef ossl_bio__printf__
+
+BIO_METHOD *BIO_meth_new(int type, const char *name);
+void BIO_meth_free(BIO_METHOD *biom);
+int BIO_meth_set_write(BIO_METHOD *biom,
+ int (*write)(BIO *, const char *, int));
+int BIO_meth_set_write_ex(BIO_METHOD *biom,
+ int (*bwrite)(BIO *, const char *, size_t, size_t *));
+int BIO_meth_set_sendmmsg(BIO_METHOD *biom,
+ int (*f)(BIO *, BIO_MSG *, size_t, size_t,
+ uint64_t, size_t *));
+int BIO_meth_set_read(BIO_METHOD *biom,
+ int (*read)(BIO *, char *, int));
+int BIO_meth_set_read_ex(BIO_METHOD *biom,
+ int (*bread)(BIO *, char *, size_t, size_t *));
+int BIO_meth_set_recvmmsg(BIO_METHOD *biom,
+ int (*f)(BIO *, BIO_MSG *, size_t, size_t,
+ uint64_t, size_t *));
+int BIO_meth_set_puts(BIO_METHOD *biom,
+ int (*puts)(BIO *, const char *));
+int BIO_meth_set_gets(BIO_METHOD *biom,
+ int (*ossl_gets)(BIO *, char *, int));
+int BIO_meth_set_ctrl(BIO_METHOD *biom,
+ long (*ctrl)(BIO *, int, long, void *));
+int BIO_meth_set_create(BIO_METHOD *biom, int (*create)(BIO *));
+int BIO_meth_set_destroy(BIO_METHOD *biom, int (*destroy)(BIO *));
+int BIO_meth_set_callback_ctrl(BIO_METHOD *biom,
+ long (*callback_ctrl)(BIO *, int,
+ BIO_info_cb *));
+#ifndef OPENSSL_NO_DEPRECATED_3_5
+OSSL_DEPRECATEDIN_3_5 int (*BIO_meth_get_write(const BIO_METHOD *biom))(BIO *, const char *,
+ int);
+OSSL_DEPRECATEDIN_3_5 int (*BIO_meth_get_write_ex(const BIO_METHOD *biom))(BIO *, const char *,
+ size_t, size_t *);
+OSSL_DEPRECATEDIN_3_5 int (*BIO_meth_get_sendmmsg(const BIO_METHOD *biom))(BIO *, BIO_MSG *,
+ size_t, size_t,
+ uint64_t, size_t *);
+OSSL_DEPRECATEDIN_3_5 int (*BIO_meth_get_read(const BIO_METHOD *biom))(BIO *, char *, int);
+OSSL_DEPRECATEDIN_3_5 int (*BIO_meth_get_read_ex(const BIO_METHOD *biom))(BIO *, char *,
+ size_t, size_t *);
+OSSL_DEPRECATEDIN_3_5 int (*BIO_meth_get_recvmmsg(const BIO_METHOD *biom))(BIO *, BIO_MSG *,
+ size_t, size_t,
+ uint64_t, size_t *);
+OSSL_DEPRECATEDIN_3_5 int (*BIO_meth_get_puts(const BIO_METHOD *biom))(BIO *, const char *);
+OSSL_DEPRECATEDIN_3_5 int (*BIO_meth_get_gets(const BIO_METHOD *biom))(BIO *, char *, int);
+OSSL_DEPRECATEDIN_3_5 long (*BIO_meth_get_ctrl(const BIO_METHOD *biom))(BIO *, int,
+ long, void *);
+OSSL_DEPRECATEDIN_3_5 int (*BIO_meth_get_create(const BIO_METHOD *bion))(BIO *);
+OSSL_DEPRECATEDIN_3_5 int (*BIO_meth_get_destroy(const BIO_METHOD *biom))(BIO *);
+OSSL_DEPRECATEDIN_3_5 long (*BIO_meth_get_callback_ctrl(const BIO_METHOD *biom))(BIO *, int,
+ BIO_info_cb *);
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/third_party/ios/openssl/include/openssl/bioerr.h b/third_party/ios/openssl/include/openssl/bioerr.h
new file mode 100644
index 0000000..b4ee5c6
--- /dev/null
+++ b/third_party/ios/openssl/include/openssl/bioerr.h
@@ -0,0 +1,70 @@
+/*
+ * Generated by util/mkerr.pl DO NOT EDIT
+ * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#ifndef OPENSSL_BIOERR_H
+#define OPENSSL_BIOERR_H
+#pragma once
+
+#include
+#include
+#include
+
+/*
+ * BIO reason codes.
+ */
+#define BIO_R_ACCEPT_ERROR 100
+#define BIO_R_ADDRINFO_ADDR_IS_NOT_AF_INET 141
+#define BIO_R_AMBIGUOUS_HOST_OR_SERVICE 129
+#define BIO_R_BAD_FOPEN_MODE 101
+#define BIO_R_BROKEN_PIPE 124
+#define BIO_R_CONNECT_ERROR 103
+#define BIO_R_CONNECT_TIMEOUT 147
+#define BIO_R_GETHOSTBYNAME_ADDR_IS_NOT_AF_INET 107
+#define BIO_R_GETSOCKNAME_ERROR 132
+#define BIO_R_GETSOCKNAME_TRUNCATED_ADDRESS 133
+#define BIO_R_GETTING_SOCKTYPE 134
+#define BIO_R_INVALID_ARGUMENT 125
+#define BIO_R_INVALID_SOCKET 135
+#define BIO_R_IN_USE 123
+#define BIO_R_LENGTH_TOO_LONG 102
+#define BIO_R_LISTEN_V6_ONLY 136
+#define BIO_R_LOCAL_ADDR_NOT_AVAILABLE 111
+#define BIO_R_LOOKUP_RETURNED_NOTHING 142
+#define BIO_R_MALFORMED_HOST_OR_SERVICE 130
+#define BIO_R_NBIO_CONNECT_ERROR 110
+#define BIO_R_NON_FATAL 112
+#define BIO_R_NO_ACCEPT_ADDR_OR_SERVICE_SPECIFIED 143
+#define BIO_R_NO_HOSTNAME_OR_SERVICE_SPECIFIED 144
+#define BIO_R_NO_PORT_DEFINED 113
+#define BIO_R_NO_SUCH_FILE 128
+#define BIO_R_NULL_PARAMETER 115 /* unused */
+#define BIO_R_TFO_DISABLED 106
+#define BIO_R_TFO_NO_KERNEL_SUPPORT 108
+#define BIO_R_TRANSFER_ERROR 104
+#define BIO_R_TRANSFER_TIMEOUT 105
+#define BIO_R_UNABLE_TO_BIND_SOCKET 117
+#define BIO_R_UNABLE_TO_CREATE_SOCKET 118
+#define BIO_R_UNABLE_TO_KEEPALIVE 137
+#define BIO_R_UNABLE_TO_LISTEN_SOCKET 119
+#define BIO_R_UNABLE_TO_NODELAY 138
+#define BIO_R_UNABLE_TO_REUSEADDR 139
+#define BIO_R_UNABLE_TO_TFO 109
+#define BIO_R_UNAVAILABLE_IP_FAMILY 145
+#define BIO_R_UNINITIALIZED 120
+#define BIO_R_UNKNOWN_INFO_TYPE 140
+#define BIO_R_UNSUPPORTED_IP_FAMILY 146
+#define BIO_R_UNSUPPORTED_METHOD 121
+#define BIO_R_UNSUPPORTED_PROTOCOL_FAMILY 131
+#define BIO_R_WRITE_TO_READ_ONLY_BIO 126
+#define BIO_R_WSASTARTUP 122
+#define BIO_R_PORT_MISMATCH 150
+#define BIO_R_PEER_ADDR_NOT_AVAILABLE 151
+
+#endif
diff --git a/third_party/ios/openssl/include/openssl/blowfish.h b/third_party/ios/openssl/include/openssl/blowfish.h
new file mode 100644
index 0000000..49c74e9
--- /dev/null
+++ b/third_party/ios/openssl/include/openssl/blowfish.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#ifndef OPENSSL_BLOWFISH_H
+#define OPENSSL_BLOWFISH_H
+#pragma once
+
+#include
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+#define HEADER_BLOWFISH_H
+#endif
+
+#include
+
+#ifndef OPENSSL_NO_BF
+#include
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define BF_BLOCK 8
+
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+
+#define BF_ENCRYPT 1
+#define BF_DECRYPT 0
+
+/*-
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ * ! BF_LONG has to be at least 32 bits wide. !
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ */
+#define BF_LONG unsigned int
+
+#define BF_ROUNDS 16
+
+typedef struct bf_key_st {
+ BF_LONG P[BF_ROUNDS + 2];
+ BF_LONG S[4 * 256];
+} BF_KEY;
+
+#endif /* OPENSSL_NO_DEPRECATED_3_0 */
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+OSSL_DEPRECATEDIN_3_0 void BF_set_key(BF_KEY *key, int len,
+ const unsigned char *data);
+OSSL_DEPRECATEDIN_3_0 void BF_encrypt(BF_LONG *data, const BF_KEY *key);
+OSSL_DEPRECATEDIN_3_0 void BF_decrypt(BF_LONG *data, const BF_KEY *key);
+OSSL_DEPRECATEDIN_3_0 void BF_ecb_encrypt(const unsigned char *in,
+ unsigned char *out, const BF_KEY *key,
+ int enc);
+OSSL_DEPRECATEDIN_3_0 void BF_cbc_encrypt(const unsigned char *in,
+ unsigned char *out, long length,
+ const BF_KEY *schedule,
+ unsigned char *ivec, int enc);
+OSSL_DEPRECATEDIN_3_0 void BF_cfb64_encrypt(const unsigned char *in,
+ unsigned char *out,
+ long length, const BF_KEY *schedule,
+ unsigned char *ivec, int *num,
+ int enc);
+OSSL_DEPRECATEDIN_3_0 void BF_ofb64_encrypt(const unsigned char *in,
+ unsigned char *out,
+ long length, const BF_KEY *schedule,
+ unsigned char *ivec, int *num);
+OSSL_DEPRECATEDIN_3_0 const char *BF_options(void);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
+#endif
diff --git a/third_party/ios/openssl/include/openssl/bn.h b/third_party/ios/openssl/include/openssl/bn.h
new file mode 100644
index 0000000..b7a3cd8
--- /dev/null
+++ b/third_party/ios/openssl/include/openssl/bn.h
@@ -0,0 +1,588 @@
+/*
+ * Copyright 1995-2026 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#ifndef OPENSSL_BN_H
+#define OPENSSL_BN_H
+#pragma once
+
+#include
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+#define HEADER_BN_H
+#endif
+
+#include
+#ifndef OPENSSL_NO_STDIO
+#include
+#endif
+#include
+#include
+#include
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * 64-bit processor with LP64 ABI
+ */
+#ifdef SIXTY_FOUR_BIT_LONG
+#define BN_ULONG unsigned long
+#define BN_BYTES 8
+#endif
+
+/*
+ * 64-bit processor other than LP64 ABI
+ */
+#ifdef SIXTY_FOUR_BIT
+#define BN_ULONG unsigned long long
+#define BN_BYTES 8
+#endif
+
+#ifdef THIRTY_TWO_BIT
+#define BN_ULONG unsigned int
+#define BN_BYTES 4
+#endif
+
+#define BN_BITS2 (BN_BYTES * 8)
+#define BN_BITS (BN_BITS2 * 2)
+#define BN_TBIT ((BN_ULONG)1 << (BN_BITS2 - 1))
+
+#define BN_FLG_MALLOCED 0x01
+#define BN_FLG_STATIC_DATA 0x02
+
+/*
+ * avoid leaking exponent information through timing,
+ * BN_mod_exp_mont() will call BN_mod_exp_mont_consttime,
+ * BN_div() will call BN_div_no_branch,
+ * BN_mod_inverse() will call bn_mod_inverse_no_branch.
+ */
+#define BN_FLG_CONSTTIME 0x04
+#define BN_FLG_SECURE 0x08
+
+#ifndef OPENSSL_NO_DEPRECATED_0_9_8
+/* deprecated name for the flag */
+#define BN_FLG_EXP_CONSTTIME BN_FLG_CONSTTIME
+#define BN_FLG_FREE 0x8000 /* used for debugging */
+#endif
+
+void BN_set_flags(BIGNUM *b, int n);
+int BN_get_flags(const BIGNUM *b, int n);
+
+/* Values for |top| in BN_rand() */
+#define BN_RAND_TOP_ANY -1
+#define BN_RAND_TOP_ONE 0
+#define BN_RAND_TOP_TWO 1
+
+/* Values for |bottom| in BN_rand() */
+#define BN_RAND_BOTTOM_ANY 0
+#define BN_RAND_BOTTOM_ODD 1
+
+/*
+ * get a clone of a BIGNUM with changed flags, for *temporary* use only (the
+ * two BIGNUMs cannot be used in parallel!). Also only for *read only* use. The
+ * value |dest| should be a newly allocated BIGNUM obtained via BN_new() that
+ * has not been otherwise initialised or used.
+ */
+void BN_with_flags(BIGNUM *dest, const BIGNUM *b, int flags);
+
+/* Wrapper function to make using BN_GENCB easier */
+int BN_GENCB_call(BN_GENCB *cb, int a, int b);
+
+BN_GENCB *BN_GENCB_new(void);
+void BN_GENCB_free(BN_GENCB *cb);
+
+/* Populate a BN_GENCB structure with an "old"-style callback */
+void BN_GENCB_set_old(BN_GENCB *gencb, void (*callback)(int, int, void *),
+ void *cb_arg);
+
+/* Populate a BN_GENCB structure with a "new"-style callback */
+void BN_GENCB_set(BN_GENCB *gencb, int (*callback)(int, int, BN_GENCB *),
+ void *cb_arg);
+
+void *BN_GENCB_get_arg(BN_GENCB *cb);
+
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+#define BN_prime_checks 0 /* default: select number of iterations based \
+ * on the size of the number */
+
+/*
+ * BN_prime_checks_for_size() returns the number of Miller-Rabin iterations
+ * that will be done for checking that a random number is probably prime. The
+ * error rate for accepting a composite number as prime depends on the size of
+ * the prime |b|. The error rates used are for calculating an RSA key with 2 primes,
+ * and so the level is what you would expect for a key of double the size of the
+ * prime.
+ *
+ * This table is generated using the algorithm of FIPS PUB 186-4
+ * Digital Signature Standard (DSS), section F.1, page 117.
+ * (https://dx.doi.org/10.6028/NIST.FIPS.186-4)
+ *
+ * The following magma script was used to generate the output:
+ * securitybits:=125;
+ * k:=1024;
+ * for t:=1 to 65 do
+ * for M:=3 to Floor(2*Sqrt(k-1)-1) do
+ * S:=0;
+ * // Sum over m
+ * for m:=3 to M do
+ * s:=0;
+ * // Sum over j
+ * for j:=2 to m do
+ * s+:=(RealField(32)!2)^-(j+(k-1)/j);
+ * end for;
+ * S+:=2^(m-(m-1)*t)*s;
+ * end for;
+ * A:=2^(k-2-M*t);
+ * B:=8*(Pi(RealField(32))^2-6)/3*2^(k-2)*S;
+ * pkt:=2.00743*Log(2)*k*2^-k*(A+B);
+ * seclevel:=Floor(-Log(2,pkt));
+ * if seclevel ge securitybits then
+ * printf "k: %5o, security: %o bits (t: %o, M: %o)\n",k,seclevel,t,M;
+ * break;
+ * end if;
+ * end for;
+ * if seclevel ge securitybits then break; end if;
+ * end for;
+ *
+ * It can be run online at:
+ * http://magma.maths.usyd.edu.au/calc
+ *
+ * And will output:
+ * k: 1024, security: 129 bits (t: 6, M: 23)
+ *
+ * k is the number of bits of the prime, securitybits is the level we want to
+ * reach.
+ *
+ * prime length | RSA key size | # MR tests | security level
+ * -------------+--------------|------------+---------------
+ * (b) >= 6394 | >= 12788 | 3 | 256 bit
+ * (b) >= 3747 | >= 7494 | 3 | 192 bit
+ * (b) >= 1345 | >= 2690 | 4 | 128 bit
+ * (b) >= 1080 | >= 2160 | 5 | 128 bit
+ * (b) >= 852 | >= 1704 | 5 | 112 bit
+ * (b) >= 476 | >= 952 | 5 | 80 bit
+ * (b) >= 400 | >= 800 | 6 | 80 bit
+ * (b) >= 347 | >= 694 | 7 | 80 bit
+ * (b) >= 308 | >= 616 | 8 | 80 bit
+ * (b) >= 55 | >= 110 | 27 | 64 bit
+ * (b) >= 6 | >= 12 | 34 | 64 bit
+ */
+
+#define BN_prime_checks_for_size(b) ((b) >= 3747 ? 3 : (b) >= 1345 ? 4 \
+ : (b) >= 476 ? 5 \
+ : (b) >= 400 ? 6 \
+ : (b) >= 347 ? 7 \
+ : (b) >= 308 ? 8 \
+ : (b) >= 55 ? 27 \
+ : /* b >= 6 */ 34)
+#endif
+
+#define BN_num_bytes(a) ((BN_num_bits(a) + 7) / 8)
+
+int BN_abs_is_word(const BIGNUM *a, const BN_ULONG w);
+int BN_is_zero(const BIGNUM *a);
+int BN_is_one(const BIGNUM *a);
+int BN_is_word(const BIGNUM *a, const BN_ULONG w);
+int BN_is_odd(const BIGNUM *a);
+
+#define BN_one(a) (BN_set_word((a), 1))
+
+void BN_zero_ex(BIGNUM *a);
+
+#if OPENSSL_API_LEVEL > 908
+#define BN_zero(a) BN_zero_ex(a)
+#else
+#define BN_zero(a) (BN_set_word((a), 0))
+#endif
+
+const BIGNUM *BN_value_one(void);
+char *BN_options(void);
+BN_CTX *BN_CTX_new_ex(OSSL_LIB_CTX *ctx);
+BN_CTX *BN_CTX_new(void);
+BN_CTX *BN_CTX_secure_new_ex(OSSL_LIB_CTX *ctx);
+BN_CTX *BN_CTX_secure_new(void);
+void BN_CTX_free(BN_CTX *c);
+void BN_CTX_start(BN_CTX *ctx);
+BIGNUM *BN_CTX_get(BN_CTX *ctx);
+void BN_CTX_end(BN_CTX *ctx);
+int BN_rand_ex(BIGNUM *rnd, int bits, int top, int bottom,
+ unsigned int strength, BN_CTX *ctx);
+int BN_rand(BIGNUM *rnd, int bits, int top, int bottom);
+int BN_priv_rand_ex(BIGNUM *rnd, int bits, int top, int bottom,
+ unsigned int strength, BN_CTX *ctx);
+int BN_priv_rand(BIGNUM *rnd, int bits, int top, int bottom);
+int BN_rand_range_ex(BIGNUM *r, const BIGNUM *range, unsigned int strength,
+ BN_CTX *ctx);
+int BN_rand_range(BIGNUM *rnd, const BIGNUM *range);
+int BN_priv_rand_range_ex(BIGNUM *r, const BIGNUM *range,
+ unsigned int strength, BN_CTX *ctx);
+int BN_priv_rand_range(BIGNUM *rnd, const BIGNUM *range);
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+OSSL_DEPRECATEDIN_3_0
+int BN_pseudo_rand(BIGNUM *rnd, int bits, int top, int bottom);
+OSSL_DEPRECATEDIN_3_0
+int BN_pseudo_rand_range(BIGNUM *rnd, const BIGNUM *range);
+#endif
+int BN_num_bits(const BIGNUM *a);
+int BN_num_bits_word(BN_ULONG l);
+int BN_security_bits(int L, int N);
+BIGNUM *BN_new(void);
+BIGNUM *BN_secure_new(void);
+void BN_clear_free(BIGNUM *a);
+BIGNUM *BN_copy(BIGNUM *a, const BIGNUM *b);
+void BN_swap(BIGNUM *a, BIGNUM *b);
+BIGNUM *BN_bin2bn(const unsigned char *s, int len, BIGNUM *ret);
+BIGNUM *BN_signed_bin2bn(const unsigned char *s, int len, BIGNUM *ret);
+int BN_bn2bin(const BIGNUM *a, unsigned char *to);
+int BN_bn2binpad(const BIGNUM *a, unsigned char *to, int tolen);
+int BN_signed_bn2bin(const BIGNUM *a, unsigned char *to, int tolen);
+BIGNUM *BN_lebin2bn(const unsigned char *s, int len, BIGNUM *ret);
+BIGNUM *BN_signed_lebin2bn(const unsigned char *s, int len, BIGNUM *ret);
+int BN_bn2lebinpad(const BIGNUM *a, unsigned char *to, int tolen);
+int BN_signed_bn2lebin(const BIGNUM *a, unsigned char *to, int tolen);
+BIGNUM *BN_native2bn(const unsigned char *s, int len, BIGNUM *ret);
+BIGNUM *BN_signed_native2bn(const unsigned char *s, int len, BIGNUM *ret);
+int BN_bn2nativepad(const BIGNUM *a, unsigned char *to, int tolen);
+int BN_signed_bn2native(const BIGNUM *a, unsigned char *to, int tolen);
+BIGNUM *BN_mpi2bn(const unsigned char *s, int len, BIGNUM *ret);
+int BN_bn2mpi(const BIGNUM *a, unsigned char *to);
+int BN_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b);
+int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b);
+int BN_uadd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b);
+int BN_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b);
+int BN_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx);
+int BN_sqr(BIGNUM *r, const BIGNUM *a, BN_CTX *ctx);
+/** BN_set_negative sets sign of a BIGNUM
+ * \param b pointer to the BIGNUM object
+ * \param n 0 if the BIGNUM b should be positive and a value != 0 otherwise
+ */
+void BN_set_negative(BIGNUM *b, int n);
+/** BN_is_negative returns 1 if the BIGNUM is negative
+ * \param b pointer to the BIGNUM object
+ * \return 1 if a < 0 and 0 otherwise
+ */
+int BN_is_negative(const BIGNUM *b);
+
+int BN_div(BIGNUM *dv, BIGNUM *rem, const BIGNUM *m, const BIGNUM *d,
+ BN_CTX *ctx);
+#define BN_mod(rem, a, m, ctx) BN_div(NULL, (rem), (a), (m), (ctx))
+int BN_nnmod(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, BN_CTX *ctx);
+int BN_mod_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m,
+ BN_CTX *ctx);
+int BN_mod_add_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
+ const BIGNUM *m);
+int BN_mod_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m,
+ BN_CTX *ctx);
+int BN_mod_sub_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
+ const BIGNUM *m);
+int BN_mod_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m,
+ BN_CTX *ctx);
+int BN_mod_sqr(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, BN_CTX *ctx);
+int BN_mod_lshift1(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, BN_CTX *ctx);
+int BN_mod_lshift1_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *m);
+int BN_mod_lshift(BIGNUM *r, const BIGNUM *a, int n, const BIGNUM *m,
+ BN_CTX *ctx);
+int BN_mod_lshift_quick(BIGNUM *r, const BIGNUM *a, int n, const BIGNUM *m);
+
+BN_ULONG BN_mod_word(const BIGNUM *a, BN_ULONG w);
+BN_ULONG BN_div_word(BIGNUM *a, BN_ULONG w);
+int BN_mul_word(BIGNUM *a, BN_ULONG w);
+int BN_add_word(BIGNUM *a, BN_ULONG w);
+int BN_sub_word(BIGNUM *a, BN_ULONG w);
+int BN_set_word(BIGNUM *a, BN_ULONG w);
+BN_ULONG BN_get_word(const BIGNUM *a);
+
+int BN_cmp(const BIGNUM *a, const BIGNUM *b);
+void BN_free(BIGNUM *a);
+int BN_is_bit_set(const BIGNUM *a, int n);
+int BN_lshift(BIGNUM *r, const BIGNUM *a, int n);
+int BN_lshift1(BIGNUM *r, const BIGNUM *a);
+int BN_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx);
+
+int BN_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
+ const BIGNUM *m, BN_CTX *ctx);
+int BN_mod_exp_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
+ const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx);
+int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
+ const BIGNUM *m, BN_CTX *ctx,
+ BN_MONT_CTX *in_mont);
+int BN_mod_exp_mont_word(BIGNUM *r, BN_ULONG a, const BIGNUM *p,
+ const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx);
+int BN_mod_exp2_mont(BIGNUM *r, const BIGNUM *a1, const BIGNUM *p1,
+ const BIGNUM *a2, const BIGNUM *p2, const BIGNUM *m,
+ BN_CTX *ctx, BN_MONT_CTX *m_ctx);
+int BN_mod_exp_simple(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
+ const BIGNUM *m, BN_CTX *ctx);
+int BN_mod_exp_mont_consttime_x2(BIGNUM *rr1, const BIGNUM *a1, const BIGNUM *p1,
+ const BIGNUM *m1, BN_MONT_CTX *in_mont1,
+ BIGNUM *rr2, const BIGNUM *a2, const BIGNUM *p2,
+ const BIGNUM *m2, BN_MONT_CTX *in_mont2,
+ BN_CTX *ctx);
+
+int BN_mask_bits(BIGNUM *a, int n);
+#ifndef OPENSSL_NO_STDIO
+int BN_print_fp(FILE *fp, const BIGNUM *a);
+#endif
+int BN_print(BIO *bio, const BIGNUM *a);
+int BN_reciprocal(BIGNUM *r, const BIGNUM *m, int len, BN_CTX *ctx);
+int BN_rshift(BIGNUM *r, const BIGNUM *a, int n);
+int BN_rshift1(BIGNUM *r, const BIGNUM *a);
+void BN_clear(BIGNUM *a);
+BIGNUM *BN_dup(const BIGNUM *a);
+int BN_ucmp(const BIGNUM *a, const BIGNUM *b);
+int BN_set_bit(BIGNUM *a, int n);
+int BN_clear_bit(BIGNUM *a, int n);
+char *BN_bn2hex(const BIGNUM *a);
+char *BN_bn2dec(const BIGNUM *a);
+int BN_hex2bn(BIGNUM **a, const char *str);
+int BN_dec2bn(BIGNUM **a, const char *str);
+int BN_asc2bn(BIGNUM **a, const char *str);
+int BN_gcd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx);
+int BN_kronecker(const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx); /* returns
+ * -2 for
+ * error */
+int BN_are_coprime(BIGNUM *a, const BIGNUM *b, BN_CTX *ctx);
+BIGNUM *BN_mod_inverse(BIGNUM *ret,
+ const BIGNUM *a, const BIGNUM *n, BN_CTX *ctx);
+BIGNUM *BN_mod_sqrt(BIGNUM *ret,
+ const BIGNUM *a, const BIGNUM *n, BN_CTX *ctx);
+
+void BN_consttime_swap(BN_ULONG swap, BIGNUM *a, BIGNUM *b, int nwords);
+
+/* Deprecated versions */
+#ifndef OPENSSL_NO_DEPRECATED_0_9_8
+OSSL_DEPRECATEDIN_0_9_8
+BIGNUM *BN_generate_prime(BIGNUM *ret, int bits, int safe,
+ const BIGNUM *add, const BIGNUM *rem,
+ void (*callback)(int, int, void *),
+ void *cb_arg);
+OSSL_DEPRECATEDIN_0_9_8
+int BN_is_prime(const BIGNUM *p, int nchecks,
+ void (*callback)(int, int, void *),
+ BN_CTX *ctx, void *cb_arg);
+OSSL_DEPRECATEDIN_0_9_8
+int BN_is_prime_fasttest(const BIGNUM *p, int nchecks,
+ void (*callback)(int, int, void *),
+ BN_CTX *ctx, void *cb_arg,
+ int do_trial_division);
+#endif
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+OSSL_DEPRECATEDIN_3_0
+int BN_is_prime_ex(const BIGNUM *p, int nchecks, BN_CTX *ctx, BN_GENCB *cb);
+OSSL_DEPRECATEDIN_3_0
+int BN_is_prime_fasttest_ex(const BIGNUM *p, int nchecks, BN_CTX *ctx,
+ int do_trial_division, BN_GENCB *cb);
+#endif
+/* Newer versions */
+int BN_generate_prime_ex2(BIGNUM *ret, int bits, int safe,
+ const BIGNUM *add, const BIGNUM *rem, BN_GENCB *cb,
+ BN_CTX *ctx);
+int BN_generate_prime_ex(BIGNUM *ret, int bits, int safe, const BIGNUM *add,
+ const BIGNUM *rem, BN_GENCB *cb);
+int BN_check_prime(const BIGNUM *p, BN_CTX *ctx, BN_GENCB *cb);
+
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+OSSL_DEPRECATEDIN_3_0
+int BN_X931_generate_Xpq(BIGNUM *Xp, BIGNUM *Xq, int nbits, BN_CTX *ctx);
+
+OSSL_DEPRECATEDIN_3_0
+int BN_X931_derive_prime_ex(BIGNUM *p, BIGNUM *p1, BIGNUM *p2,
+ const BIGNUM *Xp, const BIGNUM *Xp1,
+ const BIGNUM *Xp2, const BIGNUM *e, BN_CTX *ctx,
+ BN_GENCB *cb);
+OSSL_DEPRECATEDIN_3_0
+int BN_X931_generate_prime_ex(BIGNUM *p, BIGNUM *p1, BIGNUM *p2, BIGNUM *Xp1,
+ BIGNUM *Xp2, const BIGNUM *Xp, const BIGNUM *e,
+ BN_CTX *ctx, BN_GENCB *cb);
+#endif
+
+BN_MONT_CTX *BN_MONT_CTX_new(void);
+int BN_mod_mul_montgomery(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
+ BN_MONT_CTX *mont, BN_CTX *ctx);
+int BN_to_montgomery(BIGNUM *r, const BIGNUM *a, BN_MONT_CTX *mont,
+ BN_CTX *ctx);
+int BN_from_montgomery(BIGNUM *r, const BIGNUM *a, BN_MONT_CTX *mont,
+ BN_CTX *ctx);
+void BN_MONT_CTX_free(BN_MONT_CTX *mont);
+int BN_MONT_CTX_set(BN_MONT_CTX *mont, const BIGNUM *mod, BN_CTX *ctx);
+BN_MONT_CTX *BN_MONT_CTX_copy(BN_MONT_CTX *to, BN_MONT_CTX *from);
+BN_MONT_CTX *BN_MONT_CTX_set_locked(BN_MONT_CTX **pmont, CRYPTO_RWLOCK *lock,
+ const BIGNUM *mod, BN_CTX *ctx);
+
+/* BN_BLINDING flags */
+#define BN_BLINDING_NO_UPDATE 0x00000001
+#define BN_BLINDING_NO_RECREATE 0x00000002
+
+BN_BLINDING *BN_BLINDING_new(const BIGNUM *A, const BIGNUM *Ai, BIGNUM *mod);
+void BN_BLINDING_free(BN_BLINDING *b);
+int BN_BLINDING_update(BN_BLINDING *b, BN_CTX *ctx);
+int BN_BLINDING_convert(BIGNUM *n, BN_BLINDING *b, BN_CTX *ctx);
+int BN_BLINDING_invert(BIGNUM *n, BN_BLINDING *b, BN_CTX *ctx);
+int BN_BLINDING_convert_ex(BIGNUM *n, BIGNUM *r, BN_BLINDING *b, BN_CTX *);
+int BN_BLINDING_invert_ex(BIGNUM *n, const BIGNUM *r, BN_BLINDING *b,
+ BN_CTX *);
+
+int BN_BLINDING_is_current_thread(BN_BLINDING *b);
+void BN_BLINDING_set_current_thread(BN_BLINDING *b);
+int BN_BLINDING_lock(BN_BLINDING *b);
+int BN_BLINDING_unlock(BN_BLINDING *b);
+
+unsigned long BN_BLINDING_get_flags(const BN_BLINDING *);
+void BN_BLINDING_set_flags(BN_BLINDING *, unsigned long);
+BN_BLINDING *BN_BLINDING_create_param(BN_BLINDING *b,
+ const BIGNUM *e, BIGNUM *m, BN_CTX *ctx,
+ int (*bn_mod_exp)(BIGNUM *r,
+ const BIGNUM *a,
+ const BIGNUM *p,
+ const BIGNUM *m,
+ BN_CTX *ctx,
+ BN_MONT_CTX *m_ctx),
+ BN_MONT_CTX *m_ctx);
+#ifndef OPENSSL_NO_DEPRECATED_0_9_8
+OSSL_DEPRECATEDIN_0_9_8
+void BN_set_params(int mul, int high, int low, int mont);
+OSSL_DEPRECATEDIN_0_9_8
+int BN_get_params(int which); /* 0, mul, 1 high, 2 low, 3 mont */
+#endif
+
+BN_RECP_CTX *BN_RECP_CTX_new(void);
+void BN_RECP_CTX_free(BN_RECP_CTX *recp);
+int BN_RECP_CTX_set(BN_RECP_CTX *recp, const BIGNUM *rdiv, BN_CTX *ctx);
+int BN_mod_mul_reciprocal(BIGNUM *r, const BIGNUM *x, const BIGNUM *y,
+ BN_RECP_CTX *recp, BN_CTX *ctx);
+int BN_mod_exp_recp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
+ const BIGNUM *m, BN_CTX *ctx);
+int BN_div_recp(BIGNUM *dv, BIGNUM *rem, const BIGNUM *m,
+ BN_RECP_CTX *recp, BN_CTX *ctx);
+
+#ifndef OPENSSL_NO_EC2M
+
+/*
+ * Functions for arithmetic over binary polynomials represented by BIGNUMs.
+ * The BIGNUM::neg property of BIGNUMs representing binary polynomials is
+ * ignored. Note that input arguments are not const so that their bit arrays
+ * can be expanded to the appropriate size if needed.
+ */
+
+/*
+ * r = a + b
+ */
+int BN_GF2m_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b);
+#define BN_GF2m_sub(r, a, b) BN_GF2m_add(r, a, b)
+/*
+ * r=a mod p
+ */
+int BN_GF2m_mod(BIGNUM *r, const BIGNUM *a, const BIGNUM *p);
+/* r = (a * b) mod p */
+int BN_GF2m_mod_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
+ const BIGNUM *p, BN_CTX *ctx);
+/* r = (a * a) mod p */
+int BN_GF2m_mod_sqr(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx);
+/* r = (1 / b) mod p */
+int BN_GF2m_mod_inv(BIGNUM *r, const BIGNUM *b, const BIGNUM *p, BN_CTX *ctx);
+/* r = (a / b) mod p */
+int BN_GF2m_mod_div(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
+ const BIGNUM *p, BN_CTX *ctx);
+/* r = (a ^ b) mod p */
+int BN_GF2m_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
+ const BIGNUM *p, BN_CTX *ctx);
+/* r = sqrt(a) mod p */
+int BN_GF2m_mod_sqrt(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
+ BN_CTX *ctx);
+/* r^2 + r = a mod p */
+int BN_GF2m_mod_solve_quad(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
+ BN_CTX *ctx);
+#define BN_GF2m_cmp(a, b) BN_ucmp((a), (b))
+/*-
+ * Some functions allow for representation of the irreducible polynomials
+ * as an unsigned int[], say p. The irreducible f(t) is then of the form:
+ * t^p[0] + t^p[1] + ... + t^p[k]
+ * where m = p[0] > p[1] > ... > p[k] = 0.
+ */
+/* r = a mod p */
+int BN_GF2m_mod_arr(BIGNUM *r, const BIGNUM *a, const int p[]);
+/* r = (a * b) mod p */
+int BN_GF2m_mod_mul_arr(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
+ const int p[], BN_CTX *ctx);
+/* r = (a * a) mod p */
+int BN_GF2m_mod_sqr_arr(BIGNUM *r, const BIGNUM *a, const int p[],
+ BN_CTX *ctx);
+/* r = (1 / b) mod p */
+int BN_GF2m_mod_inv_arr(BIGNUM *r, const BIGNUM *b, const int p[],
+ BN_CTX *ctx);
+/* r = (a / b) mod p */
+int BN_GF2m_mod_div_arr(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
+ const int p[], BN_CTX *ctx);
+/* r = (a ^ b) mod p */
+int BN_GF2m_mod_exp_arr(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
+ const int p[], BN_CTX *ctx);
+/* r = sqrt(a) mod p */
+int BN_GF2m_mod_sqrt_arr(BIGNUM *r, const BIGNUM *a,
+ const int p[], BN_CTX *ctx);
+/* r^2 + r = a mod p */
+int BN_GF2m_mod_solve_quad_arr(BIGNUM *r, const BIGNUM *a,
+ const int p[], BN_CTX *ctx);
+int BN_GF2m_poly2arr(const BIGNUM *a, int p[], int max);
+int BN_GF2m_arr2poly(const int p[], BIGNUM *a);
+
+#endif
+
+/*
+ * faster mod functions for the 'NIST primes' 0 <= a < p^2
+ */
+int BN_nist_mod_192(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx);
+int BN_nist_mod_224(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx);
+int BN_nist_mod_256(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx);
+int BN_nist_mod_384(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx);
+int BN_nist_mod_521(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx);
+
+const BIGNUM *BN_get0_nist_prime_192(void);
+const BIGNUM *BN_get0_nist_prime_224(void);
+const BIGNUM *BN_get0_nist_prime_256(void);
+const BIGNUM *BN_get0_nist_prime_384(void);
+const BIGNUM *BN_get0_nist_prime_521(void);
+
+int (*BN_nist_mod_func(const BIGNUM *p))(BIGNUM *r, const BIGNUM *a,
+ const BIGNUM *field, BN_CTX *ctx);
+
+int BN_generate_dsa_nonce(BIGNUM *out, const BIGNUM *range,
+ const BIGNUM *priv, const unsigned char *message,
+ size_t message_len, BN_CTX *ctx);
+
+/* Primes from RFC 2409 */
+BIGNUM *BN_get_rfc2409_prime_768(BIGNUM *bn);
+BIGNUM *BN_get_rfc2409_prime_1024(BIGNUM *bn);
+
+/* Primes from RFC 3526 */
+BIGNUM *BN_get_rfc3526_prime_1536(BIGNUM *bn);
+BIGNUM *BN_get_rfc3526_prime_2048(BIGNUM *bn);
+BIGNUM *BN_get_rfc3526_prime_3072(BIGNUM *bn);
+BIGNUM *BN_get_rfc3526_prime_4096(BIGNUM *bn);
+BIGNUM *BN_get_rfc3526_prime_6144(BIGNUM *bn);
+BIGNUM *BN_get_rfc3526_prime_8192(BIGNUM *bn);
+
+#ifndef OPENSSL_NO_DEPRECATED_1_1_0
+#define get_rfc2409_prime_768 BN_get_rfc2409_prime_768
+#define get_rfc2409_prime_1024 BN_get_rfc2409_prime_1024
+#define get_rfc3526_prime_1536 BN_get_rfc3526_prime_1536
+#define get_rfc3526_prime_2048 BN_get_rfc3526_prime_2048
+#define get_rfc3526_prime_3072 BN_get_rfc3526_prime_3072
+#define get_rfc3526_prime_4096 BN_get_rfc3526_prime_4096
+#define get_rfc3526_prime_6144 BN_get_rfc3526_prime_6144
+#define get_rfc3526_prime_8192 BN_get_rfc3526_prime_8192
+#endif
+
+int BN_bntest_rand(BIGNUM *rnd, int bits, int top, int bottom);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/third_party/ios/openssl/include/openssl/bnerr.h b/third_party/ios/openssl/include/openssl/bnerr.h
new file mode 100644
index 0000000..dbbcd69
--- /dev/null
+++ b/third_party/ios/openssl/include/openssl/bnerr.h
@@ -0,0 +1,45 @@
+/*
+ * Generated by util/mkerr.pl DO NOT EDIT
+ * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#ifndef OPENSSL_BNERR_H
+#define OPENSSL_BNERR_H
+#pragma once
+
+#include
+#include
+#include
+
+/*
+ * BN reason codes.
+ */
+#define BN_R_ARG2_LT_ARG3 100
+#define BN_R_BAD_RECIPROCAL 101
+#define BN_R_BIGNUM_TOO_LONG 114
+#define BN_R_BITS_TOO_SMALL 118
+#define BN_R_CALLED_WITH_EVEN_MODULUS 102
+#define BN_R_DIV_BY_ZERO 103
+#define BN_R_ENCODING_ERROR 104
+#define BN_R_EXPAND_ON_STATIC_BIGNUM_DATA 105
+#define BN_R_INPUT_NOT_REDUCED 110
+#define BN_R_INVALID_LENGTH 106
+#define BN_R_INVALID_RANGE 115
+#define BN_R_INVALID_SHIFT 119
+#define BN_R_NOT_A_SQUARE 111
+#define BN_R_NOT_INITIALIZED 107
+#define BN_R_NO_INVERSE 108
+#define BN_R_NO_PRIME_CANDIDATE 121
+#define BN_R_NO_SOLUTION 116
+#define BN_R_NO_SUITABLE_DIGEST 120
+#define BN_R_PRIVATE_KEY_TOO_LARGE 117
+#define BN_R_P_IS_NOT_PRIME 112
+#define BN_R_TOO_MANY_ITERATIONS 113
+#define BN_R_TOO_MANY_TEMPORARY_VARIABLES 109
+
+#endif
diff --git a/third_party/ios/openssl/include/openssl/buffer.h b/third_party/ios/openssl/include/openssl/buffer.h
new file mode 100644
index 0000000..09b35e8
--- /dev/null
+++ b/third_party/ios/openssl/include/openssl/buffer.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#ifndef OPENSSL_BUFFER_H
+#define OPENSSL_BUFFER_H
+#pragma once
+
+#include
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+#define HEADER_BUFFER_H
+#endif
+
+#include
+#ifndef OPENSSL_CRYPTO_H
+#include
+#endif
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include
+#include
+
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+#define BUF_strdup(s) OPENSSL_strdup(s)
+#define BUF_strndup(s, size) OPENSSL_strndup(s, size)
+#define BUF_memdup(data, size) OPENSSL_memdup(data, size)
+#define BUF_strlcpy(dst, src, size) OPENSSL_strlcpy(dst, src, size)
+#define BUF_strlcat(dst, src, size) OPENSSL_strlcat(dst, src, size)
+#define BUF_strnlen(str, maxlen) OPENSSL_strnlen(str, maxlen)
+#endif
+
+struct buf_mem_st {
+ size_t length; /* current number of bytes */
+ char *data;
+ size_t max; /* size of buffer */
+ unsigned long flags;
+};
+
+#define BUF_MEM_FLAG_SECURE 0x01
+
+BUF_MEM *BUF_MEM_new(void);
+BUF_MEM *BUF_MEM_new_ex(unsigned long flags);
+void BUF_MEM_free(BUF_MEM *a);
+size_t BUF_MEM_grow(BUF_MEM *str, size_t len);
+size_t BUF_MEM_grow_clean(BUF_MEM *str, size_t len);
+void BUF_reverse(unsigned char *out, const unsigned char *in, size_t siz);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/third_party/ios/openssl/include/openssl/buffererr.h b/third_party/ios/openssl/include/openssl/buffererr.h
new file mode 100644
index 0000000..4fa0da4
--- /dev/null
+++ b/third_party/ios/openssl/include/openssl/buffererr.h
@@ -0,0 +1,23 @@
+/*
+ * Generated by util/mkerr.pl DO NOT EDIT
+ * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#ifndef OPENSSL_BUFFERERR_H
+#define OPENSSL_BUFFERERR_H
+#pragma once
+
+#include
+#include
+#include
+
+/*
+ * BUF reason codes.
+ */
+
+#endif
diff --git a/third_party/ios/openssl/include/openssl/byteorder.h b/third_party/ios/openssl/include/openssl/byteorder.h
new file mode 100644
index 0000000..393f34b
--- /dev/null
+++ b/third_party/ios/openssl/include/openssl/byteorder.h
@@ -0,0 +1,339 @@
+/*
+ * Copyright 2025 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#ifndef OPENSSL_BYTEORDER_H
+#define OPENSSL_BYTEORDER_H
+#pragma once
+
+#include
+#include
+
+/*
+ * "Modern" compilers do a decent job of optimising these functions to just a
+ * couple of instruction ([swap +] store, or load [+ swap]) when either no
+ * swapping is required, or a suitable swap instruction is available.
+ */
+
+#if defined(_MSC_VER) && _MSC_VER >= 1300
+#include
+#pragma intrinsic(_byteswap_ushort)
+#pragma intrinsic(_byteswap_ulong)
+#pragma intrinsic(_byteswap_uint64)
+#define OSSL_HTOBE16(x) _byteswap_ushort(x)
+#define OSSL_HTOBE32(x) _byteswap_ulong(x)
+#define OSSL_HTOBE64(x) _byteswap_uint64(x)
+#define OSSL_BE16TOH(x) _byteswap_ushort(x)
+#define OSSL_BE32TOH(x) _byteswap_ulong(x)
+#define OSSL_BE64TOH(x) _byteswap_uint64(x)
+#define OSSL_HTOLE16(x) (x)
+#define OSSL_HTOLE32(x) (x)
+#define OSSL_HTOLE64(x) (x)
+#define OSSL_LE16TOH(x) (x)
+#define OSSL_LE32TOH(x) (x)
+#define OSSL_LE64TOH(x) (x)
+
+#elif defined(__GLIBC__) && defined(__GLIBC_PREREQ)
+#if (__GLIBC_PREREQ(2, 19)) && defined(_DEFAULT_SOURCE)
+#include
+#define OSSL_HTOBE16(x) htobe16(x)
+#define OSSL_HTOBE32(x) htobe32(x)
+#define OSSL_HTOBE64(x) htobe64(x)
+#define OSSL_BE16TOH(x) be16toh(x)
+#define OSSL_BE32TOH(x) be32toh(x)
+#define OSSL_BE64TOH(x) be64toh(x)
+#define OSSL_HTOLE16(x) htole16(x)
+#define OSSL_HTOLE32(x) htole32(x)
+#define OSSL_HTOLE64(x) htole64(x)
+#define OSSL_LE16TOH(x) le16toh(x)
+#define OSSL_LE32TOH(x) le32toh(x)
+#define OSSL_LE64TOH(x) le64toh(x)
+#endif
+
+#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
+#if defined(__OpenBSD__)
+#include
+#else
+#include
+#endif
+#define OSSL_HTOBE16(x) htobe16(x)
+#define OSSL_HTOBE32(x) htobe32(x)
+#define OSSL_HTOBE64(x) htobe64(x)
+#define OSSL_BE16TOH(x) be16toh(x)
+#define OSSL_BE32TOH(x) be32toh(x)
+#define OSSL_BE64TOH(x) be64toh(x)
+#define OSSL_HTOLE16(x) htole16(x)
+#define OSSL_HTOLE32(x) htole32(x)
+#define OSSL_HTOLE64(x) htole64(x)
+#define OSSL_LE16TOH(x) le16toh(x)
+#define OSSL_LE32TOH(x) le32toh(x)
+#define OSSL_LE64TOH(x) le64toh(x)
+
+#elif defined(__APPLE__)
+#include
+#define OSSL_HTOBE16(x) OSSwapHostToBigInt16(x)
+#define OSSL_HTOBE32(x) OSSwapHostToBigInt32(x)
+#define OSSL_HTOBE64(x) OSSwapHostToBigInt64(x)
+#define OSSL_BE16TOH(x) OSSwapBigToHostInt16(x)
+#define OSSL_BE32TOH(x) OSSwapBigToHostInt32(x)
+#define OSSL_BE64TOH(x) OSSwapBigToHostInt64(x)
+#define OSSL_HTOLE16(x) OSSwapHostToLittleInt16(x)
+#define OSSL_HTOLE32(x) OSSwapHostToLittleInt32(x)
+#define OSSL_HTOLE64(x) OSSwapHostToLittleInt64(x)
+#define OSSL_LE16TOH(x) OSSwapLittleToHostInt16(x)
+#define OSSL_LE32TOH(x) OSSwapLittleToHostInt32(x)
+#define OSSL_LE64TOH(x) OSSwapLittleToHostInt64(x)
+
+#endif
+
+static ossl_inline ossl_unused unsigned char *
+OPENSSL_store_u16_le(unsigned char *out, uint16_t val)
+{
+#ifdef OSSL_HTOLE16
+ uint16_t t = OSSL_HTOLE16(val);
+
+ memcpy(out, (unsigned char *)&t, 2);
+ return out + 2;
+#else
+ *out++ = (val & 0xff);
+ *out++ = (val >> 8) & 0xff;
+ return out;
+#endif
+}
+
+static ossl_inline ossl_unused unsigned char *
+OPENSSL_store_u16_be(unsigned char *out, uint16_t val)
+{
+#ifdef OSSL_HTOBE16
+ uint16_t t = OSSL_HTOBE16(val);
+
+ memcpy(out, (unsigned char *)&t, 2);
+ return out + 2;
+#else
+ *out++ = (val >> 8) & 0xff;
+ *out++ = (val & 0xff);
+ return out;
+#endif
+}
+
+static ossl_inline ossl_unused unsigned char *
+OPENSSL_store_u32_le(unsigned char *out, uint32_t val)
+{
+#ifdef OSSL_HTOLE32
+ uint32_t t = OSSL_HTOLE32(val);
+
+ memcpy(out, (unsigned char *)&t, 4);
+ return out + 4;
+#else
+ *out++ = (val & 0xff);
+ *out++ = (val >> 8) & 0xff;
+ *out++ = (val >> 16) & 0xff;
+ *out++ = (val >> 24) & 0xff;
+ return out;
+#endif
+}
+
+static ossl_inline ossl_unused unsigned char *
+OPENSSL_store_u32_be(unsigned char *out, uint32_t val)
+{
+#ifdef OSSL_HTOBE32
+ uint32_t t = OSSL_HTOBE32(val);
+
+ memcpy(out, (unsigned char *)&t, 4);
+ return out + 4;
+#else
+ *out++ = (val >> 24) & 0xff;
+ *out++ = (val >> 16) & 0xff;
+ *out++ = (val >> 8) & 0xff;
+ *out++ = (val & 0xff);
+ return out;
+#endif
+}
+
+static ossl_inline ossl_unused unsigned char *
+OPENSSL_store_u64_le(unsigned char *out, uint64_t val)
+{
+#ifdef OSSL_HTOLE64
+ uint64_t t = OSSL_HTOLE64(val);
+
+ memcpy(out, (unsigned char *)&t, 8);
+ return out + 8;
+#else
+ *out++ = (val & 0xff);
+ *out++ = (val >> 8) & 0xff;
+ *out++ = (val >> 16) & 0xff;
+ *out++ = (val >> 24) & 0xff;
+ *out++ = (val >> 32) & 0xff;
+ *out++ = (val >> 40) & 0xff;
+ *out++ = (val >> 48) & 0xff;
+ *out++ = (val >> 56) & 0xff;
+ return out;
+#endif
+}
+
+static ossl_inline ossl_unused unsigned char *
+OPENSSL_store_u64_be(unsigned char *out, uint64_t val)
+{
+#ifdef OSSL_HTOLE64
+ uint64_t t = OSSL_HTOBE64(val);
+
+ memcpy(out, (unsigned char *)&t, 8);
+ return out + 8;
+#else
+ *out++ = (val >> 56) & 0xff;
+ *out++ = (val >> 48) & 0xff;
+ *out++ = (val >> 40) & 0xff;
+ *out++ = (val >> 32) & 0xff;
+ *out++ = (val >> 24) & 0xff;
+ *out++ = (val >> 16) & 0xff;
+ *out++ = (val >> 8) & 0xff;
+ *out++ = (val & 0xff);
+ return out;
+#endif
+}
+
+static ossl_inline ossl_unused const unsigned char *
+OPENSSL_load_u16_le(uint16_t *val, const unsigned char *in)
+{
+#ifdef OSSL_LE16TOH
+ uint16_t t;
+
+ memcpy((unsigned char *)&t, in, 2);
+ *val = OSSL_LE16TOH(t);
+ return in + 2;
+#else
+ uint16_t b0 = *in++;
+ uint16_t b1 = *in++;
+
+ *val = b0 | (b1 << 8);
+ return in;
+#endif
+}
+
+static ossl_inline ossl_unused const unsigned char *
+OPENSSL_load_u16_be(uint16_t *val, const unsigned char *in)
+{
+#ifdef OSSL_LE16TOH
+ uint16_t t;
+
+ memcpy((unsigned char *)&t, in, 2);
+ *val = OSSL_BE16TOH(t);
+ return in + 2;
+#else
+ uint16_t b1 = *in++;
+ uint16_t b0 = *in++;
+
+ *val = b0 | (b1 << 8);
+ return in;
+#endif
+}
+
+static ossl_inline ossl_unused const unsigned char *
+OPENSSL_load_u32_le(uint32_t *val, const unsigned char *in)
+{
+#ifdef OSSL_LE32TOH
+ uint32_t t;
+
+ memcpy((unsigned char *)&t, in, 4);
+ *val = OSSL_LE32TOH(t);
+ return in + 4;
+#else
+ uint32_t b0 = *in++;
+ uint32_t b1 = *in++;
+ uint32_t b2 = *in++;
+ uint32_t b3 = *in++;
+
+ *val = b0 | (b1 << 8) | (b2 << 16) | (b3 << 24);
+ return in;
+#endif
+}
+
+static ossl_inline ossl_unused const unsigned char *
+OPENSSL_load_u32_be(uint32_t *val, const unsigned char *in)
+{
+#ifdef OSSL_LE32TOH
+ uint32_t t;
+
+ memcpy((unsigned char *)&t, in, 4);
+ *val = OSSL_BE32TOH(t);
+ return in + 4;
+#else
+ uint32_t b3 = *in++;
+ uint32_t b2 = *in++;
+ uint32_t b1 = *in++;
+ uint32_t b0 = *in++;
+
+ *val = b0 | (b1 << 8) | (b2 << 16) | (b3 << 24);
+ return in;
+#endif
+}
+
+static ossl_inline ossl_unused const unsigned char *
+OPENSSL_load_u64_le(uint64_t *val, const unsigned char *in)
+{
+#ifdef OSSL_LE64TOH
+ uint64_t t;
+
+ memcpy((unsigned char *)&t, in, 8);
+ *val = OSSL_LE64TOH(t);
+ return in + 8;
+#else
+ uint64_t b0 = *in++;
+ uint64_t b1 = *in++;
+ uint64_t b2 = *in++;
+ uint64_t b3 = *in++;
+ uint64_t b4 = *in++;
+ uint64_t b5 = *in++;
+ uint64_t b6 = *in++;
+ uint64_t b7 = *in++;
+
+ *val = b0 | (b1 << 8) | (b2 << 16) | (b3 << 24)
+ | (b4 << 32) | (b5 << 40) | (b6 << 48) | (b7 << 56);
+ return in;
+#endif
+}
+
+static ossl_inline ossl_unused const unsigned char *
+OPENSSL_load_u64_be(uint64_t *val, const unsigned char *in)
+{
+#ifdef OSSL_LE64TOH
+ uint64_t t;
+
+ memcpy((unsigned char *)&t, in, 8);
+ *val = OSSL_BE64TOH(t);
+ return in + 8;
+#else
+ uint64_t b7 = *in++;
+ uint64_t b6 = *in++;
+ uint64_t b5 = *in++;
+ uint64_t b4 = *in++;
+ uint64_t b3 = *in++;
+ uint64_t b2 = *in++;
+ uint64_t b1 = *in++;
+ uint64_t b0 = *in++;
+
+ *val = b0 | (b1 << 8) | (b2 << 16) | (b3 << 24)
+ | (b4 << 32) | (b5 << 40) | (b6 << 48) | (b7 << 56);
+ return in;
+#endif
+}
+
+#undef OSSL_HTOBE16
+#undef OSSL_HTOBE32
+#undef OSSL_HTOBE64
+#undef OSSL_BE16TOH
+#undef OSSL_BE32TOH
+#undef OSSL_BE64TOH
+#undef OSSL_HTOLE16
+#undef OSSL_HTOLE32
+#undef OSSL_HTOLE64
+#undef OSSL_LE16TOH
+#undef OSSL_LE32TOH
+#undef OSSL_LE64TOH
+
+#endif
diff --git a/third_party/ios/openssl/include/openssl/camellia.h b/third_party/ios/openssl/include/openssl/camellia.h
new file mode 100644
index 0000000..aec94e4
--- /dev/null
+++ b/third_party/ios/openssl/include/openssl/camellia.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2006-2020 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#ifndef OPENSSL_CAMELLIA_H
+#define OPENSSL_CAMELLIA_H
+#pragma once
+
+#include
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+#define HEADER_CAMELLIA_H
+#endif
+
+#include
+
+#ifndef OPENSSL_NO_CAMELLIA
+#include
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define CAMELLIA_BLOCK_SIZE 16
+
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+
+#define CAMELLIA_ENCRYPT 1
+#define CAMELLIA_DECRYPT 0
+
+/*
+ * Because array size can't be a const in C, the following two are macros.
+ * Both sizes are in bytes.
+ */
+
+/* This should be a hidden type, but EVP requires that the size be known */
+
+#define CAMELLIA_TABLE_BYTE_LEN 272
+#define CAMELLIA_TABLE_WORD_LEN (CAMELLIA_TABLE_BYTE_LEN / 4)
+
+typedef unsigned int KEY_TABLE_TYPE[CAMELLIA_TABLE_WORD_LEN]; /* to match
+ * with WORD */
+
+struct camellia_key_st {
+ union {
+ double d; /* ensures 64-bit align */
+ KEY_TABLE_TYPE rd_key;
+ } u;
+ int grand_rounds;
+};
+typedef struct camellia_key_st CAMELLIA_KEY;
+
+#endif /* OPENSSL_NO_DEPRECATED_3_0 */
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+OSSL_DEPRECATEDIN_3_0 int Camellia_set_key(const unsigned char *userKey,
+ const int bits,
+ CAMELLIA_KEY *key);
+OSSL_DEPRECATEDIN_3_0 void Camellia_encrypt(const unsigned char *in,
+ unsigned char *out,
+ const CAMELLIA_KEY *key);
+OSSL_DEPRECATEDIN_3_0 void Camellia_decrypt(const unsigned char *in,
+ unsigned char *out,
+ const CAMELLIA_KEY *key);
+OSSL_DEPRECATEDIN_3_0 void Camellia_ecb_encrypt(const unsigned char *in,
+ unsigned char *out,
+ const CAMELLIA_KEY *key,
+ const int enc);
+OSSL_DEPRECATEDIN_3_0 void Camellia_cbc_encrypt(const unsigned char *in,
+ unsigned char *out,
+ size_t length,
+ const CAMELLIA_KEY *key,
+ unsigned char *ivec,
+ const int enc);
+OSSL_DEPRECATEDIN_3_0 void Camellia_cfb128_encrypt(const unsigned char *in,
+ unsigned char *out,
+ size_t length,
+ const CAMELLIA_KEY *key,
+ unsigned char *ivec,
+ int *num,
+ const int enc);
+OSSL_DEPRECATEDIN_3_0 void Camellia_cfb1_encrypt(const unsigned char *in,
+ unsigned char *out,
+ size_t length,
+ const CAMELLIA_KEY *key,
+ unsigned char *ivec,
+ int *num,
+ const int enc);
+OSSL_DEPRECATEDIN_3_0 void Camellia_cfb8_encrypt(const unsigned char *in,
+ unsigned char *out,
+ size_t length,
+ const CAMELLIA_KEY *key,
+ unsigned char *ivec,
+ int *num,
+ const int enc);
+OSSL_DEPRECATEDIN_3_0 void Camellia_ofb128_encrypt(const unsigned char *in,
+ unsigned char *out,
+ size_t length,
+ const CAMELLIA_KEY *key,
+ unsigned char *ivec,
+ int *num);
+OSSL_DEPRECATEDIN_3_0
+void Camellia_ctr128_encrypt(const unsigned char *in, unsigned char *out,
+ size_t length, const CAMELLIA_KEY *key,
+ unsigned char ivec[CAMELLIA_BLOCK_SIZE],
+ unsigned char ecount_buf[CAMELLIA_BLOCK_SIZE],
+ unsigned int *num);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
+#endif
diff --git a/third_party/ios/openssl/include/openssl/cast.h b/third_party/ios/openssl/include/openssl/cast.h
new file mode 100644
index 0000000..af94312
--- /dev/null
+++ b/third_party/ios/openssl/include/openssl/cast.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#ifndef OPENSSL_CAST_H
+#define OPENSSL_CAST_H
+#pragma once
+
+#include
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+#define HEADER_CAST_H
+#endif
+
+#include
+
+#ifndef OPENSSL_NO_CAST
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define CAST_BLOCK 8
+#define CAST_KEY_LENGTH 16
+
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+
+#define CAST_ENCRYPT 1
+#define CAST_DECRYPT 0
+
+#define CAST_LONG unsigned int
+
+typedef struct cast_key_st {
+ CAST_LONG data[32];
+ int short_key; /* Use reduced rounds for short key */
+} CAST_KEY;
+
+#endif /* OPENSSL_NO_DEPRECATED_3_0 */
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+OSSL_DEPRECATEDIN_3_0
+void CAST_set_key(CAST_KEY *key, int len, const unsigned char *data);
+OSSL_DEPRECATEDIN_3_0
+void CAST_ecb_encrypt(const unsigned char *in, unsigned char *out,
+ const CAST_KEY *key, int enc);
+OSSL_DEPRECATEDIN_3_0
+void CAST_encrypt(CAST_LONG *data, const CAST_KEY *key);
+OSSL_DEPRECATEDIN_3_0
+void CAST_decrypt(CAST_LONG *data, const CAST_KEY *key);
+OSSL_DEPRECATEDIN_3_0
+void CAST_cbc_encrypt(const unsigned char *in, unsigned char *out,
+ long length, const CAST_KEY *ks, unsigned char *iv,
+ int enc);
+OSSL_DEPRECATEDIN_3_0
+void CAST_cfb64_encrypt(const unsigned char *in, unsigned char *out,
+ long length, const CAST_KEY *schedule,
+ unsigned char *ivec, int *num, int enc);
+OSSL_DEPRECATEDIN_3_0
+void CAST_ofb64_encrypt(const unsigned char *in, unsigned char *out,
+ long length, const CAST_KEY *schedule,
+ unsigned char *ivec, int *num);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
+#endif
diff --git a/third_party/ios/openssl/include/openssl/cmac.h b/third_party/ios/openssl/include/openssl/cmac.h
new file mode 100644
index 0000000..c72da7e
--- /dev/null
+++ b/third_party/ios/openssl/include/openssl/cmac.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2010-2020 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#ifndef OPENSSL_CMAC_H
+#define OPENSSL_CMAC_H
+#pragma once
+
+#include
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+#define HEADER_CMAC_H
+#endif
+
+#ifndef OPENSSL_NO_CMAC
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include
+
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+/* Opaque */
+typedef struct CMAC_CTX_st CMAC_CTX;
+#endif
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+OSSL_DEPRECATEDIN_3_0 CMAC_CTX *CMAC_CTX_new(void);
+OSSL_DEPRECATEDIN_3_0 void CMAC_CTX_cleanup(CMAC_CTX *ctx);
+OSSL_DEPRECATEDIN_3_0 void CMAC_CTX_free(CMAC_CTX *ctx);
+OSSL_DEPRECATEDIN_3_0 EVP_CIPHER_CTX *CMAC_CTX_get0_cipher_ctx(CMAC_CTX *ctx);
+OSSL_DEPRECATEDIN_3_0 int CMAC_CTX_copy(CMAC_CTX *out, const CMAC_CTX *in);
+OSSL_DEPRECATEDIN_3_0 int CMAC_Init(CMAC_CTX *ctx,
+ const void *key, size_t keylen,
+ const EVP_CIPHER *cipher, ENGINE *impl);
+OSSL_DEPRECATEDIN_3_0 int CMAC_Update(CMAC_CTX *ctx,
+ const void *data, size_t dlen);
+OSSL_DEPRECATEDIN_3_0 int CMAC_Final(CMAC_CTX *ctx,
+ unsigned char *out, size_t *poutlen);
+OSSL_DEPRECATEDIN_3_0 int CMAC_resume(CMAC_CTX *ctx);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+#endif
diff --git a/third_party/ios/openssl/include/openssl/cmp.h b/third_party/ios/openssl/include/openssl/cmp.h
new file mode 100644
index 0000000..03a7f46
--- /dev/null
+++ b/third_party/ios/openssl/include/openssl/cmp.h
@@ -0,0 +1,741 @@
+/*
+ * WARNING: do not edit!
+ * Generated by Makefile from include/openssl/cmp.h.in
+ *
+ * Copyright 2007-2026 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright Nokia 2007-2019
+ * Copyright Siemens AG 2015-2019
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+/* clang-format off */
+
+/* clang-format on */
+
+#ifndef OPENSSL_CMP_H
+#define OPENSSL_CMP_H
+
+#include
+#ifndef OPENSSL_NO_CMP
+
+#include
+#include
+#include
+#include
+
+/* explicit #includes not strictly needed since implied by the above: */
+#include
+#include
+#include
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define OSSL_CMP_PVNO_2 2
+#define OSSL_CMP_PVNO_3 3
+#define OSSL_CMP_PVNO OSSL_CMP_PVNO_2 /* v2 is the default */
+
+/*-
+ * PKIFailureInfo ::= BIT STRING {
+ * -- since we can fail in more than one way!
+ * -- More codes may be added in the future if/when required.
+ * badAlg (0),
+ * -- unrecognized or unsupported Algorithm Identifier
+ * badMessageCheck (1),
+ * -- integrity check failed (e.g., signature did not verify)
+ * badRequest (2),
+ * -- transaction not permitted or supported
+ * badTime (3),
+ * -- messageTime was not sufficiently close to the system time,
+ * -- as defined by local policy
+ * badCertId (4),
+ * -- no certificate could be found matching the provided criteria
+ * badDataFormat (5),
+ * -- the data submitted has the wrong format
+ * wrongAuthority (6),
+ * -- the authority indicated in the request is different from the
+ * -- one creating the response token
+ * incorrectData (7),
+ * -- the requester's data is incorrect (for notary services)
+ * missingTimeStamp (8),
+ * -- when the timestamp is missing but should be there
+ * -- (by policy)
+ * badPOP (9),
+ * -- the proof-of-possession failed
+ * certRevoked (10),
+ * -- the certificate has already been revoked
+ * certConfirmed (11),
+ * -- the certificate has already been confirmed
+ * wrongIntegrity (12),
+ * -- invalid integrity, password based instead of signature or
+ * -- vice versa
+ * badRecipientNonce (13),
+ * -- invalid recipient nonce, either missing or wrong value
+ * timeNotAvailable (14),
+ * -- the TSA's time source is not available
+ * unacceptedPolicy (15),
+ * -- the requested TSA policy is not supported by the TSA.
+ * unacceptedExtension (16),
+ * -- the requested extension is not supported by the TSA.
+ * addInfoNotAvailable (17),
+ * -- the additional information requested could not be
+ * -- understood or is not available
+ * badSenderNonce (18),
+ * -- invalid sender nonce, either missing or wrong size
+ * badCertTemplate (19),
+ * -- invalid cert. template or missing mandatory information
+ * signerNotTrusted (20),
+ * -- signer of the message unknown or not trusted
+ * transactionIdInUse (21),
+ * -- the transaction identifier is already in use
+ * unsupportedVersion (22),
+ * -- the version of the message is not supported
+ * notAuthorized (23),
+ * -- the sender was not authorized to make the preceding
+ * -- request or perform the preceding action
+ * systemUnavail (24),
+ * -- the request cannot be handled due to system unavailability
+ * systemFailure (25),
+ * -- the request cannot be handled due to system failure
+ * duplicateCertReq (26)
+ * -- certificate cannot be issued because a duplicate
+ * -- certificate already exists
+ * }
+ */
+#define OSSL_CMP_PKIFAILUREINFO_badAlg 0
+#define OSSL_CMP_PKIFAILUREINFO_badMessageCheck 1
+#define OSSL_CMP_PKIFAILUREINFO_badRequest 2
+#define OSSL_CMP_PKIFAILUREINFO_badTime 3
+#define OSSL_CMP_PKIFAILUREINFO_badCertId 4
+#define OSSL_CMP_PKIFAILUREINFO_badDataFormat 5
+#define OSSL_CMP_PKIFAILUREINFO_wrongAuthority 6
+#define OSSL_CMP_PKIFAILUREINFO_incorrectData 7
+#define OSSL_CMP_PKIFAILUREINFO_missingTimeStamp 8
+#define OSSL_CMP_PKIFAILUREINFO_badPOP 9
+#define OSSL_CMP_PKIFAILUREINFO_certRevoked 10
+#define OSSL_CMP_PKIFAILUREINFO_certConfirmed 11
+#define OSSL_CMP_PKIFAILUREINFO_wrongIntegrity 12
+#define OSSL_CMP_PKIFAILUREINFO_badRecipientNonce 13
+#define OSSL_CMP_PKIFAILUREINFO_timeNotAvailable 14
+#define OSSL_CMP_PKIFAILUREINFO_unacceptedPolicy 15
+#define OSSL_CMP_PKIFAILUREINFO_unacceptedExtension 16
+#define OSSL_CMP_PKIFAILUREINFO_addInfoNotAvailable 17
+#define OSSL_CMP_PKIFAILUREINFO_badSenderNonce 18
+#define OSSL_CMP_PKIFAILUREINFO_badCertTemplate 19
+#define OSSL_CMP_PKIFAILUREINFO_signerNotTrusted 20
+#define OSSL_CMP_PKIFAILUREINFO_transactionIdInUse 21
+#define OSSL_CMP_PKIFAILUREINFO_unsupportedVersion 22
+#define OSSL_CMP_PKIFAILUREINFO_notAuthorized 23
+#define OSSL_CMP_PKIFAILUREINFO_systemUnavail 24
+#define OSSL_CMP_PKIFAILUREINFO_systemFailure 25
+#define OSSL_CMP_PKIFAILUREINFO_duplicateCertReq 26
+#define OSSL_CMP_PKIFAILUREINFO_MAX 26
+#define OSSL_CMP_PKIFAILUREINFO_MAX_BIT_PATTERN \
+ ((1 << (OSSL_CMP_PKIFAILUREINFO_MAX + 1)) - 1)
+#if OSSL_CMP_PKIFAILUREINFO_MAX_BIT_PATTERN > INT_MAX
+#error CMP_PKIFAILUREINFO_MAX bit pattern does not fit in type int
+#endif
+typedef ASN1_BIT_STRING OSSL_CMP_PKIFAILUREINFO;
+
+#define OSSL_CMP_CTX_FAILINFO_badAlg (1 << 0)
+#define OSSL_CMP_CTX_FAILINFO_badMessageCheck (1 << 1)
+#define OSSL_CMP_CTX_FAILINFO_badRequest (1 << 2)
+#define OSSL_CMP_CTX_FAILINFO_badTime (1 << 3)
+#define OSSL_CMP_CTX_FAILINFO_badCertId (1 << 4)
+#define OSSL_CMP_CTX_FAILINFO_badDataFormat (1 << 5)
+#define OSSL_CMP_CTX_FAILINFO_wrongAuthority (1 << 6)
+#define OSSL_CMP_CTX_FAILINFO_incorrectData (1 << 7)
+#define OSSL_CMP_CTX_FAILINFO_missingTimeStamp (1 << 8)
+#define OSSL_CMP_CTX_FAILINFO_badPOP (1 << 9)
+#define OSSL_CMP_CTX_FAILINFO_certRevoked (1 << 10)
+#define OSSL_CMP_CTX_FAILINFO_certConfirmed (1 << 11)
+#define OSSL_CMP_CTX_FAILINFO_wrongIntegrity (1 << 12)
+#define OSSL_CMP_CTX_FAILINFO_badRecipientNonce (1 << 13)
+#define OSSL_CMP_CTX_FAILINFO_timeNotAvailable (1 << 14)
+#define OSSL_CMP_CTX_FAILINFO_unacceptedPolicy (1 << 15)
+#define OSSL_CMP_CTX_FAILINFO_unacceptedExtension (1 << 16)
+#define OSSL_CMP_CTX_FAILINFO_addInfoNotAvailable (1 << 17)
+#define OSSL_CMP_CTX_FAILINFO_badSenderNonce (1 << 18)
+#define OSSL_CMP_CTX_FAILINFO_badCertTemplate (1 << 19)
+#define OSSL_CMP_CTX_FAILINFO_signerNotTrusted (1 << 20)
+#define OSSL_CMP_CTX_FAILINFO_transactionIdInUse (1 << 21)
+#define OSSL_CMP_CTX_FAILINFO_unsupportedVersion (1 << 22)
+#define OSSL_CMP_CTX_FAILINFO_notAuthorized (1 << 23)
+#define OSSL_CMP_CTX_FAILINFO_systemUnavail (1 << 24)
+#define OSSL_CMP_CTX_FAILINFO_systemFailure (1 << 25)
+#define OSSL_CMP_CTX_FAILINFO_duplicateCertReq (1 << 26)
+
+/*-
+ * PKIStatus ::= INTEGER {
+ * accepted (0),
+ * -- you got exactly what you asked for
+ * grantedWithMods (1),
+ * -- you got something like what you asked for; the
+ * -- requester is responsible for ascertaining the differences
+ * rejection (2),
+ * -- you don't get it, more information elsewhere in the message
+ * waiting (3),
+ * -- the request body part has not yet been processed; expect to
+ * -- hear more later (note: proper handling of this status
+ * -- response MAY use the polling req/rep PKIMessages specified
+ * -- in Section 5.3.22; alternatively, polling in the underlying
+ * -- transport layer MAY have some utility in this regard)
+ * revocationWarning (4),
+ * -- this message contains a warning that a revocation is
+ * -- imminent
+ * revocationNotification (5),
+ * -- notification that a revocation has occurred
+ * keyUpdateWarning (6)
+ * -- update already done for the oldCertId specified in
+ * -- CertReqMsg
+ * }
+ */
+#define OSSL_CMP_PKISTATUS_rejected_by_client -5
+#define OSSL_CMP_PKISTATUS_checking_response -4
+#define OSSL_CMP_PKISTATUS_request -3
+#define OSSL_CMP_PKISTATUS_trans -2
+#define OSSL_CMP_PKISTATUS_unspecified -1
+#define OSSL_CMP_PKISTATUS_accepted 0
+#define OSSL_CMP_PKISTATUS_grantedWithMods 1
+#define OSSL_CMP_PKISTATUS_rejection 2
+#define OSSL_CMP_PKISTATUS_waiting 3
+#define OSSL_CMP_PKISTATUS_revocationWarning 4
+#define OSSL_CMP_PKISTATUS_revocationNotification 5
+#define OSSL_CMP_PKISTATUS_keyUpdateWarning 6
+typedef ASN1_INTEGER OSSL_CMP_PKISTATUS;
+
+DECLARE_ASN1_ITEM(OSSL_CMP_PKISTATUS)
+
+#define OSSL_CMP_CERTORENCCERT_CERTIFICATE 0
+#define OSSL_CMP_CERTORENCCERT_ENCRYPTEDCERT 1
+
+/* data type declarations */
+typedef struct ossl_cmp_ctx_st OSSL_CMP_CTX;
+typedef struct ossl_cmp_pkiheader_st OSSL_CMP_PKIHEADER;
+DECLARE_ASN1_FUNCTIONS(OSSL_CMP_PKIHEADER)
+typedef struct ossl_cmp_msg_st OSSL_CMP_MSG;
+DECLARE_ASN1_DUP_FUNCTION(OSSL_CMP_MSG)
+DECLARE_ASN1_ENCODE_FUNCTIONS(OSSL_CMP_MSG, OSSL_CMP_MSG, OSSL_CMP_MSG)
+typedef struct ossl_cmp_certstatus_st OSSL_CMP_CERTSTATUS;
+/* clang-format off */
+SKM_DEFINE_STACK_OF_INTERNAL(OSSL_CMP_CERTSTATUS, OSSL_CMP_CERTSTATUS, OSSL_CMP_CERTSTATUS)
+#define sk_OSSL_CMP_CERTSTATUS_num(sk) OPENSSL_sk_num(ossl_check_const_OSSL_CMP_CERTSTATUS_sk_type(sk))
+#define sk_OSSL_CMP_CERTSTATUS_value(sk, idx) ((OSSL_CMP_CERTSTATUS *)OPENSSL_sk_value(ossl_check_const_OSSL_CMP_CERTSTATUS_sk_type(sk), (idx)))
+#define sk_OSSL_CMP_CERTSTATUS_new(cmp) ((STACK_OF(OSSL_CMP_CERTSTATUS) *)OPENSSL_sk_new(ossl_check_OSSL_CMP_CERTSTATUS_compfunc_type(cmp)))
+#define sk_OSSL_CMP_CERTSTATUS_new_null() ((STACK_OF(OSSL_CMP_CERTSTATUS) *)OPENSSL_sk_new_null())
+#define sk_OSSL_CMP_CERTSTATUS_new_reserve(cmp, n) ((STACK_OF(OSSL_CMP_CERTSTATUS) *)OPENSSL_sk_new_reserve(ossl_check_OSSL_CMP_CERTSTATUS_compfunc_type(cmp), (n)))
+#define sk_OSSL_CMP_CERTSTATUS_reserve(sk, n) OPENSSL_sk_reserve(ossl_check_OSSL_CMP_CERTSTATUS_sk_type(sk), (n))
+#define sk_OSSL_CMP_CERTSTATUS_free(sk) OPENSSL_sk_free(ossl_check_OSSL_CMP_CERTSTATUS_sk_type(sk))
+#define sk_OSSL_CMP_CERTSTATUS_zero(sk) OPENSSL_sk_zero(ossl_check_OSSL_CMP_CERTSTATUS_sk_type(sk))
+#define sk_OSSL_CMP_CERTSTATUS_delete(sk, i) ((OSSL_CMP_CERTSTATUS *)OPENSSL_sk_delete(ossl_check_OSSL_CMP_CERTSTATUS_sk_type(sk), (i)))
+#define sk_OSSL_CMP_CERTSTATUS_delete_ptr(sk, ptr) ((OSSL_CMP_CERTSTATUS *)OPENSSL_sk_delete_ptr(ossl_check_OSSL_CMP_CERTSTATUS_sk_type(sk), ossl_check_OSSL_CMP_CERTSTATUS_type(ptr)))
+#define sk_OSSL_CMP_CERTSTATUS_push(sk, ptr) OPENSSL_sk_push(ossl_check_OSSL_CMP_CERTSTATUS_sk_type(sk), ossl_check_OSSL_CMP_CERTSTATUS_type(ptr))
+#define sk_OSSL_CMP_CERTSTATUS_unshift(sk, ptr) OPENSSL_sk_unshift(ossl_check_OSSL_CMP_CERTSTATUS_sk_type(sk), ossl_check_OSSL_CMP_CERTSTATUS_type(ptr))
+#define sk_OSSL_CMP_CERTSTATUS_pop(sk) ((OSSL_CMP_CERTSTATUS *)OPENSSL_sk_pop(ossl_check_OSSL_CMP_CERTSTATUS_sk_type(sk)))
+#define sk_OSSL_CMP_CERTSTATUS_shift(sk) ((OSSL_CMP_CERTSTATUS *)OPENSSL_sk_shift(ossl_check_OSSL_CMP_CERTSTATUS_sk_type(sk)))
+#define sk_OSSL_CMP_CERTSTATUS_pop_free(sk, freefunc) OPENSSL_sk_pop_free(ossl_check_OSSL_CMP_CERTSTATUS_sk_type(sk), ossl_check_OSSL_CMP_CERTSTATUS_freefunc_type(freefunc))
+#define sk_OSSL_CMP_CERTSTATUS_insert(sk, ptr, idx) OPENSSL_sk_insert(ossl_check_OSSL_CMP_CERTSTATUS_sk_type(sk), ossl_check_OSSL_CMP_CERTSTATUS_type(ptr), (idx))
+#define sk_OSSL_CMP_CERTSTATUS_set(sk, idx, ptr) ((OSSL_CMP_CERTSTATUS *)OPENSSL_sk_set(ossl_check_OSSL_CMP_CERTSTATUS_sk_type(sk), (idx), ossl_check_OSSL_CMP_CERTSTATUS_type(ptr)))
+#define sk_OSSL_CMP_CERTSTATUS_find(sk, ptr) OPENSSL_sk_find(ossl_check_OSSL_CMP_CERTSTATUS_sk_type(sk), ossl_check_OSSL_CMP_CERTSTATUS_type(ptr))
+#define sk_OSSL_CMP_CERTSTATUS_find_ex(sk, ptr) OPENSSL_sk_find_ex(ossl_check_OSSL_CMP_CERTSTATUS_sk_type(sk), ossl_check_OSSL_CMP_CERTSTATUS_type(ptr))
+#define sk_OSSL_CMP_CERTSTATUS_find_all(sk, ptr, pnum) OPENSSL_sk_find_all(ossl_check_OSSL_CMP_CERTSTATUS_sk_type(sk), ossl_check_OSSL_CMP_CERTSTATUS_type(ptr), pnum)
+#define sk_OSSL_CMP_CERTSTATUS_sort(sk) OPENSSL_sk_sort(ossl_check_OSSL_CMP_CERTSTATUS_sk_type(sk))
+#define sk_OSSL_CMP_CERTSTATUS_is_sorted(sk) OPENSSL_sk_is_sorted(ossl_check_const_OSSL_CMP_CERTSTATUS_sk_type(sk))
+#define sk_OSSL_CMP_CERTSTATUS_dup(sk) ((STACK_OF(OSSL_CMP_CERTSTATUS) *)OPENSSL_sk_dup(ossl_check_const_OSSL_CMP_CERTSTATUS_sk_type(sk)))
+#define sk_OSSL_CMP_CERTSTATUS_deep_copy(sk, copyfunc, freefunc) ((STACK_OF(OSSL_CMP_CERTSTATUS) *)OPENSSL_sk_deep_copy(ossl_check_const_OSSL_CMP_CERTSTATUS_sk_type(sk), ossl_check_OSSL_CMP_CERTSTATUS_copyfunc_type(copyfunc), ossl_check_OSSL_CMP_CERTSTATUS_freefunc_type(freefunc)))
+#define sk_OSSL_CMP_CERTSTATUS_set_cmp_func(sk, cmp) ((sk_OSSL_CMP_CERTSTATUS_compfunc)OPENSSL_sk_set_cmp_func(ossl_check_OSSL_CMP_CERTSTATUS_sk_type(sk), ossl_check_OSSL_CMP_CERTSTATUS_compfunc_type(cmp)))
+
+/* clang-format on */
+typedef struct ossl_cmp_itav_st OSSL_CMP_ITAV;
+DECLARE_ASN1_DUP_FUNCTION(OSSL_CMP_ITAV)
+/* clang-format off */
+SKM_DEFINE_STACK_OF_INTERNAL(OSSL_CMP_ITAV, OSSL_CMP_ITAV, OSSL_CMP_ITAV)
+#define sk_OSSL_CMP_ITAV_num(sk) OPENSSL_sk_num(ossl_check_const_OSSL_CMP_ITAV_sk_type(sk))
+#define sk_OSSL_CMP_ITAV_value(sk, idx) ((OSSL_CMP_ITAV *)OPENSSL_sk_value(ossl_check_const_OSSL_CMP_ITAV_sk_type(sk), (idx)))
+#define sk_OSSL_CMP_ITAV_new(cmp) ((STACK_OF(OSSL_CMP_ITAV) *)OPENSSL_sk_new(ossl_check_OSSL_CMP_ITAV_compfunc_type(cmp)))
+#define sk_OSSL_CMP_ITAV_new_null() ((STACK_OF(OSSL_CMP_ITAV) *)OPENSSL_sk_new_null())
+#define sk_OSSL_CMP_ITAV_new_reserve(cmp, n) ((STACK_OF(OSSL_CMP_ITAV) *)OPENSSL_sk_new_reserve(ossl_check_OSSL_CMP_ITAV_compfunc_type(cmp), (n)))
+#define sk_OSSL_CMP_ITAV_reserve(sk, n) OPENSSL_sk_reserve(ossl_check_OSSL_CMP_ITAV_sk_type(sk), (n))
+#define sk_OSSL_CMP_ITAV_free(sk) OPENSSL_sk_free(ossl_check_OSSL_CMP_ITAV_sk_type(sk))
+#define sk_OSSL_CMP_ITAV_zero(sk) OPENSSL_sk_zero(ossl_check_OSSL_CMP_ITAV_sk_type(sk))
+#define sk_OSSL_CMP_ITAV_delete(sk, i) ((OSSL_CMP_ITAV *)OPENSSL_sk_delete(ossl_check_OSSL_CMP_ITAV_sk_type(sk), (i)))
+#define sk_OSSL_CMP_ITAV_delete_ptr(sk, ptr) ((OSSL_CMP_ITAV *)OPENSSL_sk_delete_ptr(ossl_check_OSSL_CMP_ITAV_sk_type(sk), ossl_check_OSSL_CMP_ITAV_type(ptr)))
+#define sk_OSSL_CMP_ITAV_push(sk, ptr) OPENSSL_sk_push(ossl_check_OSSL_CMP_ITAV_sk_type(sk), ossl_check_OSSL_CMP_ITAV_type(ptr))
+#define sk_OSSL_CMP_ITAV_unshift(sk, ptr) OPENSSL_sk_unshift(ossl_check_OSSL_CMP_ITAV_sk_type(sk), ossl_check_OSSL_CMP_ITAV_type(ptr))
+#define sk_OSSL_CMP_ITAV_pop(sk) ((OSSL_CMP_ITAV *)OPENSSL_sk_pop(ossl_check_OSSL_CMP_ITAV_sk_type(sk)))
+#define sk_OSSL_CMP_ITAV_shift(sk) ((OSSL_CMP_ITAV *)OPENSSL_sk_shift(ossl_check_OSSL_CMP_ITAV_sk_type(sk)))
+#define sk_OSSL_CMP_ITAV_pop_free(sk, freefunc) OPENSSL_sk_pop_free(ossl_check_OSSL_CMP_ITAV_sk_type(sk), ossl_check_OSSL_CMP_ITAV_freefunc_type(freefunc))
+#define sk_OSSL_CMP_ITAV_insert(sk, ptr, idx) OPENSSL_sk_insert(ossl_check_OSSL_CMP_ITAV_sk_type(sk), ossl_check_OSSL_CMP_ITAV_type(ptr), (idx))
+#define sk_OSSL_CMP_ITAV_set(sk, idx, ptr) ((OSSL_CMP_ITAV *)OPENSSL_sk_set(ossl_check_OSSL_CMP_ITAV_sk_type(sk), (idx), ossl_check_OSSL_CMP_ITAV_type(ptr)))
+#define sk_OSSL_CMP_ITAV_find(sk, ptr) OPENSSL_sk_find(ossl_check_OSSL_CMP_ITAV_sk_type(sk), ossl_check_OSSL_CMP_ITAV_type(ptr))
+#define sk_OSSL_CMP_ITAV_find_ex(sk, ptr) OPENSSL_sk_find_ex(ossl_check_OSSL_CMP_ITAV_sk_type(sk), ossl_check_OSSL_CMP_ITAV_type(ptr))
+#define sk_OSSL_CMP_ITAV_find_all(sk, ptr, pnum) OPENSSL_sk_find_all(ossl_check_OSSL_CMP_ITAV_sk_type(sk), ossl_check_OSSL_CMP_ITAV_type(ptr), pnum)
+#define sk_OSSL_CMP_ITAV_sort(sk) OPENSSL_sk_sort(ossl_check_OSSL_CMP_ITAV_sk_type(sk))
+#define sk_OSSL_CMP_ITAV_is_sorted(sk) OPENSSL_sk_is_sorted(ossl_check_const_OSSL_CMP_ITAV_sk_type(sk))
+#define sk_OSSL_CMP_ITAV_dup(sk) ((STACK_OF(OSSL_CMP_ITAV) *)OPENSSL_sk_dup(ossl_check_const_OSSL_CMP_ITAV_sk_type(sk)))
+#define sk_OSSL_CMP_ITAV_deep_copy(sk, copyfunc, freefunc) ((STACK_OF(OSSL_CMP_ITAV) *)OPENSSL_sk_deep_copy(ossl_check_const_OSSL_CMP_ITAV_sk_type(sk), ossl_check_OSSL_CMP_ITAV_copyfunc_type(copyfunc), ossl_check_OSSL_CMP_ITAV_freefunc_type(freefunc)))
+#define sk_OSSL_CMP_ITAV_set_cmp_func(sk, cmp) ((sk_OSSL_CMP_ITAV_compfunc)OPENSSL_sk_set_cmp_func(ossl_check_OSSL_CMP_ITAV_sk_type(sk), ossl_check_OSSL_CMP_ITAV_compfunc_type(cmp)))
+
+/* clang-format on */
+
+typedef struct ossl_cmp_crlstatus_st OSSL_CMP_CRLSTATUS;
+/* clang-format off */
+SKM_DEFINE_STACK_OF_INTERNAL(OSSL_CMP_CRLSTATUS, OSSL_CMP_CRLSTATUS, OSSL_CMP_CRLSTATUS)
+#define sk_OSSL_CMP_CRLSTATUS_num(sk) OPENSSL_sk_num(ossl_check_const_OSSL_CMP_CRLSTATUS_sk_type(sk))
+#define sk_OSSL_CMP_CRLSTATUS_value(sk, idx) ((OSSL_CMP_CRLSTATUS *)OPENSSL_sk_value(ossl_check_const_OSSL_CMP_CRLSTATUS_sk_type(sk), (idx)))
+#define sk_OSSL_CMP_CRLSTATUS_new(cmp) ((STACK_OF(OSSL_CMP_CRLSTATUS) *)OPENSSL_sk_new(ossl_check_OSSL_CMP_CRLSTATUS_compfunc_type(cmp)))
+#define sk_OSSL_CMP_CRLSTATUS_new_null() ((STACK_OF(OSSL_CMP_CRLSTATUS) *)OPENSSL_sk_new_null())
+#define sk_OSSL_CMP_CRLSTATUS_new_reserve(cmp, n) ((STACK_OF(OSSL_CMP_CRLSTATUS) *)OPENSSL_sk_new_reserve(ossl_check_OSSL_CMP_CRLSTATUS_compfunc_type(cmp), (n)))
+#define sk_OSSL_CMP_CRLSTATUS_reserve(sk, n) OPENSSL_sk_reserve(ossl_check_OSSL_CMP_CRLSTATUS_sk_type(sk), (n))
+#define sk_OSSL_CMP_CRLSTATUS_free(sk) OPENSSL_sk_free(ossl_check_OSSL_CMP_CRLSTATUS_sk_type(sk))
+#define sk_OSSL_CMP_CRLSTATUS_zero(sk) OPENSSL_sk_zero(ossl_check_OSSL_CMP_CRLSTATUS_sk_type(sk))
+#define sk_OSSL_CMP_CRLSTATUS_delete(sk, i) ((OSSL_CMP_CRLSTATUS *)OPENSSL_sk_delete(ossl_check_OSSL_CMP_CRLSTATUS_sk_type(sk), (i)))
+#define sk_OSSL_CMP_CRLSTATUS_delete_ptr(sk, ptr) ((OSSL_CMP_CRLSTATUS *)OPENSSL_sk_delete_ptr(ossl_check_OSSL_CMP_CRLSTATUS_sk_type(sk), ossl_check_OSSL_CMP_CRLSTATUS_type(ptr)))
+#define sk_OSSL_CMP_CRLSTATUS_push(sk, ptr) OPENSSL_sk_push(ossl_check_OSSL_CMP_CRLSTATUS_sk_type(sk), ossl_check_OSSL_CMP_CRLSTATUS_type(ptr))
+#define sk_OSSL_CMP_CRLSTATUS_unshift(sk, ptr) OPENSSL_sk_unshift(ossl_check_OSSL_CMP_CRLSTATUS_sk_type(sk), ossl_check_OSSL_CMP_CRLSTATUS_type(ptr))
+#define sk_OSSL_CMP_CRLSTATUS_pop(sk) ((OSSL_CMP_CRLSTATUS *)OPENSSL_sk_pop(ossl_check_OSSL_CMP_CRLSTATUS_sk_type(sk)))
+#define sk_OSSL_CMP_CRLSTATUS_shift(sk) ((OSSL_CMP_CRLSTATUS *)OPENSSL_sk_shift(ossl_check_OSSL_CMP_CRLSTATUS_sk_type(sk)))
+#define sk_OSSL_CMP_CRLSTATUS_pop_free(sk, freefunc) OPENSSL_sk_pop_free(ossl_check_OSSL_CMP_CRLSTATUS_sk_type(sk), ossl_check_OSSL_CMP_CRLSTATUS_freefunc_type(freefunc))
+#define sk_OSSL_CMP_CRLSTATUS_insert(sk, ptr, idx) OPENSSL_sk_insert(ossl_check_OSSL_CMP_CRLSTATUS_sk_type(sk), ossl_check_OSSL_CMP_CRLSTATUS_type(ptr), (idx))
+#define sk_OSSL_CMP_CRLSTATUS_set(sk, idx, ptr) ((OSSL_CMP_CRLSTATUS *)OPENSSL_sk_set(ossl_check_OSSL_CMP_CRLSTATUS_sk_type(sk), (idx), ossl_check_OSSL_CMP_CRLSTATUS_type(ptr)))
+#define sk_OSSL_CMP_CRLSTATUS_find(sk, ptr) OPENSSL_sk_find(ossl_check_OSSL_CMP_CRLSTATUS_sk_type(sk), ossl_check_OSSL_CMP_CRLSTATUS_type(ptr))
+#define sk_OSSL_CMP_CRLSTATUS_find_ex(sk, ptr) OPENSSL_sk_find_ex(ossl_check_OSSL_CMP_CRLSTATUS_sk_type(sk), ossl_check_OSSL_CMP_CRLSTATUS_type(ptr))
+#define sk_OSSL_CMP_CRLSTATUS_find_all(sk, ptr, pnum) OPENSSL_sk_find_all(ossl_check_OSSL_CMP_CRLSTATUS_sk_type(sk), ossl_check_OSSL_CMP_CRLSTATUS_type(ptr), pnum)
+#define sk_OSSL_CMP_CRLSTATUS_sort(sk) OPENSSL_sk_sort(ossl_check_OSSL_CMP_CRLSTATUS_sk_type(sk))
+#define sk_OSSL_CMP_CRLSTATUS_is_sorted(sk) OPENSSL_sk_is_sorted(ossl_check_const_OSSL_CMP_CRLSTATUS_sk_type(sk))
+#define sk_OSSL_CMP_CRLSTATUS_dup(sk) ((STACK_OF(OSSL_CMP_CRLSTATUS) *)OPENSSL_sk_dup(ossl_check_const_OSSL_CMP_CRLSTATUS_sk_type(sk)))
+#define sk_OSSL_CMP_CRLSTATUS_deep_copy(sk, copyfunc, freefunc) ((STACK_OF(OSSL_CMP_CRLSTATUS) *)OPENSSL_sk_deep_copy(ossl_check_const_OSSL_CMP_CRLSTATUS_sk_type(sk), ossl_check_OSSL_CMP_CRLSTATUS_copyfunc_type(copyfunc), ossl_check_OSSL_CMP_CRLSTATUS_freefunc_type(freefunc)))
+#define sk_OSSL_CMP_CRLSTATUS_set_cmp_func(sk, cmp) ((sk_OSSL_CMP_CRLSTATUS_compfunc)OPENSSL_sk_set_cmp_func(ossl_check_OSSL_CMP_CRLSTATUS_sk_type(sk), ossl_check_OSSL_CMP_CRLSTATUS_compfunc_type(cmp)))
+
+/* clang-format on */
+
+typedef OSSL_CRMF_ATTRIBUTETYPEANDVALUE OSSL_CMP_ATAV;
+#define OSSL_CMP_ATAV_free OSSL_CRMF_ATTRIBUTETYPEANDVALUE_free
+typedef STACK_OF(OSSL_CRMF_ATTRIBUTETYPEANDVALUE) OSSL_CMP_ATAVS;
+DECLARE_ASN1_FUNCTIONS(OSSL_CMP_ATAVS)
+#define stack_st_OSSL_CMP_ATAV stack_st_OSSL_CRMF_ATTRIBUTETYPEANDVALUE
+#define sk_OSSL_CMP_ATAV_num sk_OSSL_CRMF_ATTRIBUTETYPEANDVALUE_num
+#define sk_OSSL_CMP_ATAV_value sk_OSSL_CRMF_ATTRIBUTETYPEANDVALUE_value
+#define sk_OSSL_CMP_ATAV_push sk_OSSL_CRMF_ATTRIBUTETYPEANDVALUE_push
+#define sk_OSSL_CMP_ATAV_pop_free sk_OSSL_CRMF_ATTRIBUTETYPEANDVALUE_pop_free
+
+typedef struct ossl_cmp_revrepcontent_st OSSL_CMP_REVREPCONTENT;
+typedef struct ossl_cmp_pkisi_st OSSL_CMP_PKISI;
+DECLARE_ASN1_FUNCTIONS(OSSL_CMP_PKISI)
+DECLARE_ASN1_DUP_FUNCTION(OSSL_CMP_PKISI)
+/* clang-format off */
+SKM_DEFINE_STACK_OF_INTERNAL(OSSL_CMP_PKISI, OSSL_CMP_PKISI, OSSL_CMP_PKISI)
+#define sk_OSSL_CMP_PKISI_num(sk) OPENSSL_sk_num(ossl_check_const_OSSL_CMP_PKISI_sk_type(sk))
+#define sk_OSSL_CMP_PKISI_value(sk, idx) ((OSSL_CMP_PKISI *)OPENSSL_sk_value(ossl_check_const_OSSL_CMP_PKISI_sk_type(sk), (idx)))
+#define sk_OSSL_CMP_PKISI_new(cmp) ((STACK_OF(OSSL_CMP_PKISI) *)OPENSSL_sk_new(ossl_check_OSSL_CMP_PKISI_compfunc_type(cmp)))
+#define sk_OSSL_CMP_PKISI_new_null() ((STACK_OF(OSSL_CMP_PKISI) *)OPENSSL_sk_new_null())
+#define sk_OSSL_CMP_PKISI_new_reserve(cmp, n) ((STACK_OF(OSSL_CMP_PKISI) *)OPENSSL_sk_new_reserve(ossl_check_OSSL_CMP_PKISI_compfunc_type(cmp), (n)))
+#define sk_OSSL_CMP_PKISI_reserve(sk, n) OPENSSL_sk_reserve(ossl_check_OSSL_CMP_PKISI_sk_type(sk), (n))
+#define sk_OSSL_CMP_PKISI_free(sk) OPENSSL_sk_free(ossl_check_OSSL_CMP_PKISI_sk_type(sk))
+#define sk_OSSL_CMP_PKISI_zero(sk) OPENSSL_sk_zero(ossl_check_OSSL_CMP_PKISI_sk_type(sk))
+#define sk_OSSL_CMP_PKISI_delete(sk, i) ((OSSL_CMP_PKISI *)OPENSSL_sk_delete(ossl_check_OSSL_CMP_PKISI_sk_type(sk), (i)))
+#define sk_OSSL_CMP_PKISI_delete_ptr(sk, ptr) ((OSSL_CMP_PKISI *)OPENSSL_sk_delete_ptr(ossl_check_OSSL_CMP_PKISI_sk_type(sk), ossl_check_OSSL_CMP_PKISI_type(ptr)))
+#define sk_OSSL_CMP_PKISI_push(sk, ptr) OPENSSL_sk_push(ossl_check_OSSL_CMP_PKISI_sk_type(sk), ossl_check_OSSL_CMP_PKISI_type(ptr))
+#define sk_OSSL_CMP_PKISI_unshift(sk, ptr) OPENSSL_sk_unshift(ossl_check_OSSL_CMP_PKISI_sk_type(sk), ossl_check_OSSL_CMP_PKISI_type(ptr))
+#define sk_OSSL_CMP_PKISI_pop(sk) ((OSSL_CMP_PKISI *)OPENSSL_sk_pop(ossl_check_OSSL_CMP_PKISI_sk_type(sk)))
+#define sk_OSSL_CMP_PKISI_shift(sk) ((OSSL_CMP_PKISI *)OPENSSL_sk_shift(ossl_check_OSSL_CMP_PKISI_sk_type(sk)))
+#define sk_OSSL_CMP_PKISI_pop_free(sk, freefunc) OPENSSL_sk_pop_free(ossl_check_OSSL_CMP_PKISI_sk_type(sk), ossl_check_OSSL_CMP_PKISI_freefunc_type(freefunc))
+#define sk_OSSL_CMP_PKISI_insert(sk, ptr, idx) OPENSSL_sk_insert(ossl_check_OSSL_CMP_PKISI_sk_type(sk), ossl_check_OSSL_CMP_PKISI_type(ptr), (idx))
+#define sk_OSSL_CMP_PKISI_set(sk, idx, ptr) ((OSSL_CMP_PKISI *)OPENSSL_sk_set(ossl_check_OSSL_CMP_PKISI_sk_type(sk), (idx), ossl_check_OSSL_CMP_PKISI_type(ptr)))
+#define sk_OSSL_CMP_PKISI_find(sk, ptr) OPENSSL_sk_find(ossl_check_OSSL_CMP_PKISI_sk_type(sk), ossl_check_OSSL_CMP_PKISI_type(ptr))
+#define sk_OSSL_CMP_PKISI_find_ex(sk, ptr) OPENSSL_sk_find_ex(ossl_check_OSSL_CMP_PKISI_sk_type(sk), ossl_check_OSSL_CMP_PKISI_type(ptr))
+#define sk_OSSL_CMP_PKISI_find_all(sk, ptr, pnum) OPENSSL_sk_find_all(ossl_check_OSSL_CMP_PKISI_sk_type(sk), ossl_check_OSSL_CMP_PKISI_type(ptr), pnum)
+#define sk_OSSL_CMP_PKISI_sort(sk) OPENSSL_sk_sort(ossl_check_OSSL_CMP_PKISI_sk_type(sk))
+#define sk_OSSL_CMP_PKISI_is_sorted(sk) OPENSSL_sk_is_sorted(ossl_check_const_OSSL_CMP_PKISI_sk_type(sk))
+#define sk_OSSL_CMP_PKISI_dup(sk) ((STACK_OF(OSSL_CMP_PKISI) *)OPENSSL_sk_dup(ossl_check_const_OSSL_CMP_PKISI_sk_type(sk)))
+#define sk_OSSL_CMP_PKISI_deep_copy(sk, copyfunc, freefunc) ((STACK_OF(OSSL_CMP_PKISI) *)OPENSSL_sk_deep_copy(ossl_check_const_OSSL_CMP_PKISI_sk_type(sk), ossl_check_OSSL_CMP_PKISI_copyfunc_type(copyfunc), ossl_check_OSSL_CMP_PKISI_freefunc_type(freefunc)))
+#define sk_OSSL_CMP_PKISI_set_cmp_func(sk, cmp) ((sk_OSSL_CMP_PKISI_compfunc)OPENSSL_sk_set_cmp_func(ossl_check_OSSL_CMP_PKISI_sk_type(sk), ossl_check_OSSL_CMP_PKISI_compfunc_type(cmp)))
+
+/* clang-format on */
+typedef struct ossl_cmp_certrepmessage_st OSSL_CMP_CERTREPMESSAGE;
+/* clang-format off */
+SKM_DEFINE_STACK_OF_INTERNAL(OSSL_CMP_CERTREPMESSAGE, OSSL_CMP_CERTREPMESSAGE, OSSL_CMP_CERTREPMESSAGE)
+#define sk_OSSL_CMP_CERTREPMESSAGE_num(sk) OPENSSL_sk_num(ossl_check_const_OSSL_CMP_CERTREPMESSAGE_sk_type(sk))
+#define sk_OSSL_CMP_CERTREPMESSAGE_value(sk, idx) ((OSSL_CMP_CERTREPMESSAGE *)OPENSSL_sk_value(ossl_check_const_OSSL_CMP_CERTREPMESSAGE_sk_type(sk), (idx)))
+#define sk_OSSL_CMP_CERTREPMESSAGE_new(cmp) ((STACK_OF(OSSL_CMP_CERTREPMESSAGE) *)OPENSSL_sk_new(ossl_check_OSSL_CMP_CERTREPMESSAGE_compfunc_type(cmp)))
+#define sk_OSSL_CMP_CERTREPMESSAGE_new_null() ((STACK_OF(OSSL_CMP_CERTREPMESSAGE) *)OPENSSL_sk_new_null())
+#define sk_OSSL_CMP_CERTREPMESSAGE_new_reserve(cmp, n) ((STACK_OF(OSSL_CMP_CERTREPMESSAGE) *)OPENSSL_sk_new_reserve(ossl_check_OSSL_CMP_CERTREPMESSAGE_compfunc_type(cmp), (n)))
+#define sk_OSSL_CMP_CERTREPMESSAGE_reserve(sk, n) OPENSSL_sk_reserve(ossl_check_OSSL_CMP_CERTREPMESSAGE_sk_type(sk), (n))
+#define sk_OSSL_CMP_CERTREPMESSAGE_free(sk) OPENSSL_sk_free(ossl_check_OSSL_CMP_CERTREPMESSAGE_sk_type(sk))
+#define sk_OSSL_CMP_CERTREPMESSAGE_zero(sk) OPENSSL_sk_zero(ossl_check_OSSL_CMP_CERTREPMESSAGE_sk_type(sk))
+#define sk_OSSL_CMP_CERTREPMESSAGE_delete(sk, i) ((OSSL_CMP_CERTREPMESSAGE *)OPENSSL_sk_delete(ossl_check_OSSL_CMP_CERTREPMESSAGE_sk_type(sk), (i)))
+#define sk_OSSL_CMP_CERTREPMESSAGE_delete_ptr(sk, ptr) ((OSSL_CMP_CERTREPMESSAGE *)OPENSSL_sk_delete_ptr(ossl_check_OSSL_CMP_CERTREPMESSAGE_sk_type(sk), ossl_check_OSSL_CMP_CERTREPMESSAGE_type(ptr)))
+#define sk_OSSL_CMP_CERTREPMESSAGE_push(sk, ptr) OPENSSL_sk_push(ossl_check_OSSL_CMP_CERTREPMESSAGE_sk_type(sk), ossl_check_OSSL_CMP_CERTREPMESSAGE_type(ptr))
+#define sk_OSSL_CMP_CERTREPMESSAGE_unshift(sk, ptr) OPENSSL_sk_unshift(ossl_check_OSSL_CMP_CERTREPMESSAGE_sk_type(sk), ossl_check_OSSL_CMP_CERTREPMESSAGE_type(ptr))
+#define sk_OSSL_CMP_CERTREPMESSAGE_pop(sk) ((OSSL_CMP_CERTREPMESSAGE *)OPENSSL_sk_pop(ossl_check_OSSL_CMP_CERTREPMESSAGE_sk_type(sk)))
+#define sk_OSSL_CMP_CERTREPMESSAGE_shift(sk) ((OSSL_CMP_CERTREPMESSAGE *)OPENSSL_sk_shift(ossl_check_OSSL_CMP_CERTREPMESSAGE_sk_type(sk)))
+#define sk_OSSL_CMP_CERTREPMESSAGE_pop_free(sk, freefunc) OPENSSL_sk_pop_free(ossl_check_OSSL_CMP_CERTREPMESSAGE_sk_type(sk), ossl_check_OSSL_CMP_CERTREPMESSAGE_freefunc_type(freefunc))
+#define sk_OSSL_CMP_CERTREPMESSAGE_insert(sk, ptr, idx) OPENSSL_sk_insert(ossl_check_OSSL_CMP_CERTREPMESSAGE_sk_type(sk), ossl_check_OSSL_CMP_CERTREPMESSAGE_type(ptr), (idx))
+#define sk_OSSL_CMP_CERTREPMESSAGE_set(sk, idx, ptr) ((OSSL_CMP_CERTREPMESSAGE *)OPENSSL_sk_set(ossl_check_OSSL_CMP_CERTREPMESSAGE_sk_type(sk), (idx), ossl_check_OSSL_CMP_CERTREPMESSAGE_type(ptr)))
+#define sk_OSSL_CMP_CERTREPMESSAGE_find(sk, ptr) OPENSSL_sk_find(ossl_check_OSSL_CMP_CERTREPMESSAGE_sk_type(sk), ossl_check_OSSL_CMP_CERTREPMESSAGE_type(ptr))
+#define sk_OSSL_CMP_CERTREPMESSAGE_find_ex(sk, ptr) OPENSSL_sk_find_ex(ossl_check_OSSL_CMP_CERTREPMESSAGE_sk_type(sk), ossl_check_OSSL_CMP_CERTREPMESSAGE_type(ptr))
+#define sk_OSSL_CMP_CERTREPMESSAGE_find_all(sk, ptr, pnum) OPENSSL_sk_find_all(ossl_check_OSSL_CMP_CERTREPMESSAGE_sk_type(sk), ossl_check_OSSL_CMP_CERTREPMESSAGE_type(ptr), pnum)
+#define sk_OSSL_CMP_CERTREPMESSAGE_sort(sk) OPENSSL_sk_sort(ossl_check_OSSL_CMP_CERTREPMESSAGE_sk_type(sk))
+#define sk_OSSL_CMP_CERTREPMESSAGE_is_sorted(sk) OPENSSL_sk_is_sorted(ossl_check_const_OSSL_CMP_CERTREPMESSAGE_sk_type(sk))
+#define sk_OSSL_CMP_CERTREPMESSAGE_dup(sk) ((STACK_OF(OSSL_CMP_CERTREPMESSAGE) *)OPENSSL_sk_dup(ossl_check_const_OSSL_CMP_CERTREPMESSAGE_sk_type(sk)))
+#define sk_OSSL_CMP_CERTREPMESSAGE_deep_copy(sk, copyfunc, freefunc) ((STACK_OF(OSSL_CMP_CERTREPMESSAGE) *)OPENSSL_sk_deep_copy(ossl_check_const_OSSL_CMP_CERTREPMESSAGE_sk_type(sk), ossl_check_OSSL_CMP_CERTREPMESSAGE_copyfunc_type(copyfunc), ossl_check_OSSL_CMP_CERTREPMESSAGE_freefunc_type(freefunc)))
+#define sk_OSSL_CMP_CERTREPMESSAGE_set_cmp_func(sk, cmp) ((sk_OSSL_CMP_CERTREPMESSAGE_compfunc)OPENSSL_sk_set_cmp_func(ossl_check_OSSL_CMP_CERTREPMESSAGE_sk_type(sk), ossl_check_OSSL_CMP_CERTREPMESSAGE_compfunc_type(cmp)))
+
+/* clang-format on */
+typedef struct ossl_cmp_pollrep_st OSSL_CMP_POLLREP;
+typedef STACK_OF(OSSL_CMP_POLLREP) OSSL_CMP_POLLREPCONTENT;
+typedef struct ossl_cmp_certresponse_st OSSL_CMP_CERTRESPONSE;
+/* clang-format off */
+SKM_DEFINE_STACK_OF_INTERNAL(OSSL_CMP_CERTRESPONSE, OSSL_CMP_CERTRESPONSE, OSSL_CMP_CERTRESPONSE)
+#define sk_OSSL_CMP_CERTRESPONSE_num(sk) OPENSSL_sk_num(ossl_check_const_OSSL_CMP_CERTRESPONSE_sk_type(sk))
+#define sk_OSSL_CMP_CERTRESPONSE_value(sk, idx) ((OSSL_CMP_CERTRESPONSE *)OPENSSL_sk_value(ossl_check_const_OSSL_CMP_CERTRESPONSE_sk_type(sk), (idx)))
+#define sk_OSSL_CMP_CERTRESPONSE_new(cmp) ((STACK_OF(OSSL_CMP_CERTRESPONSE) *)OPENSSL_sk_new(ossl_check_OSSL_CMP_CERTRESPONSE_compfunc_type(cmp)))
+#define sk_OSSL_CMP_CERTRESPONSE_new_null() ((STACK_OF(OSSL_CMP_CERTRESPONSE) *)OPENSSL_sk_new_null())
+#define sk_OSSL_CMP_CERTRESPONSE_new_reserve(cmp, n) ((STACK_OF(OSSL_CMP_CERTRESPONSE) *)OPENSSL_sk_new_reserve(ossl_check_OSSL_CMP_CERTRESPONSE_compfunc_type(cmp), (n)))
+#define sk_OSSL_CMP_CERTRESPONSE_reserve(sk, n) OPENSSL_sk_reserve(ossl_check_OSSL_CMP_CERTRESPONSE_sk_type(sk), (n))
+#define sk_OSSL_CMP_CERTRESPONSE_free(sk) OPENSSL_sk_free(ossl_check_OSSL_CMP_CERTRESPONSE_sk_type(sk))
+#define sk_OSSL_CMP_CERTRESPONSE_zero(sk) OPENSSL_sk_zero(ossl_check_OSSL_CMP_CERTRESPONSE_sk_type(sk))
+#define sk_OSSL_CMP_CERTRESPONSE_delete(sk, i) ((OSSL_CMP_CERTRESPONSE *)OPENSSL_sk_delete(ossl_check_OSSL_CMP_CERTRESPONSE_sk_type(sk), (i)))
+#define sk_OSSL_CMP_CERTRESPONSE_delete_ptr(sk, ptr) ((OSSL_CMP_CERTRESPONSE *)OPENSSL_sk_delete_ptr(ossl_check_OSSL_CMP_CERTRESPONSE_sk_type(sk), ossl_check_OSSL_CMP_CERTRESPONSE_type(ptr)))
+#define sk_OSSL_CMP_CERTRESPONSE_push(sk, ptr) OPENSSL_sk_push(ossl_check_OSSL_CMP_CERTRESPONSE_sk_type(sk), ossl_check_OSSL_CMP_CERTRESPONSE_type(ptr))
+#define sk_OSSL_CMP_CERTRESPONSE_unshift(sk, ptr) OPENSSL_sk_unshift(ossl_check_OSSL_CMP_CERTRESPONSE_sk_type(sk), ossl_check_OSSL_CMP_CERTRESPONSE_type(ptr))
+#define sk_OSSL_CMP_CERTRESPONSE_pop(sk) ((OSSL_CMP_CERTRESPONSE *)OPENSSL_sk_pop(ossl_check_OSSL_CMP_CERTRESPONSE_sk_type(sk)))
+#define sk_OSSL_CMP_CERTRESPONSE_shift(sk) ((OSSL_CMP_CERTRESPONSE *)OPENSSL_sk_shift(ossl_check_OSSL_CMP_CERTRESPONSE_sk_type(sk)))
+#define sk_OSSL_CMP_CERTRESPONSE_pop_free(sk, freefunc) OPENSSL_sk_pop_free(ossl_check_OSSL_CMP_CERTRESPONSE_sk_type(sk), ossl_check_OSSL_CMP_CERTRESPONSE_freefunc_type(freefunc))
+#define sk_OSSL_CMP_CERTRESPONSE_insert(sk, ptr, idx) OPENSSL_sk_insert(ossl_check_OSSL_CMP_CERTRESPONSE_sk_type(sk), ossl_check_OSSL_CMP_CERTRESPONSE_type(ptr), (idx))
+#define sk_OSSL_CMP_CERTRESPONSE_set(sk, idx, ptr) ((OSSL_CMP_CERTRESPONSE *)OPENSSL_sk_set(ossl_check_OSSL_CMP_CERTRESPONSE_sk_type(sk), (idx), ossl_check_OSSL_CMP_CERTRESPONSE_type(ptr)))
+#define sk_OSSL_CMP_CERTRESPONSE_find(sk, ptr) OPENSSL_sk_find(ossl_check_OSSL_CMP_CERTRESPONSE_sk_type(sk), ossl_check_OSSL_CMP_CERTRESPONSE_type(ptr))
+#define sk_OSSL_CMP_CERTRESPONSE_find_ex(sk, ptr) OPENSSL_sk_find_ex(ossl_check_OSSL_CMP_CERTRESPONSE_sk_type(sk), ossl_check_OSSL_CMP_CERTRESPONSE_type(ptr))
+#define sk_OSSL_CMP_CERTRESPONSE_find_all(sk, ptr, pnum) OPENSSL_sk_find_all(ossl_check_OSSL_CMP_CERTRESPONSE_sk_type(sk), ossl_check_OSSL_CMP_CERTRESPONSE_type(ptr), pnum)
+#define sk_OSSL_CMP_CERTRESPONSE_sort(sk) OPENSSL_sk_sort(ossl_check_OSSL_CMP_CERTRESPONSE_sk_type(sk))
+#define sk_OSSL_CMP_CERTRESPONSE_is_sorted(sk) OPENSSL_sk_is_sorted(ossl_check_const_OSSL_CMP_CERTRESPONSE_sk_type(sk))
+#define sk_OSSL_CMP_CERTRESPONSE_dup(sk) ((STACK_OF(OSSL_CMP_CERTRESPONSE) *)OPENSSL_sk_dup(ossl_check_const_OSSL_CMP_CERTRESPONSE_sk_type(sk)))
+#define sk_OSSL_CMP_CERTRESPONSE_deep_copy(sk, copyfunc, freefunc) ((STACK_OF(OSSL_CMP_CERTRESPONSE) *)OPENSSL_sk_deep_copy(ossl_check_const_OSSL_CMP_CERTRESPONSE_sk_type(sk), ossl_check_OSSL_CMP_CERTRESPONSE_copyfunc_type(copyfunc), ossl_check_OSSL_CMP_CERTRESPONSE_freefunc_type(freefunc)))
+#define sk_OSSL_CMP_CERTRESPONSE_set_cmp_func(sk, cmp) ((sk_OSSL_CMP_CERTRESPONSE_compfunc)OPENSSL_sk_set_cmp_func(ossl_check_OSSL_CMP_CERTRESPONSE_sk_type(sk), ossl_check_OSSL_CMP_CERTRESPONSE_compfunc_type(cmp)))
+
+/* clang-format on */
+typedef STACK_OF(ASN1_UTF8STRING) OSSL_CMP_PKIFREETEXT;
+
+/*
+ * function DECLARATIONS
+ */
+
+/* from cmp_asn.c */
+OSSL_CMP_ITAV *OSSL_CMP_ITAV_create(ASN1_OBJECT *type, ASN1_TYPE *value);
+void OSSL_CMP_ITAV_set0(OSSL_CMP_ITAV *itav, ASN1_OBJECT *type,
+ ASN1_TYPE *value);
+ASN1_OBJECT *OSSL_CMP_ITAV_get0_type(const OSSL_CMP_ITAV *itav);
+ASN1_TYPE *OSSL_CMP_ITAV_get0_value(const OSSL_CMP_ITAV *itav);
+int OSSL_CMP_ITAV_push0_stack_item(STACK_OF(OSSL_CMP_ITAV) **sk_p,
+ OSSL_CMP_ITAV *itav);
+void OSSL_CMP_ITAV_free(OSSL_CMP_ITAV *itav);
+
+OSSL_CMP_ITAV *OSSL_CMP_ITAV_new0_certProfile(STACK_OF(ASN1_UTF8STRING)
+ *certProfile);
+int OSSL_CMP_ITAV_get0_certProfile(const OSSL_CMP_ITAV *itav,
+ STACK_OF(ASN1_UTF8STRING) **out);
+OSSL_CMP_ITAV *OSSL_CMP_ITAV_new_caCerts(const STACK_OF(X509) *caCerts);
+int OSSL_CMP_ITAV_get0_caCerts(const OSSL_CMP_ITAV *itav, STACK_OF(X509) **out);
+
+OSSL_CMP_ITAV *OSSL_CMP_ITAV_new_rootCaCert(const X509 *rootCaCert);
+int OSSL_CMP_ITAV_get0_rootCaCert(const OSSL_CMP_ITAV *itav, X509 **out);
+OSSL_CMP_ITAV *OSSL_CMP_ITAV_new_rootCaKeyUpdate(const X509 *newWithNew,
+ const X509 *newWithOld,
+ const X509 *oldWithNew);
+int OSSL_CMP_ITAV_get0_rootCaKeyUpdate(const OSSL_CMP_ITAV *itav,
+ X509 **newWithNew,
+ X509 **newWithOld,
+ X509 **oldWithNew);
+
+OSSL_CMP_CRLSTATUS *OSSL_CMP_CRLSTATUS_create(const X509_CRL *crl,
+ const X509 *cert, int only_DN);
+OSSL_CMP_CRLSTATUS *OSSL_CMP_CRLSTATUS_new1(const DIST_POINT_NAME *dpn,
+ const GENERAL_NAMES *issuer,
+ const ASN1_TIME *thisUpdate);
+int OSSL_CMP_CRLSTATUS_get0(const OSSL_CMP_CRLSTATUS *crlstatus,
+ DIST_POINT_NAME **dpn, GENERAL_NAMES **issuer,
+ ASN1_TIME **thisUpdate);
+void OSSL_CMP_CRLSTATUS_free(OSSL_CMP_CRLSTATUS *crlstatus);
+OSSL_CMP_ITAV
+*OSSL_CMP_ITAV_new0_crlStatusList(STACK_OF(OSSL_CMP_CRLSTATUS) *crlStatusList);
+int OSSL_CMP_ITAV_get0_crlStatusList(const OSSL_CMP_ITAV *itav,
+ STACK_OF(OSSL_CMP_CRLSTATUS) **out);
+OSSL_CMP_ITAV *OSSL_CMP_ITAV_new_crls(const X509_CRL *crls);
+int OSSL_CMP_ITAV_get0_crls(const OSSL_CMP_ITAV *it, STACK_OF(X509_CRL) **out);
+OSSL_CMP_ITAV
+*OSSL_CMP_ITAV_new0_certReqTemplate(OSSL_CRMF_CERTTEMPLATE *certTemplate,
+ OSSL_CMP_ATAVS *keySpec);
+int OSSL_CMP_ITAV_get1_certReqTemplate(const OSSL_CMP_ITAV *itav,
+ OSSL_CRMF_CERTTEMPLATE **certTemplate,
+ OSSL_CMP_ATAVS **keySpec);
+
+OSSL_CMP_ATAV *OSSL_CMP_ATAV_create(ASN1_OBJECT *type, ASN1_TYPE *value);
+void OSSL_CMP_ATAV_set0(OSSL_CMP_ATAV *itav, ASN1_OBJECT *type,
+ ASN1_TYPE *value);
+ASN1_OBJECT *OSSL_CMP_ATAV_get0_type(const OSSL_CMP_ATAV *itav);
+ASN1_TYPE *OSSL_CMP_ATAV_get0_value(const OSSL_CMP_ATAV *itav);
+OSSL_CMP_ATAV *OSSL_CMP_ATAV_new_algId(const X509_ALGOR *alg);
+X509_ALGOR *OSSL_CMP_ATAV_get0_algId(const OSSL_CMP_ATAV *atav);
+OSSL_CMP_ATAV *OSSL_CMP_ATAV_new_rsaKeyLen(int len);
+int OSSL_CMP_ATAV_get_rsaKeyLen(const OSSL_CMP_ATAV *atav);
+int OSSL_CMP_ATAV_push1(OSSL_CMP_ATAVS **sk_p, const OSSL_CMP_ATAV *atav);
+
+void OSSL_CMP_MSG_free(OSSL_CMP_MSG *msg);
+
+/* from cmp_ctx.c */
+OSSL_CMP_CTX *OSSL_CMP_CTX_new(OSSL_LIB_CTX *libctx, const char *propq);
+void OSSL_CMP_CTX_free(OSSL_CMP_CTX *ctx);
+int OSSL_CMP_CTX_reinit(OSSL_CMP_CTX *ctx);
+OSSL_LIB_CTX *OSSL_CMP_CTX_get0_libctx(const OSSL_CMP_CTX *ctx);
+const char *OSSL_CMP_CTX_get0_propq(const OSSL_CMP_CTX *ctx);
+/* CMP general options: */
+#define OSSL_CMP_OPT_LOG_VERBOSITY 0
+/* CMP transfer options: */
+#define OSSL_CMP_OPT_KEEP_ALIVE 10
+#define OSSL_CMP_OPT_MSG_TIMEOUT 11
+#define OSSL_CMP_OPT_TOTAL_TIMEOUT 12
+#define OSSL_CMP_OPT_USE_TLS 13
+/* CMP request options: */
+#define OSSL_CMP_OPT_VALIDITY_DAYS 20
+#define OSSL_CMP_OPT_SUBJECTALTNAME_NODEFAULT 21
+#define OSSL_CMP_OPT_SUBJECTALTNAME_CRITICAL 22
+#define OSSL_CMP_OPT_POLICIES_CRITICAL 23
+#define OSSL_CMP_OPT_POPO_METHOD 24
+#define OSSL_CMP_OPT_IMPLICIT_CONFIRM 25
+#define OSSL_CMP_OPT_DISABLE_CONFIRM 26
+#define OSSL_CMP_OPT_REVOCATION_REASON 27
+/* CMP protection options: */
+#define OSSL_CMP_OPT_UNPROTECTED_SEND 30
+#define OSSL_CMP_OPT_UNPROTECTED_ERRORS 31
+#define OSSL_CMP_OPT_OWF_ALGNID 32
+#define OSSL_CMP_OPT_MAC_ALGNID 33
+#define OSSL_CMP_OPT_DIGEST_ALGNID 34
+#define OSSL_CMP_OPT_IGNORE_KEYUSAGE 35
+#define OSSL_CMP_OPT_PERMIT_TA_IN_EXTRACERTS_FOR_IR 36
+#define OSSL_CMP_OPT_NO_CACHE_EXTRACERTS 37
+int OSSL_CMP_CTX_set_option(OSSL_CMP_CTX *ctx, int opt, int val);
+int OSSL_CMP_CTX_get_option(const OSSL_CMP_CTX *ctx, int opt);
+/* CMP-specific callback for logging and outputting the error queue: */
+int OSSL_CMP_CTX_set_log_cb(OSSL_CMP_CTX *ctx, OSSL_CMP_log_cb_t cb);
+#define OSSL_CMP_CTX_set_log_verbosity(ctx, level) \
+ OSSL_CMP_CTX_set_option(ctx, OSSL_CMP_OPT_LOG_VERBOSITY, level)
+void OSSL_CMP_CTX_print_errors(const OSSL_CMP_CTX *ctx);
+/* message transfer: */
+int OSSL_CMP_CTX_set1_serverPath(OSSL_CMP_CTX *ctx, const char *path);
+int OSSL_CMP_CTX_set1_server(OSSL_CMP_CTX *ctx, const char *address);
+int OSSL_CMP_CTX_set_serverPort(OSSL_CMP_CTX *ctx, int port);
+int OSSL_CMP_CTX_set1_proxy(OSSL_CMP_CTX *ctx, const char *name);
+int OSSL_CMP_CTX_set1_no_proxy(OSSL_CMP_CTX *ctx, const char *names);
+#ifndef OPENSSL_NO_HTTP
+int OSSL_CMP_CTX_set_http_cb(OSSL_CMP_CTX *ctx, OSSL_HTTP_bio_cb_t cb);
+int OSSL_CMP_CTX_set_http_cb_arg(OSSL_CMP_CTX *ctx, void *arg);
+void *OSSL_CMP_CTX_get_http_cb_arg(const OSSL_CMP_CTX *ctx);
+#endif
+typedef OSSL_CMP_MSG *(*OSSL_CMP_transfer_cb_t)(OSSL_CMP_CTX *ctx,
+ const OSSL_CMP_MSG *req);
+int OSSL_CMP_CTX_set_transfer_cb(OSSL_CMP_CTX *ctx, OSSL_CMP_transfer_cb_t cb);
+int OSSL_CMP_CTX_set_transfer_cb_arg(OSSL_CMP_CTX *ctx, void *arg);
+void *OSSL_CMP_CTX_get_transfer_cb_arg(const OSSL_CMP_CTX *ctx);
+/* server authentication: */
+int OSSL_CMP_CTX_set1_srvCert(OSSL_CMP_CTX *ctx, X509 *cert);
+int OSSL_CMP_CTX_set1_expected_sender(OSSL_CMP_CTX *ctx, const X509_NAME *name);
+int OSSL_CMP_CTX_set0_trustedStore(OSSL_CMP_CTX *ctx, X509_STORE *store);
+#define OSSL_CMP_CTX_set0_trusted OSSL_CMP_CTX_set0_trustedStore
+X509_STORE *OSSL_CMP_CTX_get0_trustedStore(const OSSL_CMP_CTX *ctx);
+#define OSSL_CMP_CTX_get0_trusted OSSL_CMP_CTX_get0_trustedStore
+int OSSL_CMP_CTX_set1_untrusted(OSSL_CMP_CTX *ctx, STACK_OF(X509) *certs);
+STACK_OF(X509) *OSSL_CMP_CTX_get0_untrusted(const OSSL_CMP_CTX *ctx);
+/* client authentication: */
+int OSSL_CMP_CTX_set1_cert(OSSL_CMP_CTX *ctx, X509 *cert);
+int OSSL_CMP_CTX_build_cert_chain(OSSL_CMP_CTX *ctx, X509_STORE *own_trusted,
+ STACK_OF(X509) *candidates);
+int OSSL_CMP_CTX_set1_pkey(OSSL_CMP_CTX *ctx, EVP_PKEY *pkey);
+int OSSL_CMP_CTX_set1_referenceValue(OSSL_CMP_CTX *ctx,
+ const unsigned char *ref, int len);
+int OSSL_CMP_CTX_set1_secretValue(OSSL_CMP_CTX *ctx,
+ const unsigned char *sec, int len);
+/* CMP message header and extra certificates: */
+int OSSL_CMP_CTX_set1_recipient(OSSL_CMP_CTX *ctx, const X509_NAME *name);
+int OSSL_CMP_CTX_push0_geninfo_ITAV(OSSL_CMP_CTX *ctx, OSSL_CMP_ITAV *itav);
+int OSSL_CMP_CTX_reset_geninfo_ITAVs(OSSL_CMP_CTX *ctx);
+STACK_OF(OSSL_CMP_ITAV)
+*OSSL_CMP_CTX_get0_geninfo_ITAVs(const OSSL_CMP_CTX *ctx);
+int OSSL_CMP_CTX_set1_extraCertsOut(OSSL_CMP_CTX *ctx,
+ STACK_OF(X509) *extraCertsOut);
+/* certificate template: */
+int OSSL_CMP_CTX_set0_newPkey(OSSL_CMP_CTX *ctx, int priv, EVP_PKEY *pkey);
+EVP_PKEY *OSSL_CMP_CTX_get0_newPkey(const OSSL_CMP_CTX *ctx, int priv);
+int OSSL_CMP_CTX_set1_issuer(OSSL_CMP_CTX *ctx, const X509_NAME *name);
+int OSSL_CMP_CTX_set1_serialNumber(OSSL_CMP_CTX *ctx, const ASN1_INTEGER *sn);
+int OSSL_CMP_CTX_set1_subjectName(OSSL_CMP_CTX *ctx, const X509_NAME *name);
+int OSSL_CMP_CTX_push1_subjectAltName(OSSL_CMP_CTX *ctx,
+ const GENERAL_NAME *name);
+int OSSL_CMP_CTX_set0_reqExtensions(OSSL_CMP_CTX *ctx, X509_EXTENSIONS *exts);
+int OSSL_CMP_CTX_reqExtensions_have_SAN(OSSL_CMP_CTX *ctx);
+int OSSL_CMP_CTX_push0_policy(OSSL_CMP_CTX *ctx, POLICYINFO *pinfo);
+int OSSL_CMP_CTX_set1_oldCert(OSSL_CMP_CTX *ctx, X509 *cert);
+int OSSL_CMP_CTX_set1_p10CSR(OSSL_CMP_CTX *ctx, const X509_REQ *csr);
+/* misc body contents: */
+int OSSL_CMP_CTX_push0_genm_ITAV(OSSL_CMP_CTX *ctx, OSSL_CMP_ITAV *itav);
+/* certificate confirmation: */
+typedef int (*OSSL_CMP_certConf_cb_t)(OSSL_CMP_CTX *ctx, X509 *cert,
+ int fail_info, const char **txt);
+int OSSL_CMP_certConf_cb(OSSL_CMP_CTX *ctx, X509 *cert, int fail_info,
+ const char **text);
+int OSSL_CMP_CTX_set_certConf_cb(OSSL_CMP_CTX *ctx, OSSL_CMP_certConf_cb_t cb);
+int OSSL_CMP_CTX_set_certConf_cb_arg(OSSL_CMP_CTX *ctx, void *arg);
+void *OSSL_CMP_CTX_get_certConf_cb_arg(const OSSL_CMP_CTX *ctx);
+/* result fetching: */
+int OSSL_CMP_CTX_get_status(const OSSL_CMP_CTX *ctx);
+OSSL_CMP_PKIFREETEXT *OSSL_CMP_CTX_get0_statusString(const OSSL_CMP_CTX *ctx);
+int OSSL_CMP_CTX_get_failInfoCode(const OSSL_CMP_CTX *ctx);
+#define OSSL_CMP_PKISI_BUFLEN 1024
+X509 *OSSL_CMP_CTX_get0_validatedSrvCert(const OSSL_CMP_CTX *ctx);
+X509 *OSSL_CMP_CTX_get0_newCert(const OSSL_CMP_CTX *ctx);
+STACK_OF(X509) *OSSL_CMP_CTX_get1_newChain(const OSSL_CMP_CTX *ctx);
+STACK_OF(X509) *OSSL_CMP_CTX_get1_caPubs(const OSSL_CMP_CTX *ctx);
+STACK_OF(X509) *OSSL_CMP_CTX_get1_extraCertsIn(const OSSL_CMP_CTX *ctx);
+int OSSL_CMP_CTX_set1_transactionID(OSSL_CMP_CTX *ctx,
+ const ASN1_OCTET_STRING *id);
+int OSSL_CMP_CTX_set1_senderNonce(OSSL_CMP_CTX *ctx,
+ const ASN1_OCTET_STRING *nonce);
+
+/* from cmp_status.c */
+char *OSSL_CMP_CTX_snprint_PKIStatus(const OSSL_CMP_CTX *ctx, char *buf,
+ size_t bufsize);
+char *OSSL_CMP_snprint_PKIStatusInfo(const OSSL_CMP_PKISI *statusInfo,
+ char *buf, size_t bufsize);
+OSSL_CMP_PKISI *
+OSSL_CMP_STATUSINFO_new(int status, int fail_info, const char *text);
+
+/* from cmp_hdr.c */
+ASN1_OCTET_STRING *OSSL_CMP_HDR_get0_transactionID(const OSSL_CMP_PKIHEADER *hdr);
+ASN1_OCTET_STRING *OSSL_CMP_HDR_get0_recipNonce(const OSSL_CMP_PKIHEADER *hdr);
+STACK_OF(OSSL_CMP_ITAV)
+*OSSL_CMP_HDR_get0_geninfo_ITAVs(const OSSL_CMP_PKIHEADER *hdr);
+
+/* from cmp_msg.c */
+OSSL_CMP_PKIHEADER *OSSL_CMP_MSG_get0_header(const OSSL_CMP_MSG *msg);
+int OSSL_CMP_MSG_get_bodytype(const OSSL_CMP_MSG *msg);
+X509_PUBKEY *OSSL_CMP_MSG_get0_certreq_publickey(const OSSL_CMP_MSG *msg);
+int OSSL_CMP_MSG_update_transactionID(OSSL_CMP_CTX *ctx, OSSL_CMP_MSG *msg);
+int OSSL_CMP_MSG_update_recipNonce(OSSL_CMP_CTX *ctx, OSSL_CMP_MSG *msg);
+OSSL_CRMF_MSG *OSSL_CMP_CTX_setup_CRM(OSSL_CMP_CTX *ctx, int for_KUR, int rid);
+OSSL_CMP_MSG *OSSL_CMP_MSG_read(const char *file, OSSL_LIB_CTX *libctx,
+ const char *propq);
+int OSSL_CMP_MSG_write(const char *file, const OSSL_CMP_MSG *msg);
+OSSL_CMP_MSG *d2i_OSSL_CMP_MSG_bio(BIO *bio, OSSL_CMP_MSG **msg);
+int i2d_OSSL_CMP_MSG_bio(BIO *bio, const OSSL_CMP_MSG *msg);
+
+/* from cmp_vfy.c */
+int OSSL_CMP_validate_msg(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg);
+int OSSL_CMP_validate_cert_path(const OSSL_CMP_CTX *ctx,
+ X509_STORE *trusted_store, X509 *cert);
+
+/* from cmp_http.c */
+#ifndef OPENSSL_NO_HTTP
+OSSL_CMP_MSG *OSSL_CMP_MSG_http_perform(OSSL_CMP_CTX *ctx,
+ const OSSL_CMP_MSG *req);
+#endif
+
+/* from cmp_server.c */
+typedef struct ossl_cmp_srv_ctx_st OSSL_CMP_SRV_CTX;
+OSSL_CMP_MSG *OSSL_CMP_SRV_process_request(OSSL_CMP_SRV_CTX *srv_ctx,
+ const OSSL_CMP_MSG *req);
+OSSL_CMP_MSG *OSSL_CMP_CTX_server_perform(OSSL_CMP_CTX *client_ctx,
+ const OSSL_CMP_MSG *req);
+OSSL_CMP_SRV_CTX *OSSL_CMP_SRV_CTX_new(OSSL_LIB_CTX *libctx, const char *propq);
+void OSSL_CMP_SRV_CTX_free(OSSL_CMP_SRV_CTX *srv_ctx);
+typedef OSSL_CMP_PKISI *(*OSSL_CMP_SRV_cert_request_cb_t)(OSSL_CMP_SRV_CTX *srv_ctx, const OSSL_CMP_MSG *req, int certReqId,
+ const OSSL_CRMF_MSG *crm, const X509_REQ *p10cr,
+ X509 **certOut, STACK_OF(X509) **chainOut, STACK_OF(X509) **caPubs);
+typedef OSSL_CMP_PKISI *(*OSSL_CMP_SRV_rr_cb_t)(OSSL_CMP_SRV_CTX *srv_ctx,
+ const OSSL_CMP_MSG *req,
+ const X509_NAME *issuer,
+ const ASN1_INTEGER *serial);
+typedef int (*OSSL_CMP_SRV_genm_cb_t)(OSSL_CMP_SRV_CTX *srv_ctx,
+ const OSSL_CMP_MSG *req,
+ const STACK_OF(OSSL_CMP_ITAV) *in,
+ STACK_OF(OSSL_CMP_ITAV) **out);
+typedef void (*OSSL_CMP_SRV_error_cb_t)(OSSL_CMP_SRV_CTX *srv_ctx,
+ const OSSL_CMP_MSG *req,
+ const OSSL_CMP_PKISI *statusInfo,
+ const ASN1_INTEGER *errorCode,
+ const OSSL_CMP_PKIFREETEXT *errDetails);
+typedef int (*OSSL_CMP_SRV_certConf_cb_t)(OSSL_CMP_SRV_CTX *srv_ctx,
+ const OSSL_CMP_MSG *req,
+ int certReqId,
+ const ASN1_OCTET_STRING *certHash,
+ const OSSL_CMP_PKISI *si);
+typedef int (*OSSL_CMP_SRV_pollReq_cb_t)(OSSL_CMP_SRV_CTX *srv_ctx,
+ const OSSL_CMP_MSG *req, int certReqId,
+ OSSL_CMP_MSG **certReq,
+ int64_t *check_after);
+int OSSL_CMP_SRV_CTX_init(OSSL_CMP_SRV_CTX *srv_ctx, void *custom_ctx,
+ OSSL_CMP_SRV_cert_request_cb_t process_cert_request,
+ OSSL_CMP_SRV_rr_cb_t process_rr,
+ OSSL_CMP_SRV_genm_cb_t process_genm,
+ OSSL_CMP_SRV_error_cb_t process_error,
+ OSSL_CMP_SRV_certConf_cb_t process_certConf,
+ OSSL_CMP_SRV_pollReq_cb_t process_pollReq);
+typedef int (*OSSL_CMP_SRV_delayed_delivery_cb_t)(OSSL_CMP_SRV_CTX *srv_ctx,
+ const OSSL_CMP_MSG *req);
+typedef int (*OSSL_CMP_SRV_clean_transaction_cb_t)(OSSL_CMP_SRV_CTX *srv_ctx,
+ const ASN1_OCTET_STRING *id);
+int OSSL_CMP_SRV_CTX_init_trans(OSSL_CMP_SRV_CTX *srv_ctx,
+ OSSL_CMP_SRV_delayed_delivery_cb_t delay,
+ OSSL_CMP_SRV_clean_transaction_cb_t clean);
+OSSL_CMP_CTX *OSSL_CMP_SRV_CTX_get0_cmp_ctx(const OSSL_CMP_SRV_CTX *srv_ctx);
+void *OSSL_CMP_SRV_CTX_get0_custom_ctx(const OSSL_CMP_SRV_CTX *srv_ctx);
+int OSSL_CMP_SRV_CTX_set_send_unprotected_errors(OSSL_CMP_SRV_CTX *srv_ctx,
+ int val);
+int OSSL_CMP_SRV_CTX_set_accept_unprotected(OSSL_CMP_SRV_CTX *srv_ctx, int val);
+int OSSL_CMP_SRV_CTX_set_accept_raverified(OSSL_CMP_SRV_CTX *srv_ctx, int val);
+int OSSL_CMP_SRV_CTX_set_grant_implicit_confirm(OSSL_CMP_SRV_CTX *srv_ctx,
+ int val);
+
+/* from cmp_client.c */
+X509 *OSSL_CMP_exec_certreq(OSSL_CMP_CTX *ctx, int req_type,
+ const OSSL_CRMF_MSG *crm);
+#define OSSL_CMP_IR 0
+#define OSSL_CMP_CR 2
+#define OSSL_CMP_P10CR 4
+#define OSSL_CMP_KUR 7
+#define OSSL_CMP_GENM 21
+#define OSSL_CMP_ERROR 23
+#define OSSL_CMP_exec_IR_ses(ctx) \
+ OSSL_CMP_exec_certreq(ctx, OSSL_CMP_IR, NULL)
+#define OSSL_CMP_exec_CR_ses(ctx) \
+ OSSL_CMP_exec_certreq(ctx, OSSL_CMP_CR, NULL)
+#define OSSL_CMP_exec_P10CR_ses(ctx) \
+ OSSL_CMP_exec_certreq(ctx, OSSL_CMP_P10CR, NULL)
+#define OSSL_CMP_exec_KUR_ses(ctx) \
+ OSSL_CMP_exec_certreq(ctx, OSSL_CMP_KUR, NULL)
+int OSSL_CMP_try_certreq(OSSL_CMP_CTX *ctx, int req_type,
+ const OSSL_CRMF_MSG *crm, int *checkAfter);
+int OSSL_CMP_exec_RR_ses(OSSL_CMP_CTX *ctx);
+STACK_OF(OSSL_CMP_ITAV) *OSSL_CMP_exec_GENM_ses(OSSL_CMP_CTX *ctx);
+
+/* from cmp_genm.c */
+int OSSL_CMP_get1_caCerts(OSSL_CMP_CTX *ctx, STACK_OF(X509) **out);
+int OSSL_CMP_get1_rootCaKeyUpdate(OSSL_CMP_CTX *ctx,
+ const X509 *oldWithOld, X509 **newWithNew,
+ X509 **newWithOld, X509 **oldWithNew);
+int OSSL_CMP_get1_crlUpdate(OSSL_CMP_CTX *ctx, const X509 *crlcert,
+ const X509_CRL *last_crl,
+ X509_CRL **crl);
+int OSSL_CMP_get1_certReqTemplate(OSSL_CMP_CTX *ctx,
+ OSSL_CRMF_CERTTEMPLATE **certTemplate,
+ OSSL_CMP_ATAVS **keySpec);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* !defined(OPENSSL_NO_CMP) */
+#endif /* !defined(OPENSSL_CMP_H) */
diff --git a/third_party/ios/openssl/include/openssl/cmp_util.h b/third_party/ios/openssl/include/openssl/cmp_util.h
new file mode 100644
index 0000000..a0ee20f
--- /dev/null
+++ b/third_party/ios/openssl/include/openssl/cmp_util.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2007-2021 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright Nokia 2007-2019
+ * Copyright Siemens AG 2015-2019
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#ifndef OPENSSL_CMP_UTIL_H
+#define OPENSSL_CMP_UTIL_H
+#pragma once
+
+#include
+#ifndef OPENSSL_NO_CMP
+
+#include
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int OSSL_CMP_log_open(void);
+void OSSL_CMP_log_close(void);
+#define OSSL_CMP_LOG_PREFIX "CMP "
+
+/*
+ * generalized logging/error callback mirroring the severity levels of syslog.h
+ */
+typedef int OSSL_CMP_severity;
+#define OSSL_CMP_LOG_EMERG 0
+#define OSSL_CMP_LOG_ALERT 1
+#define OSSL_CMP_LOG_CRIT 2
+#define OSSL_CMP_LOG_ERR 3
+#define OSSL_CMP_LOG_WARNING 4
+#define OSSL_CMP_LOG_NOTICE 5
+#define OSSL_CMP_LOG_INFO 6
+#define OSSL_CMP_LOG_DEBUG 7
+#define OSSL_CMP_LOG_TRACE 8
+#define OSSL_CMP_LOG_MAX OSSL_CMP_LOG_TRACE
+typedef int (*OSSL_CMP_log_cb_t)(const char *func, const char *file, int line,
+ OSSL_CMP_severity level, const char *msg);
+
+int OSSL_CMP_print_to_bio(BIO *bio, const char *component, const char *file,
+ int line, OSSL_CMP_severity level, const char *msg);
+/* use of the logging callback for outputting error queue */
+void OSSL_CMP_print_errors_cb(OSSL_CMP_log_cb_t log_fn);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* !defined(OPENSSL_NO_CMP) */
+#endif /* !defined(OPENSSL_CMP_UTIL_H) */
diff --git a/third_party/ios/openssl/include/openssl/cmperr.h b/third_party/ios/openssl/include/openssl/cmperr.h
new file mode 100644
index 0000000..b07ac6d
--- /dev/null
+++ b/third_party/ios/openssl/include/openssl/cmperr.h
@@ -0,0 +1,132 @@
+/*
+ * Generated by util/mkerr.pl DO NOT EDIT
+ * Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#ifndef OPENSSL_CMPERR_H
+#define OPENSSL_CMPERR_H
+#pragma once
+
+#include
+#include
+#include
+
+#ifndef OPENSSL_NO_CMP
+
+/*
+ * CMP reason codes.
+ */
+#define CMP_R_ALGORITHM_NOT_SUPPORTED 139
+#define CMP_R_BAD_CHECKAFTER_IN_POLLREP 167
+#define CMP_R_BAD_REQUEST_ID 108
+#define CMP_R_CERTHASH_UNMATCHED 156
+#define CMP_R_CERTID_NOT_FOUND 109
+#define CMP_R_CERTIFICATE_NOT_ACCEPTED 169
+#define CMP_R_CERTIFICATE_NOT_FOUND 112
+#define CMP_R_CERTREQMSG_NOT_FOUND 157
+#define CMP_R_CERTRESPONSE_NOT_FOUND 113
+#define CMP_R_CERT_AND_KEY_DO_NOT_MATCH 114
+#define CMP_R_CHECKAFTER_OUT_OF_RANGE 181
+#define CMP_R_ENCOUNTERED_KEYUPDATEWARNING 176
+#define CMP_R_ENCOUNTERED_WAITING 162
+#define CMP_R_ERROR_CALCULATING_PROTECTION 115
+#define CMP_R_ERROR_CREATING_CERTCONF 116
+#define CMP_R_ERROR_CREATING_CERTREP 117
+#define CMP_R_ERROR_CREATING_CERTREQ 163
+#define CMP_R_ERROR_CREATING_ERROR 118
+#define CMP_R_ERROR_CREATING_GENM 119
+#define CMP_R_ERROR_CREATING_GENP 120
+#define CMP_R_ERROR_CREATING_PKICONF 122
+#define CMP_R_ERROR_CREATING_POLLREP 123
+#define CMP_R_ERROR_CREATING_POLLREQ 124
+#define CMP_R_ERROR_CREATING_RP 125
+#define CMP_R_ERROR_CREATING_RR 126
+#define CMP_R_ERROR_PARSING_PKISTATUS 107
+#define CMP_R_ERROR_PROCESSING_MESSAGE 158
+#define CMP_R_ERROR_PROTECTING_MESSAGE 127
+#define CMP_R_ERROR_SETTING_CERTHASH 128
+#define CMP_R_ERROR_UNEXPECTED_CERTCONF 160
+#define CMP_R_ERROR_VALIDATING_PROTECTION 140
+#define CMP_R_ERROR_VALIDATING_SIGNATURE 171
+#define CMP_R_EXPECTED_POLLREQ 104
+#define CMP_R_FAILED_BUILDING_OWN_CHAIN 164
+#define CMP_R_FAILED_EXTRACTING_CENTRAL_GEN_KEY 203
+#define CMP_R_FAILED_EXTRACTING_PUBKEY 141
+#define CMP_R_FAILURE_OBTAINING_RANDOM 110
+#define CMP_R_FAIL_INFO_OUT_OF_RANGE 129
+#define CMP_R_GENERATE_CERTREQTEMPLATE 197
+#define CMP_R_GENERATE_CRLSTATUS 198
+#define CMP_R_GETTING_GENP 192
+#define CMP_R_GET_ITAV 199
+#define CMP_R_INVALID_ARGS 100
+#define CMP_R_INVALID_GENP 193
+#define CMP_R_INVALID_KEYSPEC 202
+#define CMP_R_INVALID_OPTION 174
+#define CMP_R_INVALID_ROOTCAKEYUPDATE 195
+#define CMP_R_MISSING_CENTRAL_GEN_KEY 204
+#define CMP_R_MISSING_CERTID 165
+#define CMP_R_MISSING_KEY_INPUT_FOR_CREATING_PROTECTION 130
+#define CMP_R_MISSING_KEY_USAGE_DIGITALSIGNATURE 142
+#define CMP_R_MISSING_P10CSR 121
+#define CMP_R_MISSING_PBM_SECRET 166
+#define CMP_R_MISSING_PRIVATE_KEY 131
+#define CMP_R_MISSING_PRIVATE_KEY_FOR_POPO 190
+#define CMP_R_MISSING_PROTECTION 143
+#define CMP_R_MISSING_PUBLIC_KEY 183
+#define CMP_R_MISSING_REFERENCE_CERT 168
+#define CMP_R_MISSING_SECRET 178
+#define CMP_R_MISSING_SENDER_IDENTIFICATION 111
+#define CMP_R_MISSING_TRUST_ANCHOR 179
+#define CMP_R_MISSING_TRUST_STORE 144
+#define CMP_R_MULTIPLE_REQUESTS_NOT_SUPPORTED 161
+#define CMP_R_MULTIPLE_RESPONSES_NOT_SUPPORTED 170
+#define CMP_R_MULTIPLE_SAN_SOURCES 102
+#define CMP_R_NO_STDIO 194
+#define CMP_R_NO_SUITABLE_SENDER_CERT 145
+#define CMP_R_NULL_ARGUMENT 103
+#define CMP_R_PKIBODY_ERROR 146
+#define CMP_R_PKISTATUSINFO_NOT_FOUND 132
+#define CMP_R_POLLING_FAILED 172
+#define CMP_R_POTENTIALLY_INVALID_CERTIFICATE 147
+#define CMP_R_RECEIVED_ERROR 180
+#define CMP_R_RECIPNONCE_UNMATCHED 148
+#define CMP_R_REQUEST_NOT_ACCEPTED 149
+#define CMP_R_REQUEST_REJECTED_BY_SERVER 182
+#define CMP_R_SENDER_GENERALNAME_TYPE_NOT_SUPPORTED 150
+#define CMP_R_SRVCERT_DOES_NOT_VALIDATE_MSG 151
+#define CMP_R_TOTAL_TIMEOUT 184
+#define CMP_R_TRANSACTIONID_UNMATCHED 152
+#define CMP_R_TRANSFER_ERROR 159
+#define CMP_R_UNCLEAN_CTX 191
+#define CMP_R_UNEXPECTED_CENTRAL_GEN_KEY 205
+#define CMP_R_UNEXPECTED_CERTPROFILE 196
+#define CMP_R_UNEXPECTED_CRLSTATUSLIST 201
+#define CMP_R_UNEXPECTED_PKIBODY 133
+#define CMP_R_UNEXPECTED_PKISTATUS 185
+#define CMP_R_UNEXPECTED_POLLREQ 105
+#define CMP_R_UNEXPECTED_PVNO 153
+#define CMP_R_UNEXPECTED_SENDER 106
+#define CMP_R_UNKNOWN_ALGORITHM_ID 134
+#define CMP_R_UNKNOWN_CERT_TYPE 135
+#define CMP_R_UNKNOWN_CRL_ISSUER 200
+#define CMP_R_UNKNOWN_PKISTATUS 186
+#define CMP_R_UNSUPPORTED_ALGORITHM 136
+#define CMP_R_UNSUPPORTED_KEY_TYPE 137
+#define CMP_R_UNSUPPORTED_PKIBODY 101
+#define CMP_R_UNSUPPORTED_PROTECTION_ALG_DHBASEDMAC 154
+#define CMP_R_VALUE_TOO_LARGE 175
+#define CMP_R_VALUE_TOO_SMALL 177
+#define CMP_R_WRONG_ALGORITHM_OID 138
+#define CMP_R_WRONG_CERTID 189
+#define CMP_R_WRONG_CERTID_IN_RP 187
+#define CMP_R_WRONG_PBM_VALUE 155
+#define CMP_R_WRONG_RP_COMPONENT_COUNT 188
+#define CMP_R_WRONG_SERIAL_IN_RP 173
+
+#endif
+#endif
diff --git a/third_party/ios/openssl/include/openssl/cms.h b/third_party/ios/openssl/include/openssl/cms.h
new file mode 100644
index 0000000..f10cac9
--- /dev/null
+++ b/third_party/ios/openssl/include/openssl/cms.h
@@ -0,0 +1,524 @@
+/*
+ * WARNING: do not edit!
+ * Generated by Makefile from include/openssl/cms.h.in
+ *
+ * Copyright 2008-2025 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+/* clang-format off */
+
+/* clang-format on */
+
+#ifndef OPENSSL_CMS_H
+#define OPENSSL_CMS_H
+#pragma once
+
+#include
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+#define HEADER_CMS_H
+#endif
+
+#include
+
+#ifndef OPENSSL_NO_CMS
+#include
+#include
+#include
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct CMS_EnvelopedData_st CMS_EnvelopedData;
+typedef struct CMS_ContentInfo_st CMS_ContentInfo;
+typedef struct CMS_SignerInfo_st CMS_SignerInfo;
+typedef struct CMS_SignedData_st CMS_SignedData;
+typedef struct CMS_CertificateChoices CMS_CertificateChoices;
+typedef struct CMS_RevocationInfoChoice_st CMS_RevocationInfoChoice;
+typedef struct CMS_RecipientInfo_st CMS_RecipientInfo;
+typedef struct CMS_ReceiptRequest_st CMS_ReceiptRequest;
+typedef struct CMS_Receipt_st CMS_Receipt;
+typedef struct CMS_RecipientEncryptedKey_st CMS_RecipientEncryptedKey;
+typedef struct CMS_OtherKeyAttribute_st CMS_OtherKeyAttribute;
+
+/* clang-format off */
+SKM_DEFINE_STACK_OF_INTERNAL(CMS_SignerInfo, CMS_SignerInfo, CMS_SignerInfo)
+#define sk_CMS_SignerInfo_num(sk) OPENSSL_sk_num(ossl_check_const_CMS_SignerInfo_sk_type(sk))
+#define sk_CMS_SignerInfo_value(sk, idx) ((CMS_SignerInfo *)OPENSSL_sk_value(ossl_check_const_CMS_SignerInfo_sk_type(sk), (idx)))
+#define sk_CMS_SignerInfo_new(cmp) ((STACK_OF(CMS_SignerInfo) *)OPENSSL_sk_new(ossl_check_CMS_SignerInfo_compfunc_type(cmp)))
+#define sk_CMS_SignerInfo_new_null() ((STACK_OF(CMS_SignerInfo) *)OPENSSL_sk_new_null())
+#define sk_CMS_SignerInfo_new_reserve(cmp, n) ((STACK_OF(CMS_SignerInfo) *)OPENSSL_sk_new_reserve(ossl_check_CMS_SignerInfo_compfunc_type(cmp), (n)))
+#define sk_CMS_SignerInfo_reserve(sk, n) OPENSSL_sk_reserve(ossl_check_CMS_SignerInfo_sk_type(sk), (n))
+#define sk_CMS_SignerInfo_free(sk) OPENSSL_sk_free(ossl_check_CMS_SignerInfo_sk_type(sk))
+#define sk_CMS_SignerInfo_zero(sk) OPENSSL_sk_zero(ossl_check_CMS_SignerInfo_sk_type(sk))
+#define sk_CMS_SignerInfo_delete(sk, i) ((CMS_SignerInfo *)OPENSSL_sk_delete(ossl_check_CMS_SignerInfo_sk_type(sk), (i)))
+#define sk_CMS_SignerInfo_delete_ptr(sk, ptr) ((CMS_SignerInfo *)OPENSSL_sk_delete_ptr(ossl_check_CMS_SignerInfo_sk_type(sk), ossl_check_CMS_SignerInfo_type(ptr)))
+#define sk_CMS_SignerInfo_push(sk, ptr) OPENSSL_sk_push(ossl_check_CMS_SignerInfo_sk_type(sk), ossl_check_CMS_SignerInfo_type(ptr))
+#define sk_CMS_SignerInfo_unshift(sk, ptr) OPENSSL_sk_unshift(ossl_check_CMS_SignerInfo_sk_type(sk), ossl_check_CMS_SignerInfo_type(ptr))
+#define sk_CMS_SignerInfo_pop(sk) ((CMS_SignerInfo *)OPENSSL_sk_pop(ossl_check_CMS_SignerInfo_sk_type(sk)))
+#define sk_CMS_SignerInfo_shift(sk) ((CMS_SignerInfo *)OPENSSL_sk_shift(ossl_check_CMS_SignerInfo_sk_type(sk)))
+#define sk_CMS_SignerInfo_pop_free(sk, freefunc) OPENSSL_sk_pop_free(ossl_check_CMS_SignerInfo_sk_type(sk), ossl_check_CMS_SignerInfo_freefunc_type(freefunc))
+#define sk_CMS_SignerInfo_insert(sk, ptr, idx) OPENSSL_sk_insert(ossl_check_CMS_SignerInfo_sk_type(sk), ossl_check_CMS_SignerInfo_type(ptr), (idx))
+#define sk_CMS_SignerInfo_set(sk, idx, ptr) ((CMS_SignerInfo *)OPENSSL_sk_set(ossl_check_CMS_SignerInfo_sk_type(sk), (idx), ossl_check_CMS_SignerInfo_type(ptr)))
+#define sk_CMS_SignerInfo_find(sk, ptr) OPENSSL_sk_find(ossl_check_CMS_SignerInfo_sk_type(sk), ossl_check_CMS_SignerInfo_type(ptr))
+#define sk_CMS_SignerInfo_find_ex(sk, ptr) OPENSSL_sk_find_ex(ossl_check_CMS_SignerInfo_sk_type(sk), ossl_check_CMS_SignerInfo_type(ptr))
+#define sk_CMS_SignerInfo_find_all(sk, ptr, pnum) OPENSSL_sk_find_all(ossl_check_CMS_SignerInfo_sk_type(sk), ossl_check_CMS_SignerInfo_type(ptr), pnum)
+#define sk_CMS_SignerInfo_sort(sk) OPENSSL_sk_sort(ossl_check_CMS_SignerInfo_sk_type(sk))
+#define sk_CMS_SignerInfo_is_sorted(sk) OPENSSL_sk_is_sorted(ossl_check_const_CMS_SignerInfo_sk_type(sk))
+#define sk_CMS_SignerInfo_dup(sk) ((STACK_OF(CMS_SignerInfo) *)OPENSSL_sk_dup(ossl_check_const_CMS_SignerInfo_sk_type(sk)))
+#define sk_CMS_SignerInfo_deep_copy(sk, copyfunc, freefunc) ((STACK_OF(CMS_SignerInfo) *)OPENSSL_sk_deep_copy(ossl_check_const_CMS_SignerInfo_sk_type(sk), ossl_check_CMS_SignerInfo_copyfunc_type(copyfunc), ossl_check_CMS_SignerInfo_freefunc_type(freefunc)))
+#define sk_CMS_SignerInfo_set_cmp_func(sk, cmp) ((sk_CMS_SignerInfo_compfunc)OPENSSL_sk_set_cmp_func(ossl_check_CMS_SignerInfo_sk_type(sk), ossl_check_CMS_SignerInfo_compfunc_type(cmp)))
+SKM_DEFINE_STACK_OF_INTERNAL(CMS_RecipientEncryptedKey, CMS_RecipientEncryptedKey, CMS_RecipientEncryptedKey)
+#define sk_CMS_RecipientEncryptedKey_num(sk) OPENSSL_sk_num(ossl_check_const_CMS_RecipientEncryptedKey_sk_type(sk))
+#define sk_CMS_RecipientEncryptedKey_value(sk, idx) ((CMS_RecipientEncryptedKey *)OPENSSL_sk_value(ossl_check_const_CMS_RecipientEncryptedKey_sk_type(sk), (idx)))
+#define sk_CMS_RecipientEncryptedKey_new(cmp) ((STACK_OF(CMS_RecipientEncryptedKey) *)OPENSSL_sk_new(ossl_check_CMS_RecipientEncryptedKey_compfunc_type(cmp)))
+#define sk_CMS_RecipientEncryptedKey_new_null() ((STACK_OF(CMS_RecipientEncryptedKey) *)OPENSSL_sk_new_null())
+#define sk_CMS_RecipientEncryptedKey_new_reserve(cmp, n) ((STACK_OF(CMS_RecipientEncryptedKey) *)OPENSSL_sk_new_reserve(ossl_check_CMS_RecipientEncryptedKey_compfunc_type(cmp), (n)))
+#define sk_CMS_RecipientEncryptedKey_reserve(sk, n) OPENSSL_sk_reserve(ossl_check_CMS_RecipientEncryptedKey_sk_type(sk), (n))
+#define sk_CMS_RecipientEncryptedKey_free(sk) OPENSSL_sk_free(ossl_check_CMS_RecipientEncryptedKey_sk_type(sk))
+#define sk_CMS_RecipientEncryptedKey_zero(sk) OPENSSL_sk_zero(ossl_check_CMS_RecipientEncryptedKey_sk_type(sk))
+#define sk_CMS_RecipientEncryptedKey_delete(sk, i) ((CMS_RecipientEncryptedKey *)OPENSSL_sk_delete(ossl_check_CMS_RecipientEncryptedKey_sk_type(sk), (i)))
+#define sk_CMS_RecipientEncryptedKey_delete_ptr(sk, ptr) ((CMS_RecipientEncryptedKey *)OPENSSL_sk_delete_ptr(ossl_check_CMS_RecipientEncryptedKey_sk_type(sk), ossl_check_CMS_RecipientEncryptedKey_type(ptr)))
+#define sk_CMS_RecipientEncryptedKey_push(sk, ptr) OPENSSL_sk_push(ossl_check_CMS_RecipientEncryptedKey_sk_type(sk), ossl_check_CMS_RecipientEncryptedKey_type(ptr))
+#define sk_CMS_RecipientEncryptedKey_unshift(sk, ptr) OPENSSL_sk_unshift(ossl_check_CMS_RecipientEncryptedKey_sk_type(sk), ossl_check_CMS_RecipientEncryptedKey_type(ptr))
+#define sk_CMS_RecipientEncryptedKey_pop(sk) ((CMS_RecipientEncryptedKey *)OPENSSL_sk_pop(ossl_check_CMS_RecipientEncryptedKey_sk_type(sk)))
+#define sk_CMS_RecipientEncryptedKey_shift(sk) ((CMS_RecipientEncryptedKey *)OPENSSL_sk_shift(ossl_check_CMS_RecipientEncryptedKey_sk_type(sk)))
+#define sk_CMS_RecipientEncryptedKey_pop_free(sk, freefunc) OPENSSL_sk_pop_free(ossl_check_CMS_RecipientEncryptedKey_sk_type(sk), ossl_check_CMS_RecipientEncryptedKey_freefunc_type(freefunc))
+#define sk_CMS_RecipientEncryptedKey_insert(sk, ptr, idx) OPENSSL_sk_insert(ossl_check_CMS_RecipientEncryptedKey_sk_type(sk), ossl_check_CMS_RecipientEncryptedKey_type(ptr), (idx))
+#define sk_CMS_RecipientEncryptedKey_set(sk, idx, ptr) ((CMS_RecipientEncryptedKey *)OPENSSL_sk_set(ossl_check_CMS_RecipientEncryptedKey_sk_type(sk), (idx), ossl_check_CMS_RecipientEncryptedKey_type(ptr)))
+#define sk_CMS_RecipientEncryptedKey_find(sk, ptr) OPENSSL_sk_find(ossl_check_CMS_RecipientEncryptedKey_sk_type(sk), ossl_check_CMS_RecipientEncryptedKey_type(ptr))
+#define sk_CMS_RecipientEncryptedKey_find_ex(sk, ptr) OPENSSL_sk_find_ex(ossl_check_CMS_RecipientEncryptedKey_sk_type(sk), ossl_check_CMS_RecipientEncryptedKey_type(ptr))
+#define sk_CMS_RecipientEncryptedKey_find_all(sk, ptr, pnum) OPENSSL_sk_find_all(ossl_check_CMS_RecipientEncryptedKey_sk_type(sk), ossl_check_CMS_RecipientEncryptedKey_type(ptr), pnum)
+#define sk_CMS_RecipientEncryptedKey_sort(sk) OPENSSL_sk_sort(ossl_check_CMS_RecipientEncryptedKey_sk_type(sk))
+#define sk_CMS_RecipientEncryptedKey_is_sorted(sk) OPENSSL_sk_is_sorted(ossl_check_const_CMS_RecipientEncryptedKey_sk_type(sk))
+#define sk_CMS_RecipientEncryptedKey_dup(sk) ((STACK_OF(CMS_RecipientEncryptedKey) *)OPENSSL_sk_dup(ossl_check_const_CMS_RecipientEncryptedKey_sk_type(sk)))
+#define sk_CMS_RecipientEncryptedKey_deep_copy(sk, copyfunc, freefunc) ((STACK_OF(CMS_RecipientEncryptedKey) *)OPENSSL_sk_deep_copy(ossl_check_const_CMS_RecipientEncryptedKey_sk_type(sk), ossl_check_CMS_RecipientEncryptedKey_copyfunc_type(copyfunc), ossl_check_CMS_RecipientEncryptedKey_freefunc_type(freefunc)))
+#define sk_CMS_RecipientEncryptedKey_set_cmp_func(sk, cmp) ((sk_CMS_RecipientEncryptedKey_compfunc)OPENSSL_sk_set_cmp_func(ossl_check_CMS_RecipientEncryptedKey_sk_type(sk), ossl_check_CMS_RecipientEncryptedKey_compfunc_type(cmp)))
+SKM_DEFINE_STACK_OF_INTERNAL(CMS_RecipientInfo, CMS_RecipientInfo, CMS_RecipientInfo)
+#define sk_CMS_RecipientInfo_num(sk) OPENSSL_sk_num(ossl_check_const_CMS_RecipientInfo_sk_type(sk))
+#define sk_CMS_RecipientInfo_value(sk, idx) ((CMS_RecipientInfo *)OPENSSL_sk_value(ossl_check_const_CMS_RecipientInfo_sk_type(sk), (idx)))
+#define sk_CMS_RecipientInfo_new(cmp) ((STACK_OF(CMS_RecipientInfo) *)OPENSSL_sk_new(ossl_check_CMS_RecipientInfo_compfunc_type(cmp)))
+#define sk_CMS_RecipientInfo_new_null() ((STACK_OF(CMS_RecipientInfo) *)OPENSSL_sk_new_null())
+#define sk_CMS_RecipientInfo_new_reserve(cmp, n) ((STACK_OF(CMS_RecipientInfo) *)OPENSSL_sk_new_reserve(ossl_check_CMS_RecipientInfo_compfunc_type(cmp), (n)))
+#define sk_CMS_RecipientInfo_reserve(sk, n) OPENSSL_sk_reserve(ossl_check_CMS_RecipientInfo_sk_type(sk), (n))
+#define sk_CMS_RecipientInfo_free(sk) OPENSSL_sk_free(ossl_check_CMS_RecipientInfo_sk_type(sk))
+#define sk_CMS_RecipientInfo_zero(sk) OPENSSL_sk_zero(ossl_check_CMS_RecipientInfo_sk_type(sk))
+#define sk_CMS_RecipientInfo_delete(sk, i) ((CMS_RecipientInfo *)OPENSSL_sk_delete(ossl_check_CMS_RecipientInfo_sk_type(sk), (i)))
+#define sk_CMS_RecipientInfo_delete_ptr(sk, ptr) ((CMS_RecipientInfo *)OPENSSL_sk_delete_ptr(ossl_check_CMS_RecipientInfo_sk_type(sk), ossl_check_CMS_RecipientInfo_type(ptr)))
+#define sk_CMS_RecipientInfo_push(sk, ptr) OPENSSL_sk_push(ossl_check_CMS_RecipientInfo_sk_type(sk), ossl_check_CMS_RecipientInfo_type(ptr))
+#define sk_CMS_RecipientInfo_unshift(sk, ptr) OPENSSL_sk_unshift(ossl_check_CMS_RecipientInfo_sk_type(sk), ossl_check_CMS_RecipientInfo_type(ptr))
+#define sk_CMS_RecipientInfo_pop(sk) ((CMS_RecipientInfo *)OPENSSL_sk_pop(ossl_check_CMS_RecipientInfo_sk_type(sk)))
+#define sk_CMS_RecipientInfo_shift(sk) ((CMS_RecipientInfo *)OPENSSL_sk_shift(ossl_check_CMS_RecipientInfo_sk_type(sk)))
+#define sk_CMS_RecipientInfo_pop_free(sk, freefunc) OPENSSL_sk_pop_free(ossl_check_CMS_RecipientInfo_sk_type(sk), ossl_check_CMS_RecipientInfo_freefunc_type(freefunc))
+#define sk_CMS_RecipientInfo_insert(sk, ptr, idx) OPENSSL_sk_insert(ossl_check_CMS_RecipientInfo_sk_type(sk), ossl_check_CMS_RecipientInfo_type(ptr), (idx))
+#define sk_CMS_RecipientInfo_set(sk, idx, ptr) ((CMS_RecipientInfo *)OPENSSL_sk_set(ossl_check_CMS_RecipientInfo_sk_type(sk), (idx), ossl_check_CMS_RecipientInfo_type(ptr)))
+#define sk_CMS_RecipientInfo_find(sk, ptr) OPENSSL_sk_find(ossl_check_CMS_RecipientInfo_sk_type(sk), ossl_check_CMS_RecipientInfo_type(ptr))
+#define sk_CMS_RecipientInfo_find_ex(sk, ptr) OPENSSL_sk_find_ex(ossl_check_CMS_RecipientInfo_sk_type(sk), ossl_check_CMS_RecipientInfo_type(ptr))
+#define sk_CMS_RecipientInfo_find_all(sk, ptr, pnum) OPENSSL_sk_find_all(ossl_check_CMS_RecipientInfo_sk_type(sk), ossl_check_CMS_RecipientInfo_type(ptr), pnum)
+#define sk_CMS_RecipientInfo_sort(sk) OPENSSL_sk_sort(ossl_check_CMS_RecipientInfo_sk_type(sk))
+#define sk_CMS_RecipientInfo_is_sorted(sk) OPENSSL_sk_is_sorted(ossl_check_const_CMS_RecipientInfo_sk_type(sk))
+#define sk_CMS_RecipientInfo_dup(sk) ((STACK_OF(CMS_RecipientInfo) *)OPENSSL_sk_dup(ossl_check_const_CMS_RecipientInfo_sk_type(sk)))
+#define sk_CMS_RecipientInfo_deep_copy(sk, copyfunc, freefunc) ((STACK_OF(CMS_RecipientInfo) *)OPENSSL_sk_deep_copy(ossl_check_const_CMS_RecipientInfo_sk_type(sk), ossl_check_CMS_RecipientInfo_copyfunc_type(copyfunc), ossl_check_CMS_RecipientInfo_freefunc_type(freefunc)))
+#define sk_CMS_RecipientInfo_set_cmp_func(sk, cmp) ((sk_CMS_RecipientInfo_compfunc)OPENSSL_sk_set_cmp_func(ossl_check_CMS_RecipientInfo_sk_type(sk), ossl_check_CMS_RecipientInfo_compfunc_type(cmp)))
+SKM_DEFINE_STACK_OF_INTERNAL(CMS_RevocationInfoChoice, CMS_RevocationInfoChoice, CMS_RevocationInfoChoice)
+#define sk_CMS_RevocationInfoChoice_num(sk) OPENSSL_sk_num(ossl_check_const_CMS_RevocationInfoChoice_sk_type(sk))
+#define sk_CMS_RevocationInfoChoice_value(sk, idx) ((CMS_RevocationInfoChoice *)OPENSSL_sk_value(ossl_check_const_CMS_RevocationInfoChoice_sk_type(sk), (idx)))
+#define sk_CMS_RevocationInfoChoice_new(cmp) ((STACK_OF(CMS_RevocationInfoChoice) *)OPENSSL_sk_new(ossl_check_CMS_RevocationInfoChoice_compfunc_type(cmp)))
+#define sk_CMS_RevocationInfoChoice_new_null() ((STACK_OF(CMS_RevocationInfoChoice) *)OPENSSL_sk_new_null())
+#define sk_CMS_RevocationInfoChoice_new_reserve(cmp, n) ((STACK_OF(CMS_RevocationInfoChoice) *)OPENSSL_sk_new_reserve(ossl_check_CMS_RevocationInfoChoice_compfunc_type(cmp), (n)))
+#define sk_CMS_RevocationInfoChoice_reserve(sk, n) OPENSSL_sk_reserve(ossl_check_CMS_RevocationInfoChoice_sk_type(sk), (n))
+#define sk_CMS_RevocationInfoChoice_free(sk) OPENSSL_sk_free(ossl_check_CMS_RevocationInfoChoice_sk_type(sk))
+#define sk_CMS_RevocationInfoChoice_zero(sk) OPENSSL_sk_zero(ossl_check_CMS_RevocationInfoChoice_sk_type(sk))
+#define sk_CMS_RevocationInfoChoice_delete(sk, i) ((CMS_RevocationInfoChoice *)OPENSSL_sk_delete(ossl_check_CMS_RevocationInfoChoice_sk_type(sk), (i)))
+#define sk_CMS_RevocationInfoChoice_delete_ptr(sk, ptr) ((CMS_RevocationInfoChoice *)OPENSSL_sk_delete_ptr(ossl_check_CMS_RevocationInfoChoice_sk_type(sk), ossl_check_CMS_RevocationInfoChoice_type(ptr)))
+#define sk_CMS_RevocationInfoChoice_push(sk, ptr) OPENSSL_sk_push(ossl_check_CMS_RevocationInfoChoice_sk_type(sk), ossl_check_CMS_RevocationInfoChoice_type(ptr))
+#define sk_CMS_RevocationInfoChoice_unshift(sk, ptr) OPENSSL_sk_unshift(ossl_check_CMS_RevocationInfoChoice_sk_type(sk), ossl_check_CMS_RevocationInfoChoice_type(ptr))
+#define sk_CMS_RevocationInfoChoice_pop(sk) ((CMS_RevocationInfoChoice *)OPENSSL_sk_pop(ossl_check_CMS_RevocationInfoChoice_sk_type(sk)))
+#define sk_CMS_RevocationInfoChoice_shift(sk) ((CMS_RevocationInfoChoice *)OPENSSL_sk_shift(ossl_check_CMS_RevocationInfoChoice_sk_type(sk)))
+#define sk_CMS_RevocationInfoChoice_pop_free(sk, freefunc) OPENSSL_sk_pop_free(ossl_check_CMS_RevocationInfoChoice_sk_type(sk), ossl_check_CMS_RevocationInfoChoice_freefunc_type(freefunc))
+#define sk_CMS_RevocationInfoChoice_insert(sk, ptr, idx) OPENSSL_sk_insert(ossl_check_CMS_RevocationInfoChoice_sk_type(sk), ossl_check_CMS_RevocationInfoChoice_type(ptr), (idx))
+#define sk_CMS_RevocationInfoChoice_set(sk, idx, ptr) ((CMS_RevocationInfoChoice *)OPENSSL_sk_set(ossl_check_CMS_RevocationInfoChoice_sk_type(sk), (idx), ossl_check_CMS_RevocationInfoChoice_type(ptr)))
+#define sk_CMS_RevocationInfoChoice_find(sk, ptr) OPENSSL_sk_find(ossl_check_CMS_RevocationInfoChoice_sk_type(sk), ossl_check_CMS_RevocationInfoChoice_type(ptr))
+#define sk_CMS_RevocationInfoChoice_find_ex(sk, ptr) OPENSSL_sk_find_ex(ossl_check_CMS_RevocationInfoChoice_sk_type(sk), ossl_check_CMS_RevocationInfoChoice_type(ptr))
+#define sk_CMS_RevocationInfoChoice_find_all(sk, ptr, pnum) OPENSSL_sk_find_all(ossl_check_CMS_RevocationInfoChoice_sk_type(sk), ossl_check_CMS_RevocationInfoChoice_type(ptr), pnum)
+#define sk_CMS_RevocationInfoChoice_sort(sk) OPENSSL_sk_sort(ossl_check_CMS_RevocationInfoChoice_sk_type(sk))
+#define sk_CMS_RevocationInfoChoice_is_sorted(sk) OPENSSL_sk_is_sorted(ossl_check_const_CMS_RevocationInfoChoice_sk_type(sk))
+#define sk_CMS_RevocationInfoChoice_dup(sk) ((STACK_OF(CMS_RevocationInfoChoice) *)OPENSSL_sk_dup(ossl_check_const_CMS_RevocationInfoChoice_sk_type(sk)))
+#define sk_CMS_RevocationInfoChoice_deep_copy(sk, copyfunc, freefunc) ((STACK_OF(CMS_RevocationInfoChoice) *)OPENSSL_sk_deep_copy(ossl_check_const_CMS_RevocationInfoChoice_sk_type(sk), ossl_check_CMS_RevocationInfoChoice_copyfunc_type(copyfunc), ossl_check_CMS_RevocationInfoChoice_freefunc_type(freefunc)))
+#define sk_CMS_RevocationInfoChoice_set_cmp_func(sk, cmp) ((sk_CMS_RevocationInfoChoice_compfunc)OPENSSL_sk_set_cmp_func(ossl_check_CMS_RevocationInfoChoice_sk_type(sk), ossl_check_CMS_RevocationInfoChoice_compfunc_type(cmp)))
+
+/* clang-format on */
+
+DECLARE_ASN1_ITEM(CMS_EnvelopedData)
+DECLARE_ASN1_ALLOC_FUNCTIONS(CMS_SignedData)
+DECLARE_ASN1_FUNCTIONS(CMS_ContentInfo)
+DECLARE_ASN1_FUNCTIONS(CMS_ReceiptRequest)
+DECLARE_ASN1_PRINT_FUNCTION(CMS_ContentInfo)
+
+DECLARE_ASN1_DUP_FUNCTION(CMS_EnvelopedData)
+
+CMS_ContentInfo *CMS_ContentInfo_new_ex(OSSL_LIB_CTX *libctx, const char *propq);
+
+#define CMS_SIGNERINFO_ISSUER_SERIAL 0
+#define CMS_SIGNERINFO_KEYIDENTIFIER 1
+
+#define CMS_RECIPINFO_NONE -1
+#define CMS_RECIPINFO_TRANS 0
+#define CMS_RECIPINFO_AGREE 1
+#define CMS_RECIPINFO_KEK 2
+#define CMS_RECIPINFO_PASS 3
+#define CMS_RECIPINFO_OTHER 4
+#define CMS_RECIPINFO_KEM 5
+
+/* S/MIME related flags */
+
+#define CMS_TEXT 0x1
+#define CMS_NOCERTS 0x2
+#define CMS_NO_CONTENT_VERIFY 0x4
+#define CMS_NO_ATTR_VERIFY 0x8
+#define CMS_NOSIGS \
+ (CMS_NO_CONTENT_VERIFY | CMS_NO_ATTR_VERIFY)
+#define CMS_NOINTERN 0x10
+#define CMS_NO_SIGNER_CERT_VERIFY 0x20
+#define CMS_NOVERIFY 0x20
+#define CMS_DETACHED 0x40
+#define CMS_BINARY 0x80
+#define CMS_NOATTR 0x100
+#define CMS_NOSMIMECAP 0x200
+#define CMS_NOOLDMIMETYPE 0x400
+#define CMS_CRLFEOL 0x800
+#define CMS_STREAM 0x1000
+#define CMS_NOCRL 0x2000
+#define CMS_PARTIAL 0x4000
+#define CMS_REUSE_DIGEST 0x8000
+#define CMS_USE_KEYID 0x10000
+#define CMS_DEBUG_DECRYPT 0x20000
+#define CMS_KEY_PARAM 0x40000
+#define CMS_ASCIICRLF 0x80000
+#define CMS_CADES 0x100000
+#define CMS_USE_ORIGINATOR_KEYID 0x200000
+#define CMS_NO_SIGNING_TIME 0x400000
+
+const ASN1_OBJECT *CMS_get0_type(const CMS_ContentInfo *cms);
+
+BIO *CMS_dataInit(CMS_ContentInfo *cms, BIO *icont);
+int CMS_dataFinal(CMS_ContentInfo *cms, BIO *bio);
+
+ASN1_OCTET_STRING **CMS_get0_content(CMS_ContentInfo *cms);
+int CMS_is_detached(CMS_ContentInfo *cms);
+int CMS_set_detached(CMS_ContentInfo *cms, int detached);
+
+#ifdef OPENSSL_PEM_H
+DECLARE_PEM_rw(CMS, CMS_ContentInfo)
+#endif
+int CMS_stream(unsigned char ***boundary, CMS_ContentInfo *cms);
+CMS_ContentInfo *d2i_CMS_bio(BIO *bp, CMS_ContentInfo **cms);
+int i2d_CMS_bio(BIO *bp, CMS_ContentInfo *cms);
+
+BIO *BIO_new_CMS(BIO *out, CMS_ContentInfo *cms);
+int i2d_CMS_bio_stream(BIO *out, CMS_ContentInfo *cms, BIO *in, int flags);
+int PEM_write_bio_CMS_stream(BIO *out, CMS_ContentInfo *cms, BIO *in,
+ int flags);
+CMS_ContentInfo *SMIME_read_CMS(BIO *bio, BIO **bcont);
+CMS_ContentInfo *SMIME_read_CMS_ex(BIO *bio, int flags, BIO **bcont, CMS_ContentInfo **ci);
+int SMIME_write_CMS(BIO *bio, CMS_ContentInfo *cms, BIO *data, int flags);
+
+int CMS_final(CMS_ContentInfo *cms, BIO *data, BIO *dcont,
+ unsigned int flags);
+int CMS_final_digest(CMS_ContentInfo *cms,
+ const unsigned char *md, unsigned int mdlen, BIO *dcont,
+ unsigned int flags);
+
+CMS_ContentInfo *CMS_sign(X509 *signcert, EVP_PKEY *pkey,
+ STACK_OF(X509) *certs, BIO *data,
+ unsigned int flags);
+CMS_ContentInfo *CMS_sign_ex(X509 *signcert, EVP_PKEY *pkey,
+ STACK_OF(X509) *certs, BIO *data,
+ unsigned int flags, OSSL_LIB_CTX *libctx,
+ const char *propq);
+
+CMS_ContentInfo *CMS_sign_receipt(CMS_SignerInfo *si,
+ X509 *signcert, EVP_PKEY *pkey,
+ STACK_OF(X509) *certs, unsigned int flags);
+
+int CMS_data(CMS_ContentInfo *cms, BIO *out, unsigned int flags);
+CMS_ContentInfo *CMS_data_create(BIO *in, unsigned int flags);
+CMS_ContentInfo *CMS_data_create_ex(BIO *in, unsigned int flags,
+ OSSL_LIB_CTX *libctx, const char *propq);
+
+int CMS_digest_verify(CMS_ContentInfo *cms, BIO *dcont, BIO *out,
+ unsigned int flags);
+CMS_ContentInfo *CMS_digest_create(BIO *in, const EVP_MD *md,
+ unsigned int flags);
+CMS_ContentInfo *CMS_digest_create_ex(BIO *in, const EVP_MD *md,
+ unsigned int flags, OSSL_LIB_CTX *libctx,
+ const char *propq);
+
+int CMS_EncryptedData_decrypt(CMS_ContentInfo *cms,
+ const unsigned char *key, size_t keylen,
+ BIO *dcont, BIO *out, unsigned int flags);
+CMS_ContentInfo *CMS_EncryptedData_encrypt(BIO *in, const EVP_CIPHER *cipher,
+ const unsigned char *key,
+ size_t keylen, unsigned int flags);
+CMS_ContentInfo *CMS_EncryptedData_encrypt_ex(BIO *in, const EVP_CIPHER *cipher,
+ const unsigned char *key,
+ size_t keylen, unsigned int flags,
+ OSSL_LIB_CTX *libctx,
+ const char *propq);
+
+int CMS_EncryptedData_set1_key(CMS_ContentInfo *cms, const EVP_CIPHER *ciph,
+ const unsigned char *key, size_t keylen);
+
+int CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs,
+ X509_STORE *store, BIO *dcont, BIO *out, unsigned int flags);
+
+int CMS_verify_receipt(CMS_ContentInfo *rcms, CMS_ContentInfo *ocms,
+ STACK_OF(X509) *certs,
+ X509_STORE *store, unsigned int flags);
+
+STACK_OF(X509) *CMS_get0_signers(CMS_ContentInfo *cms);
+
+CMS_ContentInfo *CMS_encrypt(STACK_OF(X509) *certs, BIO *in,
+ const EVP_CIPHER *cipher, unsigned int flags);
+CMS_ContentInfo *CMS_encrypt_ex(STACK_OF(X509) *certs, BIO *in,
+ const EVP_CIPHER *cipher, unsigned int flags,
+ OSSL_LIB_CTX *libctx, const char *propq);
+
+int CMS_decrypt(CMS_ContentInfo *cms, EVP_PKEY *pkey, X509 *cert,
+ BIO *dcont, BIO *out, unsigned int flags);
+
+int CMS_decrypt_set1_pkey(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert);
+int CMS_decrypt_set1_pkey_and_peer(CMS_ContentInfo *cms, EVP_PKEY *pk,
+ X509 *cert, X509 *peer);
+int CMS_decrypt_set1_key(CMS_ContentInfo *cms,
+ unsigned char *key, size_t keylen,
+ const unsigned char *id, size_t idlen);
+int CMS_decrypt_set1_password(CMS_ContentInfo *cms,
+ unsigned char *pass, ossl_ssize_t passlen);
+
+STACK_OF(CMS_RecipientInfo) *CMS_get0_RecipientInfos(CMS_ContentInfo *cms);
+int CMS_RecipientInfo_type(CMS_RecipientInfo *ri);
+EVP_PKEY_CTX *CMS_RecipientInfo_get0_pkey_ctx(CMS_RecipientInfo *ri);
+CMS_ContentInfo *CMS_AuthEnvelopedData_create(const EVP_CIPHER *cipher);
+CMS_ContentInfo *
+CMS_AuthEnvelopedData_create_ex(const EVP_CIPHER *cipher, OSSL_LIB_CTX *libctx,
+ const char *propq);
+CMS_ContentInfo *CMS_EnvelopedData_create(const EVP_CIPHER *cipher);
+CMS_ContentInfo *CMS_EnvelopedData_create_ex(const EVP_CIPHER *cipher,
+ OSSL_LIB_CTX *libctx,
+ const char *propq);
+BIO *CMS_EnvelopedData_decrypt(CMS_EnvelopedData *env, BIO *detached_data,
+ EVP_PKEY *pkey, X509 *cert,
+ ASN1_OCTET_STRING *secret, unsigned int flags,
+ OSSL_LIB_CTX *libctx, const char *propq);
+
+CMS_RecipientInfo *CMS_add1_recipient_cert(CMS_ContentInfo *cms,
+ X509 *recip, unsigned int flags);
+CMS_RecipientInfo *CMS_add1_recipient(CMS_ContentInfo *cms, X509 *recip,
+ EVP_PKEY *originatorPrivKey, X509 *originator, unsigned int flags);
+int CMS_RecipientInfo_set0_pkey(CMS_RecipientInfo *ri, EVP_PKEY *pkey);
+int CMS_RecipientInfo_ktri_cert_cmp(CMS_RecipientInfo *ri, X509 *cert);
+int CMS_RecipientInfo_ktri_get0_algs(CMS_RecipientInfo *ri,
+ EVP_PKEY **pk, X509 **recip,
+ X509_ALGOR **palg);
+int CMS_RecipientInfo_ktri_get0_signer_id(CMS_RecipientInfo *ri,
+ ASN1_OCTET_STRING **keyid,
+ X509_NAME **issuer,
+ ASN1_INTEGER **sno);
+
+CMS_RecipientInfo *CMS_add0_recipient_key(CMS_ContentInfo *cms, int nid,
+ unsigned char *key, size_t keylen,
+ unsigned char *id, size_t idlen,
+ ASN1_GENERALIZEDTIME *date,
+ ASN1_OBJECT *otherTypeId,
+ ASN1_TYPE *otherType);
+
+int CMS_RecipientInfo_kekri_get0_id(CMS_RecipientInfo *ri,
+ X509_ALGOR **palg,
+ ASN1_OCTET_STRING **pid,
+ ASN1_GENERALIZEDTIME **pdate,
+ ASN1_OBJECT **potherid,
+ ASN1_TYPE **pothertype);
+
+int CMS_RecipientInfo_set0_key(CMS_RecipientInfo *ri,
+ unsigned char *key, size_t keylen);
+
+int CMS_RecipientInfo_kekri_id_cmp(CMS_RecipientInfo *ri,
+ const unsigned char *id, size_t idlen);
+
+int CMS_RecipientInfo_set0_password(CMS_RecipientInfo *ri,
+ unsigned char *pass,
+ ossl_ssize_t passlen);
+
+CMS_RecipientInfo *CMS_add0_recipient_password(CMS_ContentInfo *cms,
+ int iter, int wrap_nid,
+ int pbe_nid,
+ unsigned char *pass,
+ ossl_ssize_t passlen,
+ const EVP_CIPHER *kekciph);
+
+int CMS_RecipientInfo_decrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri);
+int CMS_RecipientInfo_encrypt(const CMS_ContentInfo *cms, CMS_RecipientInfo *ri);
+
+int CMS_uncompress(CMS_ContentInfo *cms, BIO *dcont, BIO *out,
+ unsigned int flags);
+CMS_ContentInfo *CMS_compress(BIO *in, int comp_nid, unsigned int flags);
+
+int CMS_set1_eContentType(CMS_ContentInfo *cms, const ASN1_OBJECT *oid);
+const ASN1_OBJECT *CMS_get0_eContentType(CMS_ContentInfo *cms);
+
+CMS_CertificateChoices *CMS_add0_CertificateChoices(CMS_ContentInfo *cms);
+int CMS_add0_cert(CMS_ContentInfo *cms, X509 *cert);
+int CMS_add1_cert(CMS_ContentInfo *cms, X509 *cert);
+STACK_OF(X509) *CMS_get1_certs(CMS_ContentInfo *cms);
+
+CMS_RevocationInfoChoice *CMS_add0_RevocationInfoChoice(CMS_ContentInfo *cms);
+int CMS_add0_crl(CMS_ContentInfo *cms, X509_CRL *crl);
+int CMS_add1_crl(CMS_ContentInfo *cms, X509_CRL *crl);
+STACK_OF(X509_CRL) *CMS_get1_crls(CMS_ContentInfo *cms);
+
+int CMS_SignedData_init(CMS_ContentInfo *cms);
+CMS_SignerInfo *CMS_add1_signer(CMS_ContentInfo *cms,
+ X509 *signer, EVP_PKEY *pk, const EVP_MD *md,
+ unsigned int flags);
+EVP_PKEY_CTX *CMS_SignerInfo_get0_pkey_ctx(CMS_SignerInfo *si);
+EVP_MD_CTX *CMS_SignerInfo_get0_md_ctx(CMS_SignerInfo *si);
+STACK_OF(CMS_SignerInfo) *CMS_get0_SignerInfos(CMS_ContentInfo *cms);
+
+void CMS_SignerInfo_set1_signer_cert(CMS_SignerInfo *si, X509 *signer);
+int CMS_SignerInfo_get0_signer_id(CMS_SignerInfo *si,
+ ASN1_OCTET_STRING **keyid,
+ X509_NAME **issuer, ASN1_INTEGER **sno);
+int CMS_SignerInfo_cert_cmp(CMS_SignerInfo *si, X509 *cert);
+int CMS_set1_signers_certs(CMS_ContentInfo *cms, STACK_OF(X509) *certs,
+ unsigned int flags);
+void CMS_SignerInfo_get0_algs(CMS_SignerInfo *si, EVP_PKEY **pk,
+ X509 **signer, X509_ALGOR **pdig,
+ X509_ALGOR **psig);
+ASN1_OCTET_STRING *CMS_SignerInfo_get0_signature(CMS_SignerInfo *si);
+int CMS_SignerInfo_sign(CMS_SignerInfo *si);
+int CMS_SignerInfo_verify(CMS_SignerInfo *si);
+int CMS_SignerInfo_verify_content(CMS_SignerInfo *si, BIO *chain);
+BIO *CMS_SignedData_verify(CMS_SignedData *sd, BIO *detached_data,
+ STACK_OF(X509) *scerts, X509_STORE *store,
+ STACK_OF(X509) *extra, STACK_OF(X509_CRL) *crls,
+ unsigned int flags,
+ OSSL_LIB_CTX *libctx, const char *propq);
+
+int CMS_add_smimecap(CMS_SignerInfo *si, STACK_OF(X509_ALGOR) *algs);
+int CMS_add_simple_smimecap(STACK_OF(X509_ALGOR) **algs,
+ int algnid, int keysize);
+int CMS_add_standard_smimecap(STACK_OF(X509_ALGOR) **smcap);
+
+int CMS_signed_get_attr_count(const CMS_SignerInfo *si);
+int CMS_signed_get_attr_by_NID(const CMS_SignerInfo *si, int nid,
+ int lastpos);
+int CMS_signed_get_attr_by_OBJ(const CMS_SignerInfo *si, const ASN1_OBJECT *obj,
+ int lastpos);
+X509_ATTRIBUTE *CMS_signed_get_attr(const CMS_SignerInfo *si, int loc);
+X509_ATTRIBUTE *CMS_signed_delete_attr(CMS_SignerInfo *si, int loc);
+int CMS_signed_add1_attr(CMS_SignerInfo *si, X509_ATTRIBUTE *attr);
+int CMS_signed_add1_attr_by_OBJ(CMS_SignerInfo *si,
+ const ASN1_OBJECT *obj, int type,
+ const void *bytes, int len);
+int CMS_signed_add1_attr_by_NID(CMS_SignerInfo *si,
+ int nid, int type,
+ const void *bytes, int len);
+int CMS_signed_add1_attr_by_txt(CMS_SignerInfo *si,
+ const char *attrname, int type,
+ const void *bytes, int len);
+void *CMS_signed_get0_data_by_OBJ(const CMS_SignerInfo *si,
+ const ASN1_OBJECT *oid,
+ int lastpos, int type);
+
+int CMS_unsigned_get_attr_count(const CMS_SignerInfo *si);
+int CMS_unsigned_get_attr_by_NID(const CMS_SignerInfo *si, int nid,
+ int lastpos);
+int CMS_unsigned_get_attr_by_OBJ(const CMS_SignerInfo *si,
+ const ASN1_OBJECT *obj, int lastpos);
+X509_ATTRIBUTE *CMS_unsigned_get_attr(const CMS_SignerInfo *si, int loc);
+X509_ATTRIBUTE *CMS_unsigned_delete_attr(CMS_SignerInfo *si, int loc);
+int CMS_unsigned_add1_attr(CMS_SignerInfo *si, X509_ATTRIBUTE *attr);
+int CMS_unsigned_add1_attr_by_OBJ(CMS_SignerInfo *si,
+ const ASN1_OBJECT *obj, int type,
+ const void *bytes, int len);
+int CMS_unsigned_add1_attr_by_NID(CMS_SignerInfo *si,
+ int nid, int type,
+ const void *bytes, int len);
+int CMS_unsigned_add1_attr_by_txt(CMS_SignerInfo *si,
+ const char *attrname, int type,
+ const void *bytes, int len);
+void *CMS_unsigned_get0_data_by_OBJ(CMS_SignerInfo *si, ASN1_OBJECT *oid,
+ int lastpos, int type);
+
+int CMS_get1_ReceiptRequest(CMS_SignerInfo *si, CMS_ReceiptRequest **prr);
+CMS_ReceiptRequest *CMS_ReceiptRequest_create0(
+ unsigned char *id, int idlen, int allorfirst,
+ STACK_OF(GENERAL_NAMES) *receiptList,
+ STACK_OF(GENERAL_NAMES) *receiptsTo);
+CMS_ReceiptRequest *CMS_ReceiptRequest_create0_ex(
+ unsigned char *id, int idlen, int allorfirst,
+ STACK_OF(GENERAL_NAMES) *receiptList,
+ STACK_OF(GENERAL_NAMES) *receiptsTo,
+ OSSL_LIB_CTX *libctx);
+
+int CMS_add1_ReceiptRequest(CMS_SignerInfo *si, CMS_ReceiptRequest *rr);
+void CMS_ReceiptRequest_get0_values(CMS_ReceiptRequest *rr,
+ ASN1_STRING **pcid,
+ int *pallorfirst,
+ STACK_OF(GENERAL_NAMES) **plist,
+ STACK_OF(GENERAL_NAMES) **prto);
+int CMS_RecipientInfo_kari_get0_alg(CMS_RecipientInfo *ri,
+ X509_ALGOR **palg,
+ ASN1_OCTET_STRING **pukm);
+STACK_OF(CMS_RecipientEncryptedKey)
+*CMS_RecipientInfo_kari_get0_reks(CMS_RecipientInfo *ri);
+
+int CMS_RecipientInfo_kari_get0_orig_id(CMS_RecipientInfo *ri,
+ X509_ALGOR **pubalg,
+ ASN1_BIT_STRING **pubkey,
+ ASN1_OCTET_STRING **keyid,
+ X509_NAME **issuer,
+ ASN1_INTEGER **sno);
+
+int CMS_RecipientInfo_kari_orig_id_cmp(CMS_RecipientInfo *ri, X509 *cert);
+
+int CMS_RecipientEncryptedKey_get0_id(CMS_RecipientEncryptedKey *rek,
+ ASN1_OCTET_STRING **keyid,
+ ASN1_GENERALIZEDTIME **tm,
+ CMS_OtherKeyAttribute **other,
+ X509_NAME **issuer, ASN1_INTEGER **sno);
+int CMS_RecipientEncryptedKey_cert_cmp(CMS_RecipientEncryptedKey *rek,
+ X509 *cert);
+int CMS_RecipientInfo_kari_set0_pkey(CMS_RecipientInfo *ri, EVP_PKEY *pk);
+int CMS_RecipientInfo_kari_set0_pkey_and_peer(CMS_RecipientInfo *ri, EVP_PKEY *pk, X509 *peer);
+EVP_CIPHER_CTX *CMS_RecipientInfo_kari_get0_ctx(CMS_RecipientInfo *ri);
+int CMS_RecipientInfo_kari_decrypt(CMS_ContentInfo *cms,
+ CMS_RecipientInfo *ri,
+ CMS_RecipientEncryptedKey *rek);
+
+int CMS_SharedInfo_encode(unsigned char **pder, X509_ALGOR *kekalg,
+ ASN1_OCTET_STRING *ukm, int keylen);
+
+int CMS_RecipientInfo_kemri_cert_cmp(CMS_RecipientInfo *ri, X509 *cert);
+int CMS_RecipientInfo_kemri_set0_pkey(CMS_RecipientInfo *ri, EVP_PKEY *pk);
+EVP_CIPHER_CTX *CMS_RecipientInfo_kemri_get0_ctx(CMS_RecipientInfo *ri);
+X509_ALGOR *CMS_RecipientInfo_kemri_get0_kdf_alg(CMS_RecipientInfo *ri);
+int CMS_RecipientInfo_kemri_set_ukm(CMS_RecipientInfo *ri,
+ const unsigned char *ukm,
+ int ukmLength);
+
+/* Backward compatibility for spelling errors. */
+#define CMS_R_UNKNOWN_DIGEST_ALGORITM CMS_R_UNKNOWN_DIGEST_ALGORITHM
+#define CMS_R_UNSUPPORTED_RECPIENTINFO_TYPE \
+ CMS_R_UNSUPPORTED_RECIPIENTINFO_TYPE
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+#endif
diff --git a/third_party/ios/openssl/include/openssl/cmserr.h b/third_party/ios/openssl/include/openssl/cmserr.h
new file mode 100644
index 0000000..49c22c2
--- /dev/null
+++ b/third_party/ios/openssl/include/openssl/cmserr.h
@@ -0,0 +1,128 @@
+/*
+ * Generated by util/mkerr.pl DO NOT EDIT
+ * Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#ifndef OPENSSL_CMSERR_H
+#define OPENSSL_CMSERR_H
+#pragma once
+
+#include
+#include