MacStd/include/MacStd/Security.hpp
Simon Rozman bf4dd4a1d0 common: merge dup_handle and handle and use traits
Signed-off-by: Simon Rozman <simon@rozman.si>
2025-06-20 10:22:00 +02:00

135 lines
4.0 KiB
C++

/*
SPDX-License-Identifier: MIT
Copyright © 2025 Amebis
*/
#pragma once
#include "common.hpp"
#include "CoreFoundation.hpp"
#include <Security/Security.h>
namespace macstd
{
///
/// Security runtime error
///
class security_runtime_error : public num_runtime_error<OSStatus>
{
public:
///
/// Constructs an exception
///
/// \param[in] num Security error code
///
security_runtime_error(error_type num) : num_runtime_error<OSStatus>(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<OSStatus>(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<OSStatus>(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<AuthorizationRef>(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<AuthorizationRef, authorization_traits>
{
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<SecKeychainRef>;
using sec_certificate = cfobject<SecCertificateRef>;
}