#include "cs.h"
#include "StaticCode.h"
#include <security_utilities/cfmunge.h>
#include <security_utilities/logging.h>
#include <fcntl.h>
#include <dirent.h>
using namespace CodeSigning;
CFTypeID SecStaticCodeGetTypeID(void)
{
BEGIN_CSAPI
return gCFObjects().StaticCode.typeID;
END_CSAPI1(_kCFRuntimeNotATypeID)
}
OSStatus SecStaticCodeCreateWithPath(CFURLRef path, SecCSFlags flags, SecStaticCodeRef *staticCodeRef)
{
BEGIN_CSAPI
checkFlags(flags, kSecCSForceOnlineNotarizationCheck);
CodeSigning::Required(staticCodeRef) = (new SecStaticCode(DiskRep::bestGuess(cfString(path).c_str()), flags))->handle();
END_CSAPI
}
const CFStringRef kSecCodeAttributeArchitecture = CFSTR("architecture");
const CFStringRef kSecCodeAttributeSubarchitecture =CFSTR("subarchitecture");
const CFStringRef kSecCodeAttributeBundleVersion = CFSTR("bundleversion");
const CFStringRef kSecCodeAttributeUniversalFileOffset = CFSTR("UniversalFileOffset");
OSStatus SecStaticCodeCreateWithPathAndAttributes(CFURLRef path, SecCSFlags flags, CFDictionaryRef attributes,
SecStaticCodeRef *staticCodeRef)
{
BEGIN_CSAPI
checkFlags(flags, kSecCSForceOnlineNotarizationCheck);
DiskRep::Context ctx;
std::string version; if (attributes) {
std::string archName;
int archNumber, subarchNumber, offset;
if (cfscan(attributes, "{%O=%d}", kSecCodeAttributeUniversalFileOffset, &offset)) {
ctx.offset = offset;
} else if (cfscan(attributes, "{%O=%s}", kSecCodeAttributeArchitecture, &archName)) {
ctx.arch = Architecture(archName.c_str());
} else if (cfscan(attributes, "{%O=%d,%O=%d}",
kSecCodeAttributeArchitecture, &archNumber, kSecCodeAttributeSubarchitecture, &subarchNumber))
ctx.arch = Architecture(archNumber, subarchNumber);
else if (cfscan(attributes, "{%O=%d}", kSecCodeAttributeArchitecture, &archNumber))
ctx.arch = Architecture(archNumber);
if (cfscan(attributes, "{%O=%s}", kSecCodeAttributeBundleVersion, &version))
ctx.version = version.c_str();
}
CodeSigning::Required(staticCodeRef) = (new SecStaticCode(DiskRep::bestGuess(cfString(path).c_str(), &ctx), flags))->handle();
END_CSAPI
}
OSStatus SecStaticCodeCheckValidity(SecStaticCodeRef staticCodeRef, SecCSFlags flags,
SecRequirementRef requirementRef)
{
return SecStaticCodeCheckValidityWithErrors(staticCodeRef, flags, requirementRef, NULL);
}
OSStatus SecStaticCodeCheckValidityWithErrors(SecStaticCodeRef staticCodeRef, SecCSFlags flags,
SecRequirementRef requirementRef, CFErrorRef *errors)
{
BEGIN_CSAPI
checkFlags(flags,
kSecCSReportProgress
| kSecCSCheckAllArchitectures
| kSecCSDoNotValidateExecutable
| kSecCSDoNotValidateResources
| kSecCSConsiderExpiration
| kSecCSEnforceRevocationChecks
| kSecCSNoNetworkAccess
| kSecCSCheckNestedCode
| kSecCSStrictValidate
| kSecCSStrictValidateStructure
| kSecCSRestrictSidebandData
| kSecCSCheckGatekeeperArchitectures
| kSecCSRestrictSymlinks
| kSecCSRestrictToAppLike
| kSecCSUseSoftwareSigningCert
| kSecCSValidatePEH
| kSecCSSingleThreaded
| kSecCSApplyEmbeddedPolicy
| kSecCSSkipRootVolumeExceptions
| kSecCSSkipXattrFiles
);
if (errors)
flags |= kSecCSFullReport;
#if !TARGET_OS_OSX
flags |= kSecCSApplyEmbeddedPolicy;
#endif
SecPointer<SecStaticCode> code = SecStaticCode::requiredStatic(staticCodeRef);
code->setValidationFlags(flags);
const SecRequirement *req = SecRequirement::optional(requirementRef);
DTRACK(CODESIGN_EVAL_STATIC, code, (char*)code->mainExecutablePath().c_str());
code->staticValidate(flags, req);
if ((flags & kSecCSApplyEmbeddedPolicy) && code->trustedSigningCertChain() == false) {
return CSError::cfError(errors, errSecCSSignatureUntrusted);
}
END_CSAPI_ERRORS
}
OSStatus SecCodeCopyPath(SecStaticCodeRef staticCodeRef, SecCSFlags flags, CFURLRef *path)
{
BEGIN_CSAPI
checkFlags(flags);
SecPointer<SecStaticCode> staticCode = SecStaticCode::requiredStatic(staticCodeRef);
CodeSigning::Required(path) = staticCode->copyCanonicalPath();
END_CSAPI
}
OSStatus SecCodeCopyDesignatedRequirement(SecStaticCodeRef staticCodeRef, SecCSFlags flags,
SecRequirementRef *requirementRef)
{
BEGIN_CSAPI
checkFlags(flags);
const Requirement *req =
SecStaticCode::requiredStatic(staticCodeRef)->designatedRequirement();
CodeSigning::Required(requirementRef) = (new SecRequirement(req))->handle();
END_CSAPI
}
OSStatus SecCodeCopyInternalRequirement(SecStaticCodeRef staticCodeRef, SecRequirementType type,
SecCSFlags flags, SecRequirementRef *requirementRef)
{
BEGIN_CSAPI
checkFlags(flags);
const Requirement *req =
SecStaticCode::requiredStatic(staticCodeRef)->internalRequirement(type);
CodeSigning::Required(requirementRef) = req ? (new SecRequirement(req))->handle() : NULL;
END_CSAPI
}
OSStatus SecCodeSetDetachedSignature(SecStaticCodeRef codeRef, CFDataRef signature,
SecCSFlags flags)
{
BEGIN_CSAPI
checkFlags(flags);
SecPointer<SecStaticCode> code = SecStaticCode::requiredStatic(codeRef);
code->detachedSignature(signature); code->resetValidity();
END_CSAPI
}
OSStatus SecCodeMapMemory(SecStaticCodeRef codeRef, SecCSFlags flags)
{
BEGIN_CSAPI
checkFlags(flags);
SecPointer<SecStaticCode> code = SecStaticCode::requiredStatic(codeRef);
if (const CodeDirectory *cd = code->codeDirectory(false)) {
if (code->isDetached()) {
fsignatures args = { static_cast<off_t>(code->diskRep()->signingBase()), (void *)cd, cd->length() };
UnixError::check(::fcntl(code->diskRep()->fd(), F_ADDSIGS, &args));
} else {
Universal *execImage = code->diskRep()->mainExecutableImage();
if (execImage == NULL) {
MacOSError::throwMe(errSecCSNoMainExecutable);
}
unique_ptr<MachO> arch(execImage->architecture());
if (arch.get() == NULL) {
MacOSError::throwMe(errSecCSNoMainExecutable);
}
size_t signatureOffset = arch->signingOffset();
size_t signatureLength = arch->signingLength();
if (signatureOffset == 0) {
MacOSError::throwMe(errSecCSUnsigned);
}
fsignatures args = {
static_cast<off_t>(code->diskRep()->signingBase()),
(void *)signatureOffset,
signatureLength,
};
UnixError::check(::fcntl(code->diskRep()->fd(), F_ADDFILESIGS, &args));
}
} else {
MacOSError::throwMe(errSecCSUnsigned);
}
END_CSAPI
}
OSStatus SecStaticCodeSetCallback(SecStaticCodeRef codeRef, SecCSFlags flags, SecCodeCallback *old, SecCodeCallback monitor)
{
BEGIN_CSAPI
checkFlags(flags);
SecStaticCode *code = SecStaticCode::requiredStatic(codeRef);
if (old)
*old = code->monitor();
code->setMonitor(monitor);
END_CSAPI
}
OSStatus SecStaticCodeSetValidationConditions(SecStaticCodeRef codeRef, CFDictionaryRef conditions)
{
BEGIN_CSAPI
checkFlags(0);
SecStaticCode *code = SecStaticCode::requiredStatic(codeRef);
code->setValidationModifiers(conditions);
END_CSAPI
}
OSStatus SecStaticCodeCancelValidation(SecStaticCodeRef codeRef, SecCSFlags flags)
{
BEGIN_CSAPI
checkFlags(0);
SecStaticCode *code = SecStaticCode::requiredStatic(codeRef);
code->cancelValidation();
END_CSAPI
}
CFDataRef SecCodeCopyComponent(SecCodeRef codeRef, int slot, CFDataRef hash)
{
BEGIN_CSAPI
SecStaticCode* code = SecStaticCode::requiredStatic(codeRef);
return code->copyComponent(slot, hash);
END_CSAPI1(NULL)
}
OSStatus SecCodeValidateFileResource(SecStaticCodeRef codeRef, CFStringRef relativePath, CFDataRef fileData, SecCSFlags flags)
{
BEGIN_CSAPI
checkFlags(0);
if (fileData == NULL)
MacOSError::throwMe(errSecCSObjectRequired);
SecStaticCode *code = SecStaticCode::requiredStatic(codeRef);
code->validatePlainMemoryResource(cfString(relativePath), fileData, flags);
END_CSAPI
}