#include "signerutils.h"
#include "signer.h"
#include "SecCodeSigner.h"
#include <Security/SecIdentity.h>
#include <Security/CMSEncoder.h>
#include "renum.h"
#include "csutilities.h"
#include "drmaker.h"
#include <security_utilities/unix++.h>
#include <security_utilities/unixchild.h>
#include <vector>
#include "Code.h"
#include <security_utilities/cfmunge.h>
#include <sys/codesign.h>
namespace Security {
namespace CodeSigning {
static const char helperName[] = "codesign_allocate";
static const char helperPath[] = "/usr/bin/codesign_allocate";
static const char helperOverride[] = "CODESIGN_ALLOCATE";
static const size_t csAlign = 16;
void BlobWriter::component(CodeDirectory::SpecialSlot slot, CFDataRef data)
{
return EmbeddedSignatureBlob::Maker::component(slot, data);
}
void DetachedBlobWriter::flush()
{
EmbeddedSignatureBlob *blob = this->make();
signer.code->detachedSignature(makeCFData(*blob));
signer.state.returnDetachedSignature(blob, signer);
::free(blob);
}
ArchEditor::ArchEditor(Universal &code, CodeDirectory::HashAlgorithm hashType, uint32_t attrs)
: DiskRep::Writer(attrs)
{
Universal::Architectures archList;
code.architectures(archList);
for (Universal::Architectures::const_iterator it = archList.begin();
it != archList.end(); ++it)
architecture[*it] = new Arch(*it, hashType);
}
ArchEditor::~ArchEditor()
{
for (ArchMap::iterator it = begin(); it != end(); ++it)
delete it->second;
}
BlobEditor::BlobEditor(Universal &fat, SecCodeSigner::Signer &s)
: ArchEditor(fat, s.digestAlgorithm(), 0), signer(s)
{ }
void BlobEditor::component(CodeDirectory::SpecialSlot slot, CFDataRef data)
{
mGlobal.component(slot, data);
}
void BlobEditor::write(Arch &arch, EmbeddedSignatureBlob *blob)
{
mMaker.add(arch.architecture.cpuType(), blob);
}
void BlobEditor::commit()
{
mMaker.add(0, mGlobal.make());
DetachedSignatureBlob *blob = mMaker.make();
signer.state.returnDetachedSignature(blob, signer);
::free(blob);
}
MachOEditor::MachOEditor(DiskRep::Writer *w, Universal &code, CodeDirectory::HashAlgorithm hashType, std::string srcPath)
: ArchEditor(code, hashType, w->attributes()),
writer(w),
sourcePath(srcPath),
tempPath(srcPath + ".cstemp"),
mNewCode(NULL),
mTempMayExist(false)
{
if (const char *path = getenv(helperOverride)) {
mHelperPath = path;
mHelperOverridden = true;
} else {
mHelperPath = helperPath;
mHelperOverridden = false;
}
}
MachOEditor::~MachOEditor()
{
delete mNewCode;
if (mTempMayExist)
::remove(tempPath.c_str()); this->kill();
}
void MachOEditor::component(CodeDirectory::SpecialSlot slot, CFDataRef data)
{
writer->component(slot, data);
}
void MachOEditor::allocate()
{
mTempMayExist = true;
fork();
wait();
if (!Child::succeeded())
UnixError::throwMe(ENOEXEC);
{
UidGuard guard(0);
mFd.open(tempPath, O_RDWR);
}
mNewCode = new Universal(mFd);
}
static const unsigned char appleReq[] = {
0xfa, 0xde, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06,
0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x11, 0x41, 0x70, 0x70, 0x6c,
0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c,
0x65, 0x2e, 0x74, 0x6f, 0x6f, 0x6c, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x73, 0x69, 0x67, 0x6e, 0x5f,
0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x65,
};
void MachOEditor::parentAction()
{
if (mHelperOverridden) {
CODESIGN_ALLOCATE_VALIDATE((char*)mHelperPath, this->pid());
SecPointer<SecStaticCode> code = new SecStaticCode(DiskRep::bestGuess(mHelperPath));
code->validateDirectory();
code->validateExecutable();
code->validateResources();
code->validateRequirement((const Requirement *)appleReq, errSecCSReqFailed);
}
}
void MachOEditor::childAction()
{
vector<const char *> arguments;
arguments.push_back(helperName);
arguments.push_back("-i");
arguments.push_back(sourcePath.c_str());
arguments.push_back("-o");
arguments.push_back(tempPath.c_str());
for (Iterator it = architecture.begin(); it != architecture.end(); ++it) {
size_t size = LowLevelMemoryUtilities::alignUp(it->second->blobSize, csAlign);
char *ssize; asprintf(&ssize, "%zd", size);
if (const char *arch = it->first.name()) {
CODESIGN_ALLOCATE_ARCH((char*)arch, size);
arguments.push_back("-a");
arguments.push_back(arch);
} else {
CODESIGN_ALLOCATE_ARCHN(it->first.cpuType(), it->first.cpuSubtype(), size);
arguments.push_back("-A");
char *anum;
asprintf(&anum, "%d", it->first.cpuType());
arguments.push_back(anum);
asprintf(&anum, "%d", it->first.cpuSubtype());
arguments.push_back(anum);
}
arguments.push_back(ssize);
}
arguments.push_back(NULL);
if (mHelperOverridden)
::csops(0, CS_EXEC_SET_KILL, NULL, 0); ::seteuid(0); execv(mHelperPath, (char * const *)&arguments[0]);
}
void MachOEditor::reset(Arch &arch)
{
arch.source.reset(mNewCode->architecture(arch.architecture));
arch.cdbuilder.reopen(tempPath,
arch.source->offset(), arch.source->signingOffset());
}
void MachOEditor::write(Arch &arch, EmbeddedSignatureBlob *blob)
{
if (size_t offset = arch.source->signingOffset()) {
size_t signingLength = arch.source->signingLength();
CODESIGN_ALLOCATE_WRITE((char*)arch.architecture.name(), offset, blob->length(), signingLength);
if (signingLength < blob->length())
MacOSError::throwMe(errSecCSCMSTooLarge);
arch.source->seek(offset);
arch.source->writeAll(*blob);
::free(blob); } else {
secdebug("signer", "%p cannot find CODESIGNING section", this);
MacOSError::throwMe(errSecCSInternalError);
}
}
void MachOEditor::commit()
{
struct stat st;
UnixError::check(::stat(sourcePath.c_str(), &st));
Copyfile copy;
int fd = mFd;
copy.set(COPYFILE_STATE_DST_FD, &fd);
{
UidGuard guard;
if (!guard.seteuid(0))
guard.seteuid(st.st_uid);
copy(sourcePath.c_str(), NULL, COPYFILE_SECURITY | COPYFILE_METADATA);
char buf;
mFd.read(&buf, sizeof(buf), 0);
mFd.write(&buf, sizeof(buf), 0);
UnixError::check(::rename(tempPath.c_str(), sourcePath.c_str()));
mTempMayExist = false; }
}
void InternalRequirements::operator () (const Requirements *given, const Requirements *defaulted, const Requirement::Context &context)
{
if (defaulted) {
this->add(defaulted);
::free((void *)defaulted); }
if (given)
this->add(given);
if (!this->contains(kSecDesignatedRequirementType)) {
DRMaker maker(context);
if (Requirement *dr = maker.make()) {
this->add(kSecDesignatedRequirementType, dr); }
}
mReqs = this->make();
}
PreSigningContext::PreSigningContext(const SecCodeSigner::Signer &signer)
{
if (signer.signingIdentity() != SecIdentityRef(kCFNull)) {
CFRef<SecCertificateRef> signingCert;
MacOSError::check(SecIdentityCopyCertificate(signer.signingIdentity(), &signingCert.aref()));
CFRef<SecPolicyRef> policy = SecPolicyCreateWithOID(kSecPolicyAppleCodeSigning);
CFRef<SecTrustRef> trust;
MacOSError::check(SecTrustCreateWithCertificates(CFArrayRef(signingCert.get()), policy, &trust.aref()));
SecTrustResultType result;
MacOSError::check(SecTrustEvaluate(trust, &result));
CSSM_TP_APPLE_EVIDENCE_INFO *info;
MacOSError::check(SecTrustGetResult(trust, &result, &mCerts.aref(), &info));
this->certs = mCerts;
}
this->identifier = signer.signingIdentifier();
}
} }