135 lines
4.0 KiB
C++
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>;
|
|
}
|