#include "CodeSigner.h"
#include "signer.h"
#include "csdatabase.h"
#include "drmaker.h"
#include "csutilities.h"
#include <security_utilities/unix++.h>
#include <security_utilities/unixchild.h>
#include <Security/SecCertificate.h>
#include <vector>
namespace Security {
__SEC_CFTYPE(SecIdentity)
namespace CodeSigning {
using namespace UnixPlusPlus;
class SecCodeSigner::Parser : CFDictionary {
public:
Parser(SecCodeSigner &signer, CFDictionaryRef parameters);
bool getBool(CFStringRef key) const
{
if (CFBooleanRef flag = get<CFBooleanRef>(key))
return flag == kCFBooleanTrue;
else
return false;
}
};
SecCodeSigner::SecCodeSigner(SecCSFlags flags)
: mOpFlags(flags), mDigestAlgorithm(kSecCodeSignatureDefaultDigestAlgorithm)
{
}
SecCodeSigner::~SecCodeSigner() throw()
try {
} catch (...) {
return;
}
void SecCodeSigner::parameters(CFDictionaryRef paramDict)
{
Parser(*this, paramDict);
if (!valid())
MacOSError::throwMe(errSecCSInvalidObjectRef);
}
bool SecCodeSigner::valid() const
{
if (mOpFlags & kSecCSRemoveSignature)
return true;
return mSigner;
}
void SecCodeSigner::sign(SecStaticCode *code, SecCSFlags flags)
{
if (code->isSigned() && (flags & kSecCSSignPreserveSignature))
return;
Signer operation(*this, code);
if ((flags | mOpFlags) & kSecCSRemoveSignature) {
secdebug("signer", "%p will remove signature from %p", this, code);
operation.remove(flags);
} else {
if (!valid())
MacOSError::throwMe(errSecCSInvalidObjectRef);
secdebug("signer", "%p will sign %p (flags 0x%x)", this, code, flags);
operation.sign(flags);
}
code->resetValidity();
}
void SecCodeSigner::returnDetachedSignature(BlobCore *blob, Signer &signer)
{
assert(mDetached);
if (CFGetTypeID(mDetached) == CFURLGetTypeID()) {
AutoFileDesc fd(cfString(CFURLRef(mDetached.get())), O_WRONLY | O_CREAT | O_TRUNC);
fd.writeAll(*blob);
} else if (CFGetTypeID(mDetached) == CFDataGetTypeID()) {
CFDataAppendBytes(CFMutableDataRef(mDetached.get()),
(const UInt8 *)blob, blob->length());
} else if (CFGetTypeID(mDetached) == CFNullGetTypeID()) {
SignatureDatabaseWriter db;
db.storeCode(blob, signer.path().c_str());
} else
assert(false);
}
string SecCodeSigner::sdkPath(const std::string &path) const
{
assert(path[0] == '/'); if (mSDKRoot)
return cfString(mSDKRoot) + path;
else
return path;
}
bool SecCodeSigner::isAdhoc() const
{
return mSigner == SecIdentityRef(kCFNull);
}
SecCSFlags SecCodeSigner::signingFlags() const
{
return mOpFlags;
}
SecCodeSigner::Parser::Parser(SecCodeSigner &state, CFDictionaryRef parameters)
: CFDictionary(parameters, errSecCSBadDictionaryFormat)
{
state.mSigner = SecIdentityRef(get<CFTypeRef>(kSecCodeSignerIdentity));
if (state.mSigner)
if (CFGetTypeID(state.mSigner) != SecIdentityGetTypeID() && !CFEqual(state.mSigner, kCFNull))
MacOSError::throwMe(errSecCSInvalidObjectRef);
if (CFNumberRef flags = get<CFNumberRef>(kSecCodeSignerFlags)) {
state.mCdFlagsGiven = true;
state.mCdFlags = cfNumber<uint32_t>(flags);
} else
state.mCdFlagsGiven = false;
if (CFNumberRef digestAlgorithm = get<CFNumberRef>(kSecCodeSignerDigestAlgorithm))
state.mDigestAlgorithm = cfNumber<unsigned int>(digestAlgorithm);
if (CFNumberRef cmsSize = get<CFNumberRef>(CFSTR("cmssize")))
state.mCMSSize = cfNumber<size_t>(cmsSize);
else
state.mCMSSize = 9000;
if (CFNumberRef preserve = get<CFNumberRef>(kSecCodeSignerPreserveMetadata)) {
state.mPreserveMetadata = cfNumber<uint32_t>(preserve);
} else
state.mPreserveMetadata = 0;
if (CFTypeRef time = get<CFTypeRef>(kSecCodeSignerSigningTime)) {
if (CFGetTypeID(time) == CFDateGetTypeID() || time == kCFNull)
state.mSigningTime = CFDateRef(time);
else
MacOSError::throwMe(errSecCSInvalidObjectRef);
}
if (CFStringRef ident = get<CFStringRef>(kSecCodeSignerIdentifier))
state.mIdentifier = cfString(ident);
if (CFStringRef prefix = get<CFStringRef>(kSecCodeSignerIdentifierPrefix))
state.mIdentifierPrefix = cfString(prefix);
if (CFTypeRef reqs = get<CFTypeRef>(kSecCodeSignerRequirements)) {
if (CFGetTypeID(reqs) == CFDataGetTypeID() || CFGetTypeID(reqs) == CFStringGetTypeID())
state.mRequirements = reqs;
else
MacOSError::throwMe(errSecCSInvalidObjectRef);
} else
state.mRequirements = NULL;
state.mNoMachO = getBool(CFSTR("no-macho"));
state.mPageSize = get<CFNumberRef>(kSecCodeSignerPageSize);
if ((state.mDetached = get<CFTypeRef>(kSecCodeSignerDetached))) {
CFTypeID type = CFGetTypeID(state.mDetached);
if (type != CFURLGetTypeID() && type != CFDataGetTypeID() && type != CFNullGetTypeID())
MacOSError::throwMe(errSecCSInvalidObjectRef);
}
state.mDryRun = getBool(kSecCodeSignerDryRun);
state.mResourceRules = get<CFDictionaryRef>(kSecCodeSignerResourceRules);
state.mApplicationData = get<CFDataRef>(kSecCodeSignerApplicationData);
state.mEntitlementData = get<CFDataRef>(kSecCodeSignerEntitlements);
state.mSDKRoot = get<CFURLRef>(kSecCodeSignerSDKRoot);
if (CFBooleanRef timestampRequest = get<CFBooleanRef>(kSecCodeSignerRequireTimestamp)) {
state.mWantTimeStamp = timestampRequest == kCFBooleanTrue;
} else { state.mWantTimeStamp = false;
if (state.mSigner && state.mSigner != SecIdentityRef(kCFNull)) {
CFRef<SecCertificateRef> signerCert;
MacOSError::check(SecIdentityCopyCertificate(state.mSigner, &signerCert.aref()));
if (certificateHasField(signerCert, devIdLeafMarkerOID))
state.mWantTimeStamp = true;
}
}
state.mTimestampAuthentication = get<SecIdentityRef>(kSecCodeSignerTimestampAuthentication);
state.mTimestampService = get<CFURLRef>(kSecCodeSignerTimestampServer);
state.mNoTimeStampCerts = getBool(kSecCodeSignerTimestampOmitCertificates);
}
} }