/* SPDX-License-Identifier: MIT Copyright © 2025 Amebis */ #pragma once #include "common.hpp" #include "CoreFoundation.hpp" #include namespace macstd { /// /// Security runtime error /// class security_runtime_error : public num_runtime_error { public: /// /// Constructs an exception /// /// \param[in] num Security error code /// security_runtime_error(error_type num) : num_runtime_error(num, message(num)) { } /// /// Constructs an exception /// /// \param[in] num Security error code /// \param[in] msg Error message /// security_runtime_error(error_type num, const std::string &msg) : num_runtime_error(num, msg + ": " + message(num)) { } /// /// Constructs an exception /// /// \param[in] num Security error code /// \param[in] msg Error message /// security_runtime_error(error_type num, const char *msg) : num_runtime_error(num, std::string(msg) + ": " + message(num)) { } protected: /// /// Returns a string explaining the meaning of a security result code /// /// \sa [SecCopyErrorMessageString function](https://developer.apple.com/documentation/security/seccopyerrormessagestring) /// static std::string message(error_type num) { // Handle common errors Apple does not provide message strings for. switch (num) { case errSecWrPerm: return "Write permissions error"; case errSecDuplicateItem: return "The specified item already exists in the keychain"; case errAuthorizationCanceled: return "Authorization was canceled by user"; case errAuthorizationDenied: return "Authorization was denied"; case errAuthorizationInteractionNotAllowed: return "User interaction not allowed for authorization"; } cfstring cfstr(SecCopyErrorMessageString(num, NULL)); if (!cfstr.valid()) return "Security Framework error " + std::to_string(num); auto ptr = CFStringGetCStringPtr(cfstr, kCFStringEncodingUTF8); if (!ptr) return "Security Framework error " + std::to_string(num); std::string str(ptr); return str; } }; /// /// Authorization traits /// struct authorization_traits { static inline constexpr AuthorizationRef invalid = static_cast(NULL); /// /// Releases an object handle /// /// \sa [AuthorizationFree function](https://developer.apple.com/documentation/security/authorizationfree) /// static void free(AuthorizationRef h) noexcept { AuthorizationFree(h, kAuthorizationFlagDefaults); } private: static AuthorizationRef duplicate(AuthorizationRef h); }; /// /// Authorization reference wrapper class /// class authorization : public handle { public: /// /// Creates a new authorization reference and provides an option to authorize or preauthorize rights /// /// \sa [AuthorizationCreate function](https://developer.apple.com/documentation/security/authorizationcreate) /// authorization(const AuthorizationRights* rights, const AuthorizationEnvironment* environment, AuthorizationFlags flags) { AuthorizationRef h; OSStatus status = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &h); if (status != errAuthorizationSuccess) throw security_runtime_error(status, "AuthorizationCreate failed"); this->m_h = h; } /// /// Internalizes the external representation of an authorization reference /// /// \sa [AuthorizationCreateFromExternalForm function](https://developer.apple.com/documentation/security/authorizationcreatefromexternalform) /// authorization(const AuthorizationExternalForm& extForm) { AuthorizationRef h; OSStatus status = AuthorizationCreateFromExternalForm(&extForm, &h); if (status != errAuthorizationSuccess) throw security_runtime_error(status, "AuthorizationCreateFromExternalForm failed"); this->m_h = h; } }; using sec_keychain = cfobject; using sec_certificate = cfobject; }