--- /dev/null
+#!/usr/sbin/dtrace -qs
+#
+#
+#
+self unsigned char *cdhash;
+
+syspolicy*:::assess-*
+{
+ self->cdhash = 0;
+}
+
+self string type;
+syspolicy*:::assess-outcome-* / arg1 == 1 / { type = "execute"; }
+syspolicy*:::assess-outcome-* / arg1 == 2 / { type = "install"; }
+
+syspolicy*:::assess-outcome-accept
+{
+ printf("accept %s %s;%s", self->type, copyinstr(arg0), copyinstr(arg1));
+ self->cdhash = copyin(arg2, 20);
+}
+
+syspolicy*:::assess-outcome-deny
+{
+ printf("deny %s %s;%s", self->type, copyinstr(arg0), copyinstr(arg1));
+ self->cdhash = copyin(arg2, 20);
+}
+
+syspolicy*:::assess-outcome-default
+{
+ printf("default %s %s;%s", self->type, copyinstr(arg0), copyinstr(arg1));
+ self->cdhash = copyin(arg2, 20);
+}
+
+syspolicy*:::assess-outcome-unsigned
+{
+ printf("unsigned %s %s;", self->type, copyinstr(arg0));
+}
+
+syspolicy*:::assess-*
+/ self->cdhash /
+{
+ printf(";%02.2x%02.2x%02.2x%02.2x%02.2x%02.2x%02.2x%02.2x%02.2x%02.2x%02.2x%02.2x%02.2x%02.2x%02.2x%02.2x%02.2x%02.2x%02.2x%02.2x",
+ self->cdhash[0], self->cdhash[1], self->cdhash[2], self->cdhash[3], self->cdhash[4],
+ self->cdhash[5], self->cdhash[6], self->cdhash[7], self->cdhash[8], self->cdhash[9],
+ self->cdhash[10], self->cdhash[11], self->cdhash[12], self->cdhash[13], self->cdhash[14],
+ self->cdhash[15], self->cdhash[16], self->cdhash[17], self->cdhash[18], self->cdhash[19]);
+}
+
+syspolicy*:::assess-*
+{
+ printf("\n");
+}
--- /dev/null
+#!/usr/bin/python
+#
+# gkclear - clear system state for Gatekeeper recording sessions
+#
+# This removes DetachedSignatures, resets SystemPolicy, and removes existing gke files.
+#
+import sys
+import os
+import signal
+import errno
+import subprocess
+import shutil
+
+
+#
+# Usage and fail
+#
+def usage():
+ print >>sys.stderr, "Usage: %s" % sys.argv[0]
+ sys.exit(2)
+
+def fail(whatever):
+ print >>sys.stderr, "%s: %s" % (sys.argv[0], whatever)
+ sys.exit(1)
+
+
+#
+# Argument processing
+#
+if len(sys.argv) != 1:
+ usage()
+
+
+#
+# Places and things
+#
+db = "/var/db/"
+detachedsignatures = db + "DetachedSignatures"
+gkeauth = db + "gke.auth"
+gkesigs = db + "gke.sigs"
+policydb = db + "SystemPolicy"
+policydb_default = db + ".SystemPolicy-default"
+
+
+# must be root
+if os.getuid() != 0:
+ fail("Must have root privileges")
+
+
+#
+# Make sure Gatekeeper is disabled
+#
+subprocess.check_call(["/usr/sbin/spctl", "--master-disable"])
+
+
+#
+# Clear detached signatures database
+#
+for file in [detachedsignatures, gkeauth, gkesigs]:
+ try:
+ os.remove(file)
+ except OSError, e:
+ if e[0] != errno.ENOENT:
+ raise
+
+
+#
+# Reset system policy to default values
+#
+shutil.copyfile(policydb_default, policydb)
+
+
+#
+# Kill any extant syspolicyd to flush state
+#
+null = open("/dev/null", "w")
+subprocess.call(["/usr/bin/killall", "syspolicyd"], stderr=null)
+
+
+#
+# Done
+#
+print "System state has been reset."
+sys.exit(0)
--- /dev/null
+#!/usr/bin/python
+#
+# gkgenerate - produce Gatekeeper explicit allow data
+#
+# gkgenerate [--output name] files...
+# will collect GKE data from all files and write two output files (name.auth and name.sigs)
+# that are ready to drop into a /var/db for pickup.
+#
+import sys
+import os
+import signal
+import errno
+import subprocess
+import argparse
+import plistlib
+import uuid
+
+
+#
+# Parameters and constants
+#
+authfile = "gke.auth"
+sigfile = "gke.dsig"
+
+
+#
+# Usage and fail
+#
+def usage():
+ print >>sys.stderr, "Usage: %s sourcedir" % sys.argv[0]
+ sys.exit(2)
+
+def fail(whatever):
+ print >>sys.stderr, "%s: %s" % (sys.argv[0], whatever)
+ sys.exit(1)
+
+
+#
+# Argument processing
+#
+parser = argparse.ArgumentParser()
+parser.add_argument("--output", default="./gke", help="name of output files")
+parser.add_argument("--uuid", default=uuid.uuid4(), help="explicitly specify the uuid stamp")
+parser.add_argument("--empty", action='store_true', help="allow empty output sets")
+parser.add_argument('source', nargs='+', help='files generated by the gkrecord command')
+args = parser.parse_args()
+
+authfile = args.output + ".auth"
+sigsfile = args.output + ".sigs"
+
+
+#
+# Start by collecting authority evidence from the authority records
+#
+auth = { }
+sigs = { }
+for source in args.source:
+ if source[0] == '+':
+ data = plistlib.readPlist(source[1:])
+ auth.update(data["authority"])
+ sigs.update(data["signatures"])
+ else:
+ data = plistlib.readPlist(source)
+ auth.update(data["authority"])
+
+if not auth and not args.empty:
+ fail("No authority records (nothing to do)")
+
+
+#
+# Scrub the authority records to remove incriminating evidence
+#
+new_auth = { }
+for rec in auth.values():
+ u = uuid.uuid4()
+ rec["path"] = "(gke)"
+ del rec["status"]
+ new_auth[str(u)] = rec
+auth = new_auth
+
+
+#
+# The authority file is written as-is, as a plist
+#
+wrap = dict(
+ authority=auth,
+ uuid=str(args.uuid)
+)
+plistlib.writePlist(wrap, authfile)
+print "Wrote %d authority record(s) to %s" % (len(auth), authfile)
+
+
+#
+# The signatures are written as tightly packed signature blobs
+#
+sigblobs = open(sigsfile, "w")
+for sig in sigs:
+ sigdata = sigs[sig]
+ sigblobs.write(sigdata["signature"].data)
+sigblobs.close()
+print "Wrote %d signature record(s) to %s" % (len(sigs), sigsfile)
--- /dev/null
+#!/usr/bin/python
+#
+# gkhandmake - manually create a recorded snippet
+#
+# gkhandmake path type source outputfile
+#
+import sys
+import os
+import signal
+import errno
+import subprocess
+import plistlib
+
+
+#
+# Usage and fail
+#
+def usage():
+ print >>sys.stderr, "Usage: %s program specfile outputfile" % sys.argv[0]
+ sys.exit(2)
+
+def fail(whatever):
+ print >>sys.stderr, "%s: %s" % (sys.argv[0], whatever)
+ sys.exit(1)
+
+
+#
+# Argument processing
+#
+if len(sys.argv) != 4:
+ usage()
+path=os.path.abspath(sys.argv[1])
+specfile=sys.argv[2]
+outputfile = sys.argv[3]
+type=1 # always execution
+
+
+#
+# If the output file already exists, bail
+#
+if os.path.exists(outputfile):
+ fail("already exists: %s" % outputfile)
+
+
+#
+# We'll let the detached signature live in case we need to inspect it
+#
+sigpath = "/tmp/%s.dsig" % os.path.basename(path.strip('/'))
+
+
+#
+# Generate an adhoc detached signature with the given resource specification
+#
+
+display = subprocess.check_call(["/usr/bin/codesign",
+ "--sign", "-",
+ "--detached", sigpath,
+ "--resource-rules", specfile,
+ path
+])
+
+
+#
+# Now verify it so we can extract the cdhash
+#
+display = subprocess.Popen(["/usr/bin/codesign",
+ "--display", "--verbose=3",
+ "--detached", sigpath,
+ path
+], stderr=subprocess.PIPE)
+(stdout, stderr) = display.communicate()
+
+cdhash = None
+for line in stderr.split('\n'):
+ if line.startswith("CDHash="):
+ cdhash = line[7:]
+ break
+if cdhash is None:
+ fail("no cdhash in generated signature?!")
+
+
+#
+# Pack up a single (detached) signature as a snippet
+# under the given path
+#
+with open(sigpath, "r") as sigfile:
+ sigdata = sigfile.read()
+auth = { }
+sigs = { }
+
+auth[path] = dict(
+ type=type,
+ path=path,
+ status=9,
+ cdhash=cdhash
+)
+
+sigs[path] = dict(
+ type=type,
+ path=path,
+ signature=plistlib.Data(sigdata)
+)
+gkedict = dict(
+ authority = auth,
+ signatures = sigs
+)
+plistlib.writePlist(gkedict, outputfile)
+
+sys.exit(0)
--- /dev/null
+#!/usr/bin/python
+#
+# gklist - report Gatekeeper MessageTracer data since last reset
+#
+# mtdebug --reset
+# ... exercise Gatekeeper ...
+# gklist
+#
+import os
+import plistlib
+
+
+data = os.popen("mtdebug --plist", "r")
+for mt in plistlib.readPlistFromString(data.read()):
+ if mt["com.apple.message.domain"] == "com.apple.security.assessment.outcome":
+ outcome = mt["com.apple.message.signature"]
+ id = mt["com.apple.message.signature2"]
+ print outcome, "--", id
--- /dev/null
+#!/usr/bin/python
+#
+# gkmerge - merge Gatekeeper whitelist snippets
+#
+# gkmerge [--output name] files...
+# Takes GKE data from all files, merges it together, and writes it to a new snippet file 'output'.
+#
+import sys
+import os
+import signal
+import errno
+import subprocess
+import argparse
+import plistlib
+import uuid
+
+
+#
+# Usage and fail
+#
+def fail(whatever):
+ print >>sys.stderr, "%s: %s" % (sys.argv[0], whatever)
+ sys.exit(1)
+
+
+#
+# Argument processing
+#
+parser = argparse.ArgumentParser()
+parser.add_argument("--output", default="./snippet.gke", help="name of output file")
+parser.add_argument('source', nargs='+', help='files generated by the gkrecord command')
+args = parser.parse_args()
+
+
+#
+# Merge all the plist data from the input files, overriding with later files
+#
+gkedict = { }
+for source in args.source:
+ data = plistlib.readPlist(source)
+ gkedict.update(data)
+
+
+#
+# Write it back out as a snippet file
+#
+plistlib.writePlist(gkedict, args.output)
+print "Wrote %d authority records + %d signatures to %s" % (
+ len(gkedict["authority"]), len(gkedict["signatures"]), args.output
+)
--- /dev/null
+#!/usr/bin/python
+#
+# gkrecord - record Gatekeeper rejection activity
+#
+# gkrecord filename
+#
+import sys
+import os
+import signal
+import errno
+import subprocess
+import tempfile
+import plistlib
+
+
+#
+# Usage and fail
+#
+def usage():
+ print >>sys.stderr, "Usage: %s outputfile" % sys.argv[0]
+ sys.exit(2)
+
+def fail(whatever):
+ print >>sys.stderr, "%s: %s" % (sys.argv[0], whatever)
+ sys.exit(1)
+
+
+#
+# Argument processing
+#
+if len(sys.argv) != 2:
+ usage()
+outputfile = sys.argv[1]
+
+
+#
+# If the output file already exists, bail
+#
+if os.path.exists(outputfile):
+ fail("already exists: %s" % outputfile)
+
+
+#
+# Places and things
+#
+collect = "/tmp/gke/"
+
+
+# must be root
+if os.getuid() != 0:
+ fail("Must have root privileges")
+
+
+#
+# Make sure Gatekeeper is disabled
+#
+subprocess.check_call(["/usr/sbin/spctl", "--master-disable"])
+
+
+#
+# make sure we have a fresh syspolicyd and get its pid
+#
+subprocess.check_call(["/usr/sbin/spctl", "--assess", "--ignore-cache", "/bin/ls"])
+try:
+ psax = subprocess.check_output("ps ax|grep syspolicyd|grep -v grep", shell=True).split("\n")
+ if len(psax) != 2: # [ found_syspolicyd, '' ]
+ fail("Cannot find syspolicyd")
+ spd_pid = int(psax[0].split()[0])
+except subprocess.CalledProcessError:
+ fail("Cannot find syspolicyd")
+
+
+#
+# run collector dtrace script until dtrace dies.
+# recorder_mode arguments are (path, type, label, cdhash, flags)
+#
+DSCRIPT = '''
+syspolicy$1:::recorder_mode { printf("RECORD;%d;%d", arg1, arg4); }
+
+self unsigned char *cdhash;
+
+syspolicy$1:::recorder_mode
+{
+ self->cdhash = copyin(arg3, 20);
+ printf(";%02.2x%02.2x%02.2x%02.2x%02.2x%02.2x%02.2x%02.2x%02.2x%02.2x%02.2x%02.2x%02.2x%02.2x%02.2x%02.2x%02.2x%02.2x%02.2x%02.2x",
+ self->cdhash[0], self->cdhash[1], self->cdhash[2], self->cdhash[3], self->cdhash[4],
+ self->cdhash[5], self->cdhash[6], self->cdhash[7], self->cdhash[8], self->cdhash[9],
+ self->cdhash[10], self->cdhash[11], self->cdhash[12], self->cdhash[13], self->cdhash[14],
+ self->cdhash[15], self->cdhash[16], self->cdhash[17], self->cdhash[18], self->cdhash[19]);
+ printf(";%s\\n", copyinstr(arg0));
+}
+
+syspolicy$1:::recorder_mode_adhoc_path
+{
+ printf("SIGNATURE;%d;%s;%s\\n", arg1, copyinstr(arg2), copyinstr(arg0));
+}
+
+syspolicy$1:::assess-outcome-unsigned
+{
+ printf("UNSIGNED;%d;%s\\n", arg1, copyinstr(arg0));
+}
+
+syspolicy$1:::assess-outcome-broken
+{
+ printf("BROKEN;%d;%d;%s\\n", arg1, arg2, copyinstr(arg0));
+}
+'''
+
+def sigint(sig, ctx):
+ os.kill(spd_pid, signal.SIGINT)
+signal.signal(signal.SIGINT, sigint)
+
+(authfd, authfile) = tempfile.mkstemp()
+dtrace = subprocess.Popen(["dtrace", "-qs", "/dev/stdin", str(spd_pid)], stdin=subprocess.PIPE, stdout=authfd, stderr=subprocess.PIPE)
+print "Exercise the programs to be whitelisted now. Interrupt this script (^C) when you are done."
+(stdout, stderr) = dtrace.communicate(input=DSCRIPT)
+signal.signal(signal.SIGINT, signal.SIG_DFL)
+if stderr:
+ fail("dtrace failed: %s" % stderr)
+os.lseek(authfd, os.SEEK_SET, 0) # rewind
+
+
+#
+# Collect all the data into dicts
+#
+auth = { }
+sigs = { }
+unsigned = { }
+badsigned = { }
+errors = { }
+
+file = os.fdopen(authfd, "r")
+for line in file:
+ (cmd, s, args) = line.strip().partition(";")
+ if s != ";":
+ continue # spurious
+# print cmd, "--->", args
+ if cmd == "RECORD":
+ (type, status, cdhash, path) = args.split(";", 3)
+ auth[path] = dict(
+ path=path,
+ type=type,
+ status=status,
+ cdhash=cdhash
+ )
+ elif cmd == "SIGNATURE":
+ (type, sigpath, path) = args.split(";", 2)
+ with open(sigpath, "r") as sigfile:
+ sigdata = sigfile.read()
+ sigs[path] = dict(
+ path=path,
+ type=type,
+ signature=plistlib.Data(sigdata)
+ )
+ elif cmd == "UNSIGNED":
+ (type, path) = args.split(";", 1)
+ unsigned[path] = dict(
+ path=path,
+ type=type
+ )
+ elif cmd == "BROKEN":
+ (type, exception, path) = args.split(";", 2)
+ badsigned[path] = dict(
+ path=path,
+ type=type,
+ exception=exception
+ )
+
+# unsigned code that had a good detached signature recorded is okay
+for rec in sigs:
+ if rec in unsigned:
+ del unsigned[rec]
+
+
+#
+# Pack them up as a single output (plist) file
+#
+gkedict = dict(
+ authority = auth,
+ signatures = sigs
+)
+plistlib.writePlist(gkedict, outputfile)
+
+
+#
+# Report on any problems found
+#
+for rec in unsigned.values():
+ print >>sys.stderr, "PROBLEM: unsigned type %d object not whitelisted: %s" % (rec["type"], rec["path"])
+for rec in badsigned.values():
+ print >>sys.stderr, "PROBLEM: broken code signature; object not whitelisted: %s" % rec["path"]
+
+
+#
+# Done
+#
+print "Recorded %d authorization(s), %d signature(s) in %s" % (len(auth), len(sigs), outputfile)
+sys.exit(0)
errSecCSInfoPlistFailed = -67030, /* invalid Info.plist (plist or signature have been modified) */
errSecCSNoMainExecutable = -67029, /* the code has no main executable file */
errSecCSBadBundleFormat = -67028, /* bundle format unrecognized, invalid, or unsuitable */
- errSecCSNoMatches = -67027, /* no matches for search or update operation */
+ errSecCSNoMatches = -67027, /* no matches for search or update operation */
+ errSecCSFileHardQuarantined = -67026, /* File created by an AppSandbox, exec/open not allowed */
+ errSecCSOutdated = -67025, /* presented data is out of date */
+ errSecCSDbCorrupt = -67024, /* a system database of file is corrupt */
};
numbers. This is not a valid ASCII character; test for this to distinguish
between text and binary data if you expect a code signing-related binary blob.
*/
-typedef uint32_t SecCodeSignatureFlags;
enum {
kSecCodeMagicRequirement = 0xfade0c00, /* single requirement */
#include "reqparser.h"
#include "renum.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 {
: CFDictionary(parameters, errSecCSBadDictionaryFormat)
{
// the signer may be an identity or null
- if (CFTypeRef signer = get<CFTypeRef>(kSecCodeSignerIdentity))
- if (CFGetTypeID(signer) == SecIdentityGetTypeID() || signer == kCFNull)
- state.mSigner = SecIdentityRef(signer);
- else
+ state.mSigner = SecIdentityRef(get<CFTypeRef>(kSecCodeSignerIdentity));
+ if (state.mSigner)
+ if (CFGetTypeID(state.mSigner) != SecIdentityGetTypeID() && !CFEqual(state.mSigner, kCFNull))
MacOSError::throwMe(errSecCSInvalidObjectRef);
// the flags need some augmentation
// digest algorithms are specified as a numeric code
if (CFNumberRef digestAlgorithm = get<CFNumberRef>(kSecCodeSignerDigestAlgorithm))
- state.mDigestAlgorithm = cfNumber<long>(digestAlgorithm);
+ state.mDigestAlgorithm = cfNumber<unsigned int>(digestAlgorithm);
if (CFNumberRef cmsSize = get<CFNumberRef>(CFSTR("cmssize")))
state.mCMSSize = cfNumber<size_t>(cmsSize);
else
- state.mCMSSize = 5000; // likely big enough
+ state.mCMSSize = 9000; // likely big enough
// signing time can be a CFDateRef or null
- if (CFTypeRef time = get<CFTypeRef>(kSecCodeSignerSigningTime))
+ 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);
state.mPageSize = get<CFNumberRef>(kSecCodeSignerPageSize);
// detached can be (destination) file URL or (mutable) Data to be appended-to
- if (state.mDetached = get<CFTypeRef>(kSecCodeSignerDetached)) {
+ if ((state.mDetached = get<CFTypeRef>(kSecCodeSignerDetached))) {
CFTypeID type = CFGetTypeID(state.mDetached);
if (type != CFURLGetTypeID() && type != CFDataGetTypeID() && type != CFNullGetTypeID())
MacOSError::throwMe(errSecCSInvalidObjectRef);
state.mEntitlementData = get<CFDataRef>(kSecCodeSignerEntitlements);
state.mSDKRoot = get<CFURLRef>(kSecCodeSignerSDKRoot);
+
+ if (CFBooleanRef timestampRequest = get<CFBooleanRef>(kSecCodeSignerRequireTimestamp)) {
+ state.mWantTimeStamp = timestampRequest == kCFBooleanTrue;
+ } else { // pick default
+ 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);
}
bool mNoMachO; // override to perform non-Mach-O signing
bool mDryRun; // dry run (do not change target)
CFRef<CFNumberRef> mPageSize; // main executable page size
+ CFRef<SecIdentityRef> mTimestampAuthentication; // identity for client-side authentication to the Timestamp server
+ CFRef<CFURLRef> mTimestampService; // URL for Timestamp server
+ bool mWantTimeStamp; // use a Timestamp server
+ bool mNoTimeStampCerts; // don't request certificates with timestamping request
};
--- /dev/null
+ "guest",
+ "host",
+ "designated",
+ "library",
+ "plugin",
+ "or",
+ "and",
+ "always",
+ "true",
+ "never",
+ "false",
+ "identifier",
+ "cdhash",
+ "anchor",
+ "apple",
+ "generic",
+ "certificate",
+ "cert",
+ "trusted",
+ "info",
+ "entitlement",
+ "exists",
+ "leaf",
+ "root",
--- /dev/null
+/* $ANTLR 2.7.7 (20120228): "requirements.grammar" -> "RequirementLexer.cpp"$ */
+#include "RequirementLexer.hpp"
+#include <antlr/CharBuffer.hpp>
+#include <antlr/TokenStreamException.hpp>
+#include <antlr/TokenStreamIOException.hpp>
+#include <antlr/TokenStreamRecognitionException.hpp>
+#include <antlr/CharStreamException.hpp>
+#include <antlr/CharStreamIOException.hpp>
+#include <antlr/NoViableAltForCharException.hpp>
+
+
+#include "requirement.h"
+#include "reqmaker.h"
+#include "csutilities.h"
+#include <security_utilities/cfutilities.h>
+#include <security_utilities/hashing.h>
+#include <security_cdsa_utilities/cssmdata.h> // OID coding
+using namespace CodeSigning;
+typedef Requirement::Maker Maker;
+
+ANTLR_BEGIN_NAMESPACE(Security_CodeSigning)
+RequirementLexer::RequirementLexer(std::istream& in)
+ : antlr::CharScanner(new antlr::CharBuffer(in),true)
+{
+ initLiterals();
+}
+
+RequirementLexer::RequirementLexer(antlr::InputBuffer& ib)
+ : antlr::CharScanner(ib,true)
+{
+ initLiterals();
+}
+
+RequirementLexer::RequirementLexer(const antlr::LexerSharedInputState& state)
+ : antlr::CharScanner(state,true)
+{
+ initLiterals();
+}
+
+void RequirementLexer::initLiterals()
+{
+ literals["certificate"] = 25;
+ literals["always"] = 16;
+ literals["host"] = 6;
+ literals["guest"] = 5;
+ literals["cdhash"] = 21;
+ literals["entitlement"] = 29;
+ literals["library"] = 8;
+ literals["never"] = 18;
+ literals["cert"] = 26;
+ literals["plugin"] = 9;
+ literals["or"] = 11;
+ literals["leaf"] = 42;
+ literals["info"] = 28;
+ literals["designated"] = 7;
+ literals["apple"] = 23;
+ literals["trusted"] = 27;
+ literals["true"] = 17;
+ literals["and"] = 12;
+ literals["root"] = 43;
+ literals["anchor"] = 22;
+ literals["false"] = 19;
+ literals["generic"] = 24;
+ literals["identifier"] = 20;
+ literals["exists"] = 30;
+}
+
+antlr::RefToken RequirementLexer::nextToken()
+{
+ antlr::RefToken theRetToken;
+ for (;;) {
+ antlr::RefToken theRetToken;
+ int _ttype = antlr::Token::INVALID_TYPE;
+ resetText();
+ try { // for lexical and char stream error handling
+ switch ( LA(1)) {
+ case 0x22 /* '\"' */ :
+ {
+ mSTRING(true);
+ theRetToken=_returnToken;
+ break;
+ }
+ case 0x3b /* ';' */ :
+ {
+ mSEMI(true);
+ theRetToken=_returnToken;
+ break;
+ }
+ case 0x28 /* '(' */ :
+ {
+ mLPAREN(true);
+ theRetToken=_returnToken;
+ break;
+ }
+ case 0x29 /* ')' */ :
+ {
+ mRPAREN(true);
+ theRetToken=_returnToken;
+ break;
+ }
+ case 0x5b /* '[' */ :
+ {
+ mLBRACK(true);
+ theRetToken=_returnToken;
+ break;
+ }
+ case 0x5d /* ']' */ :
+ {
+ mRBRACK(true);
+ theRetToken=_returnToken;
+ break;
+ }
+ case 0x2c /* ',' */ :
+ {
+ mCOMMA(true);
+ theRetToken=_returnToken;
+ break;
+ }
+ case 0x7e /* '~' */ :
+ {
+ mSUBS(true);
+ theRetToken=_returnToken;
+ break;
+ }
+ case 0x2d /* '-' */ :
+ {
+ mNEG(true);
+ theRetToken=_returnToken;
+ break;
+ }
+ case 0x21 /* '!' */ :
+ {
+ mNOT(true);
+ theRetToken=_returnToken;
+ break;
+ }
+ case 0x2a /* '*' */ :
+ {
+ mSTAR(true);
+ theRetToken=_returnToken;
+ break;
+ }
+ case 0x9 /* '\t' */ :
+ case 0xa /* '\n' */ :
+ case 0x20 /* ' ' */ :
+ {
+ mWS(true);
+ theRetToken=_returnToken;
+ break;
+ }
+ case 0x23 /* '#' */ :
+ {
+ mSHELLCOMMENT(true);
+ theRetToken=_returnToken;
+ break;
+ }
+ default:
+ if ((LA(1) == 0x2f /* '/' */ ) && (_tokenSet_0.member(LA(2)))) {
+ mPATHNAME(true);
+ theRetToken=_returnToken;
+ }
+ else if ((LA(1) == 0x48 /* 'H' */ ) && (LA(2) == 0x22 /* '\"' */ )) {
+ mHASHCONSTANT(true);
+ theRetToken=_returnToken;
+ }
+ else if ((LA(1) == 0x30 /* '0' */ ) && (LA(2) == 0x78 /* 'x' */ )) {
+ mHEXCONSTANT(true);
+ theRetToken=_returnToken;
+ }
+ else if ((LA(1) == 0x3d /* '=' */ ) && (LA(2) == 0x3e /* '>' */ )) {
+ mARROW(true);
+ theRetToken=_returnToken;
+ }
+ else if ((LA(1) == 0x3c /* '<' */ ) && (LA(2) == 0x3d /* '=' */ )) {
+ mLE(true);
+ theRetToken=_returnToken;
+ }
+ else if ((LA(1) == 0x3e /* '>' */ ) && (LA(2) == 0x3d /* '=' */ )) {
+ mGE(true);
+ theRetToken=_returnToken;
+ }
+ else if ((LA(1) == 0x3d /* '=' */ ) && (LA(2) == 0x3d /* '=' */ )) {
+ mEQQL(true);
+ theRetToken=_returnToken;
+ }
+ else if ((LA(1) == 0x2f /* '/' */ ) && (LA(2) == 0x2a /* '*' */ )) {
+ mC_COMMENT(true);
+ theRetToken=_returnToken;
+ }
+ else if ((LA(1) == 0x2f /* '/' */ ) && (LA(2) == 0x2f /* '/' */ )) {
+ mCPP_COMMENT(true);
+ theRetToken=_returnToken;
+ }
+ else if ((_tokenSet_0.member(LA(1))) && (true)) {
+ mDOTKEY(true);
+ theRetToken=_returnToken;
+ }
+ else if (((LA(1) >= 0x30 /* '0' */ && LA(1) <= 0x39 /* '9' */ )) && (true)) {
+ mINTEGER(true);
+ theRetToken=_returnToken;
+ }
+ else if ((LA(1) == 0x3c /* '<' */ ) && (true)) {
+ mLESS(true);
+ theRetToken=_returnToken;
+ }
+ else if ((LA(1) == 0x3e /* '>' */ ) && (true)) {
+ mGT(true);
+ theRetToken=_returnToken;
+ }
+ else if ((LA(1) == 0x3d /* '=' */ ) && (true)) {
+ mEQL(true);
+ theRetToken=_returnToken;
+ }
+ else {
+ if (LA(1)==EOF_CHAR)
+ {
+ uponEOF();
+ _returnToken = makeToken(antlr::Token::EOF_TYPE);
+ }
+ else {throw antlr::NoViableAltForCharException(LA(1), getFilename(), getLine(), getColumn());}
+ }
+ }
+ if ( !_returnToken )
+ goto tryAgain; // found SKIP token
+
+ _ttype = _returnToken->getType();
+ _returnToken->setType(_ttype);
+ return _returnToken;
+ }
+ catch (antlr::RecognitionException& e) {
+ throw antlr::TokenStreamRecognitionException(e);
+ }
+ catch (antlr::CharStreamIOException& csie) {
+ throw antlr::TokenStreamIOException(csie.io);
+ }
+ catch (antlr::CharStreamException& cse) {
+ throw antlr::TokenStreamException(cse.getMessage());
+ }
+tryAgain:;
+ }
+}
+
+void RequirementLexer::mIDENT(bool _createToken) {
+ int _ttype; antlr::RefToken _token; std::string::size_type _begin = text.length();
+ _ttype = IDENT;
+ std::string::size_type _saveIndex;
+
+ {
+ switch ( LA(1)) {
+ case 0x41 /* 'A' */ :
+ case 0x42 /* 'B' */ :
+ case 0x43 /* 'C' */ :
+ case 0x44 /* 'D' */ :
+ case 0x45 /* 'E' */ :
+ case 0x46 /* 'F' */ :
+ case 0x47 /* 'G' */ :
+ case 0x48 /* 'H' */ :
+ case 0x49 /* 'I' */ :
+ case 0x4a /* 'J' */ :
+ case 0x4b /* 'K' */ :
+ case 0x4c /* 'L' */ :
+ case 0x4d /* 'M' */ :
+ case 0x4e /* 'N' */ :
+ case 0x4f /* 'O' */ :
+ case 0x50 /* 'P' */ :
+ case 0x51 /* 'Q' */ :
+ case 0x52 /* 'R' */ :
+ case 0x53 /* 'S' */ :
+ case 0x54 /* 'T' */ :
+ case 0x55 /* 'U' */ :
+ case 0x56 /* 'V' */ :
+ case 0x57 /* 'W' */ :
+ case 0x58 /* 'X' */ :
+ case 0x59 /* 'Y' */ :
+ case 0x5a /* 'Z' */ :
+ {
+ matchRange('A','Z');
+ break;
+ }
+ case 0x61 /* 'a' */ :
+ case 0x62 /* 'b' */ :
+ case 0x63 /* 'c' */ :
+ case 0x64 /* 'd' */ :
+ case 0x65 /* 'e' */ :
+ case 0x66 /* 'f' */ :
+ case 0x67 /* 'g' */ :
+ case 0x68 /* 'h' */ :
+ case 0x69 /* 'i' */ :
+ case 0x6a /* 'j' */ :
+ case 0x6b /* 'k' */ :
+ case 0x6c /* 'l' */ :
+ case 0x6d /* 'm' */ :
+ case 0x6e /* 'n' */ :
+ case 0x6f /* 'o' */ :
+ case 0x70 /* 'p' */ :
+ case 0x71 /* 'q' */ :
+ case 0x72 /* 'r' */ :
+ case 0x73 /* 's' */ :
+ case 0x74 /* 't' */ :
+ case 0x75 /* 'u' */ :
+ case 0x76 /* 'v' */ :
+ case 0x77 /* 'w' */ :
+ case 0x78 /* 'x' */ :
+ case 0x79 /* 'y' */ :
+ case 0x7a /* 'z' */ :
+ {
+ matchRange('a','z');
+ break;
+ }
+ default:
+ {
+ throw antlr::NoViableAltForCharException(LA(1), getFilename(), getLine(), getColumn());
+ }
+ }
+ }
+ { // ( ... )*
+ for (;;) {
+ switch ( LA(1)) {
+ case 0x41 /* 'A' */ :
+ case 0x42 /* 'B' */ :
+ case 0x43 /* 'C' */ :
+ case 0x44 /* 'D' */ :
+ case 0x45 /* 'E' */ :
+ case 0x46 /* 'F' */ :
+ case 0x47 /* 'G' */ :
+ case 0x48 /* 'H' */ :
+ case 0x49 /* 'I' */ :
+ case 0x4a /* 'J' */ :
+ case 0x4b /* 'K' */ :
+ case 0x4c /* 'L' */ :
+ case 0x4d /* 'M' */ :
+ case 0x4e /* 'N' */ :
+ case 0x4f /* 'O' */ :
+ case 0x50 /* 'P' */ :
+ case 0x51 /* 'Q' */ :
+ case 0x52 /* 'R' */ :
+ case 0x53 /* 'S' */ :
+ case 0x54 /* 'T' */ :
+ case 0x55 /* 'U' */ :
+ case 0x56 /* 'V' */ :
+ case 0x57 /* 'W' */ :
+ case 0x58 /* 'X' */ :
+ case 0x59 /* 'Y' */ :
+ case 0x5a /* 'Z' */ :
+ {
+ matchRange('A','Z');
+ break;
+ }
+ case 0x61 /* 'a' */ :
+ case 0x62 /* 'b' */ :
+ case 0x63 /* 'c' */ :
+ case 0x64 /* 'd' */ :
+ case 0x65 /* 'e' */ :
+ case 0x66 /* 'f' */ :
+ case 0x67 /* 'g' */ :
+ case 0x68 /* 'h' */ :
+ case 0x69 /* 'i' */ :
+ case 0x6a /* 'j' */ :
+ case 0x6b /* 'k' */ :
+ case 0x6c /* 'l' */ :
+ case 0x6d /* 'm' */ :
+ case 0x6e /* 'n' */ :
+ case 0x6f /* 'o' */ :
+ case 0x70 /* 'p' */ :
+ case 0x71 /* 'q' */ :
+ case 0x72 /* 'r' */ :
+ case 0x73 /* 's' */ :
+ case 0x74 /* 't' */ :
+ case 0x75 /* 'u' */ :
+ case 0x76 /* 'v' */ :
+ case 0x77 /* 'w' */ :
+ case 0x78 /* 'x' */ :
+ case 0x79 /* 'y' */ :
+ case 0x7a /* 'z' */ :
+ {
+ matchRange('a','z');
+ break;
+ }
+ case 0x30 /* '0' */ :
+ case 0x31 /* '1' */ :
+ case 0x32 /* '2' */ :
+ case 0x33 /* '3' */ :
+ case 0x34 /* '4' */ :
+ case 0x35 /* '5' */ :
+ case 0x36 /* '6' */ :
+ case 0x37 /* '7' */ :
+ case 0x38 /* '8' */ :
+ case 0x39 /* '9' */ :
+ {
+ matchRange('0','9');
+ break;
+ }
+ default:
+ {
+ goto _loop46;
+ }
+ }
+ }
+ _loop46:;
+ } // ( ... )*
+ _ttype = testLiteralsTable(text.substr(_begin, text.length()-_begin),_ttype);
+ if ( _createToken && _token==antlr::nullToken && _ttype!=antlr::Token::SKIP ) {
+ _token = makeToken(_ttype);
+ _token->setText(text.substr(_begin, text.length()-_begin));
+ }
+ _returnToken = _token;
+ _saveIndex=0;
+}
+
+void RequirementLexer::mDOTKEY(bool _createToken) {
+ int _ttype; antlr::RefToken _token; std::string::size_type _begin = text.length();
+ _ttype = DOTKEY;
+ std::string::size_type _saveIndex;
+
+ mIDENT(false);
+ { // ( ... )*
+ for (;;) {
+ if ((LA(1) == 0x2e /* '.' */ )) {
+ match(".");
+ {
+ switch ( LA(1)) {
+ case 0x41 /* 'A' */ :
+ case 0x42 /* 'B' */ :
+ case 0x43 /* 'C' */ :
+ case 0x44 /* 'D' */ :
+ case 0x45 /* 'E' */ :
+ case 0x46 /* 'F' */ :
+ case 0x47 /* 'G' */ :
+ case 0x48 /* 'H' */ :
+ case 0x49 /* 'I' */ :
+ case 0x4a /* 'J' */ :
+ case 0x4b /* 'K' */ :
+ case 0x4c /* 'L' */ :
+ case 0x4d /* 'M' */ :
+ case 0x4e /* 'N' */ :
+ case 0x4f /* 'O' */ :
+ case 0x50 /* 'P' */ :
+ case 0x51 /* 'Q' */ :
+ case 0x52 /* 'R' */ :
+ case 0x53 /* 'S' */ :
+ case 0x54 /* 'T' */ :
+ case 0x55 /* 'U' */ :
+ case 0x56 /* 'V' */ :
+ case 0x57 /* 'W' */ :
+ case 0x58 /* 'X' */ :
+ case 0x59 /* 'Y' */ :
+ case 0x5a /* 'Z' */ :
+ case 0x61 /* 'a' */ :
+ case 0x62 /* 'b' */ :
+ case 0x63 /* 'c' */ :
+ case 0x64 /* 'd' */ :
+ case 0x65 /* 'e' */ :
+ case 0x66 /* 'f' */ :
+ case 0x67 /* 'g' */ :
+ case 0x68 /* 'h' */ :
+ case 0x69 /* 'i' */ :
+ case 0x6a /* 'j' */ :
+ case 0x6b /* 'k' */ :
+ case 0x6c /* 'l' */ :
+ case 0x6d /* 'm' */ :
+ case 0x6e /* 'n' */ :
+ case 0x6f /* 'o' */ :
+ case 0x70 /* 'p' */ :
+ case 0x71 /* 'q' */ :
+ case 0x72 /* 'r' */ :
+ case 0x73 /* 's' */ :
+ case 0x74 /* 't' */ :
+ case 0x75 /* 'u' */ :
+ case 0x76 /* 'v' */ :
+ case 0x77 /* 'w' */ :
+ case 0x78 /* 'x' */ :
+ case 0x79 /* 'y' */ :
+ case 0x7a /* 'z' */ :
+ {
+ mIDENT(false);
+ break;
+ }
+ case 0x30 /* '0' */ :
+ case 0x31 /* '1' */ :
+ case 0x32 /* '2' */ :
+ case 0x33 /* '3' */ :
+ case 0x34 /* '4' */ :
+ case 0x35 /* '5' */ :
+ case 0x36 /* '6' */ :
+ case 0x37 /* '7' */ :
+ case 0x38 /* '8' */ :
+ case 0x39 /* '9' */ :
+ {
+ mINTEGER(false);
+ break;
+ }
+ default:
+ {
+ throw antlr::NoViableAltForCharException(LA(1), getFilename(), getLine(), getColumn());
+ }
+ }
+ }
+ }
+ else {
+ goto _loop50;
+ }
+
+ }
+ _loop50:;
+ } // ( ... )*
+ _ttype = testLiteralsTable(_ttype);
+ if ( _createToken && _token==antlr::nullToken && _ttype!=antlr::Token::SKIP ) {
+ _token = makeToken(_ttype);
+ _token->setText(text.substr(_begin, text.length()-_begin));
+ }
+ _returnToken = _token;
+ _saveIndex=0;
+}
+
+void RequirementLexer::mINTEGER(bool _createToken) {
+ int _ttype; antlr::RefToken _token; std::string::size_type _begin = text.length();
+ _ttype = INTEGER;
+ std::string::size_type _saveIndex;
+
+ { // ( ... )+
+ int _cnt68=0;
+ for (;;) {
+ if (((LA(1) >= 0x30 /* '0' */ && LA(1) <= 0x39 /* '9' */ ))) {
+ matchRange('0','9');
+ }
+ else {
+ if ( _cnt68>=1 ) { goto _loop68; } else {throw antlr::NoViableAltForCharException(LA(1), getFilename(), getLine(), getColumn());}
+ }
+
+ _cnt68++;
+ }
+ _loop68:;
+ } // ( ... )+
+ if ( _createToken && _token==antlr::nullToken && _ttype!=antlr::Token::SKIP ) {
+ _token = makeToken(_ttype);
+ _token->setText(text.substr(_begin, text.length()-_begin));
+ }
+ _returnToken = _token;
+ _saveIndex=0;
+}
+
+void RequirementLexer::mPATHNAME(bool _createToken) {
+ int _ttype; antlr::RefToken _token; std::string::size_type _begin = text.length();
+ _ttype = PATHNAME;
+ std::string::size_type _saveIndex;
+
+ match("/");
+ mIDENT(false);
+ { // ( ... )+
+ int _cnt53=0;
+ for (;;) {
+ if ((LA(1) == 0x2f /* '/' */ )) {
+ match("/");
+ mIDENT(false);
+ }
+ else {
+ if ( _cnt53>=1 ) { goto _loop53; } else {throw antlr::NoViableAltForCharException(LA(1), getFilename(), getLine(), getColumn());}
+ }
+
+ _cnt53++;
+ }
+ _loop53:;
+ } // ( ... )+
+ if ( _createToken && _token==antlr::nullToken && _ttype!=antlr::Token::SKIP ) {
+ _token = makeToken(_ttype);
+ _token->setText(text.substr(_begin, text.length()-_begin));
+ }
+ _returnToken = _token;
+ _saveIndex=0;
+}
+
+void RequirementLexer::mHASHCONSTANT(bool _createToken) {
+ int _ttype; antlr::RefToken _token; std::string::size_type _begin = text.length();
+ _ttype = HASHCONSTANT;
+ std::string::size_type _saveIndex;
+
+ _saveIndex = text.length();
+ match('H' /* charlit */ );
+ text.erase(_saveIndex);
+ _saveIndex = text.length();
+ match('\"' /* charlit */ );
+ text.erase(_saveIndex);
+ { // ( ... )+
+ int _cnt56=0;
+ for (;;) {
+ if ((_tokenSet_1.member(LA(1)))) {
+ mHEX(false);
+ }
+ else {
+ if ( _cnt56>=1 ) { goto _loop56; } else {throw antlr::NoViableAltForCharException(LA(1), getFilename(), getLine(), getColumn());}
+ }
+
+ _cnt56++;
+ }
+ _loop56:;
+ } // ( ... )+
+ _saveIndex = text.length();
+ match('\"' /* charlit */ );
+ text.erase(_saveIndex);
+ if ( _createToken && _token==antlr::nullToken && _ttype!=antlr::Token::SKIP ) {
+ _token = makeToken(_ttype);
+ _token->setText(text.substr(_begin, text.length()-_begin));
+ }
+ _returnToken = _token;
+ _saveIndex=0;
+}
+
+void RequirementLexer::mHEX(bool _createToken) {
+ int _ttype; antlr::RefToken _token; std::string::size_type _begin = text.length();
+ _ttype = HEX;
+ std::string::size_type _saveIndex;
+
+ switch ( LA(1)) {
+ case 0x30 /* '0' */ :
+ case 0x31 /* '1' */ :
+ case 0x32 /* '2' */ :
+ case 0x33 /* '3' */ :
+ case 0x34 /* '4' */ :
+ case 0x35 /* '5' */ :
+ case 0x36 /* '6' */ :
+ case 0x37 /* '7' */ :
+ case 0x38 /* '8' */ :
+ case 0x39 /* '9' */ :
+ {
+ matchRange('0','9');
+ break;
+ }
+ case 0x61 /* 'a' */ :
+ case 0x62 /* 'b' */ :
+ case 0x63 /* 'c' */ :
+ case 0x64 /* 'd' */ :
+ case 0x65 /* 'e' */ :
+ case 0x66 /* 'f' */ :
+ {
+ matchRange('a','f');
+ break;
+ }
+ case 0x41 /* 'A' */ :
+ case 0x42 /* 'B' */ :
+ case 0x43 /* 'C' */ :
+ case 0x44 /* 'D' */ :
+ case 0x45 /* 'E' */ :
+ case 0x46 /* 'F' */ :
+ {
+ matchRange('A','F');
+ break;
+ }
+ default:
+ {
+ throw antlr::NoViableAltForCharException(LA(1), getFilename(), getLine(), getColumn());
+ }
+ }
+ if ( _createToken && _token==antlr::nullToken && _ttype!=antlr::Token::SKIP ) {
+ _token = makeToken(_ttype);
+ _token->setText(text.substr(_begin, text.length()-_begin));
+ }
+ _returnToken = _token;
+ _saveIndex=0;
+}
+
+void RequirementLexer::mHEXCONSTANT(bool _createToken) {
+ int _ttype; antlr::RefToken _token; std::string::size_type _begin = text.length();
+ _ttype = HEXCONSTANT;
+ std::string::size_type _saveIndex;
+
+ _saveIndex = text.length();
+ match('0' /* charlit */ );
+ text.erase(_saveIndex);
+ _saveIndex = text.length();
+ match('x' /* charlit */ );
+ text.erase(_saveIndex);
+ { // ( ... )+
+ int _cnt59=0;
+ for (;;) {
+ if ((_tokenSet_1.member(LA(1)))) {
+ mHEX(false);
+ }
+ else {
+ if ( _cnt59>=1 ) { goto _loop59; } else {throw antlr::NoViableAltForCharException(LA(1), getFilename(), getLine(), getColumn());}
+ }
+
+ _cnt59++;
+ }
+ _loop59:;
+ } // ( ... )+
+ if ( _createToken && _token==antlr::nullToken && _ttype!=antlr::Token::SKIP ) {
+ _token = makeToken(_ttype);
+ _token->setText(text.substr(_begin, text.length()-_begin));
+ }
+ _returnToken = _token;
+ _saveIndex=0;
+}
+
+void RequirementLexer::mSTRING(bool _createToken) {
+ int _ttype; antlr::RefToken _token; std::string::size_type _begin = text.length();
+ _ttype = STRING;
+ std::string::size_type _saveIndex;
+
+ _saveIndex = text.length();
+ match('\"' /* charlit */ );
+ text.erase(_saveIndex);
+ { // ( ... )*
+ for (;;) {
+ switch ( LA(1)) {
+ case 0x5c /* '\\' */ :
+ {
+ {
+ _saveIndex = text.length();
+ match('\\' /* charlit */ );
+ text.erase(_saveIndex);
+ match('\"' /* charlit */ );
+ }
+ break;
+ }
+ case 0x0 /* '\0' */ :
+ case 0x1 /* '\1' */ :
+ case 0x2 /* '\2' */ :
+ case 0x3 /* '\3' */ :
+ case 0x4 /* '\4' */ :
+ case 0x5 /* '\5' */ :
+ case 0x6 /* '\6' */ :
+ case 0x7 /* '\7' */ :
+ case 0x8 /* '\10' */ :
+ case 0x9 /* '\t' */ :
+ case 0xa /* '\n' */ :
+ case 0xb /* '\13' */ :
+ case 0xc /* '\14' */ :
+ case 0xd /* '\r' */ :
+ case 0xe /* '\16' */ :
+ case 0xf /* '\17' */ :
+ case 0x10 /* '\20' */ :
+ case 0x11 /* '\21' */ :
+ case 0x12 /* '\22' */ :
+ case 0x13 /* '\23' */ :
+ case 0x14 /* '\24' */ :
+ case 0x15 /* '\25' */ :
+ case 0x16 /* '\26' */ :
+ case 0x17 /* '\27' */ :
+ case 0x18 /* '\30' */ :
+ case 0x19 /* '\31' */ :
+ case 0x1a /* '\32' */ :
+ case 0x1b /* '\33' */ :
+ case 0x1c /* '\34' */ :
+ case 0x1d /* '\35' */ :
+ case 0x1e /* '\36' */ :
+ case 0x1f /* '\37' */ :
+ case 0x20 /* ' ' */ :
+ case 0x21 /* '!' */ :
+ case 0x23 /* '#' */ :
+ case 0x24 /* '$' */ :
+ case 0x25 /* '%' */ :
+ case 0x26 /* '&' */ :
+ case 0x27 /* '\'' */ :
+ case 0x28 /* '(' */ :
+ case 0x29 /* ')' */ :
+ case 0x2a /* '*' */ :
+ case 0x2b /* '+' */ :
+ case 0x2c /* ',' */ :
+ case 0x2d /* '-' */ :
+ case 0x2e /* '.' */ :
+ case 0x2f /* '/' */ :
+ case 0x30 /* '0' */ :
+ case 0x31 /* '1' */ :
+ case 0x32 /* '2' */ :
+ case 0x33 /* '3' */ :
+ case 0x34 /* '4' */ :
+ case 0x35 /* '5' */ :
+ case 0x36 /* '6' */ :
+ case 0x37 /* '7' */ :
+ case 0x38 /* '8' */ :
+ case 0x39 /* '9' */ :
+ case 0x3a /* ':' */ :
+ case 0x3b /* ';' */ :
+ case 0x3c /* '<' */ :
+ case 0x3d /* '=' */ :
+ case 0x3e /* '>' */ :
+ case 0x3f /* '?' */ :
+ case 0x40 /* '@' */ :
+ case 0x41 /* 'A' */ :
+ case 0x42 /* 'B' */ :
+ case 0x43 /* 'C' */ :
+ case 0x44 /* 'D' */ :
+ case 0x45 /* 'E' */ :
+ case 0x46 /* 'F' */ :
+ case 0x47 /* 'G' */ :
+ case 0x48 /* 'H' */ :
+ case 0x49 /* 'I' */ :
+ case 0x4a /* 'J' */ :
+ case 0x4b /* 'K' */ :
+ case 0x4c /* 'L' */ :
+ case 0x4d /* 'M' */ :
+ case 0x4e /* 'N' */ :
+ case 0x4f /* 'O' */ :
+ case 0x50 /* 'P' */ :
+ case 0x51 /* 'Q' */ :
+ case 0x52 /* 'R' */ :
+ case 0x53 /* 'S' */ :
+ case 0x54 /* 'T' */ :
+ case 0x55 /* 'U' */ :
+ case 0x56 /* 'V' */ :
+ case 0x57 /* 'W' */ :
+ case 0x58 /* 'X' */ :
+ case 0x59 /* 'Y' */ :
+ case 0x5a /* 'Z' */ :
+ case 0x5b /* '[' */ :
+ case 0x5d /* ']' */ :
+ case 0x5e /* '^' */ :
+ case 0x5f /* '_' */ :
+ case 0x60 /* '`' */ :
+ case 0x61 /* 'a' */ :
+ case 0x62 /* 'b' */ :
+ case 0x63 /* 'c' */ :
+ case 0x64 /* 'd' */ :
+ case 0x65 /* 'e' */ :
+ case 0x66 /* 'f' */ :
+ case 0x67 /* 'g' */ :
+ case 0x68 /* 'h' */ :
+ case 0x69 /* 'i' */ :
+ case 0x6a /* 'j' */ :
+ case 0x6b /* 'k' */ :
+ case 0x6c /* 'l' */ :
+ case 0x6d /* 'm' */ :
+ case 0x6e /* 'n' */ :
+ case 0x6f /* 'o' */ :
+ case 0x70 /* 'p' */ :
+ case 0x71 /* 'q' */ :
+ case 0x72 /* 'r' */ :
+ case 0x73 /* 's' */ :
+ case 0x74 /* 't' */ :
+ case 0x75 /* 'u' */ :
+ case 0x76 /* 'v' */ :
+ case 0x77 /* 'w' */ :
+ case 0x78 /* 'x' */ :
+ case 0x79 /* 'y' */ :
+ case 0x7a /* 'z' */ :
+ case 0x7b /* '{' */ :
+ case 0x7c /* '|' */ :
+ case 0x7d /* '}' */ :
+ case 0x7e /* '~' */ :
+ case 0x7f:
+ {
+ {
+ {
+ match(_tokenSet_2);
+ }
+ }
+ break;
+ }
+ default:
+ {
+ goto _loop65;
+ }
+ }
+ }
+ _loop65:;
+ } // ( ... )*
+ _saveIndex = text.length();
+ match('\"' /* charlit */ );
+ text.erase(_saveIndex);
+ if ( _createToken && _token==antlr::nullToken && _ttype!=antlr::Token::SKIP ) {
+ _token = makeToken(_ttype);
+ _token->setText(text.substr(_begin, text.length()-_begin));
+ }
+ _returnToken = _token;
+ _saveIndex=0;
+}
+
+void RequirementLexer::mARROW(bool _createToken) {
+ int _ttype; antlr::RefToken _token; std::string::size_type _begin = text.length();
+ _ttype = ARROW;
+ std::string::size_type _saveIndex;
+
+ match("=>");
+ if ( _createToken && _token==antlr::nullToken && _ttype!=antlr::Token::SKIP ) {
+ _token = makeToken(_ttype);
+ _token->setText(text.substr(_begin, text.length()-_begin));
+ }
+ _returnToken = _token;
+ _saveIndex=0;
+}
+
+void RequirementLexer::mSEMI(bool _createToken) {
+ int _ttype; antlr::RefToken _token; std::string::size_type _begin = text.length();
+ _ttype = SEMI;
+ std::string::size_type _saveIndex;
+
+ match(';' /* charlit */ );
+ if ( _createToken && _token==antlr::nullToken && _ttype!=antlr::Token::SKIP ) {
+ _token = makeToken(_ttype);
+ _token->setText(text.substr(_begin, text.length()-_begin));
+ }
+ _returnToken = _token;
+ _saveIndex=0;
+}
+
+void RequirementLexer::mLPAREN(bool _createToken) {
+ int _ttype; antlr::RefToken _token; std::string::size_type _begin = text.length();
+ _ttype = LPAREN;
+ std::string::size_type _saveIndex;
+
+ match('(' /* charlit */ );
+ if ( _createToken && _token==antlr::nullToken && _ttype!=antlr::Token::SKIP ) {
+ _token = makeToken(_ttype);
+ _token->setText(text.substr(_begin, text.length()-_begin));
+ }
+ _returnToken = _token;
+ _saveIndex=0;
+}
+
+void RequirementLexer::mRPAREN(bool _createToken) {
+ int _ttype; antlr::RefToken _token; std::string::size_type _begin = text.length();
+ _ttype = RPAREN;
+ std::string::size_type _saveIndex;
+
+ match(')' /* charlit */ );
+ if ( _createToken && _token==antlr::nullToken && _ttype!=antlr::Token::SKIP ) {
+ _token = makeToken(_ttype);
+ _token->setText(text.substr(_begin, text.length()-_begin));
+ }
+ _returnToken = _token;
+ _saveIndex=0;
+}
+
+void RequirementLexer::mLBRACK(bool _createToken) {
+ int _ttype; antlr::RefToken _token; std::string::size_type _begin = text.length();
+ _ttype = LBRACK;
+ std::string::size_type _saveIndex;
+
+ match('[' /* charlit */ );
+ if ( _createToken && _token==antlr::nullToken && _ttype!=antlr::Token::SKIP ) {
+ _token = makeToken(_ttype);
+ _token->setText(text.substr(_begin, text.length()-_begin));
+ }
+ _returnToken = _token;
+ _saveIndex=0;
+}
+
+void RequirementLexer::mRBRACK(bool _createToken) {
+ int _ttype; antlr::RefToken _token; std::string::size_type _begin = text.length();
+ _ttype = RBRACK;
+ std::string::size_type _saveIndex;
+
+ match(']' /* charlit */ );
+ if ( _createToken && _token==antlr::nullToken && _ttype!=antlr::Token::SKIP ) {
+ _token = makeToken(_ttype);
+ _token->setText(text.substr(_begin, text.length()-_begin));
+ }
+ _returnToken = _token;
+ _saveIndex=0;
+}
+
+void RequirementLexer::mLESS(bool _createToken) {
+ int _ttype; antlr::RefToken _token; std::string::size_type _begin = text.length();
+ _ttype = LESS;
+ std::string::size_type _saveIndex;
+
+ match('<' /* charlit */ );
+ if ( _createToken && _token==antlr::nullToken && _ttype!=antlr::Token::SKIP ) {
+ _token = makeToken(_ttype);
+ _token->setText(text.substr(_begin, text.length()-_begin));
+ }
+ _returnToken = _token;
+ _saveIndex=0;
+}
+
+void RequirementLexer::mGT(bool _createToken) {
+ int _ttype; antlr::RefToken _token; std::string::size_type _begin = text.length();
+ _ttype = GT;
+ std::string::size_type _saveIndex;
+
+ match('>' /* charlit */ );
+ if ( _createToken && _token==antlr::nullToken && _ttype!=antlr::Token::SKIP ) {
+ _token = makeToken(_ttype);
+ _token->setText(text.substr(_begin, text.length()-_begin));
+ }
+ _returnToken = _token;
+ _saveIndex=0;
+}
+
+void RequirementLexer::mLE(bool _createToken) {
+ int _ttype; antlr::RefToken _token; std::string::size_type _begin = text.length();
+ _ttype = LE;
+ std::string::size_type _saveIndex;
+
+ match("<=");
+ if ( _createToken && _token==antlr::nullToken && _ttype!=antlr::Token::SKIP ) {
+ _token = makeToken(_ttype);
+ _token->setText(text.substr(_begin, text.length()-_begin));
+ }
+ _returnToken = _token;
+ _saveIndex=0;
+}
+
+void RequirementLexer::mGE(bool _createToken) {
+ int _ttype; antlr::RefToken _token; std::string::size_type _begin = text.length();
+ _ttype = GE;
+ std::string::size_type _saveIndex;
+
+ match(">=");
+ if ( _createToken && _token==antlr::nullToken && _ttype!=antlr::Token::SKIP ) {
+ _token = makeToken(_ttype);
+ _token->setText(text.substr(_begin, text.length()-_begin));
+ }
+ _returnToken = _token;
+ _saveIndex=0;
+}
+
+void RequirementLexer::mCOMMA(bool _createToken) {
+ int _ttype; antlr::RefToken _token; std::string::size_type _begin = text.length();
+ _ttype = COMMA;
+ std::string::size_type _saveIndex;
+
+ match(',' /* charlit */ );
+ if ( _createToken && _token==antlr::nullToken && _ttype!=antlr::Token::SKIP ) {
+ _token = makeToken(_ttype);
+ _token->setText(text.substr(_begin, text.length()-_begin));
+ }
+ _returnToken = _token;
+ _saveIndex=0;
+}
+
+void RequirementLexer::mEQL(bool _createToken) {
+ int _ttype; antlr::RefToken _token; std::string::size_type _begin = text.length();
+ _ttype = EQL;
+ std::string::size_type _saveIndex;
+
+ match('=' /* charlit */ );
+ if ( _createToken && _token==antlr::nullToken && _ttype!=antlr::Token::SKIP ) {
+ _token = makeToken(_ttype);
+ _token->setText(text.substr(_begin, text.length()-_begin));
+ }
+ _returnToken = _token;
+ _saveIndex=0;
+}
+
+void RequirementLexer::mEQQL(bool _createToken) {
+ int _ttype; antlr::RefToken _token; std::string::size_type _begin = text.length();
+ _ttype = EQQL;
+ std::string::size_type _saveIndex;
+
+ match("==");
+ if ( _createToken && _token==antlr::nullToken && _ttype!=antlr::Token::SKIP ) {
+ _token = makeToken(_ttype);
+ _token->setText(text.substr(_begin, text.length()-_begin));
+ }
+ _returnToken = _token;
+ _saveIndex=0;
+}
+
+void RequirementLexer::mSUBS(bool _createToken) {
+ int _ttype; antlr::RefToken _token; std::string::size_type _begin = text.length();
+ _ttype = SUBS;
+ std::string::size_type _saveIndex;
+
+ match('~' /* charlit */ );
+ if ( _createToken && _token==antlr::nullToken && _ttype!=antlr::Token::SKIP ) {
+ _token = makeToken(_ttype);
+ _token->setText(text.substr(_begin, text.length()-_begin));
+ }
+ _returnToken = _token;
+ _saveIndex=0;
+}
+
+void RequirementLexer::mNEG(bool _createToken) {
+ int _ttype; antlr::RefToken _token; std::string::size_type _begin = text.length();
+ _ttype = NEG;
+ std::string::size_type _saveIndex;
+
+ match('-' /* charlit */ );
+ if ( _createToken && _token==antlr::nullToken && _ttype!=antlr::Token::SKIP ) {
+ _token = makeToken(_ttype);
+ _token->setText(text.substr(_begin, text.length()-_begin));
+ }
+ _returnToken = _token;
+ _saveIndex=0;
+}
+
+void RequirementLexer::mNOT(bool _createToken) {
+ int _ttype; antlr::RefToken _token; std::string::size_type _begin = text.length();
+ _ttype = NOT;
+ std::string::size_type _saveIndex;
+
+ match('!' /* charlit */ );
+ if ( _createToken && _token==antlr::nullToken && _ttype!=antlr::Token::SKIP ) {
+ _token = makeToken(_ttype);
+ _token->setText(text.substr(_begin, text.length()-_begin));
+ }
+ _returnToken = _token;
+ _saveIndex=0;
+}
+
+void RequirementLexer::mSTAR(bool _createToken) {
+ int _ttype; antlr::RefToken _token; std::string::size_type _begin = text.length();
+ _ttype = STAR;
+ std::string::size_type _saveIndex;
+
+ match('*' /* charlit */ );
+ if ( _createToken && _token==antlr::nullToken && _ttype!=antlr::Token::SKIP ) {
+ _token = makeToken(_ttype);
+ _token->setText(text.substr(_begin, text.length()-_begin));
+ }
+ _returnToken = _token;
+ _saveIndex=0;
+}
+
+void RequirementLexer::mWS(bool _createToken) {
+ int _ttype; antlr::RefToken _token; std::string::size_type _begin = text.length();
+ _ttype = WS;
+ std::string::size_type _saveIndex;
+
+ { // ( ... )+
+ int _cnt89=0;
+ for (;;) {
+ switch ( LA(1)) {
+ case 0x20 /* ' ' */ :
+ {
+ match(' ' /* charlit */ );
+ break;
+ }
+ case 0xa /* '\n' */ :
+ {
+ match('\n' /* charlit */ );
+ newline();
+ break;
+ }
+ case 0x9 /* '\t' */ :
+ {
+ match('\t' /* charlit */ );
+ break;
+ }
+ default:
+ {
+ if ( _cnt89>=1 ) { goto _loop89; } else {throw antlr::NoViableAltForCharException(LA(1), getFilename(), getLine(), getColumn());}
+ }
+ }
+ _cnt89++;
+ }
+ _loop89:;
+ } // ( ... )+
+ _ttype = antlr::Token::SKIP;
+ if ( _createToken && _token==antlr::nullToken && _ttype!=antlr::Token::SKIP ) {
+ _token = makeToken(_ttype);
+ _token->setText(text.substr(_begin, text.length()-_begin));
+ }
+ _returnToken = _token;
+ _saveIndex=0;
+}
+
+void RequirementLexer::mSHELLCOMMENT(bool _createToken) {
+ int _ttype; antlr::RefToken _token; std::string::size_type _begin = text.length();
+ _ttype = SHELLCOMMENT;
+ std::string::size_type _saveIndex;
+
+ match('#' /* charlit */ );
+ { // ( ... )*
+ for (;;) {
+ if ((_tokenSet_3.member(LA(1)))) {
+ matchNot('\n' /* charlit */ );
+ }
+ else {
+ goto _loop92;
+ }
+
+ }
+ _loop92:;
+ } // ( ... )*
+ _ttype = antlr::Token::SKIP;
+ if ( _createToken && _token==antlr::nullToken && _ttype!=antlr::Token::SKIP ) {
+ _token = makeToken(_ttype);
+ _token->setText(text.substr(_begin, text.length()-_begin));
+ }
+ _returnToken = _token;
+ _saveIndex=0;
+}
+
+void RequirementLexer::mC_COMMENT(bool _createToken) {
+ int _ttype; antlr::RefToken _token; std::string::size_type _begin = text.length();
+ _ttype = C_COMMENT;
+ std::string::size_type _saveIndex;
+
+ match("/*");
+ { // ( ... )*
+ for (;;) {
+ if ((LA(1) == 0x2a /* '*' */ ) && (_tokenSet_4.member(LA(2)))) {
+ {
+ match('*' /* charlit */ );
+ {
+ matchNot('/' /* charlit */ );
+ }
+ }
+ }
+ else if ((_tokenSet_5.member(LA(1)))) {
+ {
+ matchNot('*' /* charlit */ );
+ }
+ }
+ else {
+ goto _loop98;
+ }
+
+ }
+ _loop98:;
+ } // ( ... )*
+ match("*/");
+ _ttype = antlr::Token::SKIP;
+ if ( _createToken && _token==antlr::nullToken && _ttype!=antlr::Token::SKIP ) {
+ _token = makeToken(_ttype);
+ _token->setText(text.substr(_begin, text.length()-_begin));
+ }
+ _returnToken = _token;
+ _saveIndex=0;
+}
+
+void RequirementLexer::mCPP_COMMENT(bool _createToken) {
+ int _ttype; antlr::RefToken _token; std::string::size_type _begin = text.length();
+ _ttype = CPP_COMMENT;
+ std::string::size_type _saveIndex;
+
+ match("//");
+ { // ( ... )*
+ for (;;) {
+ if ((_tokenSet_3.member(LA(1)))) {
+ matchNot('\n' /* charlit */ );
+ }
+ else {
+ goto _loop101;
+ }
+
+ }
+ _loop101:;
+ } // ( ... )*
+ _ttype = antlr::Token::SKIP;
+ if ( _createToken && _token==antlr::nullToken && _ttype!=antlr::Token::SKIP ) {
+ _token = makeToken(_ttype);
+ _token->setText(text.substr(_begin, text.length()-_begin));
+ }
+ _returnToken = _token;
+ _saveIndex=0;
+}
+
+
+const unsigned long RequirementLexer::_tokenSet_0_data_[] = { 0UL, 0UL, 134217726UL, 134217726UL, 0UL, 0UL, 0UL, 0UL };
+const antlr::BitSet RequirementLexer::_tokenSet_0(_tokenSet_0_data_,8);
+const unsigned long RequirementLexer::_tokenSet_1_data_[] = { 0UL, 67043328UL, 126UL, 126UL, 0UL, 0UL, 0UL, 0UL };
+// 0 1 2 3 4 5 6 7 8
+const antlr::BitSet RequirementLexer::_tokenSet_1(_tokenSet_1_data_,8);
+const unsigned long RequirementLexer::_tokenSet_2_data_[] = { 4294967295UL, 4294967291UL, 4026531839UL, 4294967295UL, 0UL, 0UL, 0UL, 0UL };
+// 0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf 0x10
+// 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1a 0x1b 0x1c 0x1d 0x1e
+// 0x1f ! # $ % & \' ( ) * + , - . / 0 1 2 3 4 5 6 7 8
+const antlr::BitSet RequirementLexer::_tokenSet_2(_tokenSet_2_data_,8);
+const unsigned long RequirementLexer::_tokenSet_3_data_[] = { 4294966271UL, 4294967295UL, 4294967295UL, 4294967295UL, 0UL, 0UL, 0UL, 0UL };
+// 0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xb 0xc 0xd 0xe 0xf 0x10 0x11
+// 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1a 0x1b 0x1c 0x1d 0x1e 0x1f
+// ! \" # $ % & \' ( ) * + , - . / 0 1 2 3 4 5 6 7 8
+const antlr::BitSet RequirementLexer::_tokenSet_3(_tokenSet_3_data_,8);
+const unsigned long RequirementLexer::_tokenSet_4_data_[] = { 4294967295UL, 4294934527UL, 4294967295UL, 4294967295UL, 0UL, 0UL, 0UL, 0UL };
+// 0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf 0x10
+// 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1a 0x1b 0x1c 0x1d 0x1e
+// 0x1f ! \" # $ % & \' ( ) * + , - . 0 1 2 3 4 5 6 7 8
+const antlr::BitSet RequirementLexer::_tokenSet_4(_tokenSet_4_data_,8);
+const unsigned long RequirementLexer::_tokenSet_5_data_[] = { 4294967295UL, 4294966271UL, 4294967295UL, 4294967295UL, 0UL, 0UL, 0UL, 0UL };
+// 0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf 0x10
+// 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1a 0x1b 0x1c 0x1d 0x1e
+// 0x1f ! \" # $ % & \' ( ) + , - . / 0 1 2 3 4 5 6 7 8
+const antlr::BitSet RequirementLexer::_tokenSet_5(_tokenSet_5_data_,8);
+
+ANTLR_END_NAMESPACE
--- /dev/null
+#ifndef INC_RequirementLexer_hpp_
+#define INC_RequirementLexer_hpp_
+
+#include <antlr/config.hpp>
+/* $ANTLR 2.7.7 (20120228): "requirements.grammar" -> "RequirementLexer.hpp"$ */
+#include <antlr/CommonToken.hpp>
+#include <antlr/InputBuffer.hpp>
+#include <antlr/BitSet.hpp>
+#include "RequirementParserTokenTypes.hpp"
+#include <antlr/CharScanner.hpp>
+
+#include "requirement.h"
+using namespace CodeSigning;
+typedef Requirement::Maker Maker;
+
+ANTLR_BEGIN_NAMESPACE(Security_CodeSigning)
+class CUSTOM_API RequirementLexer : public antlr::CharScanner, public RequirementParserTokenTypes
+{
+private:
+ void initLiterals();
+public:
+ bool getCaseSensitiveLiterals() const
+ {
+ return true;
+ }
+public:
+ RequirementLexer(std::istream& in);
+ RequirementLexer(antlr::InputBuffer& ib);
+ RequirementLexer(const antlr::LexerSharedInputState& state);
+ antlr::RefToken nextToken();
+ protected: void mIDENT(bool _createToken);
+ public: void mDOTKEY(bool _createToken);
+ public: void mINTEGER(bool _createToken);
+ public: void mPATHNAME(bool _createToken);
+ public: void mHASHCONSTANT(bool _createToken);
+ protected: void mHEX(bool _createToken);
+ public: void mHEXCONSTANT(bool _createToken);
+ public: void mSTRING(bool _createToken);
+ public: void mARROW(bool _createToken);
+ public: void mSEMI(bool _createToken);
+ public: void mLPAREN(bool _createToken);
+ public: void mRPAREN(bool _createToken);
+ public: void mLBRACK(bool _createToken);
+ public: void mRBRACK(bool _createToken);
+ public: void mLESS(bool _createToken);
+ public: void mGT(bool _createToken);
+ public: void mLE(bool _createToken);
+ public: void mGE(bool _createToken);
+ public: void mCOMMA(bool _createToken);
+ public: void mEQL(bool _createToken);
+ public: void mEQQL(bool _createToken);
+ public: void mSUBS(bool _createToken);
+ public: void mNEG(bool _createToken);
+ public: void mNOT(bool _createToken);
+ public: void mSTAR(bool _createToken);
+ public: void mWS(bool _createToken);
+ public: void mSHELLCOMMENT(bool _createToken);
+ public: void mC_COMMENT(bool _createToken);
+ public: void mCPP_COMMENT(bool _createToken);
+private:
+
+ static const unsigned long _tokenSet_0_data_[];
+ static const antlr::BitSet _tokenSet_0;
+ static const unsigned long _tokenSet_1_data_[];
+ static const antlr::BitSet _tokenSet_1;
+ static const unsigned long _tokenSet_2_data_[];
+ static const antlr::BitSet _tokenSet_2;
+ static const unsigned long _tokenSet_3_data_[];
+ static const antlr::BitSet _tokenSet_3;
+ static const unsigned long _tokenSet_4_data_[];
+ static const antlr::BitSet _tokenSet_4;
+ static const unsigned long _tokenSet_5_data_[];
+ static const antlr::BitSet _tokenSet_5;
+};
+
+ANTLR_END_NAMESPACE
+#endif /*INC_RequirementLexer_hpp_*/
--- /dev/null
+/* $ANTLR 2.7.7 (20120228): "requirements.grammar" -> "RequirementParser.cpp"$ */
+#include "RequirementParser.hpp"
+#include <antlr/NoViableAltException.hpp>
+#include <antlr/SemanticException.hpp>
+#include <antlr/ASTFactory.hpp>
+
+#include "requirement.h"
+#include "reqmaker.h"
+#include "csutilities.h"
+#include <security_utilities/cfutilities.h>
+#include <security_utilities/hashing.h>
+#include <security_cdsa_utilities/cssmdata.h> // OID coding
+using namespace CodeSigning;
+typedef Requirement::Maker Maker;
+
+ANTLR_BEGIN_NAMESPACE(Security_CodeSigning)
+
+ //
+ // Collect error messages.
+ // Note that the immediate caller takes the absence of collected error messages
+ // to indicate compilation success.
+ //
+ void RequirementParser::reportError(const antlr::RecognitionException &ex)
+ {
+ errors += ex.toString() + "\n";
+ }
+
+ void RequirementParser::reportError(const std::string &s)
+ {
+ errors += s + "\n";
+ }
+
+
+ //
+ // Parser helper functions
+ //
+ string RequirementParser::hexString(const string &s)
+ {
+ if (s.size() % 2)
+ throw antlr::SemanticException("odd number of digits");
+ const char *p = s.data();
+ string result;
+ for (unsigned n = 0; n < s.length(); n += 2) {
+ char c;
+ sscanf(p+n, "%2hhx", &c);
+ result.push_back(c);
+ }
+ return result;
+ }
+
+ void RequirementParser::hashString(const string &s, SHA1::Digest hash)
+ {
+ if (s.size() != 2 * SHA1::digestLength)
+ throw antlr::SemanticException("invalid hash length");
+ memcpy(hash, hexString(s).data(), SHA1::digestLength);
+ }
+
+ static const char *matchPrefix(const string &key, const char *prefix)
+ {
+ unsigned pLength = strlen(prefix);
+ if (!key.compare(0, pLength, prefix, 0, pLength))
+ return key.c_str() + pLength;
+ else
+ return NULL;
+ }
+
+ void RequirementParser::certMatchOperation(Maker &maker, int32_t slot, string key)
+ {
+ if (matchPrefix(key, "subject.")) {
+ maker.put(opCertField);
+ maker.put(slot);
+ maker.put(key);
+ } else if (const char *oids = matchPrefix(key, "field.")) {
+ maker.put(opCertGeneric);
+ maker.put(slot);
+ CssmAutoData oid(Allocator::standard()); oid.fromOid(oids);
+ maker.putData(oid.data(), oid.length());
+ } else if (const char *oids = matchPrefix(key, "extension.")) {
+ maker.put(opCertGeneric);
+ maker.put(slot);
+ CssmAutoData oid(Allocator::standard()); oid.fromOid(oids);
+ maker.putData(oid.data(), oid.length());
+ } else if (const char *oids = matchPrefix(key, "policy.")) {
+ maker.put(opCertPolicy);
+ maker.put(slot);
+ CssmAutoData oid(Allocator::standard()); oid.fromOid(oids);
+ maker.putData(oid.data(), oid.length());
+ } else {
+ throw antlr::SemanticException(key + ": unrecognized certificate field");
+ }
+ }
+
+RequirementParser::RequirementParser(antlr::TokenBuffer& tokenBuf, int k)
+: antlr::LLkParser(tokenBuf,k)
+{
+}
+
+RequirementParser::RequirementParser(antlr::TokenBuffer& tokenBuf)
+: antlr::LLkParser(tokenBuf,2)
+{
+}
+
+RequirementParser::RequirementParser(antlr::TokenStream& lexer, int k)
+: antlr::LLkParser(lexer,k)
+{
+}
+
+RequirementParser::RequirementParser(antlr::TokenStream& lexer)
+: antlr::LLkParser(lexer,2)
+{
+}
+
+RequirementParser::RequirementParser(const antlr::ParserSharedInputState& state)
+: antlr::LLkParser(state,2)
+{
+}
+
+BlobCore * RequirementParser::autosense() {
+ BlobCore *result = NULL;
+
+ try { // for error handling
+ switch ( LA(1)) {
+ case LPAREN:
+ case NOT:
+ case LITERAL_always:
+ case LITERAL_true:
+ case LITERAL_never:
+ case LITERAL_false:
+ case LITERAL_identifier:
+ case LITERAL_cdhash:
+ case LITERAL_anchor:
+ case LITERAL_certificate:
+ case LITERAL_cert:
+ case LITERAL_info:
+ case LITERAL_entitlement:
+ {
+ result=requirement();
+ break;
+ }
+ case LITERAL_guest:
+ case LITERAL_host:
+ case LITERAL_designated:
+ case LITERAL_library:
+ case LITERAL_plugin:
+ case INTEGER:
+ {
+ result=requirementSet();
+ break;
+ }
+ default:
+ {
+ throw antlr::NoViableAltException(LT(1), getFilename());
+ }
+ }
+ }
+ catch (antlr::RecognitionException& ex) {
+ reportError(ex);
+ recover(ex,_tokenSet_0);
+ }
+ return result;
+}
+
+Requirement * RequirementParser::requirement() {
+ Requirement *result = NULL;
+
+ try { // for error handling
+ result=requirementElement();
+ match(antlr::Token::EOF_TYPE);
+ }
+ catch (antlr::RecognitionException& ex) {
+ reportError(ex);
+ recover(ex,_tokenSet_0);
+ }
+ return result;
+}
+
+Requirements * RequirementParser::requirementSet() {
+ Requirements *result = NULL;
+ Requirements::Maker maker;
+
+ try { // for error handling
+ { // ( ... )+
+ int _cnt4=0;
+ for (;;) {
+ if (((LA(1) >= LITERAL_guest && LA(1) <= INTEGER))) {
+ uint32_t t; Requirement *req;
+ t=requirementType();
+ match(ARROW);
+ req=requirementElement();
+ maker.add(t, req);
+ }
+ else {
+ if ( _cnt4>=1 ) { goto _loop4; } else {throw antlr::NoViableAltException(LT(1), getFilename());}
+ }
+
+ _cnt4++;
+ }
+ _loop4:;
+ } // ( ... )+
+ result = errors.empty() ? maker() : NULL;
+ match(antlr::Token::EOF_TYPE);
+ }
+ catch (antlr::RecognitionException& ex) {
+ reportError(ex);
+ recover(ex,_tokenSet_0);
+ }
+ return result;
+}
+
+uint32_t RequirementParser::requirementType() {
+ uint32_t type = kSecInvalidRequirementType;
+ antlr::RefToken stype = antlr::nullToken;
+
+ try { // for error handling
+ switch ( LA(1)) {
+ case LITERAL_guest:
+ {
+ match(LITERAL_guest);
+ type = kSecGuestRequirementType;
+ break;
+ }
+ case LITERAL_host:
+ {
+ match(LITERAL_host);
+ type = kSecHostRequirementType;
+ break;
+ }
+ case LITERAL_designated:
+ {
+ match(LITERAL_designated);
+ type = kSecDesignatedRequirementType;
+ break;
+ }
+ case LITERAL_library:
+ {
+ match(LITERAL_library);
+ type = kSecLibraryRequirementType;
+ break;
+ }
+ case LITERAL_plugin:
+ {
+ match(LITERAL_plugin);
+ type = kSecPluginRequirementType;
+ break;
+ }
+ case INTEGER:
+ {
+ stype = LT(1);
+ match(INTEGER);
+ type = atol(stype->getText().c_str());
+ break;
+ }
+ default:
+ {
+ throw antlr::NoViableAltException(LT(1), getFilename());
+ }
+ }
+ }
+ catch (antlr::RecognitionException& ex) {
+ reportError(ex);
+ recover(ex,_tokenSet_1);
+ }
+ return type;
+}
+
+Requirement * RequirementParser::requirementElement() {
+ Requirement *result = NULL;
+ Requirement::Maker maker;
+
+ try { // for error handling
+ expr(maker);
+ result = maker();
+ { // ( ... )*
+ for (;;) {
+ if ((LA(1) == SEMI)) {
+ fluff();
+ }
+ else {
+ goto _loop9;
+ }
+
+ }
+ _loop9:;
+ } // ( ... )*
+ }
+ catch (antlr::RecognitionException& ex) {
+ reportError(ex);
+ recover(ex,_tokenSet_2);
+ }
+ return result;
+}
+
+void RequirementParser::expr(
+ Maker &maker
+) {
+ Maker::Label label(maker);
+
+ try { // for error handling
+ term(maker);
+ { // ( ... )*
+ for (;;) {
+ if ((LA(1) == LITERAL_or)) {
+ match(LITERAL_or);
+ maker.insert<ExprOp>(label) = opOr;
+ term(maker);
+ }
+ else {
+ goto _loop12;
+ }
+
+ }
+ _loop12:;
+ } // ( ... )*
+ }
+ catch (antlr::RecognitionException& ex) {
+ reportError(ex);
+ recover(ex,_tokenSet_3);
+ }
+}
+
+void RequirementParser::fluff() {
+
+ try { // for error handling
+ match(SEMI);
+ }
+ catch (antlr::RecognitionException& ex) {
+ reportError(ex);
+ recover(ex,_tokenSet_4);
+ }
+}
+
+void RequirementParser::term(
+ Maker &maker
+) {
+ Maker::Label label(maker);
+
+ try { // for error handling
+ primary(maker);
+ { // ( ... )*
+ for (;;) {
+ if ((LA(1) == LITERAL_and)) {
+ match(LITERAL_and);
+ maker.insert<ExprOp>(label) = opAnd;
+ primary(maker);
+ }
+ else {
+ goto _loop15;
+ }
+
+ }
+ _loop15:;
+ } // ( ... )*
+ }
+ catch (antlr::RecognitionException& ex) {
+ reportError(ex);
+ recover(ex,_tokenSet_5);
+ }
+}
+
+void RequirementParser::primary(
+ Maker &maker
+) {
+
+ try { // for error handling
+ switch ( LA(1)) {
+ case NOT:
+ {
+ match(NOT);
+ maker.put(opNot);
+ primary(maker);
+ break;
+ }
+ case LITERAL_always:
+ case LITERAL_true:
+ {
+ {
+ switch ( LA(1)) {
+ case LITERAL_always:
+ {
+ match(LITERAL_always);
+ break;
+ }
+ case LITERAL_true:
+ {
+ match(LITERAL_true);
+ break;
+ }
+ default:
+ {
+ throw antlr::NoViableAltException(LT(1), getFilename());
+ }
+ }
+ }
+ maker.put(opTrue);
+ break;
+ }
+ case LITERAL_never:
+ case LITERAL_false:
+ {
+ {
+ switch ( LA(1)) {
+ case LITERAL_never:
+ {
+ match(LITERAL_never);
+ break;
+ }
+ case LITERAL_false:
+ {
+ match(LITERAL_false);
+ break;
+ }
+ default:
+ {
+ throw antlr::NoViableAltException(LT(1), getFilename());
+ }
+ }
+ }
+ maker.put(opFalse);
+ break;
+ }
+ case LITERAL_anchor:
+ case LITERAL_certificate:
+ case LITERAL_cert:
+ {
+ certspec(maker);
+ break;
+ }
+ case LITERAL_info:
+ {
+ infospec(maker);
+ break;
+ }
+ case LITERAL_entitlement:
+ {
+ entitlementspec(maker);
+ break;
+ }
+ case LITERAL_identifier:
+ {
+ match(LITERAL_identifier);
+ string code;
+ eql();
+ code=identifierString();
+ maker.ident(code);
+ break;
+ }
+ case LITERAL_cdhash:
+ {
+ match(LITERAL_cdhash);
+ SHA1::Digest digest;
+ eql();
+ hash(digest);
+ maker.cdhash(digest);
+ break;
+ }
+ default:
+ if ((LA(1) == LPAREN) && (_tokenSet_6.member(LA(2)))) {
+ match(LPAREN);
+ expr(maker);
+ match(RPAREN);
+ }
+ else if ((LA(1) == LPAREN) && (LA(2) == DOTKEY || LA(2) == STRING)) {
+ match(LPAREN);
+ string name;
+ name=identifierString();
+ match(RPAREN);
+ maker.put(opNamedCode); maker.put(name);
+ }
+ else {
+ throw antlr::NoViableAltException(LT(1), getFilename());
+ }
+ }
+ }
+ catch (antlr::RecognitionException& ex) {
+ reportError(ex);
+ recover(ex,_tokenSet_7);
+ }
+}
+
+void RequirementParser::certspec(
+ Maker &maker
+) {
+
+ try { // for error handling
+ if ((LA(1) == LITERAL_anchor) && (LA(2) == LITERAL_apple)) {
+ match(LITERAL_anchor);
+ match(LITERAL_apple);
+ appleanchor(maker);
+ }
+ else if ((LA(1) == LITERAL_anchor) && (LA(2) == LITERAL_generic)) {
+ match(LITERAL_anchor);
+ match(LITERAL_generic);
+ match(LITERAL_apple);
+ maker.put(opAppleGenericAnchor);
+ }
+ else if ((LA(1) == LITERAL_anchor || LA(1) == LITERAL_certificate || LA(1) == LITERAL_cert) && (LA(2) == LITERAL_trusted)) {
+ {
+ switch ( LA(1)) {
+ case LITERAL_certificate:
+ {
+ match(LITERAL_certificate);
+ break;
+ }
+ case LITERAL_cert:
+ {
+ match(LITERAL_cert);
+ break;
+ }
+ case LITERAL_anchor:
+ {
+ match(LITERAL_anchor);
+ break;
+ }
+ default:
+ {
+ throw antlr::NoViableAltException(LT(1), getFilename());
+ }
+ }
+ }
+ match(LITERAL_trusted);
+ maker.trustedAnchor();
+ }
+ else if ((LA(1) == LITERAL_certificate || LA(1) == LITERAL_cert) && (_tokenSet_8.member(LA(2)))) {
+ {
+ switch ( LA(1)) {
+ case LITERAL_certificate:
+ {
+ match(LITERAL_certificate);
+ break;
+ }
+ case LITERAL_cert:
+ {
+ match(LITERAL_cert);
+ break;
+ }
+ default:
+ {
+ throw antlr::NoViableAltException(LT(1), getFilename());
+ }
+ }
+ }
+ int32_t slot;
+ slot=certSlot();
+ {
+ switch ( LA(1)) {
+ case EQL:
+ case EQQL:
+ case LBRACK:
+ case HASHCONSTANT:
+ case DOTKEY:
+ case STRING:
+ case PATHNAME:
+ {
+ certslotspec(maker, slot);
+ break;
+ }
+ case LITERAL_trusted:
+ {
+ match(LITERAL_trusted);
+ maker.trustedAnchor(slot);
+ break;
+ }
+ default:
+ {
+ throw antlr::NoViableAltException(LT(1), getFilename());
+ }
+ }
+ }
+ }
+ else if ((LA(1) == LITERAL_anchor) && (_tokenSet_9.member(LA(2)))) {
+ match(LITERAL_anchor);
+ certslotspec(maker, Requirement::anchorCert);
+ }
+ else {
+ throw antlr::NoViableAltException(LT(1), getFilename());
+ }
+
+ }
+ catch (antlr::RecognitionException& ex) {
+ reportError(ex);
+ recover(ex,_tokenSet_7);
+ }
+}
+
+void RequirementParser::infospec(
+ Maker &maker
+) {
+ string key;
+
+ try { // for error handling
+ match(LITERAL_info);
+ key=bracketKey();
+ maker.put(opInfoKeyField); maker.put(key);
+ match_suffix(maker);
+ }
+ catch (antlr::RecognitionException& ex) {
+ reportError(ex);
+ recover(ex,_tokenSet_7);
+ }
+}
+
+void RequirementParser::entitlementspec(
+ Maker &maker
+) {
+ string key;
+
+ try { // for error handling
+ match(LITERAL_entitlement);
+ key=bracketKey();
+ maker.put(opEntitlementField); maker.put(key);
+ match_suffix(maker);
+ }
+ catch (antlr::RecognitionException& ex) {
+ reportError(ex);
+ recover(ex,_tokenSet_7);
+ }
+}
+
+void RequirementParser::eql() {
+
+ try { // for error handling
+ switch ( LA(1)) {
+ case EQL:
+ {
+ match(EQL);
+ break;
+ }
+ case EQQL:
+ {
+ match(EQQL);
+ break;
+ }
+ case HASHCONSTANT:
+ case DOTKEY:
+ case STRING:
+ case PATHNAME:
+ {
+ empty();
+ break;
+ }
+ default:
+ {
+ throw antlr::NoViableAltException(LT(1), getFilename());
+ }
+ }
+ }
+ catch (antlr::RecognitionException& ex) {
+ reportError(ex);
+ recover(ex,_tokenSet_10);
+ }
+}
+
+string RequirementParser::identifierString() {
+ string result;
+ antlr::RefToken dk = antlr::nullToken;
+ antlr::RefToken s = antlr::nullToken;
+
+ try { // for error handling
+ switch ( LA(1)) {
+ case DOTKEY:
+ {
+ dk = LT(1);
+ match(DOTKEY);
+ result = dk->getText();
+ break;
+ }
+ case STRING:
+ {
+ s = LT(1);
+ match(STRING);
+ result = s->getText();
+ break;
+ }
+ default:
+ {
+ throw antlr::NoViableAltException(LT(1), getFilename());
+ }
+ }
+ }
+ catch (antlr::RecognitionException& ex) {
+ reportError(ex);
+ recover(ex,_tokenSet_7);
+ }
+ return result;
+}
+
+void RequirementParser::hash(
+ SHA1::Digest digest
+) {
+ antlr::RefToken hash = antlr::nullToken;
+
+ try { // for error handling
+ hash = LT(1);
+ match(HASHCONSTANT);
+ hashString(hash->getText(), digest);
+ }
+ catch (antlr::RecognitionException& ex) {
+ reportError(ex);
+ recover(ex,_tokenSet_7);
+ }
+}
+
+void RequirementParser::appleanchor(
+ Maker &maker
+) {
+
+ try { // for error handling
+ switch ( LA(1)) {
+ case antlr::Token::EOF_TYPE:
+ case LITERAL_guest:
+ case LITERAL_host:
+ case LITERAL_designated:
+ case LITERAL_library:
+ case LITERAL_plugin:
+ case INTEGER:
+ case LITERAL_or:
+ case LITERAL_and:
+ case RPAREN:
+ case SEMI:
+ {
+ empty();
+ maker.put(opAppleAnchor);
+ break;
+ }
+ case LITERAL_generic:
+ {
+ match(LITERAL_generic);
+ maker.put(opAppleGenericAnchor);
+ break;
+ }
+ case DOTKEY:
+ case STRING:
+ {
+ string name;
+ name=identifierString();
+ maker.put(opNamedAnchor); maker.put(name);
+ break;
+ }
+ default:
+ {
+ throw antlr::NoViableAltException(LT(1), getFilename());
+ }
+ }
+ }
+ catch (antlr::RecognitionException& ex) {
+ reportError(ex);
+ recover(ex,_tokenSet_7);
+ }
+}
+
+int32_t RequirementParser::certSlot() {
+ int32_t slot = 0;
+ antlr::RefToken s = antlr::nullToken;
+ antlr::RefToken ss = antlr::nullToken;
+
+ try { // for error handling
+ switch ( LA(1)) {
+ case INTEGER:
+ {
+ s = LT(1);
+ match(INTEGER);
+ slot = atol(s->getText().c_str());
+ break;
+ }
+ case NEG:
+ {
+ match(NEG);
+ ss = LT(1);
+ match(INTEGER);
+ slot = -atol(ss->getText().c_str());
+ break;
+ }
+ case LITERAL_leaf:
+ {
+ match(LITERAL_leaf);
+ slot = Requirement::leafCert;
+ break;
+ }
+ case LITERAL_root:
+ {
+ match(LITERAL_root);
+ slot = Requirement::anchorCert;
+ break;
+ }
+ default:
+ {
+ throw antlr::NoViableAltException(LT(1), getFilename());
+ }
+ }
+ }
+ catch (antlr::RecognitionException& ex) {
+ reportError(ex);
+ recover(ex,_tokenSet_11);
+ }
+ return slot;
+}
+
+void RequirementParser::certslotspec(
+ Maker &maker, int32_t slot
+) {
+ string key;
+
+ try { // for error handling
+ switch ( LA(1)) {
+ case EQL:
+ case EQQL:
+ case HASHCONSTANT:
+ case DOTKEY:
+ case STRING:
+ case PATHNAME:
+ {
+ eql();
+ SHA1::Digest digest;
+ certificateDigest(digest);
+ maker.anchor(slot, digest);
+ break;
+ }
+ case LBRACK:
+ {
+ key=bracketKey();
+ certMatchOperation(maker, slot, key);
+ match_suffix(maker);
+ break;
+ }
+ default:
+ {
+ throw antlr::NoViableAltException(LT(1), getFilename());
+ }
+ }
+ }
+ catch (antlr::RecognitionException& ex) {
+ reportError(ex);
+ recover(ex,_tokenSet_7);
+ }
+}
+
+void RequirementParser::empty() {
+
+ try { // for error handling
+ }
+ catch (antlr::RecognitionException& ex) {
+ reportError(ex);
+ recover(ex,_tokenSet_12);
+ }
+}
+
+void RequirementParser::certificateDigest(
+ SHA1::Digest digest
+) {
+
+ try { // for error handling
+ switch ( LA(1)) {
+ case HASHCONSTANT:
+ {
+ hash(digest);
+ break;
+ }
+ case DOTKEY:
+ case STRING:
+ case PATHNAME:
+ {
+ string path;
+ path=pathstring();
+ if (CFRef<CFDataRef> certData = cfLoadFile(path))
+ hashOfCertificate(CFDataGetBytePtr(certData), CFDataGetLength(certData), digest);
+ else
+ throw antlr::SemanticException(path + ": not found");
+
+ break;
+ }
+ default:
+ {
+ throw antlr::NoViableAltException(LT(1), getFilename());
+ }
+ }
+ }
+ catch (antlr::RecognitionException& ex) {
+ reportError(ex);
+ recover(ex,_tokenSet_7);
+ }
+}
+
+string RequirementParser::bracketKey() {
+ string key;
+
+ try { // for error handling
+ match(LBRACK);
+ key=stringvalue();
+ match(RBRACK);
+ }
+ catch (antlr::RecognitionException& ex) {
+ reportError(ex);
+ recover(ex,_tokenSet_13);
+ }
+ return key;
+}
+
+void RequirementParser::match_suffix(
+ Maker &maker
+) {
+
+ try { // for error handling
+ switch ( LA(1)) {
+ case antlr::Token::EOF_TYPE:
+ case LITERAL_guest:
+ case LITERAL_host:
+ case LITERAL_designated:
+ case LITERAL_library:
+ case LITERAL_plugin:
+ case INTEGER:
+ case LITERAL_or:
+ case LITERAL_and:
+ case RPAREN:
+ case LITERAL_exists:
+ case SEMI:
+ {
+ empty();
+ {
+ switch ( LA(1)) {
+ case LITERAL_exists:
+ {
+ match(LITERAL_exists);
+ break;
+ }
+ case antlr::Token::EOF_TYPE:
+ case LITERAL_guest:
+ case LITERAL_host:
+ case LITERAL_designated:
+ case LITERAL_library:
+ case LITERAL_plugin:
+ case INTEGER:
+ case LITERAL_or:
+ case LITERAL_and:
+ case RPAREN:
+ case SEMI:
+ {
+ break;
+ }
+ default:
+ {
+ throw antlr::NoViableAltException(LT(1), getFilename());
+ }
+ }
+ }
+ maker.put(matchExists);
+ break;
+ }
+ case EQL:
+ case EQQL:
+ {
+ {
+ switch ( LA(1)) {
+ case EQL:
+ {
+ match(EQL);
+ break;
+ }
+ case EQQL:
+ {
+ match(EQQL);
+ break;
+ }
+ default:
+ {
+ throw antlr::NoViableAltException(LT(1), getFilename());
+ }
+ }
+ }
+ MatchOperation mop = matchEqual; string value;
+ {
+ switch ( LA(1)) {
+ case STAR:
+ {
+ match(STAR);
+ mop = matchEndsWith;
+ break;
+ }
+ case HEXCONSTANT:
+ case DOTKEY:
+ case STRING:
+ {
+ break;
+ }
+ default:
+ {
+ throw antlr::NoViableAltException(LT(1), getFilename());
+ }
+ }
+ }
+ value=datavalue();
+ {
+ switch ( LA(1)) {
+ case STAR:
+ {
+ match(STAR);
+ mop = (mop == matchEndsWith) ? matchContains : matchBeginsWith;
+ break;
+ }
+ case antlr::Token::EOF_TYPE:
+ case LITERAL_guest:
+ case LITERAL_host:
+ case LITERAL_designated:
+ case LITERAL_library:
+ case LITERAL_plugin:
+ case INTEGER:
+ case LITERAL_or:
+ case LITERAL_and:
+ case RPAREN:
+ case SEMI:
+ {
+ break;
+ }
+ default:
+ {
+ throw antlr::NoViableAltException(LT(1), getFilename());
+ }
+ }
+ }
+ maker.put(mop); maker.put(value);
+ break;
+ }
+ case SUBS:
+ {
+ match(SUBS);
+ string value;
+ value=datavalue();
+ maker.put(matchContains); maker.put(value);
+ break;
+ }
+ case LESS:
+ {
+ match(LESS);
+ string value;
+ value=datavalue();
+ maker.put(matchLessThan); maker.put(value);
+ break;
+ }
+ case GT:
+ {
+ match(GT);
+ string value;
+ value=datavalue();
+ maker.put(matchGreaterThan); maker.put(value);
+ break;
+ }
+ case LE:
+ {
+ match(LE);
+ string value;
+ value=datavalue();
+ maker.put(matchLessEqual); maker.put(value);
+ break;
+ }
+ case GE:
+ {
+ match(GE);
+ string value;
+ value=datavalue();
+ maker.put(matchGreaterEqual); maker.put(value);
+ break;
+ }
+ default:
+ {
+ throw antlr::NoViableAltException(LT(1), getFilename());
+ }
+ }
+ }
+ catch (antlr::RecognitionException& ex) {
+ reportError(ex);
+ recover(ex,_tokenSet_7);
+ }
+}
+
+string RequirementParser::datavalue() {
+ string result;
+ antlr::RefToken hex = antlr::nullToken;
+
+ try { // for error handling
+ switch ( LA(1)) {
+ case DOTKEY:
+ case STRING:
+ {
+ result=stringvalue();
+ break;
+ }
+ case HEXCONSTANT:
+ {
+ hex = LT(1);
+ match(HEXCONSTANT);
+ result = hexString(hex->getText());
+ break;
+ }
+ default:
+ {
+ throw antlr::NoViableAltException(LT(1), getFilename());
+ }
+ }
+ }
+ catch (antlr::RecognitionException& ex) {
+ reportError(ex);
+ recover(ex,_tokenSet_14);
+ }
+ return result;
+}
+
+string RequirementParser::stringvalue() {
+ string result;
+ antlr::RefToken dk = antlr::nullToken;
+ antlr::RefToken s = antlr::nullToken;
+
+ try { // for error handling
+ switch ( LA(1)) {
+ case DOTKEY:
+ {
+ dk = LT(1);
+ match(DOTKEY);
+ result = dk->getText();
+ break;
+ }
+ case STRING:
+ {
+ s = LT(1);
+ match(STRING);
+ result = s->getText();
+ break;
+ }
+ default:
+ {
+ throw antlr::NoViableAltException(LT(1), getFilename());
+ }
+ }
+ }
+ catch (antlr::RecognitionException& ex) {
+ reportError(ex);
+ recover(ex,_tokenSet_15);
+ }
+ return result;
+}
+
+string RequirementParser::pathstring() {
+ string result;
+ antlr::RefToken dk = antlr::nullToken;
+ antlr::RefToken s = antlr::nullToken;
+ antlr::RefToken pn = antlr::nullToken;
+
+ try { // for error handling
+ switch ( LA(1)) {
+ case DOTKEY:
+ {
+ dk = LT(1);
+ match(DOTKEY);
+ result = dk->getText();
+ break;
+ }
+ case STRING:
+ {
+ s = LT(1);
+ match(STRING);
+ result = s->getText();
+ break;
+ }
+ case PATHNAME:
+ {
+ pn = LT(1);
+ match(PATHNAME);
+ result = pn->getText();
+ break;
+ }
+ default:
+ {
+ throw antlr::NoViableAltException(LT(1), getFilename());
+ }
+ }
+ }
+ catch (antlr::RecognitionException& ex) {
+ reportError(ex);
+ recover(ex,_tokenSet_7);
+ }
+ return result;
+}
+
+void RequirementParser::initializeASTFactory( antlr::ASTFactory& )
+{
+}
+const char* RequirementParser::tokenNames[] = {
+ "<0>",
+ "EOF",
+ "<2>",
+ "NULL_TREE_LOOKAHEAD",
+ "ARROW",
+ "\"guest\"",
+ "\"host\"",
+ "\"designated\"",
+ "\"library\"",
+ "\"plugin\"",
+ "INTEGER",
+ "\"or\"",
+ "\"and\"",
+ "LPAREN",
+ "RPAREN",
+ "NOT",
+ "\"always\"",
+ "\"true\"",
+ "\"never\"",
+ "\"false\"",
+ "\"identifier\"",
+ "\"cdhash\"",
+ "\"anchor\"",
+ "\"apple\"",
+ "\"generic\"",
+ "\"certificate\"",
+ "\"cert\"",
+ "\"trusted\"",
+ "\"info\"",
+ "\"entitlement\"",
+ "\"exists\"",
+ "EQL",
+ "EQQL",
+ "STAR",
+ "SUBS",
+ "LESS",
+ "GT",
+ "LE",
+ "GE",
+ "LBRACK",
+ "RBRACK",
+ "NEG",
+ "\"leaf\"",
+ "\"root\"",
+ "HASHCONSTANT",
+ "HEXCONSTANT",
+ "DOTKEY",
+ "STRING",
+ "PATHNAME",
+ "SEMI",
+ "IDENT",
+ "HEX",
+ "COMMA",
+ "WS",
+ "SHELLCOMMENT",
+ "C_COMMENT",
+ "CPP_COMMENT",
+ 0
+};
+
+const unsigned long RequirementParser::_tokenSet_0_data_[] = { 2UL, 0UL, 0UL, 0UL };
+// EOF
+const antlr::BitSet RequirementParser::_tokenSet_0(_tokenSet_0_data_,4);
+const unsigned long RequirementParser::_tokenSet_1_data_[] = { 16UL, 0UL, 0UL, 0UL };
+// ARROW
+const antlr::BitSet RequirementParser::_tokenSet_1(_tokenSet_1_data_,4);
+const unsigned long RequirementParser::_tokenSet_2_data_[] = { 2018UL, 0UL, 0UL, 0UL };
+// EOF "guest" "host" "designated" "library" "plugin" INTEGER
+const antlr::BitSet RequirementParser::_tokenSet_2(_tokenSet_2_data_,4);
+const unsigned long RequirementParser::_tokenSet_3_data_[] = { 18402UL, 131072UL, 0UL, 0UL };
+// EOF "guest" "host" "designated" "library" "plugin" INTEGER RPAREN SEMI
+const antlr::BitSet RequirementParser::_tokenSet_3(_tokenSet_3_data_,4);
+const unsigned long RequirementParser::_tokenSet_4_data_[] = { 2018UL, 131072UL, 0UL, 0UL };
+// EOF "guest" "host" "designated" "library" "plugin" INTEGER SEMI
+const antlr::BitSet RequirementParser::_tokenSet_4(_tokenSet_4_data_,4);
+const unsigned long RequirementParser::_tokenSet_5_data_[] = { 20450UL, 131072UL, 0UL, 0UL };
+// EOF "guest" "host" "designated" "library" "plugin" INTEGER "or" RPAREN
+// SEMI
+const antlr::BitSet RequirementParser::_tokenSet_5(_tokenSet_5_data_,4);
+const unsigned long RequirementParser::_tokenSet_6_data_[] = { 914333696UL, 0UL, 0UL, 0UL };
+// LPAREN NOT "always" "true" "never" "false" "identifier" "cdhash" "anchor"
+// "certificate" "cert" "info" "entitlement"
+const antlr::BitSet RequirementParser::_tokenSet_6(_tokenSet_6_data_,4);
+const unsigned long RequirementParser::_tokenSet_7_data_[] = { 24546UL, 131072UL, 0UL, 0UL };
+// EOF "guest" "host" "designated" "library" "plugin" INTEGER "or" "and"
+// RPAREN SEMI
+const antlr::BitSet RequirementParser::_tokenSet_7(_tokenSet_7_data_,4);
+const unsigned long RequirementParser::_tokenSet_8_data_[] = { 1024UL, 3584UL, 0UL, 0UL };
+// INTEGER NEG "leaf" "root"
+const antlr::BitSet RequirementParser::_tokenSet_8(_tokenSet_8_data_,4);
+const unsigned long RequirementParser::_tokenSet_9_data_[] = { 2147483648UL, 118913UL, 0UL, 0UL };
+// EQL EQQL LBRACK HASHCONSTANT DOTKEY STRING PATHNAME
+const antlr::BitSet RequirementParser::_tokenSet_9(_tokenSet_9_data_,4);
+const unsigned long RequirementParser::_tokenSet_10_data_[] = { 0UL, 118784UL, 0UL, 0UL };
+// HASHCONSTANT DOTKEY STRING PATHNAME
+const antlr::BitSet RequirementParser::_tokenSet_10(_tokenSet_10_data_,4);
+const unsigned long RequirementParser::_tokenSet_11_data_[] = { 2281701376UL, 118913UL, 0UL, 0UL };
+// "trusted" EQL EQQL LBRACK HASHCONSTANT DOTKEY STRING PATHNAME
+const antlr::BitSet RequirementParser::_tokenSet_11(_tokenSet_11_data_,4);
+const unsigned long RequirementParser::_tokenSet_12_data_[] = { 1073766370UL, 249856UL, 0UL, 0UL };
+// EOF "guest" "host" "designated" "library" "plugin" INTEGER "or" "and"
+// RPAREN "exists" HASHCONSTANT DOTKEY STRING PATHNAME SEMI
+const antlr::BitSet RequirementParser::_tokenSet_12(_tokenSet_12_data_,4);
+const unsigned long RequirementParser::_tokenSet_13_data_[] = { 3221250018UL, 131197UL, 0UL, 0UL };
+// EOF "guest" "host" "designated" "library" "plugin" INTEGER "or" "and"
+// RPAREN "exists" EQL EQQL SUBS LESS GT LE GE SEMI
+const antlr::BitSet RequirementParser::_tokenSet_13(_tokenSet_13_data_,4);
+const unsigned long RequirementParser::_tokenSet_14_data_[] = { 24546UL, 131074UL, 0UL, 0UL };
+// EOF "guest" "host" "designated" "library" "plugin" INTEGER "or" "and"
+// RPAREN STAR SEMI
+const antlr::BitSet RequirementParser::_tokenSet_14(_tokenSet_14_data_,4);
+const unsigned long RequirementParser::_tokenSet_15_data_[] = { 24546UL, 131330UL, 0UL, 0UL };
+// EOF "guest" "host" "designated" "library" "plugin" INTEGER "or" "and"
+// RPAREN STAR RBRACK SEMI
+const antlr::BitSet RequirementParser::_tokenSet_15(_tokenSet_15_data_,4);
+
+
+ANTLR_END_NAMESPACE
--- /dev/null
+#ifndef INC_RequirementParser_hpp_
+#define INC_RequirementParser_hpp_
+
+#include <antlr/config.hpp>
+/* $ANTLR 2.7.7 (20120228): "requirements.grammar" -> "RequirementParser.hpp"$ */
+#include <antlr/TokenStream.hpp>
+#include <antlr/TokenBuffer.hpp>
+#include "RequirementParserTokenTypes.hpp"
+#include <antlr/LLkParser.hpp>
+
+
+#include "requirement.h"
+using namespace CodeSigning;
+typedef Requirement::Maker Maker;
+
+ANTLR_BEGIN_NAMESPACE(Security_CodeSigning)
+class CUSTOM_API RequirementParser : public antlr::LLkParser, public RequirementParserTokenTypes
+{
+
+public:
+ std::string errors;
+ void reportError(const antlr::RecognitionException &ex);
+ void reportError(const std::string &s);
+
+private:
+ static string hexString(const string &s);
+ static void hashString(const string &s, SHA1::Digest hash);
+ void certMatchOperation(Maker &maker, int32_t slot, string key);
+public:
+ void initializeASTFactory( antlr::ASTFactory& factory );
+protected:
+ RequirementParser(antlr::TokenBuffer& tokenBuf, int k);
+public:
+ RequirementParser(antlr::TokenBuffer& tokenBuf);
+protected:
+ RequirementParser(antlr::TokenStream& lexer, int k);
+public:
+ RequirementParser(antlr::TokenStream& lexer);
+ RequirementParser(const antlr::ParserSharedInputState& state);
+ int getNumTokens() const
+ {
+ return RequirementParser::NUM_TOKENS;
+ }
+ const char* getTokenName( int type ) const
+ {
+ if( type > getNumTokens() ) return 0;
+ return RequirementParser::tokenNames[type];
+ }
+ const char* const* getTokenNames() const
+ {
+ return RequirementParser::tokenNames;
+ }
+ public: BlobCore * autosense();
+ public: Requirement * requirement();
+ public: Requirements * requirementSet();
+ public: uint32_t requirementType();
+ public: Requirement * requirementElement();
+ public: void expr(
+ Maker &maker
+ );
+ public: void fluff();
+ public: void term(
+ Maker &maker
+ );
+ public: void primary(
+ Maker &maker
+ );
+ public: void certspec(
+ Maker &maker
+ );
+ public: void infospec(
+ Maker &maker
+ );
+ public: void entitlementspec(
+ Maker &maker
+ );
+ public: void eql();
+ public: string identifierString();
+ public: void hash(
+ SHA1::Digest digest
+ );
+ public: void appleanchor(
+ Maker &maker
+ );
+ public: int32_t certSlot();
+ public: void certslotspec(
+ Maker &maker, int32_t slot
+ );
+ public: void empty();
+ public: void certificateDigest(
+ SHA1::Digest digest
+ );
+ public: string bracketKey();
+ public: void match_suffix(
+ Maker &maker
+ );
+ public: string datavalue();
+ public: string stringvalue();
+ public: string pathstring();
+public:
+ antlr::RefAST getAST()
+ {
+ return returnAST;
+ }
+
+protected:
+ antlr::RefAST returnAST;
+private:
+ static const char* tokenNames[];
+#ifndef NO_STATIC_CONSTS
+ static const int NUM_TOKENS = 57;
+#else
+ enum {
+ NUM_TOKENS = 57
+ };
+#endif
+
+ static const unsigned long _tokenSet_0_data_[];
+ static const antlr::BitSet _tokenSet_0;
+ static const unsigned long _tokenSet_1_data_[];
+ static const antlr::BitSet _tokenSet_1;
+ static const unsigned long _tokenSet_2_data_[];
+ static const antlr::BitSet _tokenSet_2;
+ static const unsigned long _tokenSet_3_data_[];
+ static const antlr::BitSet _tokenSet_3;
+ static const unsigned long _tokenSet_4_data_[];
+ static const antlr::BitSet _tokenSet_4;
+ static const unsigned long _tokenSet_5_data_[];
+ static const antlr::BitSet _tokenSet_5;
+ static const unsigned long _tokenSet_6_data_[];
+ static const antlr::BitSet _tokenSet_6;
+ static const unsigned long _tokenSet_7_data_[];
+ static const antlr::BitSet _tokenSet_7;
+ static const unsigned long _tokenSet_8_data_[];
+ static const antlr::BitSet _tokenSet_8;
+ static const unsigned long _tokenSet_9_data_[];
+ static const antlr::BitSet _tokenSet_9;
+ static const unsigned long _tokenSet_10_data_[];
+ static const antlr::BitSet _tokenSet_10;
+ static const unsigned long _tokenSet_11_data_[];
+ static const antlr::BitSet _tokenSet_11;
+ static const unsigned long _tokenSet_12_data_[];
+ static const antlr::BitSet _tokenSet_12;
+ static const unsigned long _tokenSet_13_data_[];
+ static const antlr::BitSet _tokenSet_13;
+ static const unsigned long _tokenSet_14_data_[];
+ static const antlr::BitSet _tokenSet_14;
+ static const unsigned long _tokenSet_15_data_[];
+ static const antlr::BitSet _tokenSet_15;
+};
+
+ANTLR_END_NAMESPACE
+#endif /*INC_RequirementParser_hpp_*/
--- /dev/null
+#ifndef INC_RequirementParserTokenTypes_hpp_
+#define INC_RequirementParserTokenTypes_hpp_
+
+ANTLR_BEGIN_NAMESPACE(Security_CodeSigning)
+/* $ANTLR 2.7.7 (20120228): "requirements.grammar" -> "RequirementParserTokenTypes.hpp"$ */
+
+#ifndef CUSTOM_API
+# define CUSTOM_API
+#endif
+
+#ifdef __cplusplus
+struct CUSTOM_API RequirementParserTokenTypes {
+#endif
+ enum {
+ EOF_ = 1,
+ ARROW = 4,
+ LITERAL_guest = 5,
+ LITERAL_host = 6,
+ LITERAL_designated = 7,
+ LITERAL_library = 8,
+ LITERAL_plugin = 9,
+ INTEGER = 10,
+ LITERAL_or = 11,
+ LITERAL_and = 12,
+ LPAREN = 13,
+ RPAREN = 14,
+ NOT = 15,
+ LITERAL_always = 16,
+ LITERAL_true = 17,
+ LITERAL_never = 18,
+ LITERAL_false = 19,
+ LITERAL_identifier = 20,
+ LITERAL_cdhash = 21,
+ LITERAL_anchor = 22,
+ LITERAL_apple = 23,
+ LITERAL_generic = 24,
+ LITERAL_certificate = 25,
+ LITERAL_cert = 26,
+ LITERAL_trusted = 27,
+ LITERAL_info = 28,
+ LITERAL_entitlement = 29,
+ LITERAL_exists = 30,
+ EQL = 31,
+ EQQL = 32,
+ STAR = 33,
+ SUBS = 34,
+ LESS = 35,
+ GT = 36,
+ LE = 37,
+ GE = 38,
+ LBRACK = 39,
+ RBRACK = 40,
+ NEG = 41,
+ LITERAL_leaf = 42,
+ LITERAL_root = 43,
+ HASHCONSTANT = 44,
+ HEXCONSTANT = 45,
+ DOTKEY = 46,
+ STRING = 47,
+ PATHNAME = 48,
+ SEMI = 49,
+ IDENT = 50,
+ HEX = 51,
+ COMMA = 52,
+ WS = 53,
+ SHELLCOMMENT = 54,
+ C_COMMENT = 55,
+ CPP_COMMENT = 56,
+ NULL_TREE_LOOKAHEAD = 3
+ };
+#ifdef __cplusplus
+};
+#endif
+ANTLR_END_NAMESPACE
+#endif /*INC_RequirementParserTokenTypes_hpp_*/
--- /dev/null
+// $ANTLR 2.7.7 (20120228): requirements.grammar -> RequirementParserTokenTypes.txt$
+RequirementParser // output token vocab name
+ARROW=4
+LITERAL_guest="guest"=5
+LITERAL_host="host"=6
+LITERAL_designated="designated"=7
+LITERAL_library="library"=8
+LITERAL_plugin="plugin"=9
+INTEGER=10
+LITERAL_or="or"=11
+LITERAL_and="and"=12
+LPAREN=13
+RPAREN=14
+NOT=15
+LITERAL_always="always"=16
+LITERAL_true="true"=17
+LITERAL_never="never"=18
+LITERAL_false="false"=19
+LITERAL_identifier="identifier"=20
+LITERAL_cdhash="cdhash"=21
+LITERAL_anchor="anchor"=22
+LITERAL_apple="apple"=23
+LITERAL_generic="generic"=24
+LITERAL_certificate="certificate"=25
+LITERAL_cert="cert"=26
+LITERAL_trusted="trusted"=27
+LITERAL_info="info"=28
+LITERAL_entitlement="entitlement"=29
+LITERAL_exists="exists"=30
+EQL=31
+EQQL=32
+STAR=33
+SUBS=34
+LESS=35
+GT=36
+LE=37
+GE=38
+LBRACK=39
+RBRACK=40
+NEG=41
+LITERAL_leaf="leaf"=42
+LITERAL_root="root"=43
+HASHCONSTANT=44
+HEXCONSTANT=45
+DOTKEY=46
+STRING=47
+PATHNAME=48
+SEMI=49
+IDENT=50
+HEX=51
+COMMA=52
+WS=53
+SHELLCOMMENT=54
+C_COMMENT=55
+CPP_COMMENT=56
const CFStringRef kSecAssessmentAssessmentAuthorityOverride = CFSTR("assessment:authority:override");
const CFStringRef kSecAssessmentAssessmentFromCache = CFSTR("assessment:authority:cached");
+const CFStringRef kDisabledOverride = CFSTR("security disabled");
+
const CFStringRef kSecAssessmentContextKeyCertificates = CFSTR("context:certificates"); // obsolete
SecAssessmentRef SecAssessmentCreate(CFURLRef path,
CFErrorRef *errors)
{
BEGIN_CSAPI
- SYSPOLICY_ASSESS_API(cfString(path).c_str(), flags);
if (flags & kSecAssessmentFlagAsynchronous)
MacOSError::throwMe(errSecCSUnimplemented);
AuthorityType type = typeFor(context, kAuthorityExecute);
CFRef<CFMutableDictionaryRef> result = makeCFMutableDictionary();
+ SYSPOLICY_ASSESS_API(cfString(path).c_str(), int(type), flags);
+
try {
// check the object cache first unless caller denied that or we need extended processing
if (!(flags & (kSecAssessmentFlagRequestOrigin | kSecAssessmentFlagIgnoreCache))) {
authority = cfString(auth);
else
authority = "no authority";
- if (CFDictionaryGetValue(authdict, kSecAssessmentAssessmentAuthorityOverride))
- overridden = true;
+ if (CFTypeRef override = CFDictionaryGetValue(authdict, kSecAssessmentAssessmentAuthorityOverride))
+ if (CFEqual(override, kDisabledOverride))
+ overridden = true;
}
MessageTrace trace("com.apple.security.assessment.outcome", NULL);
CFDictionarySetValue(adulterated, kSecAssessmentAssessmentVerdict, kCFBooleanTrue);
if (CFDictionaryRef authority = CFDictionaryRef(CFDictionaryGetValue(adulterated, kSecAssessmentAssessmentAuthority))) {
CFRef<CFMutableDictionaryRef> authority2 = makeCFMutableDictionary(authority);
- CFDictionarySetValue(authority2, kSecAssessmentAssessmentAuthorityOverride, CFSTR("security disabled"));
+ CFDictionarySetValue(authority2, kSecAssessmentAssessmentAuthorityOverride, kDisabledOverride);
CFDictionarySetValue(adulterated, kSecAssessmentAssessmentAuthority, authority2);
} else {
- cfadd(adulterated, "{%O={%O='security disabled'}}",
- kSecAssessmentAssessmentAuthority, kSecAssessmentAssessmentAuthorityOverride);
+ cfadd(adulterated, "{%O={%O=%O}}",
+ kSecAssessmentAssessmentAuthority, kSecAssessmentAssessmentAuthorityOverride, kDisabledOverride);
}
result = adulterated.get();
}
const CFStringRef kSecAssessmentUpdateOperationRemove = CFSTR("update:remove");
const CFStringRef kSecAssessmentUpdateOperationEnable = CFSTR("update:enable");
const CFStringRef kSecAssessmentUpdateOperationDisable = CFSTR("update:disable");
+const CFStringRef kSecAssessmentUpdateOperationFind = CFSTR("update:find");
const CFStringRef kSecAssessmentUpdateKeyAuthorization = CFSTR("update:authorization");
const CFStringRef kSecAssessmentUpdateKeyPriority = CFSTR("update:priority");
const CFStringRef kSecAssessmentUpdateKeyAllow = CFSTR("update:allow");
const CFStringRef kSecAssessmentUpdateKeyRemarks = CFSTR("update:remarks");
+const CFStringRef kSecAssessmentUpdateKeyRow = CFSTR("update:row");
+const CFStringRef kSecAssessmentUpdateKeyCount = CFSTR("update:count");
+const CFStringRef kSecAssessmentUpdateKeyFound = CFSTR("update:found");
+
+const CFStringRef kSecAssessmentRuleKeyID = CFSTR("rule:id");
+const CFStringRef kSecAssessmentRuleKeyPriority = CFSTR("rule:priority");
+const CFStringRef kSecAssessmentRuleKeyAllow = CFSTR("rule:allow");
+const CFStringRef kSecAssessmentRuleKeyLabel = CFSTR("rule:label");
+const CFStringRef kSecAssessmentRuleKeyRemarks = CFSTR("rule:remarks");
+const CFStringRef kSecAssessmentRuleKeyRequirement = CFSTR("rule:requirement");
+const CFStringRef kSecAssessmentRuleKeyType = CFSTR("rule:type");
+const CFStringRef kSecAssessmentRuleKeyExpires = CFSTR("rule:expires");
+const CFStringRef kSecAssessmentRuleKeyDisabled = CFSTR("rule:disabled");
+const CFStringRef kSecAssessmentRuleKeyBookmark = CFSTR("rule:bookmark");
+
+
Boolean SecAssessmentUpdate(CFTypeRef target,
SecAssessmentFlags flags,
CFDictionaryRef context,
CFErrorRef *errors)
+{
+ if (CFDictionaryRef outcome = SecAssessmentCopyUpdate(target, flags, context, errors)) {
+ CFRelease(outcome);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+CFDictionaryRef SecAssessmentCopyUpdate(CFTypeRef target,
+ SecAssessmentFlags flags,
+ CFDictionaryRef context,
+ CFErrorRef *errors)
{
BEGIN_CSAPI
BEGIN_CSAPI
if (CFEqual(control, CFSTR("ui-enable"))) {
- { UnixPlusPlus::AutoFileDesc flagFile(visibleSecurityFlagFile, O_CREAT | O_WRONLY, 0644); }
- notify_post(kNotifySecAssessmentMasterSwitch);
+ setAssessment(true);
MessageTrace trace("com.apple.security.assessment.state", "enable");
trace.send("enable assessment outcomes");
return true;
} else if (CFEqual(control, CFSTR("ui-disable"))) {
- if (::remove(visibleSecurityFlagFile) == 0 || errno == ENOENT) {
- notify_post(kNotifySecAssessmentMasterSwitch);
- MessageTrace trace("com.apple.security.assessment.state", "disable");
- trace.send("disable assessment outcomes");
- return true;
- }
- UnixError::throwMe();
+ setAssessment(false);
+ MessageTrace trace("com.apple.security.assessment.state", "disable");
+ trace.send("disable assessment outcomes");
+ return true;
} else if (CFEqual(control, CFSTR("ui-status"))) {
CFBooleanRef &result = *(CFBooleanRef*)(arguments);
if (overrideAssessment())
return true;
} else if (CFEqual(control, CFSTR("ui-enable-devid"))) {
CFTemp<CFDictionaryRef> ctx("{%O=%s}", kSecAssessmentUpdateKeyLabel, "Developer ID");
- return gEngine().enable(NULL, kAuthorityInvalid, kSecCSDefaultFlags, ctx);
+ if (CFDictionaryRef result = gEngine().enable(NULL, kAuthorityInvalid, kSecCSDefaultFlags, ctx))
+ CFRelease(result);
+ return true;
} else if (CFEqual(control, CFSTR("ui-disable-devid"))) {
CFTemp<CFDictionaryRef> ctx("{%O=%s}", kSecAssessmentUpdateKeyLabel, "Developer ID");
- return gEngine().disable(NULL, kAuthorityInvalid, kSecCSDefaultFlags, ctx);
+ if (CFDictionaryRef result = gEngine().disable(NULL, kAuthorityInvalid, kSecCSDefaultFlags, ctx))
+ CFRelease(result);
+ return true;
} else if (CFEqual(control, CFSTR("ui-get-devid"))) {
CFBooleanRef &result = *(CFBooleanRef*)(arguments);
if (gEngine().value<int>("SELECT disabled FROM authority WHERE label = 'Developer ID';", true))
@constant kSecAssessmentContextKeyOperation Type of operation (see overview above). This defaults
to the kSecAssessmentOperationTypeExecute.
*/
-extern const CFStringRef kSecAssessmentContextKeyCertificates; // certificate chain as provided by caller
-
extern const CFStringRef kSecAssessmentAssessmentVerdict; // CFBooleanRef: master result - allow or deny
extern const CFStringRef kSecAssessmentAssessmentOriginator; // CFStringRef: describing the signature originator
extern const CFStringRef kSecAssessmentAssessmentAuthority; // CFDictionaryRef: authority used to arrive at result
extern const CFStringRef kSecAssessmentAssessmentAuthorityRow; // (internal)
extern const CFStringRef kSecAssessmentAssessmentAuthorityOverride; // (internal)
+extern const CFStringRef kDisabledOverride; // AuthorityOverride value for "Gatekeeper is disabled"
+
enum {
kSecAssessmentFlagRequestOrigin = 1 << 0, // request origin information (slower)
};
/*!
- @function SecAssessmentUpdate
+ @function SecAssessmentCopyUpdate
Make changes to the system policy configuration.
@param path CFTypeRef describing the subject of the operation. Depending on the operation,
on the requested assessment. Must at least contain the kSecAssessmentContextKeyEdit key.
@param errors Standard CFError argument for reporting errors. Note that declining to permit
the proposed operation is not an error. Inability to form a judgment is.
- @result Returns True on success. Returns False on failure (and sets *error).
+ @result Returns On success, a CFDictionary containing information pertaining to the completed operation.
+ Caller must CFRelease it when done. On failure, NULL, with *errors set if provided.
+
+ Note: The SecAssessmentUpdate variant does not return data. It returns True on success, or False on error.
Context keys and values:
@constant kSecAssessmentUpdateOperationRemove Remove rules from the rule database.
@constant kSecAssessmentUpdateOperationEnable (Re)enable rules in the rule database.
@constant kSecAssessmentUpdateOperationDisable Disable rules in the rule database.
+ @constant kSecAssessmentUpdateOperationFind Locate and return rules from the rule database.
+ This operation does not change the database, and does not require authorization or privileges.
+
@constant kSecAssessmentUpdateKeyAuthorization A CFData containing the external form of a
system AuthorizationRef used to authorize the change. The call will automatically generate
a suitable authorization if this is missing; however, if the request is on behalf of
assessment. The default is to allow; set to kCFBooleanFalse to create a negative (denial) rule.
@constant kSecAssessmentUpdateKeyRemarks CFString containing a colloquial description or comment
about a newly created rule. This is mean to be human readable and is not used when evaluating rules.
+
+ Keys returned as the result of a successful kSecAssessmentUpdateOperationFind operation:
+
+ @constant kSecAssessmentRuleKeyID A CFNumber uniquely identifying a rule.
+ @constant kSecAssessmentRuleKeyPriority A CFNumber indicating the rule's priority.
+ This is a floating point number. Higher values indicate higher priority.
+ @constant kSecAssessmentRuleKeyAllow A CFBoolean indicating whether the rule allows (true) or denies (false) the operation.
+ @constant kSecAssessmentRuleKeyLabel An optional CFString labeling the rule. Multiple rules may have the same label;
+ this can be used to group rules. Labels are not presented to the user. The label has no effect on evaluation.
+ @constant kSecAssessmentRuleKeyRemarks An optional CFString containing user-readable text characterizing the rule's meaning.
+ The remark has no effect on the evaluation.
+ @constant kSecAssessmentRuleKeyRequirement A CFString containing the (text form of) the code requirement governing the rule's match.
+ @constant kSecAssessmentRuleKeyType A CFString denoting the type of operation governed by the rule.
+ One of the kSecAssessmentOperationType* constants.
+ @constant kSecAssessmentRuleKeyExpires A CFDate indicating when the rule expires. Absent if the rule does not expire. Expired rules are never returned.
+ @constant kSecAssessmentRuleKeyDisabled A CFNumber; non zero if temporarily disabled. Optional.
+ @constant kSecAssessmentRuleKeyBookmark A CFData with the bookmark to the rule. Optional.
*/
extern const CFStringRef kSecAssessmentContextKeyUpdate; // proposed operation
extern const CFStringRef kSecAssessmentUpdateOperationAdd; // add rule to policy database
extern const CFStringRef kSecAssessmentUpdateOperationRemove; // remove rule from policy database
extern const CFStringRef kSecAssessmentUpdateOperationEnable; // enable rule(s) in policy database
extern const CFStringRef kSecAssessmentUpdateOperationDisable; // disable rule(s) in policy database
+extern const CFStringRef kSecAssessmentUpdateOperationFind; // extract rule(s) from the policy database
+extern const CFStringRef kSecAssessmentContextKeyCertificates; // obsolete
extern const CFStringRef kSecAssessmentUpdateKeyAuthorization; // [CFData] external form of governing authorization
extern const CFStringRef kSecAssessmentUpdateKeyPriority; // rule priority
extern const CFStringRef kSecAssessmentUpdateKeyAllow; // rule outcome (allow/deny)
extern const CFStringRef kSecAssessmentUpdateKeyRemarks; // rule remarks (human readable)
-extern const CFStringRef kSecAssessmentContextKeyCertificates; // obsolete
+extern const CFStringRef kSecAssessmentUpdateKeyRow; // rule identifier (CFNumber; add only)
+extern const CFStringRef kSecAssessmentUpdateKeyCount; // count of changed rules (CFNumber)
+extern const CFStringRef kSecAssessmentUpdateKeyFound; // set of found rules (CFArray of CFDictionaries)
+
+extern const CFStringRef kSecAssessmentRuleKeyID; // rule content returned: rule ID
+extern const CFStringRef kSecAssessmentRuleKeyPriority; // rule content returned: rule priority (floating point)
+extern const CFStringRef kSecAssessmentRuleKeyAllow; // rule content returned: rule allows (boolean)
+extern const CFStringRef kSecAssessmentRuleKeyLabel; // rule content returned: rule label (string; optional)
+extern const CFStringRef kSecAssessmentRuleKeyRemarks; // rule content returned: rule remarks (string; optional)
+extern const CFStringRef kSecAssessmentRuleKeyRequirement; // rule content returned: rule code requirement (string)
+extern const CFStringRef kSecAssessmentRuleKeyType; // rule content returned: rule type (string)
+extern const CFStringRef kSecAssessmentRuleKeyExpires; // rule content returned: rule expiration (CFDate; optional)
+extern const CFStringRef kSecAssessmentRuleKeyDisabled; // rule content returned: rule disabled (CFNumber; nonzero means temporarily disabled)
+extern const CFStringRef kSecAssessmentRuleKeyBookmark; // rule content returned: bookmark data (CFBookmark; optional)
+
+CFDictionaryRef SecAssessmentCopyUpdate(CFTypeRef target,
+ SecAssessmentFlags flags,
+ CFDictionaryRef context,
+ CFErrorRef *errors);
Boolean SecAssessmentUpdate(CFTypeRef target,
SecAssessmentFlags flags,
@param arguments Arguments to the operation as documented for control.
@param errors Standard CFErrorRef * argument to report errors.
@result Returns True on success. Returns False on failure (and sets *errors).
-
*/
Boolean SecAssessmentControl(CFStringRef control, void *arguments, CFErrorRef *errors);
const CFStringRef kSecCodeInfoCMS = CFSTR("cms");
const CFStringRef kSecCodeInfoDesignatedRequirement = CFSTR("designated-requirement");
const CFStringRef kSecCodeInfoEntitlements = CFSTR("entitlements");
+const CFStringRef kSecCodeInfoEntitlementsDict = CFSTR("entitlements-dict");
const CFStringRef kSecCodeInfoFormat = CFSTR("format");
const CFStringRef kSecCodeInfoDigestAlgorithm = CFSTR("digest-algorithm");
const CFStringRef kSecCodeInfoIdentifier = CFSTR("identifier");
const CFStringRef kSecCodeInfoSource = CFSTR("source");
const CFStringRef kSecCodeInfoStatus = CFSTR("status");
const CFStringRef kSecCodeInfoTime = CFSTR("signing-time");
+const CFStringRef kSecCodeInfoTimestamp = CFSTR("signing-timestamp");
const CFStringRef kSecCodeInfoTrust = CFSTR("trust");
const CFStringRef kSecCodeInfoUnique = CFSTR("unique");
if (flags & kSecCSDynamicInformation)
if (SecPointer<SecCode> dcode = SecStaticCode::optionalDynamic(codeRef))
- info = cfmake<CFDictionaryRef>("{+%O,%O=%u}", info.get(),
- kSecCodeInfoStatus, dcode->status());
+ info.take(cfmake<CFDictionaryRef>("{+%O,%O=%u}", info.get(), kSecCodeInfoStatus, dcode->status()));
CodeSigning::Required(infoRef) = info.yield();
actual Designated Requirement of the code.
@constant kSecCodeInfoEntitlements A CFData containing the embedded entitlement
blob of the code, if any.
+ @constant kSecCodeInfoEntitlementsDict A CFDictionary containing the embedded entitlements
+ of the code if it has entitlements and they are in standard dictionary form.
+ Absent if the code has no entitlements, or they are in a different format (in which
+ case, see kSecCodeInfoEntitlements).
@constant kSecCodeInfoFormat A CFString characterizing the type and format of
the code. Suitable for display to a (knowledeable) user.
@constant kSecCodeInfoDigestAlgorithm A CFNumber indicating the kind of cryptographic
it. Nobody certifies that this was really the date the code was signed; however,
you do know that this is the date the signer wanted you to see.
Ad-hoc signatures have no CMS and thus never have secured signing dates.
+ @constant kSecCodeInfoTimestamp A CFDate describing the signing date as (securely)
+ certified by a timestamp authority service. This time cannot be falsified by the
+ signer; you trust the timestamp authority's word on this.
+ Ad-hoc signatures have no CMS and thus never have secured signing dates.
@constant kSecCodeInfoTrust The (retained) SecTrust object the system uses to
evaluate the validity of the code's signature. You may use the SecTrust API
to extract detailed information, particularly for reasons why certificate
This is currently the SHA-1 hash of the code's CodeDirectory. However, future
versions of the system may use a different algorithm for newly signed code.
Already-signed code not change the reported value in this case.
+ @constant kSecCodeSignerFlags A CFNumber with the dynamic state of the object.
+ Contants are defined by the type SecCodeSignatureFlags.
*/
enum {
kSecCSInternalInformation = 1 << 0,
extern const CFStringRef kSecCodeInfoCMS; /* Signing */
extern const CFStringRef kSecCodeInfoDesignatedRequirement; /* Requirement */
extern const CFStringRef kSecCodeInfoEntitlements; /* Requirement */
+extern const CFStringRef kSecCodeInfoEntitlementsDict; /* Requirement */
extern const CFStringRef kSecCodeInfoFormat; /* generic */
extern const CFStringRef kSecCodeInfoDigestAlgorithm; /* generic */
extern const CFStringRef kSecCodeInfoIdentifier; /* generic */
extern const CFStringRef kSecCodeInfoSource; /* generic */
extern const CFStringRef kSecCodeInfoStatus; /* Dynamic */
extern const CFStringRef kSecCodeInfoTime; /* Signing */
+extern const CFStringRef kSecCodeInfoTimestamp; /* Signing */
extern const CFStringRef kSecCodeInfoTrust; /* Signing */
extern const CFStringRef kSecCodeInfoUnique; /* generic */
+extern const CFStringRef kSecCodeSignerFlags; /* dynamic */
OSStatus SecCodeCopySigningInformation(SecStaticCodeRef code, SecCSFlags flags,
CFDictionaryRef *information);
const CFStringRef kSecCodeSignerResourceRules = CFSTR("resource-rules");
const CFStringRef kSecCodeSignerSDKRoot = CFSTR("sdkroot");
const CFStringRef kSecCodeSignerSigningTime = CFSTR("signing-time");
+const CFStringRef kSecCodeSignerRequireTimestamp = CFSTR("timestamp-required");
+const CFStringRef kSecCodeSignerTimestampServer = CFSTR("timestamp-url");
+const CFStringRef kSecCodeSignerTimestampAuthentication = CFSTR("timestamp-authentication");
+const CFStringRef kSecCodeSignerTimestampOmitCertificates = CFSTR("timestamp-omit-certificates");
+
+// temporary add-back to bridge B&I build dependencies -- remove soon
+const CFStringRef kSecCodeSignerTSAUse = CFSTR("timestamp-required");
+const CFStringRef kSecCodeSignerTSAURL = CFSTR("timestamp-url");
+const CFStringRef kSecCodeSignerTSAClientAuth = CFSTR("timestamp-authentication");
+const CFStringRef kSecCodeSignerTSANoCerts = CFSTR("timestamp-omit-certificates");
//
If not specified, the current date is chosen and sealed.
Since an ad-hoc signature has no CMS data, this argument is ineffective
for ad-hoc signing operations.
+ @constant kSecCodeSignerRequireTimestamp A CFBoolean indicating (if kCFBooleanTrue) that
+ the code signature should be certified by a timestamp authority service. This option
+ requires access to a timestamp server (usually over the Internet). If requested and
+ the timestamp server cannot be contacted or refuses service, the signing operation fails.
+ The timestamp value is not under the caller's control.
+ If the value is kCFBooleanFalse, no timestamp service is contacted and the resulting signature
+ has no certified timestamp.
+ If this key is omitted, a default is used that may vary from release to release.
+ Note that when signing multi-architectural ("fat") programs, each architecture will
+ be signed separately, and thus each architecture will have a slightly different timestamp.
+ @constant kSecCodeSignerTimestampServer A CFURL specifying which timestamp authority service
+ to contact for timestamping if requested by the kSecCodeSignerRequireTimestamp argument.
+ If omitted (and timestamping is performed), a system-defined default value is used, referring
+ to an Apple-operated timestamp service. Note that this service may not freely serve all requests.
+ @constant kSecCodeSignerTimestampAuthentication A SecIdentityRef describing the identity
+ used to authenticate to the timestamp authority server, if the server requires client-side
+ (SSL/TLS) authentication. This will not generally be the identity used to sign the actual
+ code, depending on the requirements of the timestamp authority service used.
+ If omitted, the timestamp server is contacted using unauthenticated HTTP requests.
+ @constant kSecCodeSignerTimestampOmitCertificates A CFBoolean indicating (if kCFBooleanTrue)
+ that the timestamp embedded in the signature, if requested, not contain the full certificate chain
+ of the timestamp service used. This will make for a marginally smaller signature, but may not
+ verify correctly unless all such certificates are available (through the keychain system)
+ on the verifying system.
+ The default is to embed enough certificates to ensure proper verification of Apple-generated
+ timestamp signatures.
*/
extern const CFStringRef kSecCodeSignerApplicationData;
extern const CFStringRef kSecCodeSignerDetached;
extern const CFStringRef kSecCodeSignerResourceRules;
extern const CFStringRef kSecCodeSignerSDKRoot;
extern const CFStringRef kSecCodeSignerSigningTime;
+extern const CFStringRef kSecCodeSignerTimestampAuthentication;
+extern const CFStringRef kSecCodeSignerRequireTimestamp;
+extern const CFStringRef kSecCodeSignerTimestampServer;
+extern const CFStringRef kSecCodeSignerTimestampOmitCertificates;
+
+// temporary add-back to bridge B&I build dependencies -- remove soon
+extern const CFStringRef kSecCodeSignerTSAUse;
+extern const CFStringRef kSecCodeSignerTSAURL;
+extern const CFStringRef kSecCodeSignerTSAClientAuth;
+extern const CFStringRef kSecCodeSignerTSANoCerts;
/*!
//
CFStringRef kSecRequirementKeyInfoPlist = CFSTR("requirement:eval:info");
CFStringRef kSecRequirementKeyEntitlements = CFSTR("requirement:eval:entitlements");
+CFStringRef kSecRequirementKeyIdentifier = CFSTR("requirement:eval:identifier");
OSStatus SecRequirementEvaluate(SecRequirementRef requirementRef,
CFArrayRef certificateChain, CFDictionaryRef context,
Requirement::Context ctx(certificateChain, // mandatory
context ? CFDictionaryRef(CFDictionaryGetValue(context, kSecRequirementKeyInfoPlist)) : NULL,
context ? CFDictionaryRef(CFDictionaryGetValue(context, kSecRequirementKeyEntitlements)) : NULL,
+ (context && CFDictionaryGetValue(context, kSecRequirementKeyIdentifier)) ?
+ cfString(CFStringRef(CFDictionaryGetValue(context, kSecRequirementKeyIdentifier))) : "",
NULL // can't specify a CodeDirectory here
);
req->validate(ctx);
an Info.plist. If this key is missing, all references to Info.plist contents will fail.
@constant kSecRequirementKeyEntitlements A context key providing an CFDictionary describing
an entitlement dictionary. If this key is missing, all references to entitlements will fail.
+ @constant kSecRequirementKeyIdentifier A context key providing the signing identifier as a CFString.
*/
extern CFStringRef kSecRequirementKeyInfoPlist;
extern CFStringRef kSecRequirementKeyEntitlements;
+extern CFStringRef kSecRequirementKeyIdentifier;
OSStatus SecRequirementEvaluate(SecRequirementRef requirement,
CFArrayRef certificateChain, CFDictionaryRef context,
/*
- * Copyright (c) 2006-2010 Apple Inc. All Rights Reserved.
+ * Copyright (c) 2006-2012 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
#include "StaticCode.h"
#include "Code.h"
#include "reqmaker.h"
+#include "drmaker.h"
#include "reqdumper.h"
#include "sigblob.h"
#include "resources.h"
#include "detachedrep.h"
#include "csdatabase.h"
#include "csutilities.h"
+#include "SecCode.h"
#include <CoreFoundation/CFURLAccess.h>
#include <Security/SecPolicyPriv.h>
#include <Security/SecTrustPriv.h>
return mSigningTime;
}
+CFAbsoluteTime SecStaticCode::signingTimestamp()
+{
+ validateDirectory();
+ return mSigningTimestamp;
+}
+
//
// Verify the CMS signature on the CodeDirectory.
if (status != kCMSSignerValid)
MacOSError::throwMe(errSecCSSignatureFailed);
- // get signing date (we've got the decoder handle right here)
- mSigningTime = 0; // "not present" marker (nobody could code sign on Jan 1, 2001 :-)
- SecCmsMessageRef cmsg;
- MacOSError::check(CMSDecoderGetCmsMessage(cms, &cmsg));
- SecCmsSignedDataRef signedData = NULL;
- int numContentInfos = SecCmsMessageContentLevelCount(cmsg);
- for(int dex = 0; !signedData && dex < numContentInfos; dex++) {
- SecCmsContentInfoRef ci = SecCmsMessageContentLevel(cmsg, dex);
- SECOidTag tag = SecCmsContentInfoGetContentTypeTag(ci);
- switch(tag) {
- case SEC_OID_PKCS7_SIGNED_DATA:
- if (SecCmsSignedDataRef signedData = SecCmsSignedDataRef(SecCmsContentInfoGetContent(ci)))
- if (SecCmsSignerInfoRef signerInfo = SecCmsSignedDataGetSignerInfo(signedData, 0))
- SecCmsSignerInfoGetSigningTime(signerInfo, &mSigningTime);
- break;
- default:
- break;
- }
- }
+ // internal signing time (as specified by the signer; optional)
+ mSigningTime = 0; // "not present" marker (nobody could code sign on Jan 1, 2001 :-)
+ switch (OSStatus rc = CMSDecoderCopySignerSigningTime(cms, 0, &mSigningTime)) {
+ case noErr:
+ case errSecSigningTimeMissing:
+ break;
+ default:
+ MacOSError::throwMe(rc);
+ }
+ // certified signing time (as specified by a TSA; optional)
+ mSigningTimestamp = 0;
+ switch (OSStatus rc = CMSDecoderCopySignerTimestamp(cms, 0, &mSigningTimestamp)) {
+ case noErr:
+ case errSecTimestampMissing:
+ break;
+ default:
+ MacOSError::throwMe(rc);
+ }
+
// set up the environment for SecTrust
MacOSError::check(SecTrustSetAnchorCertificates(mTrust, cfEmptyArray())); // no anchors
+ MacOSError::check(SecTrustSetKeychains(mTrust, cfEmptyArray())); // no keychains
CSSM_APPLE_TP_ACTION_DATA actionData = {
CSSM_APPLE_TP_ACTION_VERSION, // version of data structure
CSSM_TP_ACTION_IMPLICIT_ANCHORS // action flags
CODESIGN_EVAL_STATIC_SIGNATURE_RESULT(this, trustResult, mCertChain ? CFArrayGetCount(mCertChain) : 0);
switch (trustResult) {
case kSecTrustResultProceed:
- case kSecTrustResultConfirm:
case kSecTrustResultUnspecified:
break; // success
case kSecTrustResultDeny:
case kSecTrustResultInvalid:
assert(false); // should never happen
MacOSError::throwMe(CSSMERR_TP_NOT_TRUSTED);
- case kSecTrustResultRecoverableTrustFailure:
- case kSecTrustResultFatalTrustFailure:
- case kSecTrustResultOtherError:
+ default:
{
OSStatus result;
MacOSError::check(SecTrustGetCssmResultCode(mTrust, &result));
- if (((result == CSSMERR_TP_CERT_EXPIRED) || (result == CSSMERR_TP_CERT_NOT_VALID_YET))
- && !(actionData.ActionFlags & CSSM_TP_ACTION_ALLOW_EXPIRED)) {
- CODESIGN_EVAL_STATIC_SIGNATURE_EXPIRED(this);
- actionData.ActionFlags |= CSSM_TP_ACTION_ALLOW_EXPIRED; // (this also allows postdated certs)
- continue; // retry validation
- }
+ // if we have a valid timestamp, CMS validates against (that) signing time and all is well.
+ // If we don't have one, may validate against *now*, and must be able to tolerate expiration.
+ if (mSigningTimestamp == 0) // no timestamp available
+ if (((result == CSSMERR_TP_CERT_EXPIRED) || (result == CSSMERR_TP_CERT_NOT_VALID_YET))
+ && !(actionData.ActionFlags & CSSM_TP_ACTION_ALLOW_EXPIRED)) {
+ CODESIGN_EVAL_STATIC_SIGNATURE_EXPIRED(this);
+ actionData.ActionFlags |= CSSM_TP_ACTION_ALLOW_EXPIRED; // (this also allows postdated certs)
+ continue; // retry validation while tolerating expiration
+ }
MacOSError::throwMe(result);
}
}
throw;
}
}
- assert(!validatedResources());
+ assert(validatedResources());
if (mResourcesValidResult)
MacOSError::throwMe(mResourcesValidResult);
if (mResourcesValidContext->osStatus() != noErr)
{
CollectingContext *ctx = static_cast<CollectingContext *>(context);
ResourceSeal seal(value);
- if (!seal.optional())
+ if (!seal.optional()) {
if (key && CFGetTypeID(key) == CFStringGetTypeID()) {
ctx->reportProblem(errSecCSBadResource, kSecCFErrorResourceMissing,
CFTempURL(CFStringRef(key), false, ctx->code.resourceBase()));
- } else
+ } else {
ctx->reportProblem(errSecCSBadResource, kSecCFErrorResourceSeal, key);
+ }
+ }
}
//
-// Return the Designated Requirement. This can be either explicit in the
-// Internal Requirements resource, or implicitly generated.
+// Return the Designated Requirement (DR). This can be either explicit in the
+// Internal Requirements component, or implicitly generated on demand here.
+// Note that an explicit DR may have been implicitly generated at signing time;
+// we don't distinguish this case.
//
const Requirement *SecStaticCode::designatedRequirement()
{
//
-// Generate the default (implicit) Designated Requirement for this StaticCode.
-// This is a heuristic of sorts, and may change over time (for the better, we hope).
-//
-// The current logic is this:
-// * If the code is ad-hoc signed, use the CodeDirectory hash directory.
-// * Otherwise, use the form anchor (anchor) and identifier (CodeDirectory identifier).
-// ** If the root CA is Apple's, we use the "anchor apple" construct. Otherwise,
-// we default to the leaf (directly signing) certificate.
+// Generate the default Designated Requirement (DR) for this StaticCode.
+// Ignore any explicit DR it may contain.
//
const Requirement *SecStaticCode::defaultDesignatedRequirement()
{
- validateDirectory(); // need the cert chain
- Requirement::Maker maker;
-
- // if this is an ad-hoc (unsigned) object, return a cdhash requirement
if (flag(kSecCodeSignatureAdhoc)) {
+ // adhoc signature: return a plain cdhash requirement
+ Requirement::Maker maker;
SHA1 hash;
hash(codeDirectory(), codeDirectory()->length());
SHA1::Digest digest;
hash.finish(digest);
maker.cdhash(digest);
+ return maker.make();
} else {
- // always require the identifier
- maker.put(opAnd);
- maker.ident(codeDirectory()->identifier());
-
- SHA1::Digest anchorHash;
- hashOfCertificate(cert(Requirement::anchorCert), anchorHash);
- if (!memcmp(anchorHash, Requirement::appleAnchorHash(), SHA1::digestLength)
-#if defined(TEST_APPLE_ANCHOR)
- || !memcmp(anchorHash, Requirement::testAppleAnchorHash(), SHA1::digestLength)
-#endif
- )
- defaultDesignatedAppleAnchor(maker);
- else
- defaultDesignatedNonAppleAnchor(maker);
+ // full signature: Gin up full context and let DRMaker do its thing
+ validateDirectory(); // need the cert chain
+ Requirement::Context context(this->certificates(),
+ this->infoDictionary(),
+ this->entitlements(),
+ this->identifier(),
+ this->codeDirectory()
+ );
+ return DRMaker(context).make();
}
-
- return maker();
-}
-
-static const uint8_t adcSdkMarker[] = { APPLE_EXTENSION_OID, 2, 1 }; // iOS intermediate marker
-static const CSSM_DATA adcSdkMarkerOID = { sizeof(adcSdkMarker), (uint8_t *)adcSdkMarker };
-
-static const uint8_t caspianSdkMarker[] = { APPLE_EXTENSION_OID, 2, 6 }; // Caspian intermediate marker
-static const CSSM_DATA caspianSdkMarkerOID = { sizeof(caspianSdkMarker), (uint8_t *)caspianSdkMarker };
-static const uint8_t caspianLeafMarker[] = { APPLE_EXTENSION_OID, 1, 13 }; // Caspian leaf certificate marker
-static const CSSM_DATA caspianLeafMarkerOID = { sizeof(caspianLeafMarker), (uint8_t *)caspianLeafMarker };
-
-void SecStaticCode::defaultDesignatedAppleAnchor(Requirement::Maker &maker)
-{
- if (isAppleSDKSignature()) {
- // get the Common Name DN element for the leaf
- CFRef<CFStringRef> leafCN;
- MacOSError::check(SecCertificateCopySubjectComponent(cert(Requirement::leafCert),
- &CSSMOID_CommonName, &leafCN.aref()));
-
- // apple anchor generic and ...
- maker.put(opAnd);
- maker.anchorGeneric(); // apple generic anchor and...
- // ... leaf[subject.CN] = <leaf's subject> and ...
- maker.put(opAnd);
- maker.put(opCertField); // certificate
- maker.put(0); // leaf
- maker.put("subject.CN"); // [subject.CN]
- maker.put(matchEqual); // =
- maker.putData(leafCN); // <leaf CN>
- // ... cert 1[field.<marker>] exists
- maker.put(opCertGeneric); // certificate
- maker.put(1); // 1
- maker.putData(adcSdkMarkerOID.Data, adcSdkMarkerOID.Length); // [field.<marker>]
- maker.put(matchExists); // exists
- return;
- }
-
- if (isAppleCaspianSignature()) {
- // get the Organizational Unit DN element for the leaf (it contains the TEAMID)
- CFRef<CFStringRef> teamID;
- MacOSError::check(SecCertificateCopySubjectComponent(cert(Requirement::leafCert),
- &CSSMOID_OrganizationalUnitName, &teamID.aref()));
-
- // apple anchor generic and ...
- maker.put(opAnd);
- maker.anchorGeneric(); // apple generic anchor and...
-
- // ... certificate 1[intermediate marker oid] exists and ...
- maker.put(opAnd);
- maker.put(opCertGeneric); // certificate
- maker.put(1); // 1
- maker.putData(caspianSdkMarker, sizeof(caspianSdkMarker));
- maker.put(matchExists); // exists
-
- // ... certificate leaf[Caspian cert oid] exists and ...
- maker.put(opAnd);
- maker.put(opCertGeneric); // certificate
- maker.put(0); // leaf
- maker.putData(caspianLeafMarker, sizeof(caspianLeafMarker));
- maker.put(matchExists); // exists
-
- // ... leaf[subject.OU] = <leaf's subject>
- maker.put(opCertField); // certificate
- maker.put(0); // leaf
- maker.put("subject.OU"); // [subject.OU]
- maker.put(matchEqual); // =
- maker.putData(teamID); // TEAMID
- return;
- }
-
- // otherwise, claim this program for Apple Proper
- maker.anchor();
-}
-
-bool SecStaticCode::isAppleSDKSignature()
-{
- if (CFArrayRef certChain = certificates()) // got cert chain
- if (CFArrayGetCount(certChain) == 3) // leaf, one intermediate, anchor
- if (SecCertificateRef intermediate = cert(1)) // get intermediate
- if (certificateHasField(intermediate, CssmOid::overlay(adcSdkMarkerOID)))
- return true;
- return false;
-}
-
-bool SecStaticCode::isAppleCaspianSignature()
-{
- if (CFArrayRef certChain = certificates()) // got cert chain
- if (CFArrayGetCount(certChain) == 3) // leaf, one intermediate, anchor
- if (SecCertificateRef intermediate = cert(1)) // get intermediate
- if (certificateHasField(intermediate, CssmOid::overlay(caspianSdkMarkerOID)))
- return true;
- return false;
-}
-
-void SecStaticCode::defaultDesignatedNonAppleAnchor(Requirement::Maker &maker)
-{
- // get the Organization DN element for the leaf
- CFRef<CFStringRef> leafOrganization;
- MacOSError::check(SecCertificateCopySubjectComponent(cert(Requirement::leafCert),
- &CSSMOID_OrganizationName, &leafOrganization.aref()));
-
- // now step up the cert chain looking for the first cert with a different one
- int slot = Requirement::leafCert; // start at leaf
- if (leafOrganization) {
- while (SecCertificateRef ca = cert(slot+1)) { // NULL if you over-run the anchor slot
- CFRef<CFStringRef> caOrganization;
- MacOSError::check(SecCertificateCopySubjectComponent(ca, &CSSMOID_OrganizationName, &caOrganization.aref()));
- if (!caOrganization || CFStringCompare(leafOrganization, caOrganization, 0) != kCFCompareEqualTo)
- break;
- slot++;
- }
- if (slot == CFArrayGetCount(mCertChain) - 1) // went all the way to the anchor...
- slot = Requirement::anchorCert; // ... so say that
- }
-
- // nail the last cert with the leaf's Organization value
- SHA1::Digest authorityHash;
- hashOfCertificate(cert(slot), authorityHash);
- maker.anchor(slot, authorityHash);
}
{
assert(req);
validateDirectory();
- return req->validates(Requirement::Context(mCertChain, infoDictionary(), entitlements(), codeDirectory()), failure);
+ return req->validates(Requirement::Context(mCertChain, infoDictionary(), entitlements(), codeDirectory()->identifier(), codeDirectory()), failure);
}
void SecStaticCode::validateRequirement(const Requirement *req, OSStatus failure)
CFDictionaryAddValue(dict, kSecCodeInfoIdentifier, CFTempString(this->identifier()));
CFDictionaryAddValue(dict, kSecCodeInfoFormat, CFTempString(this->format()));
CFDictionaryAddValue(dict, kSecCodeInfoSource, CFTempString(this->signatureSource()));
- if (CFDictionaryRef info = this->infoDictionary())
- CFDictionaryAddValue(dict, kSecCodeInfoPList, info);
CFDictionaryAddValue(dict, kSecCodeInfoUnique, this->cdHash());
CFDictionaryAddValue(dict, kSecCodeInfoDigestAlgorithm, CFTempNumber(this->codeDirectory(false)->hashType));
+ //
+ // Deliver any Info.plist only if it looks intact
+ //
+ try {
+ if (CFDictionaryRef info = this->infoDictionary())
+ CFDictionaryAddValue(dict, kSecCodeInfoPList, info);
+ } catch (...) { } // don't deliver Info.plist if questionable
+
//
// kSecCSSigningInformation adds information about signing certificates and chains
//
if (CFAbsoluteTime time = this->signingTime())
if (CFRef<CFDateRef> date = CFDateCreate(NULL, time))
CFDictionaryAddValue(dict, kSecCodeInfoTime, date);
+ if (CFAbsoluteTime time = this->signingTimestamp())
+ if (CFRef<CFDateRef> date = CFDateCreate(NULL, time))
+ CFDictionaryAddValue(dict, kSecCodeInfoTimestamp, date);
}
//
CFDictionaryAddValue(dict, kSecCodeInfoImplicitDesignatedRequirement, dreqRef);
}
- if (CFDataRef ent = this->component(cdEntitlementSlot))
+ if (CFDataRef ent = this->component(cdEntitlementSlot)) {
CFDictionaryAddValue(dict, kSecCodeInfoEntitlements, ent);
+ if (CFDictionaryRef entdict = this->entitlements())
+ CFDictionaryAddValue(dict, kSecCodeInfoEntitlementsDict, entdict);
+ }
}
//
/*
- * Copyright (c) 2006-2007 Apple Inc. All Rights Reserved.
+ * Copyright (c) 2006-2012 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
CFDataRef cdHash();
CFDataRef signature();
CFAbsoluteTime signingTime();
+ CFAbsoluteTime signingTimestamp();
bool isSigned() { return codeDirectory(false) != NULL; }
DiskRep *diskRep() { return mRep; }
std::string mainExecutablePath() { return mRep->mainExecutablePath(); }
bool validatedExecutable() const { return mExecutableValidated; }
bool validatedResources() const { return mResourcesValidated; }
-
void validateDirectory();
void validateComponent(CodeDirectory::SpecialSlot slot, OSStatus fail = errSecCSSignatureFailed);
void validateNonResourceComponents();
bool verifySignature();
CFTypeRef verificationPolicy(SecCSFlags flags);
- void defaultDesignatedAppleAnchor(Requirement::Maker &maker);
- void defaultDesignatedNonAppleAnchor(Requirement::Maker &maker);
- bool isAppleSDKSignature();
- bool isAppleCaspianSignature();
-
static void checkOptionalResource(CFTypeRef key, CFTypeRef value, void *context);
private:
CFRef<CFDataRef> mDir; // code directory data
CFRef<CFDataRef> mSignature; // CMS signature data
CFAbsoluteTime mSigningTime; // (signed) signing time
+ CFAbsoluteTime mSigningTimestamp; // Timestamp time (from timestamping authority)
CFRef<CFDataRef> mCache[cdSlotCount]; // NULL => not tried, kCFNull => absent, other => present
// alternative cache forms (storage may depend on cached contents above)
#include <CoreFoundation/CFBundlePriv.h>
#include <security_utilities/cfmunge.h>
#include <copyfile.h>
+#include <fts.h>
namespace Security {
using namespace UnixPlusPlus;
+//
+// Local helpers
+//
+static std::string findDistFile(const std::string &directory);
+
+
//
// We make a CFBundleRef immediately, but everything else is lazy
//
// common construction code
void BundleDiskRep::setup(const Context *ctx)
{
+ mInstallerPackage = false; // default
+
// deal with versioned bundles (aka Frameworks)
string version = resourcesRootPath()
+ "/Versions/"
if (ctx && ctx->version) // explicitly specified
MacOSError::throwMe(errSecCSStaticCodeNotFound);
}
-
- // conventional executable bundle: CFBundle identifies an executable for us
- if (mMainExecutableURL.take(CFBundleCopyExecutableURL(mBundle))) {
- // conventional executable bundle
- mExecRep = DiskRep::bestFileGuess(this->mainExecutablePath(), ctx);
- mFormat = string("bundle with ") + mExecRep->format();
- return;
- }
CFDictionaryRef infoDict = CFBundleGetInfoDictionary(mBundle);
assert(infoDict); // CFBundle will always make one up for us
+ CFTypeRef mainHTML = CFDictionaryGetValue(infoDict, CFSTR("MainHTML"));
+ CFTypeRef packageVersion = CFDictionaryGetValue(infoDict, CFSTR("IFMajorVersion"));
+
+ // conventional executable bundle: CFBundle identifies an executable for us
+ if (CFRef<CFURLRef> mainExec = CFBundleCopyExecutableURL(mBundle)) // if CFBundle claims an executable...
+ if (mainHTML == NULL) { // ... and it's not a widget
+ mMainExecutableURL = mainExec;
+ mExecRep = DiskRep::bestFileGuess(this->mainExecutablePath(), ctx);
+ mFormat = "bundle with " + mExecRep->format();
+ return;
+ }
- if (CFTypeRef main = CFDictionaryGetValue(infoDict, CFSTR("MainHTML"))) {
- // widget
- if (CFGetTypeID(main) != CFStringGetTypeID())
+ // widget
+ if (mainHTML) {
+ if (CFGetTypeID(mainHTML) != CFStringGetTypeID())
MacOSError::throwMe(errSecCSBadBundleFormat);
- mMainExecutableURL = makeCFURL(cfString(CFStringRef(main)), false, CFRef<CFURLRef>(CFBundleCopySupportFilesDirectoryURL(mBundle)));
+ mMainExecutableURL.take(makeCFURL(cfString(CFStringRef(mainHTML)), false,
+ CFRef<CFURLRef>(CFBundleCopySupportFilesDirectoryURL(mBundle))));
if (!mMainExecutableURL)
MacOSError::throwMe(errSecCSBadBundleFormat);
mExecRep = new FileDiskRep(this->mainExecutablePath().c_str());
return;
}
- // generic bundle case - impose our own "minimal signable bundle" standard
-
- // we MUST have an actual Info.plist in here
- CFRef<CFURLRef> infoURL = _CFBundleCopyInfoPlistURL(mBundle);
- if (!infoURL)
- MacOSError::throwMe(errSecCSBadBundleFormat);
-
+ // do we have a real Info.plist here?
+ if (CFRef<CFURLRef> infoURL = _CFBundleCopyInfoPlistURL(mBundle)) {
+ // focus on the Info.plist (which we know exists) as the nominal "main executable" file
+ if ((mMainExecutableURL = _CFBundleCopyInfoPlistURL(mBundle))) {
+ mExecRep = new FileDiskRep(this->mainExecutablePath().c_str());
+ if (packageVersion) {
+ mInstallerPackage = true;
+ mFormat = "installer package bundle";
+ } else {
+ mFormat = "bundle";
+ }
+ return;
+ }
+ }
- // focus on the Info.plist (which we know exists) as the nominal "main executable" file
- if ((mMainExecutableURL = _CFBundleCopyInfoPlistURL(mBundle))) {
+ // we're getting desperate here. Perhaps an oldish-style installer package? Look for a *.dist file
+ std::string distFile = findDistFile(this->resourcesRootPath());
+ if (!distFile.empty()) {
+ mMainExecutableURL = makeCFURL(distFile);
mExecRep = new FileDiskRep(this->mainExecutablePath().c_str());
- mFormat = "bundle";
+ mInstallerPackage = true;
+ mFormat = "installer package bundle";
return;
}
}
+//
+// Return the full path to the one-and-only file named something.dist in a directory.
+// Return empty string if none; throw an exception if multiple. Do not descend into subdirectories.
+//
+static std::string findDistFile(const std::string &directory)
+{
+ std::string found;
+ char *paths[] = {(char *)directory.c_str(), NULL};
+ FTS *fts = fts_open(paths, FTS_PHYSICAL | FTS_NOCHDIR | FTS_NOSTAT, NULL);
+ bool root = true;
+ while (FTSENT *ent = fts_read(fts)) {
+ switch (ent->fts_info) {
+ case FTS_F:
+ case FTS_NSOK:
+ if (!strcmp(ent->fts_path + ent->fts_pathlen - 5, ".dist")) { // found plain file foo.dist
+ if (found.empty()) // first found
+ found = ent->fts_path;
+ else // multiple *.dist files (bad)
+ MacOSError::throwMe(errSecCSBadBundleFormat);
+ }
+ break;
+ case FTS_D:
+ if (!root)
+ fts_set(fts, ent, FTS_SKIP); // don't descend
+ root = false;
+ break;
+ default:
+ break;
+ }
+ }
+ fts_close(fts);
+ return found;
+}
+
+
//
// Create a path to a bundle signing resource, by name.
// If the BUNDLEDISKREP_DIRECTORY directory exists in the bundle's support directory, files
string BundleDiskRep::metaPath(const char *name)
{
if (mMetaPath.empty()) {
- string support = cfString(CFBundleCopySupportFilesDirectoryURL(mBundle), true);
+ string support = cfStringRelease(CFBundleCopySupportFilesDirectoryURL(mBundle));
mMetaPath = support + "/" BUNDLEDISKREP_DIRECTORY;
if (::access(mMetaPath.c_str(), F_OK) == 0) {
mMetaExists = true;
string BundleDiskRep::resourcesRootPath()
{
- return cfString(CFBundleCopySupportFilesDirectoryURL(mBundle), true);
+ return cfStringRelease(CFBundleCopySupportFilesDirectoryURL(mBundle));
}
void BundleDiskRep::adjustResources(ResourceBuilder &builder)
string rbase = this->resourcesRootPath();
if (rbase.substr(rbase.length()-2, 2) == "/.") // produced by versioned bundle implicit "Current" case
rbase = rbase.substr(0, rbase.length()-2); // ... so take it off for this
- string resources = cfString(CFBundleCopyResourcesDirectoryURL(mBundle), true);
+ string resources = cfStringRelease(CFBundleCopyResourcesDirectoryURL(mBundle));
if (resources == rbase)
resources = "";
else if (resources.compare(0, rbase.length(), rbase, 0, rbase.length()) != 0) // Resources not in resource root
MacOSError::throwMe(errSecCSBadBundleFormat);
else
resources = resources.substr(rbase.length() + 1) + "/"; // differential path segment
+
+ // installer package rules
+ if (mInstallerPackage)
+ return cfmake<CFDictionaryRef>("{rules={"
+ "'^.*' = #T" // include everything, but...
+ "%s = {optional=#T, weight=1000}" // make localizations optional
+ "'^.*/.*\\.pkg/' = {omit=#T, weight=10000}" // and exclude all nested packages (by name)
+ "}}",
+ (string("^") + resources + ".*\\.lproj/").c_str()
+ );
+ // executable bundle rules
return cfmake<CFDictionaryRef>("{rules={"
- "'^version.plist$' = #T"
- "%s = #T"
- "%s = {optional=#T, weight=1000}"
- "%s = {omit=#T, weight=1100}"
+ "'^version.plist$' = #T" // include version.plist
+ "%s = #T" // include Resources
+ "%s = {optional=#T, weight=1000}" // make localizations optional
+ "%s = {omit=#T, weight=1100}" // exclude all locversion.plist files
"}}",
(string("^") + resources).c_str(),
(string("^") + resources + ".*\\.lproj/").c_str(),
CFRef<CFBundleRef> mBundle;
std::string mMetaPath; // path to directory containing signing files
bool mMetaExists; // separate meta-file directory exists
- CFRef<CFURLRef> mMainExecutableURL; // chosen main executable URL
+ CFRef<CFURLRef> mMainExecutableURL; // chosen main executable URL
+ bool mInstallerPackage; // is an installer (not executable) bundle
string mFormat; // format description string
RefPointer<DiskRep> mExecRep; // DiskRep for main executable file
};
if (fd.read(&sentinel, sizeof(sentinel), fd.fileSize() - sizeof(Sentinel)) == sizeof(Sentinel))
if (sentinel.magic == EmbeddedSignatureBlob::typeMagic) {
mSigningOffset = sentinel.offset;
- if (mSigningData = EmbeddedSignatureBlob::readBlob(fd, mSigningOffset))
+ if ((mSigningData = EmbeddedSignatureBlob::readBlob(fd, mSigningOffset)))
secdebug("cfmrep", "%zd signing bytes in %d blob(s) from %s(CFM)",
mSigningData->length(), mSigningData->count(),
mainExecutablePath().c_str());
// now check interior offsets for validity
if (!stringAt(identOffset))
MacOSError::throwMe(errSecCSSignatureFailed); // identifier out of blob range
- if (!contains(hashOffset - hashSize * nSpecialSlots, hashSize * (nSpecialSlots + nCodeSlots)))
+ if (!contains(hashOffset - uint64_t(hashSize) * nSpecialSlots, hashSize * (uint64_t(nSpecialSlots) + nCodeSlots)))
MacOSError::throwMe(errSecCSSignatureFailed); // hash array out of blob range
if (const Scatter *scatter = this->scatterVector()) {
// the optional scatter vector is terminated with an element having (count == 0)
// Check to see if a certificate contains a particular field, by OID. This works for extensions,
// even ones not recognized by the local CL. It does not return any value, only presence.
//
-bool certificateHasField(SecCertificateRef cert, const CssmOid &oid)
+bool certificateHasField(SecCertificateRef cert, const CSSM_OID &oid)
{
assert(cert);
CSSM_DATA *value;
// Retrieve X.509 policy extension OIDs, if any.
// This currently ignores policy qualifiers.
//
-bool certificateHasPolicy(SecCertificateRef cert, const CssmOid &policyOid)
+bool certificateHasPolicy(SecCertificateRef cert, const CSSM_OID &policyOid)
{
bool matched = false;
assert(cert);
// Check to see if a certificate contains a particular field, by OID. This works for extensions,
// even ones not recognized by the local CL. It does not return any value, only presence.
//
-bool certificateHasField(SecCertificateRef cert, const CssmOid &oid);
-bool certificateHasPolicy(SecCertificateRef cert, const CssmOid &policyOid);
+bool certificateHasField(SecCertificateRef cert, const CSSM_OID &oid);
+bool certificateHasPolicy(SecCertificateRef cert, const CSSM_OID &policyOid);
//
{
const BlobCore *sigBlob = reinterpret_cast<const BlobCore *>(CFDataGetBytePtr(sig));
if (sigBlob->is<EmbeddedSignatureBlob>()) { // architecture-less
- if (mArch = EmbeddedSignatureBlob::specific(sigBlob)) {
+ if ((mArch = EmbeddedSignatureBlob::specific(sigBlob))) {
mGlobal = NULL;
CODESIGN_DISKREP_CREATE_DETACHED(this, orig, (char*)source.c_str(), NULL);
return;
if (const DetachedSignatureBlob *dsblob = DetachedSignatureBlob::specific(sigBlob))
if (Universal *fat = orig->mainExecutableImage())
if (const BlobCore *blob = dsblob->find(fat->bestNativeArch().cpuType()))
- if (mArch = EmbeddedSignatureBlob::specific(blob))
- if (mGlobal = EmbeddedSignatureBlob::specific(dsblob->find(0))) {
+ if ((mArch = EmbeddedSignatureBlob::specific(blob)))
+ if ((mGlobal = EmbeddedSignatureBlob::specific(dsblob->find(0)))) {
CODESIGN_DISKREP_CREATE_DETACHED(this, orig, (char*)source.c_str(), (void*)mGlobal);
return;
}
std::string mainExecutablePath() { return mOriginal->mainExecutablePath(); }
CFURLRef canonicalPath() { return mOriginal->canonicalPath(); }
std::string resourcesRootPath() { return mOriginal->resourcesRootPath(); }
+ void adjustResources(ResourceBuilder &builder) { return mOriginal->adjustResources(builder); }
Universal *mainExecutableImage() { return mOriginal->mainExecutableImage(); }
size_t signingBase() { return mOriginal->signingBase(); }
size_t signingLimit() { return mOriginal->signingLimit(); }
std::string format() { return mOriginal->format(); }
+ CFArrayRef modifiedFiles() { return mOriginal->modifiedFiles(); }
UnixPlusPlus::FileDesc &fd() { return mOriginal->fd(); }
void flush() { return mOriginal->flush(); }
--- /dev/null
+/*
+ * Copyright (c) 2012 Apple Inc. All Rights Reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+//
+// drmaker - create automatic Designated Requirements
+//
+#include "drmaker.h"
+#include "csutilities.h"
+#include <Security/oidsbase.h>
+#include <Security/SecCertificatePriv.h>
+//#include <Security/cssmapplePriv.h>
+
+namespace Security {
+namespace CodeSigning {
+
+
+static const uint8_t adcSdkMarker[] = { APPLE_EXTENSION_OID, 2, 1 }; // iOS intermediate marker
+const CSSM_DATA adcSdkMarkerOID = { sizeof(adcSdkMarker), (uint8_t *)adcSdkMarker };
+
+static const uint8_t caspianSdkMarker[] = { APPLE_EXTENSION_OID, 2, 6 }; // Caspian intermediate marker
+const CSSM_DATA devIdSdkMarkerOID = { sizeof(caspianSdkMarker), (uint8_t *)caspianSdkMarker };
+static const uint8_t caspianLeafMarker[] = { APPLE_EXTENSION_OID, 1, 13 }; // Caspian leaf certificate marker
+const CSSM_DATA devIdLeafMarkerOID = { sizeof(caspianLeafMarker), (uint8_t *)caspianLeafMarker };
+
+
+
+DRMaker::DRMaker(const Requirement::Context &context)
+ : ctx(context)
+{
+}
+
+DRMaker::~DRMaker()
+{
+}
+
+
+//
+// Generate the default (implicit) Designated Requirement for this StaticCode.
+// This is a heuristic of sorts, and may change over time (for the better, we hope).
+//
+Requirement *DRMaker::make()
+{
+ // we can't make an explicit DR for a (proposed) ad-hoc signing because that requires the CodeDirectory (which we ain't got yet)
+ if (ctx.certCount() == 0)
+ return NULL;
+
+ // always require the identifier
+ this->put(opAnd);
+ this->ident(ctx.identifier);
+
+ SHA1::Digest anchorHash;
+ hashOfCertificate(ctx.cert(Requirement::anchorCert), anchorHash);
+ if (!memcmp(anchorHash, Requirement::appleAnchorHash(), SHA1::digestLength)
+#if defined(TEST_APPLE_ANCHOR)
+ || !memcmp(anchorHash, Requirement::testAppleAnchorHash(), SHA1::digestLength)
+#endif
+ )
+ appleAnchor();
+ else
+ nonAppleAnchor();
+
+ return Maker::make();
+}
+
+
+void DRMaker::nonAppleAnchor()
+{
+ // get the Organization DN element for the leaf
+ CFRef<CFStringRef> leafOrganization;
+ MacOSError::check(SecCertificateCopySubjectComponent(ctx.cert(Requirement::leafCert),
+ &CSSMOID_OrganizationName, &leafOrganization.aref()));
+
+ // now step up the cert chain looking for the first cert with a different one
+ int slot = Requirement::leafCert; // start at leaf
+ if (leafOrganization) {
+ while (SecCertificateRef ca = ctx.cert(slot+1)) { // NULL if you over-run the anchor slot
+ CFRef<CFStringRef> caOrganization;
+ MacOSError::check(SecCertificateCopySubjectComponent(ca, &CSSMOID_OrganizationName, &caOrganization.aref()));
+ if (!caOrganization || CFStringCompare(leafOrganization, caOrganization, 0) != kCFCompareEqualTo)
+ break;
+ slot++;
+ }
+ if (slot == ctx.certCount() - 1) // went all the way to the anchor...
+ slot = Requirement::anchorCert; // ... so say that
+ }
+
+ // nail the last cert with the leaf's Organization value
+ SHA1::Digest authorityHash;
+ hashOfCertificate(ctx.cert(slot), authorityHash);
+ this->anchor(slot, authorityHash);
+}
+
+
+void DRMaker::appleAnchor()
+{
+ if (isIOSSignature()) {
+ // get the Common Name DN element for the leaf
+ CFRef<CFStringRef> leafCN;
+ MacOSError::check(SecCertificateCopySubjectComponent(ctx.cert(Requirement::leafCert),
+ &CSSMOID_CommonName, &leafCN.aref()));
+
+ // apple anchor generic and ...
+ this->put(opAnd);
+ this->anchorGeneric(); // apple generic anchor and...
+ // ... leaf[subject.CN] = <leaf's subject> and ...
+ this->put(opAnd);
+ this->put(opCertField); // certificate
+ this->put(0); // leaf
+ this->put("subject.CN"); // [subject.CN]
+ this->put(matchEqual); // =
+ this->putData(leafCN); // <leaf CN>
+ // ... cert 1[field.<marker>] exists
+ this->put(opCertGeneric); // certificate
+ this->put(1); // 1
+ this->putData(adcSdkMarkerOID.Data, adcSdkMarkerOID.Length); // [field.<marker>]
+ this->put(matchExists); // exists
+ return;
+ }
+
+ if (isDeveloperIDSignature()) {
+ // get the Organizational Unit DN element for the leaf (it contains the TEAMID)
+ CFRef<CFStringRef> teamID;
+ MacOSError::check(SecCertificateCopySubjectComponent(ctx.cert(Requirement::leafCert),
+ &CSSMOID_OrganizationalUnitName, &teamID.aref()));
+
+ // apple anchor generic and ...
+ this->put(opAnd);
+ this->anchorGeneric(); // apple generic anchor and...
+
+ // ... certificate 1[intermediate marker oid] exists and ...
+ this->put(opAnd);
+ this->put(opCertGeneric); // certificate
+ this->put(1); // 1
+ this->putData(caspianSdkMarker, sizeof(caspianSdkMarker));
+ this->put(matchExists); // exists
+
+ // ... certificate leaf[Caspian cert oid] exists and ...
+ this->put(opAnd);
+ this->put(opCertGeneric); // certificate
+ this->put(0); // leaf
+ this->putData(caspianLeafMarker, sizeof(caspianLeafMarker));
+ this->put(matchExists); // exists
+
+ // ... leaf[subject.OU] = <leaf's subject>
+ this->put(opCertField); // certificate
+ this->put(0); // leaf
+ this->put("subject.OU"); // [subject.OU]
+ this->put(matchEqual); // =
+ this->putData(teamID); // TEAMID
+ return;
+ }
+
+ // otherwise, claim this program for Apple Proper
+ this->anchor();
+}
+
+bool DRMaker::isIOSSignature()
+{
+ if (ctx.certCount() == 3) // leaf, one intermediate, anchor
+ if (SecCertificateRef intermediate = ctx.cert(1)) // get intermediate
+ if (certificateHasField(intermediate, CssmOid::overlay(adcSdkMarkerOID)))
+ return true;
+ return false;
+}
+
+bool DRMaker::isDeveloperIDSignature()
+{
+ if (ctx.certCount() == 3) // leaf, one intermediate, anchor
+ if (SecCertificateRef intermediate = ctx.cert(1)) // get intermediate
+ if (certificateHasField(intermediate, CssmOid::overlay(devIdSdkMarkerOID)))
+ return true;
+ return false;
+}
+
+
+} // end namespace CodeSigning
+} // end namespace Security
--- /dev/null
+/*
+ * Copyright (c) 2012 Apple Inc. All Rights Reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+//
+// drmaker - create Designated Requirements
+//
+#ifndef _H_DRMAKER
+#define _H_DRMAKER
+
+#include "reqmaker.h"
+
+namespace Security {
+namespace CodeSigning {
+
+
+//
+// Some useful certificate OID markers
+//
+extern const CSSM_DATA adcSdkMarkerOID;
+extern const CSSM_DATA devIdSdkMarkerOID;
+extern const CSSM_DATA devIdLeafMarkerOID;
+
+
+
+//
+// A Maker of Designated Requirements
+//
+class DRMaker : public Requirement::Maker {
+public:
+ DRMaker(const Requirement::Context &context);
+ virtual ~DRMaker();
+
+ const Requirement::Context &ctx;
+
+public:
+ Requirement *make();
+
+private:
+ void appleAnchor();
+ void nonAppleAnchor();
+ bool isIOSSignature();
+ bool isDeveloperIDSignature();
+};
+
+
+} // end namespace CodeSigning
+} // end namespace Security
+
+#endif // !_H_DRMAKER
if (const linkedit_data_command *cs = macho->findCodeSignature()) {
size_t offset = macho->flip(cs->dataoff);
size_t length = macho->flip(cs->datasize);
- if (mSigningData = EmbeddedSignatureBlob::readBlob(macho->fd(), macho->offset() + offset, length)) {
+ if ((mSigningData = EmbeddedSignatureBlob::readBlob(macho->fd(), macho->offset() + offset, length))) {
secdebug("machorep", "%zd signing bytes in %d blob(s) from %s(%s)",
mSigningData->length(), mSigningData->count(),
mainExecutablePath().c_str(), macho->architecture().name());
string MachORep::recommendedIdentifier(const SigningContext &ctx)
{
if (CFDataRef info = infoPlist()) {
- if (CFDictionaryRef dict = makeCFDictionaryFrom(info)) {
+ if (CFRef<CFDictionaryRef> dict = makeCFDictionaryFrom(info)) {
CFStringRef code = CFStringRef(CFDictionaryGetValue(dict, kCFBundleIdentifierKey));
if (code && CFGetTypeID(code) != CFStringGetTypeID())
MacOSError::throwMe(errSecCSBadDictionaryFormat);
//
// The default suggested requirements for Mach-O binaries are as follows:
-// Hosting requirement: Rosetta if it's PPC, none otherwise.
// Library requirement: Composed from dynamic load commands.
//
-static const uint8_t ppc_host_ireq[] = { // anchor apple and identifier com.apple.translate
- 0xfa, 0xde, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06,
- 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x63, 0x6f, 0x6d, 0x2e,
- 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x6c, 0x61, 0x74, 0x65, 0x00,
-};
-
const Requirements *MachORep::defaultRequirements(const Architecture *arch, const SigningContext &ctx)
{
assert(arch); // enforced by signing infrastructure
Requirements::Maker maker;
-
- // if ppc architecture, add hosting requirement for Rosetta's translate tool
- if (arch->cpuType() == CPU_TYPE_POWERPC)
- maker.add(kSecHostRequirementType, ((const Requirement *)ppc_host_ireq)->clone());
// add library requirements from DYLIB commands (if any)
if (Requirement *libreq = libraryRequirements(arch, ctx))
auto_ptr<MachO> macho(mainExecutableImage()->architecture(*arch));
Requirement::Maker maker;
Requirement::Maker::Chain chain(maker, opOr);
- if (macho.get()) {
- for (const load_command *command = macho->loadCommands(); command; command = macho->nextCommand(command)) {
- if (macho->flip(command->cmd) == LC_LOAD_DYLIB) {
- const dylib_command *dycmd = (const dylib_command *)command;
- if (const char *name = macho->string(command, dycmd->dylib.name))
- try {
- string path = ctx.sdkPath(name);
- secdebug("machorep", "examining DYLIB %s", path.c_str());
- // find path on disk, get designated requirement (if signed)
- if (RefPointer<DiskRep> rep = DiskRep::bestGuess(path))
- if (SecPointer<SecStaticCode> code = new SecStaticCode(rep))
- if (const Requirement *req = code->designatedRequirement()) {
- CODESIGN_SIGN_DEP_MACHO(this, (char*)path.c_str(), (void*)req);
- chain.add();
- chain.maker.copy(req);
- }
- } catch (...) {
- CODESIGN_SIGN_DEP_MACHO(this, (char*)name, NULL);
- secdebug("machorep", "exception getting library requirement (ignored)");
+
+ if (macho.get())
+ if (const linkedit_data_command *ldep = macho->findLibraryDependencies()) {
+ size_t offset = macho->flip(ldep->dataoff);
+ size_t length = macho->flip(ldep->datasize);
+ if (LibraryDependencyBlob *deplist = LibraryDependencyBlob::readBlob(macho->fd(), macho->offset() + offset, length)) {
+ try {
+ secdebug("machorep", "%zd library dependency bytes in %d blob(s) from %s(%s)",
+ deplist->length(), deplist->count(),
+ mainExecutablePath().c_str(), macho->architecture().name());
+ unsigned count = deplist->count();
+ // we could walk through DYLIB load commands in parallel. We just don't need anything from them so far
+ for (unsigned n = 0; n < count; n++) {
+ const Requirement *req = NULL;
+ if (const BlobCore *dep = deplist->blob(n)) {
+ if ((req = Requirement::specific(dep))) {
+ // binary code requirement; good to go
+ } else if (const BlobWrapper *wrap = BlobWrapper::specific(dep)) {
+ // blob-wrapped text form - convert to binary requirement
+ std::string reqString = std::string((const char *)wrap->data(), wrap->length());
+ CFRef<SecRequirementRef> areq;
+ MacOSError::check(SecRequirementCreateWithString(CFTempString(reqString), kSecCSDefaultFlags, &areq.aref()));
+ CFRef<CFDataRef> reqData;
+ MacOSError::check(SecRequirementCopyData(areq, kSecCSDefaultFlags, &reqData.aref()));
+ req = Requirement::specific((const BlobCore *)CFDataGetBytePtr(reqData));
+ } else {
+ secdebug("machorep", "unexpected blob type 0x%x in slot %d of binary dependencies", dep->magic(), n);
+ continue;
+ }
+ chain.add();
+ maker.copy(req);
+ } else
+ secdebug("machorep", "missing DR info for library index %d", n);
}
- else
- CODESIGN_SIGN_DEP_MACHO(this, NULL, NULL);
+ ::free(deplist);
+ } catch (...) {
+ ::free(deplist);
+ throw;
+ }
}
}
- }
if (chain.empty())
return NULL;
else
/*
- * Copyright (c) 2011 Apple Inc. All Rights Reserved.
+ * Copyright (c) 2011-2012 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
#include <Security/CodeSigning.h>
#include <security_utilities/cfutilities.h>
#include <security_utilities/cfmunge.h>
+#include <security_utilities/blob.h>
+#include <security_utilities/logging.h>
+#include <security_utilities/simpleprefs.h>
+#include <security_utilities/logging.h>
+#include "csdatabase.h"
+
+#include <dispatch/dispatch.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <notify.h>
namespace Security {
namespace CodeSigning {
using namespace SQLite;
-//
-// The one and only PolicyDatabase object.
-// It auto-adapts to readonly vs. writable use.
-//
-ModuleNexus<PolicyDatabase> PolicyDatabase;
-
-
//
// Determine the database path
//
return mapEnum(context, kSecAssessmentContextKeyOperation, mapType, type);
}
+CFStringRef typeNameFor(AuthorityType type)
+{
+ for (const StringMap *mp = mapType; mp->cstring; ++mp)
+ if (type == mp->enumeration)
+ return mp->cstring;
+ return CFStringCreateWithFormat(NULL, NULL, CFSTR("type %d"), type);
+}
+
//
-// Open the database (creating it if necessary and possible).
-// Note that this isn't creating the schema; we do that on first write.
+// Open the database
//
PolicyDatabase::PolicyDatabase(const char *path, int flags)
- : SQLite::Database(path ? path : dbPath(), flags)
+ : SQLite::Database(path ? path : dbPath(), flags),
+ mLastExplicitCheck(0)
{
+ // sqlite3 doesn't do foreign key support by default, have to turn this on per connection
+ SQLite::Statement foreign(*this, "PRAGMA foreign_keys = true");
+ foreign.execute();
+
+ // Try upgrade processing if we may be open for write.
+ // Ignore any errors (we may have been downgraded to read-only)
+ // and try again later.
+ if (openFlags() & SQLITE_OPEN_READWRITE)
+ try {
+ upgradeDatabase();
+ installExplicitSet(gkeAuthFile, gkeSigsFile);
+ } catch(...) {
+ }
}
PolicyDatabase::~PolicyDatabase()
cleaner.execute();
}
+
+//
+// Database migration
+//
+std::string PolicyDatabase::featureLevel(const char *name)
+{
+ SQLite::Statement feature(*this, "SELECT value FROM feature WHERE name=:name");
+ feature.bind(":name") = name;
+ if (feature.nextRow())
+ return feature[0].string();
+ else
+ return ""; // new feature (no level)
+}
+
+void PolicyDatabase::addFeature(const char *name, const char *value, const char *remarks)
+{
+ SQLite::Statement feature(*this, "INSERT OR REPLACE INTO feature (name,value,remarks) VALUES(:name, :value, :remarks)");
+ feature.bind(":name") = name;
+ feature.bind(":value") = value;
+ feature.bind(":remarks") = remarks;
+ feature.execute();
+}
+
+void PolicyDatabase::simpleFeature(const char *feature, void (^perform)())
+{
+ if (!hasFeature(feature)) {
+ SQLite::Transaction update(*this);
+ addFeature(feature, "upgraded", "upgraded");
+ perform();
+ update.commit();
+ }
+}
+
+void PolicyDatabase::simpleFeature(const char *feature, const char *sql)
+{
+ if (!hasFeature(feature)) {
+ SQLite::Transaction update(*this);
+ addFeature(feature, "upgraded", "upgraded");
+ SQLite::Statement perform(*this, sql);
+ perform.execute();
+ update.commit();
+ }
+}
+
+
+void PolicyDatabase::upgradeDatabase()
+{
+ simpleFeature("bookmarkhints",
+ "CREATE TABLE bookmarkhints ("
+ " id INTEGER PRIMARY KEY AUTOINCREMENT, "
+ " bookmark BLOB,"
+ " authority INTEGER NOT NULL"
+ " REFERENCES authority(id) ON DELETE CASCADE"
+ ")");
+
+ if (!hasFeature("codesignedpackages")) {
+ SQLite::Transaction update(*this);
+ addFeature("codesignedpackages", "upgraded", "upgraded");
+ SQLite::Statement updates(*this,
+ "UPDATE authority"
+ " SET requirement = 'anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] exists and "
+ "(certificate leaf[field.1.2.840.113635.100.6.1.14] or certificate leaf[field.1.2.840.113635.100.6.1.13])'"
+ " WHERE type = 2 and label = 'Developer ID' and flags & :flag");
+ updates.bind(":flag") = kAuthorityFlagDefault;
+ updates.execute();
+ update.commit();
+ }
+}
+
+
+//
+// Install Gatekeeper override (GKE) data.
+// The arguments are paths to the authority and signature files.
+//
+void PolicyDatabase::installExplicitSet(const char *authfile, const char *sigfile)
+{
+ // only try this every gkeCheckInterval seconds
+ time_t now = time(NULL);
+ if (mLastExplicitCheck + gkeCheckInterval > now)
+ return;
+ mLastExplicitCheck = now;
+
+ try {
+ if (CFRef<CFDataRef> authData = cfLoadFile(authfile)) {
+ CFDictionary auth(CFRef<CFDictionaryRef>(makeCFDictionaryFrom(authData)), errSecCSDbCorrupt);
+ CFDictionaryRef content = auth.get<CFDictionaryRef>(CFSTR("authority"));
+ std::string authUUID = cfString(auth.get<CFStringRef>(CFSTR("uuid")));
+ if (authUUID.empty()) {
+ secdebug("gkupgrade", "no uuid in auth file; ignoring gke.auth");
+ return;
+ }
+ std::string dbUUID;
+ SQLite::Statement uuidQuery(*this, "SELECT value FROM feature WHERE name='gke'");
+ if (uuidQuery.nextRow())
+ dbUUID = (const char *)uuidQuery[0];
+ if (dbUUID == authUUID) {
+ secdebug("gkupgrade", "gke.auth already present, ignoring");
+ return;
+ }
+ Syslog::notice("loading GKE %s (replacing %s)", authUUID.c_str(), dbUUID.empty() ? "nothing" : dbUUID.c_str());
+
+ // first, load code signatures. This is pretty much idempotent
+ if (sigfile)
+ if (FILE *sigs = fopen(sigfile, "r")) {
+ unsigned count = 0;
+ while (const BlobCore *blob = BlobCore::readBlob(sigs)) {
+ signatureDatabaseWriter().storeCode(blob, "<remote>");
+ count++;
+ }
+ secdebug("gkupgrade", "%d detached signature(s) loaded from override data", count);
+ fclose(sigs);
+ }
+
+ // start transaction (atomic from here on out)
+ SQLite::Transaction loadAuth(*this, SQLite::Transaction::exclusive, "GKE_Upgrade");
+
+ // purge prior authority data
+ SQLite::Statement purge(*this, "DELETE FROM authority WHERE flags & :flag");
+ purge.bind(":flag") = kAuthorityFlagWhitelist;
+ purge();
+
+ // load new data
+ CFIndex count = CFDictionaryGetCount(content);
+ CFStringRef keys[count];
+ CFDictionaryRef values[count];
+ CFDictionaryGetKeysAndValues(content, (const void **)keys, (const void **)values);
+
+ SQLite::Statement insert(*this, "INSERT INTO authority (type, allow, requirement, label, flags, remarks)"
+ " VALUES (:type, 1, :requirement, 'GKE', :flags, :path)");
+ for (CFIndex n = 0; n < count; n++) {
+ CFDictionary info(values[n], errSecCSDbCorrupt);
+ insert.reset();
+ insert.bind(":type") = cfString(info.get<CFStringRef>(CFSTR("type")));
+ insert.bind(":path") = cfString(info.get<CFStringRef>(CFSTR("path")));
+ insert.bind(":requirement") = "cdhash H\"" + cfString(info.get<CFStringRef>(CFSTR("cdhash"))) + "\"";
+ insert.bind(":flags") = kAuthorityFlagWhitelist;
+ insert();
+ }
+
+ // update version and commit
+ addFeature("gke", authUUID.c_str(), "gke loaded");
+ loadAuth.commit();
+ }
+ } catch (...) {
+ secdebug("gkupgrade", "exception during GKE upgrade");
+ }
+}
+
//
// Check the override-enable master flag
//
+#define SP_ENABLE_KEY CFSTR("enabled")
+#define SP_ENABLED CFSTR("yes")
+#define SP_DISABLED CFSTR("no")
+
bool overrideAssessment()
{
- if (::access(visibleSecurityFlagFile, F_OK) == 0) {
- return false;
- } else if (errno == ENOENT) {
- return true;
- } else
- UnixError::throwMe();
+ static bool enabled = false;
+ static dispatch_once_t once;
+ static int token = -1;
+ static int have_token = 0;
+ static dispatch_queue_t queue;
+ int check;
+
+ if (have_token && notify_check(token, &check) == NOTIFY_STATUS_OK && !check)
+ return !enabled;
+
+ dispatch_once(&once, ^{
+ if (notify_register_check(kNotifySecAssessmentMasterSwitch, &token) == NOTIFY_STATUS_OK)
+ have_token = 1;
+ queue = dispatch_queue_create("com.apple.SecAssessment.assessment", NULL);
+ });
+
+ dispatch_sync(queue, ^{
+ /* upgrade configuration from emir, ignore all error since we might not be able to write to */
+ if (::access(visibleSecurityFlagFile, F_OK) == 0) {
+ try {
+ setAssessment(true);
+ ::unlink(visibleSecurityFlagFile);
+ } catch (...) {
+ }
+ enabled = true;
+ return;
+ }
+
+ try {
+ Dictionary * prefsDict = Dictionary::CreateDictionary(prefsFile);
+ if (prefsDict == NULL)
+ return;
+
+ CFStringRef value = prefsDict->getStringValue(SP_ENABLE_KEY);
+ if (value && CFStringCompare(value, SP_DISABLED, 0) == 0)
+ enabled = false;
+ else
+ enabled = true;
+ delete prefsDict;
+ } catch(...) {
+ }
+ });
+
+ return !enabled;
+}
+
+void setAssessment(bool masterSwitch)
+{
+ MutableDictionary *prefsDict = MutableDictionary::CreateMutableDictionary(prefsFile);
+ if (prefsDict == NULL)
+ prefsDict = new MutableDictionary::MutableDictionary();
+ prefsDict->setValue(SP_ENABLE_KEY, masterSwitch ? SP_ENABLED : SP_DISABLED);
+ prefsDict->writePlistToFile(prefsFile);
+ delete prefsDict;
+
+ /* make sure permissions is right */
+ ::chmod(prefsFile, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+ notify_post(kNotifySecAssessmentMasterSwitch);
}
/*
- * Copyright (c) 2011 Apple Inc. All Rights Reserved.
+ * Copyright (c) 2011-2012 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
static const char defaultDatabase[] = "/var/db/SystemPolicy";
-static const char visibleSecurityFlagFile[] = "/var/db/.sp_visible";
+static const char visibleSecurityFlagFile[] = "/var/db/.sp_visible"; /* old duchess/emir style configration */
+static const char prefsFile[] = "/var/db/SystemPolicy-prefs.plist";
-static const double never = 5000000; // expires never (i.e. in the year 8977)
+static const char gkeAuthFile[] = "/var/db/gke.auth";
+static const char gkeSigsFile[] = "/var/db/gke.sigs";
+static const unsigned int gkeCheckInterval = 60; // seconds
+
+
+//
+// We use Julian dates in the database, because SQLite understands them well and they convert easily to/from CFAbsoluteTime
+//
+static const double never = 5000000; // canonical "never" julian date (an arbitrary point in the year 8977)
+static const double julianBase = 2451910.5; // julian date of CFAbsoluteTime epoch
+
+static inline double dateToJulian(CFDateRef time)
+{ return CFDateGetAbsoluteTime(time) / 86400.0 + julianBase; }
+
+static inline CFDateRef julianToDate(double julian)
+{ return CFDateCreate(NULL, (julian - julianBase) * 86400); }
typedef SHA1::SDigest ObjectHash;
kAuthorityFlagVirtual = 0x0001, // virtual rule (anchoring object records)
kAuthorityFlagDefault = 0x0002, // rule is part of the original default set
kAuthorityFlagInhibitCache = 0x0004, // never cache outcome of this rule
+ kAuthorityFlagWhitelist = 0x1000, // whitelist override
};
// Mapping/translation to/from API space
//
AuthorityType typeFor(CFDictionaryRef context, AuthorityType type = kAuthorityInvalid);
+CFStringRef typeNameFor(AuthorityType type)
+ CF_RETURNS_RETAINED;
//
public:
void purgeAuthority();
void purgeObjects();
- void purgeObjects(double priority);
+ void purgeObjects(double priority);//
+
+ void upgradeDatabase();
+ std::string featureLevel(const char *feature);
+ bool hasFeature(const char *feature) { return !featureLevel(feature).empty(); }
+ void addFeature(const char *feature, const char *value, const char *remarks);
+ void simpleFeature(const char *feature, const char *sql);
+ void simpleFeature(const char *feature, void (^perform)());
+
+ void installExplicitSet(const char *auth, const char *sigs);
+
+private:
+ time_t mLastExplicitCheck;
};
// Check the system-wide overriding flag file
//
bool overrideAssessment();
-
+void setAssessment(bool masterSwitch);
} // end namespace CodeSigning
} // end namespace Security
/*
- * Copyright (c) 2011 Apple Inc. All Rights Reserved.
+ * Copyright (c) 2011-2012 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
*/
#include "policyengine.h"
#include "xar++.h"
+#include "quarantine++.h"
+#include "codesigning_dtrace.h"
#include <security_utilities/cfmunge.h>
#include <Security/Security.h>
+#include <Security/SecCodePriv.h>
#include <Security/SecRequirementPriv.h>
#include <Security/SecPolicyPriv.h>
#include <Security/SecTrustPriv.h>
#include <Security/SecCodeSigner.h>
#include <Security/cssmapplePriv.h>
-#include <notify.h>
#include <security_utilities/unix++.h>
-#include "quarantine++.h"
+#include <notify.h>
#include <CoreServices/CoreServicesPriv.h>
+#include "SecCodePriv.h"
#undef check // Macro! Yech.
+extern "C" {
+#include <OpenScriptingUtilPriv.h>
+}
+
+
namespace Security {
namespace CodeSigning {
static const double NEGATIVE_HOLD = 60.0/86400; // 60 seconds to cache negative outcomes
+static const char RECORDER_DIR[] = "/tmp/gke-"; // recorder mode destination for detached signatures
+enum {
+ recorder_code_untrusted = 0, // signed but untrusted
+ recorder_code_adhoc = 1, // unsigned; signature recorded
+ recorder_code_unable = 2, // unsigned; unable to record signature
+};
+
-static void authorizeUpdate(SecCSFlags flags, CFDictionaryRef context);
+static void authorizeUpdate(SecAssessmentFlags flags, CFDictionaryRef context);
static void normalizeTarget(CFRef<CFTypeRef> &target, CFDictionary &context, bool signUnsigned = false);
+static bool codeInvalidityExceptions(SecStaticCodeRef code, CFMutableDictionaryRef result);
+static CFTypeRef installerPolicy() CF_RETURNS_RETAINED;
//
{
switch (type) {
case kAuthorityExecute:
- evaluateCode(path, flags, context, result);
+ evaluateCode(path, kAuthorityExecute, flags, context, result);
break;
case kAuthorityInstall:
evaluateInstall(path, flags, context, result);
// Executable code.
// Read from disk, evaluate properly, cache as indicated. The whole thing, so far.
//
-void PolicyEngine::evaluateCode(CFURLRef path, SecAssessmentFlags flags, CFDictionaryRef context, CFMutableDictionaryRef result)
+void PolicyEngine::evaluateCode(CFURLRef path, AuthorityType type, SecAssessmentFlags flags, CFDictionaryRef context, CFMutableDictionaryRef result)
{
- const AuthorityType type = kAuthorityExecute;
+ FileQuarantine qtn(cfString(path).c_str());
+ if (qtn.flag(QTN_FLAG_HARD))
+ MacOSError::throwMe(errSecCSFileHardQuarantined);
CFRef<SecStaticCodeRef> code;
MacOSError::check(SecStaticCodeCreateWithPath(path, kSecCSDefaultFlags, &code.aref()));
CFRef<SecRequirementRef> requirement;
MacOSError::check(SecRequirementCreateWithString(CFTempString(reqString), kSecCSDefaultFlags, &requirement.aref()));
+ OSStatus rc = SecStaticCodeCheckValidity(code, validationFlags, requirement);
+
+ if (rc == errSecCSUnsigned && !overrideAssessment()) {
+ try {
+ // ad-hoc sign the code and attach the signature
+ CFRef<CFDataRef> signature = CFDataCreateMutable(NULL, 0);
+ CFTemp<CFDictionaryRef> arguments("{%O=%O, %O=#N}", kSecCodeSignerDetached, signature.get(), kSecCodeSignerIdentity);
+ CFRef<SecCodeSignerRef> signer;
+ MacOSError::check(SecCodeSignerCreate(arguments, kSecCSDefaultFlags, &signer.aref()));
+ MacOSError::check(SecCodeSignerAddSignature(signer, code, kSecCSDefaultFlags));
+ MacOSError::check(SecCodeSetDetachedSignature(code, signature, kSecCSDefaultFlags));
+
+ // if we're in GKE recording mode, save that signature and report its location
+ if (SYSPOLICY_RECORDER_MODE_ENABLED()) {
+ int status = recorder_code_unable; // ephemeral signature (not recorded)
+ if (geteuid() == 0) {
+ CFRef<CFUUIDRef> uuid = CFUUIDCreate(NULL);
+ std::string sigfile = RECORDER_DIR + cfStringRelease(CFUUIDCreateString(NULL, uuid)) + ".tsig";
+ try {
+ UnixPlusPlus::AutoFileDesc fd(sigfile, O_WRONLY | O_CREAT);
+ fd.write(CFDataGetBytePtr(signature), CFDataGetLength(signature));
+ status = recorder_code_adhoc; // recorded signature
+ SYSPOLICY_RECORDER_MODE_ADHOC_PATH(cfString(path).c_str(), type, sigfile.c_str());
+ } catch (...) { }
+ }
- OSStatus rc = SecStaticCodeCheckValidity(code, validationFlags | kSecCSBasicValidateOnly, requirement);
- // ok, so this rule matches lets do a full validation if not overriding assessments
- if (rc == noErr && !overrideAssessment())
- rc = SecStaticCodeCheckValidity(code, validationFlags, requirement);
+ // now report the D probe itself
+ CFRef<CFDictionaryRef> info;
+ MacOSError::check(SecCodeCopySigningInformation(code, kSecCSDefaultFlags, &info.aref()));
+ CFDataRef cdhash = CFDataRef(CFDictionaryGetValue(info, kSecCodeInfoUnique));
+ SYSPOLICY_RECORDER_MODE(cfString(path).c_str(), type, "",
+ cdhash ? CFDataGetBytePtr(cdhash) : NULL, status);
+ }
+
+ // rerun the validation to update state
+ rc = SecStaticCodeCheckValidity(code, validationFlags | kSecCSBasicValidateOnly, requirement);
+ } catch (...) { }
+ }
switch (rc) {
- case noErr: // success
- break;
+ case noErr: // well signed and satisfies requirement...
+ break; // ... continue below
+ case errSecCSSignatureFailed:
+ if (!codeInvalidityExceptions(code, result)) {
+ if (SYSPOLICY_ASSESS_OUTCOME_BROKEN_ENABLED())
+ SYSPOLICY_ASSESS_OUTCOME_BROKEN(cfString(path).c_str(), type, false);
+ MacOSError::throwMe(rc);
+ }
+ if (SYSPOLICY_ASSESS_OUTCOME_BROKEN_ENABLED())
+ SYSPOLICY_ASSESS_OUTCOME_BROKEN(cfString(path).c_str(), type, true);
+ // treat as unsigned to fix problems in the field
case errSecCSUnsigned:
cfadd(result, "{%O=#F}", kSecAssessmentAssessmentVerdict);
addAuthority(result, "no usable signature");
CFRef<CFDictionaryRef> xinfo;
MacOSError::check(SecTrustCopyExtendedResult(trust, &xinfo.aref()));
if (CFDateRef limit = CFDateRef(CFDictionaryGetValue(xinfo, kSecTrustExpirationDate))) {
- double julianLimit = CFDateGetAbsoluteTime(limit) / 86400.0 + 2451910.5;
- this->recordOutcome(code, allow, type, min(expires, julianLimit), id);
+ this->recordOutcome(code, allow, type, min(expires, dateToJulian(limit)), id);
}
}
}
+ if (allow) {
+ if (SYSPOLICY_ASSESS_OUTCOME_ACCEPT_ENABLED()) {
+ if (!info)
+ MacOSError::check(SecCodeCopySigningInformation(code, kSecCSSigningInformation, &info.aref()));
+ CFDataRef cdhash = CFDataRef(CFDictionaryGetValue(info, kSecCodeInfoUnique));
+ SYSPOLICY_ASSESS_OUTCOME_ACCEPT(cfString(path).c_str(), type, label, cdhash ? CFDataGetBytePtr(cdhash) : NULL);
+ }
+ } else {
+ if (SYSPOLICY_ASSESS_OUTCOME_DENY_ENABLED() || SYSPOLICY_RECORDER_MODE_ENABLED()) {
+ if (!info)
+ MacOSError::check(SecCodeCopySigningInformation(code, kSecCSSigningInformation, &info.aref()));
+ CFDataRef cdhash = CFDataRef(CFDictionaryGetValue(info, kSecCodeInfoUnique));
+ std::string cpath = cfString(path);
+ const void *hashp = cdhash ? CFDataGetBytePtr(cdhash) : NULL;
+ SYSPOLICY_ASSESS_OUTCOME_DENY(cpath.c_str(), type, label, hashp);
+ SYSPOLICY_RECORDER_MODE(cpath.c_str(), type, label, hashp, recorder_code_untrusted);
+ }
+ }
cfadd(result, "{%O=%B}", kSecAssessmentAssessmentVerdict, allow);
addAuthority(result, label, id);
return;
}
// no applicable authority. Deny by default
+ CFRef<CFDictionaryRef> info;
+ MacOSError::check(SecCodeCopySigningInformation(code, kSecCSSigningInformation, &info.aref()));
if (flags & kSecAssessmentFlagRequestOrigin) {
- CFRef<CFDictionaryRef> info; // as needed
- MacOSError::check(SecCodeCopySigningInformation(code, kSecCSSigningInformation, &info.aref()));
if (CFArrayRef chain = CFArrayRef(CFDictionaryGetValue(info, kSecCodeInfoCertificates)))
setOrigin(chain, result);
}
+ if (SYSPOLICY_ASSESS_OUTCOME_DEFAULT_ENABLED() || SYSPOLICY_RECORDER_MODE_ENABLED()) {
+ CFDataRef cdhash = CFDataRef(CFDictionaryGetValue(info, kSecCodeInfoUnique));
+ const void *hashp = cdhash ? CFDataGetBytePtr(cdhash) : NULL;
+ std::string cpath = cfString(path);
+ SYSPOLICY_ASSESS_OUTCOME_DEFAULT(cpath.c_str(), type, latentLabel.c_str(), hashp);
+ SYSPOLICY_RECORDER_MODE(cpath.c_str(), type, latentLabel.c_str(), hashp, 0);
+ }
if (!(flags & kSecAssessmentFlagNoCache))
this->recordOutcome(code, false, type, this->julianNow() + NEGATIVE_HOLD, latentID);
cfadd(result, "{%O=%B}", kSecAssessmentAssessmentVerdict, false);
//
// Installer archive.
-// Certs passed from caller (untrusted), no policy engine yet, no caching (since untrusted).
-// The current "policy" is to trust any proper signature.
+// Hybrid policy: If we detect an installer signature, use and validate that.
+// If we don't, check for a code signature instead.
//
-static CFTypeRef installerPolicy();
-
void PolicyEngine::evaluateInstall(CFURLRef path, SecAssessmentFlags flags, CFDictionaryRef context, CFMutableDictionaryRef result)
{
const AuthorityType type = kAuthorityInstall;
+
+ Xar xar(cfString(path).c_str());
+ if (!xar) {
+ // follow the code signing path
+ evaluateCode(path, type, flags, context, result);
+ return;
+ }
SQLite3::int64 latentID = 0; // first (highest priority) disabled matching ID
std::string latentLabel; // ... and associated label, if any
- Xar xar(cfString(path).c_str());
- if (xar) {
- if (!xar.isSigned()) {
- // unsigned xar
- cfadd(result, "{%O=%B}", kSecAssessmentAssessmentVerdict, false);
- addAuthority(result, "no usable signature");
- return;
- }
- if (CFRef<CFArrayRef> certs = xar.copyCertChain()) {
- CFRef<CFTypeRef> policy = installerPolicy();
- CFRef<SecTrustRef> trust;
- MacOSError::check(SecTrustCreateWithCertificates(certs, policy, &trust.aref()));
-// MacOSError::check(SecTrustSetAnchorCertificates(trust, cfEmptyArray())); // no anchors
- MacOSError::check(SecTrustSetOptions(trust, kSecTrustOptionAllowExpired | kSecTrustOptionImplicitAnchors));
-
- SecTrustResultType trustResult;
- MacOSError::check(SecTrustEvaluate(trust, &trustResult));
- CFRef<CFArrayRef> chain;
- CSSM_TP_APPLE_EVIDENCE_INFO *info;
- MacOSError::check(SecTrustGetResult(trust, &trustResult, &chain.aref(), &info));
-
- if (flags & kSecAssessmentFlagRequestOrigin)
- setOrigin(chain, result);
+ if (!xar.isSigned()) {
+ // unsigned xar
+ if (SYSPOLICY_ASSESS_OUTCOME_UNSIGNED_ENABLED())
+ SYSPOLICY_ASSESS_OUTCOME_UNSIGNED(cfString(path).c_str(), type);
+ cfadd(result, "{%O=%B}", kSecAssessmentAssessmentVerdict, false);
+ addAuthority(result, "no usable signature");
+ return;
+ }
+ if (CFRef<CFArrayRef> certs = xar.copyCertChain()) {
+ CFRef<CFTypeRef> policy = installerPolicy();
+ CFRef<SecTrustRef> trust;
+ MacOSError::check(SecTrustCreateWithCertificates(certs, policy, &trust.aref()));
+// MacOSError::check(SecTrustSetAnchorCertificates(trust, cfEmptyArray())); // no anchors
+ MacOSError::check(SecTrustSetOptions(trust, kSecTrustOptionAllowExpired | kSecTrustOptionImplicitAnchors));
+
+ SecTrustResultType trustResult;
+ MacOSError::check(SecTrustEvaluate(trust, &trustResult));
+ CFRef<CFArrayRef> chain;
+ CSSM_TP_APPLE_EVIDENCE_INFO *info;
+ MacOSError::check(SecTrustGetResult(trust, &trustResult, &chain.aref(), &info));
- switch (trustResult) {
- case kSecTrustResultProceed:
- case kSecTrustResultConfirm:
- case kSecTrustResultUnspecified:
+ if (flags & kSecAssessmentFlagRequestOrigin)
+ setOrigin(chain, result);
+
+ switch (trustResult) {
+ case kSecTrustResultProceed:
+ case kSecTrustResultUnspecified:
+ break;
+ default:
+ {
+ OSStatus rc;
+ MacOSError::check(SecTrustGetCssmResultCode(trust, &rc));
+ MacOSError::throwMe(rc);
+ }
+ }
+
+ SQLite::Statement query(*this,
+ "SELECT allow, requirement, id, label, flags, disabled FROM scan_authority"
+ " WHERE type = :type"
+ " ORDER BY priority DESC;");
+ query.bind(":type").integer(type);
+ while (query.nextRow()) {
+ bool allow = int(query[0]);
+ const char *reqString = query[1];
+ SQLite3::int64 id = query[2];
+ const char *label = query[3];
+ //sqlite_uint64 ruleFlags = query[4];
+ SQLite3::int64 disabled = query[5];
+
+ CFRef<SecRequirementRef> requirement;
+ MacOSError::check(SecRequirementCreateWithString(CFTempString(reqString), kSecCSDefaultFlags, &requirement.aref()));
+ switch (OSStatus rc = SecRequirementEvaluate(requirement, chain, NULL, kSecCSDefaultFlags)) {
+ case noErr: // success
break;
- default:
- {
- OSStatus rc;
- MacOSError::check(SecTrustGetCssmResultCode(trust, &rc));
- MacOSError::throwMe(rc);
+ case errSecCSReqFailed: // requirement missed, but otherwise okay
+ continue;
+ default: // broken in some way; all tests will fail like this so bail out
+ MacOSError::throwMe(rc);
+ }
+ if (disabled) {
+ if (latentID == 0) {
+ latentID = id;
+ if (label)
+ latentLabel = label;
}
+ continue; // the loop
}
- SQLite::Statement query(*this,
- "SELECT allow, requirement, id, label, flags, disabled FROM scan_authority"
- " WHERE type = :type"
- " ORDER BY priority DESC;");
- query.bind(":type").integer(type);
- while (query.nextRow()) {
- bool allow = int(query[0]);
- const char *reqString = query[1];
- SQLite3::int64 id = query[2];
- const char *label = query[3];
- //sqlite_uint64 ruleFlags = query[4];
- SQLite3::int64 disabled = query[5];
-
- CFRef<SecRequirementRef> requirement;
- MacOSError::check(SecRequirementCreateWithString(CFTempString(reqString), kSecCSDefaultFlags, &requirement.aref()));
- switch (OSStatus rc = SecRequirementEvaluate(requirement, chain, NULL, kSecCSDefaultFlags)) {
- case noErr: // success
- break;
- case errSecCSReqFailed: // requirement missed, but otherwise okay
- continue;
- default: // broken in some way; all tests will fail like this so bail out
- MacOSError::throwMe(rc);
- }
- if (disabled) {
- if (latentID == 0) {
- latentID = id;
- if (label)
- latentLabel = label;
- }
- continue; // the loop
- }
- // not adding to the object cache - we could, but it's not likely to be worth it
- cfadd(result, "{%O=%B}", kSecAssessmentAssessmentVerdict, allow);
- addAuthority(result, label, id);
- return;
+ if (SYSPOLICY_ASSESS_OUTCOME_ACCEPT_ENABLED() || SYSPOLICY_ASSESS_OUTCOME_DENY_ENABLED()) {
+ if (allow)
+ SYSPOLICY_ASSESS_OUTCOME_ACCEPT(cfString(path).c_str(), type, label, NULL);
+ else
+ SYSPOLICY_ASSESS_OUTCOME_DENY(cfString(path).c_str(), type, label, NULL);
}
+
+ // not adding to the object cache - we could, but it's not likely to be worth it
+ cfadd(result, "{%O=%B}", kSecAssessmentAssessmentVerdict, allow);
+ addAuthority(result, label, id);
+ return;
}
}
+ if (SYSPOLICY_ASSESS_OUTCOME_DEFAULT_ENABLED())
+ SYSPOLICY_ASSESS_OUTCOME_DEFAULT(cfString(path).c_str(), type, latentLabel.c_str(), NULL);
// no applicable authority. Deny by default
cfadd(result, "{%O=#F}", kSecAssessmentAssessmentVerdict);
{
if (context) {
if (CFStringRef riskCategory = CFStringRef(CFDictionaryGetValue(context, kLSDownloadRiskCategoryKey))) {
+ FileQuarantine qtn(cfString(path).c_str());
+
if (CFEqual(riskCategory, kLSRiskCategorySafe)
|| CFEqual(riskCategory, kLSRiskCategoryNeutral)
|| CFEqual(riskCategory, kLSRiskCategoryUnknown)
|| CFEqual(riskCategory, kLSRiskCategoryMayContainUnsafeExecutable)) {
cfadd(result, "{%O=#T}", kSecAssessmentAssessmentVerdict);
addAuthority(result, "_XProtect");
- } else if (FileQuarantine(cfString(path).c_str()).flag(QTN_FLAG_ASSESSMENT_OK)) {
+ } else if (qtn.flag(QTN_FLAG_HARD)) {
+ MacOSError::throwMe(errSecCSFileHardQuarantined);
+ } else if (qtn.flag(QTN_FLAG_ASSESSMENT_OK)) {
cfadd(result, "{%O=#T}", kSecAssessmentAssessmentVerdict);
addAuthority(result, "Prior Assessment");
} else {
cfadd(auth, "{%O=%s}", kSecAssessmentAssessmentSource, label);
if (row)
CFDictionaryAddValue(auth, kSecAssessmentAssessmentAuthorityRow, CFTempNumber(row));
+ if (overrideAssessment())
+ CFDictionaryAddValue(auth, kSecAssessmentAssessmentAuthorityOverride, kDisabledOverride);
if (cacheInfo)
CFDictionaryAddValue(auth, kSecAssessmentAssessmentFromCache, cacheInfo);
CFDictionaryAddValue(parent, kSecAssessmentAssessmentAuthority, auth);
//
// Add a rule to the policy database
//
-bool PolicyEngine::add(CFTypeRef inTarget, AuthorityType type, SecAssessmentFlags flags, CFDictionaryRef context)
+CFDictionaryRef PolicyEngine::add(CFTypeRef inTarget, AuthorityType type, SecAssessmentFlags flags, CFDictionaryRef context)
{
// default type to execution
if (type == kAuthorityInvalid)
authorizeUpdate(flags, context);
CFDictionary ctx(context, errSecCSInvalidAttributeValues);
CFCopyRef<CFTypeRef> target = inTarget;
-
- if (type == kAuthorityOpenDoc) {
+ CFRef<CFDataRef> bookmark = NULL;
+
+ switch (type) {
+ case kAuthorityExecute:
+ normalizeTarget(target, ctx, true);
+ // bookmarks are untrusted and just a hint to callers
+ bookmark = ctx.get<CFDataRef>(kSecAssessmentRuleKeyBookmark);
+ break;
+ case kAuthorityInstall:
+ if (inTarget && CFGetTypeID(inTarget) == CFURLGetTypeID()) {
+ // no good way to turn an installer file into a requirement. Pretend to succeeed so caller proceeds
+ return cfmake<CFDictionaryRef>("{%O=%O}", kSecAssessmentAssessmentAuthorityOverride, CFSTR("virtual install"));
+ }
+ break;
+ case kAuthorityOpenDoc:
// handle document-open differently: use quarantine flags for whitelisting
- if (!target || CFGetTypeID(target) != CFURLGetTypeID())
+ if (!target || CFGetTypeID(target) != CFURLGetTypeID()) // can only "add" file paths
MacOSError::throwMe(errSecCSInvalidObjectRef);
- std::string spath = cfString(target.as<CFURLRef>()).c_str();
- FileQuarantine qtn(spath.c_str());
- qtn.setFlag(QTN_FLAG_ASSESSMENT_OK);
- qtn.applyTo(spath.c_str());
- return true;
- }
-
- if (type == kAuthorityInstall) {
- return cfmake<CFDictionaryRef>("{%O=%O}", kSecAssessmentAssessmentAuthorityOverride, CFSTR("virtual install"));
+ try {
+ std::string spath = cfString(target.as<CFURLRef>());
+ FileQuarantine qtn(spath.c_str());
+ qtn.setFlag(QTN_FLAG_ASSESSMENT_OK);
+ qtn.applyTo(spath.c_str());
+ } catch (const CommonError &error) {
+ // could not set quarantine flag - report qualified success
+ return cfmake<CFDictionaryRef>("{%O=%O,'assessment:error'=%d}",
+ kSecAssessmentAssessmentAuthorityOverride, CFSTR("error setting quarantine"), error.osStatus());
+ } catch (...) {
+ return cfmake<CFDictionaryRef>("{%O=%O}", kSecAssessmentAssessmentAuthorityOverride, CFSTR("unable to set quarantine"));
+ }
+ return NULL;
}
- // resolve URLs to Requirements
- normalizeTarget(target, ctx, true);
-
// if we now have anything else, we're busted
if (!target || CFGetTypeID(target) != SecRequirementGetTypeID())
MacOSError::throwMe(errSecCSInvalidObjectRef);
label = cfString(lab);
if (CFDateRef time = ctx.get<CFDateRef>(kSecAssessmentUpdateKeyExpires))
// we're using Julian dates here; convert from CFDate
- expires = CFDateGetAbsoluteTime(time) / 86400.0 + 2451910.5;
+ expires = dateToJulian(time);
if (CFBooleanRef allowing = ctx.get<CFBooleanRef>(kSecAssessmentUpdateKeyAllow))
allow = allowing == kCFBooleanTrue;
if (CFStringRef rem = ctx.get<CFStringRef>(kSecAssessmentUpdateKeyRemarks))
insert.bind(":requirement") = requirementText.get();
insert.bind(":priority") = priority;
if (!label.empty())
- insert.bind(":label") = label.c_str();
+ insert.bind(":label") = label;
insert.bind(":expires") = expires;
if (!remarks.empty())
- insert.bind(":remarks") = remarks.c_str();
+ insert.bind(":remarks") = remarks;
insert.execute();
+ SQLite::int64 newRow = this->lastInsert();
+ if (bookmark) {
+ SQLite::Statement bi(*this, "INSERT INTO bookmarkhints (bookmark, authority) VALUES (:bookmark, :authority)");
+ bi.bind(":bookmark") = CFDataRef(bookmark);
+ bi.bind(":authority").integer(newRow);
+ bi.execute();
+ }
this->purgeObjects(priority);
xact.commit();
notify_post(kNotifySecAssessmentUpdate);
- return true;
+ return cfmake<CFDictionaryRef>("{%O=%d}", kSecAssessmentUpdateKeyRow, newRow);
+}
+
+
+CFDictionaryRef PolicyEngine::remove(CFTypeRef target, AuthorityType type, SecAssessmentFlags flags, CFDictionaryRef context)
+{
+ if (type == kAuthorityOpenDoc) {
+ // handle document-open differently: use quarantine flags for whitelisting
+ authorizeUpdate(flags, context);
+ if (!target || CFGetTypeID(target) != CFURLGetTypeID())
+ MacOSError::throwMe(errSecCSInvalidObjectRef);
+ std::string spath = cfString(CFURLRef(target)).c_str();
+ FileQuarantine qtn(spath.c_str());
+ qtn.clearFlag(QTN_FLAG_ASSESSMENT_OK);
+ qtn.applyTo(spath.c_str());
+ return NULL;
+ }
+ return manipulateRules("DELETE FROM authority", target, type, flags, context);
+}
+
+CFDictionaryRef PolicyEngine::enable(CFTypeRef target, AuthorityType type, SecAssessmentFlags flags, CFDictionaryRef context)
+{
+ return manipulateRules("UPDATE authority SET disabled = 0", target, type, flags, context);
+}
+
+CFDictionaryRef PolicyEngine::disable(CFTypeRef target, AuthorityType type, SecAssessmentFlags flags, CFDictionaryRef context)
+{
+ return manipulateRules("UPDATE authority SET disabled = 1", target, type, flags, context);
+}
+
+CFDictionaryRef PolicyEngine::find(CFTypeRef target, AuthorityType type, SecAssessmentFlags flags, CFDictionaryRef context)
+{
+ SQLite::Statement query(*this);
+ selectRules(query, "SELECT scan_authority.id, scan_authority.type, scan_authority.requirement, scan_authority.allow, scan_authority.label, scan_authority.priority, scan_authority.remarks, scan_authority.expires, scan_authority.disabled, bookmarkhints.bookmark FROM scan_authority LEFT OUTER JOIN bookmarkhints ON scan_authority.id = bookmarkhints.authority",
+ "scan_authority", target, type, flags, context,
+ " ORDER BY priority DESC");
+ CFRef<CFMutableArrayRef> found = makeCFMutableArray(0);
+ while (query.nextRow()) {
+ SQLite::int64 id = query[0];
+ int type = int(query[1]);
+ const char *requirement = query[2];
+ int allow = int(query[3]);
+ const char *label = query[4];
+ double priority = query[5];
+ const char *remarks = query[6];
+ double expires = query[7];
+ int disabled = int(query[8]);
+ CFRef<CFDataRef> bookmark = query[9].data();
+ CFRef<CFMutableDictionaryRef> rule = makeCFMutableDictionary(5,
+ kSecAssessmentRuleKeyID, CFTempNumber(id).get(),
+ kSecAssessmentRuleKeyType, CFRef<CFStringRef>(typeNameFor(type)).get(),
+ kSecAssessmentRuleKeyRequirement, CFTempString(requirement).get(),
+ kSecAssessmentRuleKeyAllow, allow ? kCFBooleanTrue : kCFBooleanFalse,
+ kSecAssessmentRuleKeyPriority, CFTempNumber(priority).get()
+ );
+ if (label)
+ CFDictionaryAddValue(rule, kSecAssessmentRuleKeyLabel, CFTempString(label));
+ if (remarks)
+ CFDictionaryAddValue(rule, kSecAssessmentRuleKeyRemarks, CFTempString(remarks));
+ if (expires != never)
+ CFDictionaryAddValue(rule, kSecAssessmentRuleKeyExpires, CFRef<CFDateRef>(julianToDate(expires)));
+ if (disabled)
+ CFDictionaryAddValue(rule, kSecAssessmentRuleKeyDisabled, CFTempNumber(disabled));
+ if (bookmark)
+ CFDictionaryAddValue(rule, kSecAssessmentRuleKeyBookmark, bookmark);
+ CFArrayAppendValue(found, rule);
+ }
+ if (CFArrayGetCount(found) == 0)
+ MacOSError::throwMe(errSecCSNoMatches);
+ return cfmake<CFDictionaryRef>("{%O=%O}", kSecAssessmentUpdateKeyFound, found.get());
+}
+
+
+CFDictionaryRef PolicyEngine::update(CFTypeRef target, SecAssessmentFlags flags, CFDictionaryRef context)
+{
+ AuthorityType type = typeFor(context, kAuthorityInvalid);
+ CFStringRef edit = CFStringRef(CFDictionaryGetValue(context, kSecAssessmentContextKeyUpdate));
+ CFDictionaryRef result;
+ if (CFEqual(edit, kSecAssessmentUpdateOperationAdd))
+ result = this->add(target, type, flags, context);
+ else if (CFEqual(edit, kSecAssessmentUpdateOperationRemove))
+ result = this->remove(target, type, flags, context);
+ else if (CFEqual(edit, kSecAssessmentUpdateOperationEnable))
+ result = this->enable(target, type, flags, context);
+ else if (CFEqual(edit, kSecAssessmentUpdateOperationDisable))
+ result = this->disable(target, type, flags, context);
+ else if (CFEqual(edit, kSecAssessmentUpdateOperationFind))
+ result = this->find(target, type, flags, context);
+ else
+ MacOSError::throwMe(errSecCSInvalidAttributeValues);
+ if (result == NULL)
+ result = makeCFDictionary(0); // success, no details
+ return result;
}
//
-// Perform an action on existing authority rule(s)
+// Construct and prepare an SQL query on the authority table, operating on some set of existing authority records.
+// In essence, this appends a suitable WHERE clause to the stanza passed and prepares it on the statement given.
//
-bool PolicyEngine::manipulateRules(const std::string &stanza,
- CFTypeRef inTarget, AuthorityType type, SecAssessmentFlags flags, CFDictionaryRef context)
+void PolicyEngine::selectRules(SQLite::Statement &action, std::string phrase, std::string table,
+ CFTypeRef inTarget, AuthorityType type, SecAssessmentFlags flags, CFDictionaryRef context, std::string suffix /* = "" */)
{
- authorizeUpdate(flags, context);
CFDictionary ctx(context, errSecCSInvalidAttributeValues);
CFCopyRef<CFTypeRef> target = inTarget;
normalizeTarget(target, ctx);
string label;
-
if (CFStringRef lab = ctx.get<CFStringRef>(kSecAssessmentUpdateKeyLabel))
label = cfString(CFStringRef(lab));
- SQLite::Transaction xact(*this, SQLite3::Transaction::deferred, "rule_change");
- SQLite::Statement action(*this);
if (!target) {
- if (label.empty()) // underspecified
- MacOSError::throwMe(errSecCSInvalidObjectRef);
- if (type == kAuthorityInvalid) {
- action.query(stanza + " WHERE label = :label");
- } else {
- action.query(stanza + " WHERE type = :type AND label = :label");
- action.bind(":type").integer(type);
+ if (label.empty()) {
+ if (type == kAuthorityInvalid) {
+ action.query(phrase + suffix);
+ } else {
+ action.query(phrase + " WHERE " + table + ".type = :type" + suffix);
+ action.bind(":type").integer(type);
+ }
+ } else { // have label
+ if (type == kAuthorityInvalid) {
+ action.query(phrase + " WHERE " + table + ".label = :label" + suffix);
+ } else {
+ action.query(phrase + " WHERE " + table + ".type = :type AND " + table + ".label = :label" + suffix);
+ action.bind(":type").integer(type);
+ }
+ action.bind(":label") = label;
}
- action.bind(":label") = label.c_str();
} else if (CFGetTypeID(target) == CFNumberGetTypeID()) {
- action.query(stanza + " WHERE id = :id");
+ action.query(phrase + " WHERE " + table + ".id = :id" + suffix);
action.bind(":id").integer(cfNumber<uint64_t>(target.as<CFNumberRef>()));
} else if (CFGetTypeID(target) == SecRequirementGetTypeID()) {
if (type == kAuthorityInvalid)
type = kAuthorityExecute;
CFRef<CFStringRef> requirementText;
MacOSError::check(SecRequirementCopyString(target.as<SecRequirementRef>(), kSecCSDefaultFlags, &requirementText.aref()));
- action.query(stanza + " WHERE type = :type AND requirement = :requirement");
+ action.query(phrase + " WHERE " + table + ".type = :type AND " + table + ".requirement = :requirement" + suffix);
action.bind(":type").integer(type);
action.bind(":requirement") = requirementText.get();
} else
MacOSError::throwMe(errSecCSInvalidObjectRef);
+}
+
+//
+// Execute an atomic change to existing records in the authority table.
+//
+CFDictionaryRef PolicyEngine::manipulateRules(const std::string &stanza,
+ CFTypeRef inTarget, AuthorityType type, SecAssessmentFlags flags, CFDictionaryRef context)
+{
+ SQLite::Transaction xact(*this, SQLite3::Transaction::deferred, "rule_change");
+ SQLite::Statement action(*this);
+ authorizeUpdate(flags, context);
+ selectRules(action, stanza, "authority", inTarget, type, flags, context);
action.execute();
unsigned int changes = this->changes(); // latch change count
// We MUST purge objects with priority <= MAX(priority of any changed rules);
this->purgeObjects(1.0E100);
xact.commit();
notify_post(kNotifySecAssessmentUpdate);
- return true;
+ return cfmake<CFDictionaryRef>("{%O=%d}", kSecAssessmentUpdateKeyCount, changes);
}
// no change; return an error
MacOSError::throwMe(errSecCSNoMatches);
}
-bool PolicyEngine::remove(CFTypeRef target, AuthorityType type, SecAssessmentFlags flags, CFDictionaryRef context)
-{
- if (type == kAuthorityOpenDoc) {
- // handle document-open differently: use quarantine flags for whitelisting
- authorizeUpdate(flags, context);
- if (!target || CFGetTypeID(target) != CFURLGetTypeID())
- MacOSError::throwMe(errSecCSInvalidObjectRef);
- std::string spath = cfString(CFURLRef(target)).c_str();
- FileQuarantine qtn(spath.c_str());
- qtn.clearFlag(QTN_FLAG_ASSESSMENT_OK);
- qtn.applyTo(spath.c_str());
- return true;
- }
- return manipulateRules("DELETE FROM authority", target, type, flags, context);
-}
-
-bool PolicyEngine::enable(CFTypeRef target, AuthorityType type, SecAssessmentFlags flags, CFDictionaryRef context)
-{
- return manipulateRules("UPDATE authority SET disabled = 0", target, type, flags, context);
-}
-
-bool PolicyEngine::disable(CFTypeRef target, AuthorityType type, SecAssessmentFlags flags, CFDictionaryRef context)
-{
- return manipulateRules("UPDATE authority SET disabled = 1", target, type, flags, context);
-}
-
-
-bool PolicyEngine::update(CFTypeRef target, SecAssessmentFlags flags, CFDictionaryRef context)
-{
- AuthorityType type = typeFor(context, kAuthorityInvalid);
- CFStringRef edit = CFStringRef(CFDictionaryGetValue(context, kSecAssessmentContextKeyUpdate));
- if (CFEqual(edit, kSecAssessmentUpdateOperationAdd))
- return this->add(target, type, flags, context);
- else if (CFEqual(edit, kSecAssessmentUpdateOperationRemove))
- return this->remove(target, type, flags, context);
- else if (CFEqual(edit, kSecAssessmentUpdateOperationEnable))
- return this->enable(target, type, flags, context);
- else if (CFEqual(edit, kSecAssessmentUpdateOperationDisable))
- return this->disable(target, type, flags, context);
- else
- MacOSError::throwMe(errSecCSInvalidAttributeValues);
-}
-
-
//
// Fill in extra information about the originator of cryptographic credentials found - if any
//
if (chain)
if (CFArrayGetCount(chain) > 0)
if (SecCertificateRef leaf = SecCertificateRef(CFArrayGetValueAtIndex(chain, 0)))
- if (CFStringRef summary = SecCertificateCopyLongDescription(NULL, leaf, NULL))
+ if (CFStringRef summary = SecCertificateCopyLongDescription(NULL, leaf, NULL)) {
CFDictionarySetValue(result, kSecAssessmentAssessmentOriginator, summary);
+ CFRelease(summary);
+ }
}
//
// Take an assessment outcome and record it in the object cache
//
-void PolicyEngine::recordOutcome(SecStaticCodeRef code, bool allow, AuthorityType type, double expires, int authority)
+void PolicyEngine::recordOutcome(SecStaticCodeRef code, bool allow, AuthorityType type, double expires, SQLite::int64 authority)
{
CFRef<CFDictionaryRef> info;
MacOSError::check(SecCodeCopySigningInformation(code, kSecCSDefaultFlags, &info.aref()));
insert.bind(":allow").integer(allow);
insert.bind(":hash") = cdHash;
insert.bind(":expires") = expires;
- insert.bind(":path") = cfString(path).c_str();
+ insert.bind(":path") = cfString(path);
insert.bind(":authority").integer(authority);
insert.execute();
xact.commit();
// Perform update authorization processing.
// Throws an exception if authorization is denied.
//
-static void authorizeUpdate(SecCSFlags flags, CFDictionaryRef context)
+static void authorizeUpdate(SecAssessmentFlags flags, CFDictionaryRef context)
{
AuthorizationRef authorization = NULL;
if (target && CFGetTypeID(target) == CFURLGetTypeID()) {
CFRef<SecStaticCodeRef> code;
MacOSError::check(SecStaticCodeCreateWithPath(target.as<CFURLRef>(), kSecCSDefaultFlags, &code.aref()));
- CFRef<SecRequirementRef> requirement;
switch (OSStatus rc = SecCodeCopyDesignatedRequirement(code, kSecCSDefaultFlags, (SecRequirementRef *)&target.aref())) {
- case noErr:
+ case noErr: {
+ // use the *default* DR to avoid unreasonably wide DRs opening up Gatekeeper to attack
+ CFRef<CFDictionaryRef> info;
+ MacOSError::check(SecCodeCopySigningInformation(code, kSecCSRequirementInformation, &info.aref()));
+ target = CFDictionaryGetValue(info, kSecCodeInfoImplicitDesignatedRequirement);
+ }
break;
case errSecCSUnsigned:
if (signUnsigned) {
MacOSError::check(SecCodeCopyDesignatedRequirement(code, kSecCSDefaultFlags, (SecRequirementRef *)&target.aref()));
break;
}
- // fall through
+ MacOSError::check(rc);
+ case errSecCSSignatureFailed:
+ // recover certain cases of broken signatures (well, try)
+ if (codeInvalidityExceptions(code, NULL)) {
+ // Ad-hoc sign the code in place (requiring a writable subject). This requires root privileges.
+ CFRef<SecCodeSignerRef> signer;
+ CFTemp<CFDictionaryRef> arguments("{%O=#N}", kSecCodeSignerIdentity);
+ MacOSError::check(SecCodeSignerCreate(arguments, kSecCSDefaultFlags, &signer.aref()));
+ MacOSError::check(SecCodeSignerAddSignature(signer, code, kSecCSDefaultFlags));
+ MacOSError::check(SecCodeCopyDesignatedRequirement(code, kSecCSDefaultFlags, (SecRequirementRef *)&target.aref()));
+ break;
+ }
+ MacOSError::check(rc);
default:
MacOSError::check(rc);
}
}
+//
+// Process special overrides for invalidly signed code.
+// This is the (hopefully minimal) concessions we make to keep hurting our customers
+// for our own prior mistakes...
+//
+static bool codeInvalidityExceptions(SecStaticCodeRef code, CFMutableDictionaryRef result)
+{
+ if (OSAIsRecognizedExecutableURL) {
+ CFRef<CFDictionaryRef> info;
+ MacOSError::check(SecCodeCopySigningInformation(code, kSecCSDefaultFlags, &info.aref()));
+ if (CFURLRef executable = CFURLRef(CFDictionaryGetValue(info, kSecCodeInfoMainExecutable))) {
+ SInt32 error;
+ if (OSAIsRecognizedExecutableURL(executable, &error)) {
+ if (result)
+ CFDictionaryAddValue(result,
+ kSecAssessmentAssessmentAuthorityOverride, CFSTR("ignoring known invalid applet signature"));
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+
} // end namespace CodeSigning
} // end namespace Security
/*
- * Copyright (c) 2011 Apple Inc. All Rights Reserved.
+ * Copyright (c) 2011-2012 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
public:
void evaluate(CFURLRef path, AuthorityType type, SecAssessmentFlags flags, CFDictionaryRef context, CFMutableDictionaryRef result);
- bool update(CFTypeRef target, SecAssessmentFlags flags, CFDictionaryRef context);
- bool add(CFTypeRef target, AuthorityType type, SecAssessmentFlags flags, CFDictionaryRef context);
- bool remove(CFTypeRef target, AuthorityType type, SecAssessmentFlags flags, CFDictionaryRef context);
- bool enable(CFTypeRef target, AuthorityType type, SecAssessmentFlags flags, CFDictionaryRef context);
- bool disable(CFTypeRef target, AuthorityType type, SecAssessmentFlags flags, CFDictionaryRef context);
+ CFDictionaryRef update(CFTypeRef target, SecAssessmentFlags flags, CFDictionaryRef context);
+ CFDictionaryRef add(CFTypeRef target, AuthorityType type, SecAssessmentFlags flags, CFDictionaryRef context);
+ CFDictionaryRef remove(CFTypeRef target, AuthorityType type, SecAssessmentFlags flags, CFDictionaryRef context);
+ CFDictionaryRef enable(CFTypeRef target, AuthorityType type, SecAssessmentFlags flags, CFDictionaryRef context);
+ CFDictionaryRef disable(CFTypeRef target, AuthorityType type, SecAssessmentFlags flags, CFDictionaryRef context);
+ CFDictionaryRef find(CFTypeRef target, AuthorityType type, SecAssessmentFlags flags, CFDictionaryRef context);
public:
static void addAuthority(CFMutableDictionaryRef parent, const char *label, SQLite::int64 row = 0, CFTypeRef cacheInfo = NULL);
static void addToAuthority(CFMutableDictionaryRef parent, CFStringRef key, CFTypeRef value);
private:
- void evaluateCode(CFURLRef path, SecAssessmentFlags flags, CFDictionaryRef context, CFMutableDictionaryRef result);
+ void evaluateCode(CFURLRef path, AuthorityType type, SecAssessmentFlags flags, CFDictionaryRef context, CFMutableDictionaryRef result);
void evaluateInstall(CFURLRef path, SecAssessmentFlags flags, CFDictionaryRef context, CFMutableDictionaryRef result);
void evaluateDocOpen(CFURLRef path, SecAssessmentFlags flags, CFDictionaryRef context, CFMutableDictionaryRef result);
- bool manipulateRules(const std::string &stanza,
+ void selectRules(SQLite::Statement &action, std::string stanza, std::string table,
+ CFTypeRef inTarget, AuthorityType type, SecAssessmentFlags flags, CFDictionaryRef context, std::string suffix = "");
+ CFDictionaryRef manipulateRules(const std::string &stanza,
CFTypeRef target, AuthorityType type, SecAssessmentFlags flags, CFDictionaryRef context);
void setOrigin(CFArrayRef chain, CFMutableDictionaryRef result);
- void recordOutcome(SecStaticCodeRef code, bool allow, AuthorityType type, double expires, int authority);
+ void recordOutcome(SecStaticCodeRef code, bool allow, AuthorityType type, double expires, SQLite::int64 authority);
};
if (cf->name == key) {
CFRef<CFStringRef> value;
if (OSStatus rc = SecCertificateCopySubjectComponent(cert, cf->oid, &value.aref())) {
- secdebug("csinterp", "cert %p lookup for DN.%s failed rc=%d", cert, key.c_str(), rc);
+ secdebug("csinterp", "cert %p lookup for DN.%s failed rc=%d", cert, key.c_str(), (int)rc);
return false;
}
return match(value);
if (key == "email") {
CFRef<CFArrayRef> value;
if (OSStatus rc = SecCertificateCopyEmailAddresses(cert, &value.aref())) {
- secdebug("csinterp", "cert %p lookup for email failed rc=%d", cert, rc);
+ secdebug("csinterp", "cert %p lookup for email failed rc=%d", cert, (int)rc);
return false;
}
return match(value);
/*
- * Copyright (c) 2006-2007 Apple Inc. All Rights Reserved.
+ * Copyright (c) 2006-2012 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
if (certs) {
if (ix < 0)
ix += certCount();
+ if (ix >= CFArrayGetCount(certs))
+ return NULL;
if (CFTypeRef element = CFArrayGetValueAtIndex(certs, ix))
return SecCertificateRef(element);
}
#endif //TEST_APPLE_ANCHOR
-//
-// InternalRequirements
-//
-void InternalRequirements::operator () (const Requirements *given, const Requirements *defaulted)
-{
- if (defaulted) {
- this->add(defaulted);
- ::free((void *)defaulted); // was malloc(3)ed by DiskRep
- }
- if (given)
- this->add(given);
- mReqs = make();
-}
-
-
//
// Debug dump support
//
/*
- * Copyright (c) 2006-2007 Apple Inc. All Rights Reserved.
+ * Copyright (c) 2006-2012 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
// An interpretation context
//
class Requirement::Context {
-public:
- Context(CFArrayRef certChain, CFDictionaryRef infoDict, CFDictionaryRef entitlementDict, const CodeDirectory *dir)
- : certs(certChain), info(infoDict), entitlements(entitlementDict), directory(dir) { }
-
- const CFArrayRef certs; // certificate chain
- const CFDictionaryRef info; // Info.plist
- const CFDictionaryRef entitlements; // entitlement plist
- const CodeDirectory * const directory; // CodeDirectory
+protected:
+ Context()
+ : certs(NULL), info(NULL), entitlements(NULL), identifier(""), directory(NULL) { }
- SecCertificateRef cert(int ix) const; // get a cert from the cert chain
- unsigned int certCount() const; // length of cert chain
+public:
+ Context(CFArrayRef certChain, CFDictionaryRef infoDict, CFDictionaryRef entitlementDict,
+ const std::string &ident, const CodeDirectory *dir)
+ : certs(certChain), info(infoDict), entitlements(entitlementDict), identifier(ident), directory(dir) { }
+
+ CFArrayRef certs; // certificate chain
+ CFDictionaryRef info; // Info.plist
+ CFDictionaryRef entitlements; // entitlement plist
+ std::string identifier; // signing identifier
+ const CodeDirectory *directory; // CodeDirectory
+
+ SecCertificateRef cert(int ix) const; // get a cert from the cert chain (NULL if not found)
+ unsigned int certCount() const; // length of cert chain (including root)
};
typedef SuperBlob<0xfade0c01> Requirements;
-//
-// A helper to deal with the magic merger logic of internal requirements
-//
-class InternalRequirements : public Requirements::Maker {
-public:
- InternalRequirements() : mReqs(NULL) { }
- ~InternalRequirements() { ::free((void *)mReqs); }
- void operator () (const Requirements *given, const Requirements *defaulted);
- operator const Requirements * () const { return mReqs; }
-
-private:
- const Requirements *mReqs;
-};
-
-
//
// Byte order flippers
//
provider syspolicy {
- probe assess_api(const char *path, uint32_t flags);
+ probe assess_api(const char *path, int type, uint64_t flags);
+
+ probe assess__outcome__accept(const char *path, int type, const char *label, const void *cdhash);
+ probe assess__outcome__deny(const char *path, int type, const char *label, const void *cdhash);
+ probe assess__outcome__default(const char *path, int type, const char *label, const void *cdhash);
+ probe assess__outcome__unsigned(const char *path, int type);
+ probe assess__outcome__broken(const char *path, int type, bool exception_made);
+
+ probe recorder_mode(const char *path, int type, const char *label, const void *cdhash, int flags);
+ probe recorder_mode_adhoc_path(const char *path, int type, const char *sig_path); // path containing adhoc signature recorded
+
probe assess_cache_hit();
probe assess_local();
probe assess_remote();
-};
\ No newline at end of file
+};
_kSecCodeSignerIdentifier
_kSecCodeSignerIdentifierPrefix
_kSecCodeSignerIdentity
+_kSecCodeSignerTimestampAuthentication
+_kSecCodeSignerRequireTimestamp
+_kSecCodeSignerTimestampServer
+_kSecCodeSignerTimestampOmitCertificates
_kSecCodeSignerPageSize
_kSecCodeSignerRequirements
_kSecCodeSignerResourceRules
_kSecCodeInfoChangedFiles
_kSecCodeInfoCMS
_kSecCodeInfoTime
+_kSecCodeInfoTimestamp
_kSecCodeInfoDesignatedRequirement
_kSecCodeInfoEntitlements
+_kSecCodeInfoEntitlementsDict
_kSecCodeInfoFormat
_kSecCodeInfoDigestAlgorithm
_kSecCodeInfoIdentifier
_kSecGuestAttributePid
_kSecRequirementKeyInfoPlist
_kSecRequirementKeyEntitlements
+_kSecRequirementKeyIdentifier
_kSecCFErrorArchitecture
_kSecCFErrorPattern
_kSecCFErrorResourceSeal
# Assessments
_SecAssessmentCreate
_SecAssessmentCopyResult
+_SecAssessmentCopyUpdate
_SecAssessmentUpdate
_SecAssessmentControl
_kSecAssessmentContextKeyOperation
_kSecAssessmentUpdateOperationRemove
_kSecAssessmentUpdateOperationEnable
_kSecAssessmentUpdateOperationDisable
-_kSecAssessmentUpdateKeyAuthorization
+_kSecAssessmentUpdateOperationFind
_kSecAssessmentUpdateKeyAllow
+_kSecAssessmentUpdateKeyLabel
_kSecAssessmentUpdateKeyExpires
_kSecAssessmentUpdateKeyPriority
-_kSecAssessmentUpdateKeyLabel
_kSecAssessmentUpdateKeyRemarks
+_kSecAssessmentUpdateKeyRow
+_kSecAssessmentUpdateKeyCount
+_kSecAssessmentUpdateKeyFound
+_kSecAssessmentRuleKeyID
+_kSecAssessmentRuleKeyPriority
+_kSecAssessmentRuleKeyAllow
+_kSecAssessmentRuleKeyLabel
+_kSecAssessmentRuleKeyRemarks
+_kSecAssessmentRuleKeyRequirement
+_kSecAssessmentRuleKeyType
+_kSecAssessmentRuleKeyExpires
+_kSecAssessmentRuleKeyDisabled
+_kSecAssessmentRuleKeyBookmark
_kSecAssessmentAssessmentAuthority
_kSecAssessmentAssessmentAuthorityRow
_kSecAssessmentAssessmentFromCache
_kSecAssessmentAssessmentSource
_kSecAssessmentAssessmentVerdict
_kSecAssessmentContextKeyCertificates
+_kSecAssessmentUpdateKeyAuthorization
typedef SuperBlob<0xfade0cc1> DetachedSignatureBlob; // indexed by main architecture
+//
+// The linkers produces a superblob of dependency records from its dylib inputs
+//
+typedef SuperBlob<0xfade0c05> LibraryDependencyBlob; // indexed sequentially from 0
+
+
//
// An entitlement blob is used for embedding entitlement configuration data
//
{
rep = code->diskRep()->base();
this->prepare(flags);
+ PreSigningContext context(*this);
if (Universal *fat = state.mNoMachO ? NULL : rep->mainExecutableImage()) {
- signMachO(fat);
+ signMachO(fat, context);
} else {
- signArchitectureAgnostic();
+ signArchitectureAgnostic(context);
}
}
} else {
cdFlags = 0;
if (infoDict)
- if (CFTypeRef csflags = CFDictionaryGetValue(infoDict, CFSTR("CSFlags")))
+ if (CFTypeRef csflags = CFDictionaryGetValue(infoDict, CFSTR("CSFlags"))) {
if (CFGetTypeID(csflags) == CFNumberGetTypeID()) {
cdFlags = cfNumber<uint32_t>(CFNumberRef(csflags));
secdebug("signer", "using numeric cdFlags=0x%x from Info.plist", cdFlags);
secdebug("signer", "using text cdFlags=0x%x from Info.plist", cdFlags);
} else
MacOSError::throwMe(errSecCSBadDictionaryFormat);
+ }
}
if (state.mSigner == SecIdentityRef(kCFNull)) // ad-hoc signing requested...
cdFlags |= kSecCodeSignatureAdhoc; // ... so note that
}
pagesize = state.mPageSize ? cfNumber<size_t>(state.mPageSize) : rep->pageSize(state);
+
+ // Timestamping setup
+ CFRef<SecIdentityRef> mTSAuth; // identity for client-side authentication to the Timestamp server
}
// treat them as architectural binaries containing (only) one architecture - that
// interpretation is courtesy of the Universal/MachO support classes.
//
-void SecCodeSigner::Signer::signMachO(Universal *fat)
+void SecCodeSigner::Signer::signMachO(Universal *fat, const Requirement::Context &context)
{
// Mach-O executable at the core - perform multi-architecture signing
auto_ptr<ArchEditor> editor(state.mDetached
for (MachOEditor::Iterator it = editor->begin(); it != editor->end(); ++it) {
MachOEditor::Arch &arch = *it->second;
arch.source.reset(fat->architecture(it->first));
- arch.ireqs(state.mRequirements, rep->defaultRequirements(&arch.architecture, state));
+ arch.ireqs(state.mRequirements, rep->defaultRequirements(&arch.architecture, state), context);
if (editor->attribute(writerNoGlobal)) // can't store globally, add per-arch
populate(arch);
populate(arch.cdbuilder, arch, arch.ireqs,
// Sign a binary that has no notion of architecture.
// That currently means anything that isn't Mach-O format.
//
-void SecCodeSigner::Signer::signArchitectureAgnostic()
+void SecCodeSigner::Signer::signArchitectureAgnostic(const Requirement::Context &context)
{
// non-Mach-O executable - single-instance signing
RefPointer<DiskRep::Writer> writer = state.mDetached ?
(new DetachedBlobWriter(*this)) : rep->writer();
CodeDirectory::Builder builder(state.mDigestAlgorithm);
InternalRequirements ireqs;
- ireqs(state.mRequirements, rep->defaultRequirements(NULL, state));
+ ireqs(state.mRequirements, rep->defaultRequirements(NULL, state), context);
populate(*writer);
populate(builder, *writer, ireqs, rep->signingBase(), rep->signingLimit());
builder.flags(cdFlags);
builder.identifier(identifier);
- if (CFDataRef data = rep->component(cdInfoSlot))
+ if (CFRef<CFDataRef> data = rep->component(cdInfoSlot))
builder.specialSlot(cdInfoSlot, data);
if (ireqs) {
CFRef<CFDataRef> data = makeCFData(*ireqs);
writer.addDiscretionary(builder);
}
+#include <Security/tsaSupport.h>
//
// Generate the CMS signature for a (finished) CodeDirectory.
CFDataRef SecCodeSigner::Signer::signCodeDirectory(const CodeDirectory *cd)
{
assert(state.mSigner);
-
+ CFRef<CFMutableDictionaryRef> defaultTSContext = NULL;
+
// a null signer generates a null signature blob
if (state.mSigner == SecIdentityRef(kCFNull))
return CFDataCreate(NULL, NULL, 0);
}
MacOSError::check(CMSEncoderUpdateContent(cms, cd, cd->length()));
+
+ // Set up to call Timestamp server if requested
+
+ if (state.mWantTimeStamp)
+ {
+ CFRef<CFErrorRef> error = NULL;
+ defaultTSContext = SecCmsTSAGetDefaultContext(&error.aref());
+ if (error)
+ MacOSError::throwMe(errSecDataNotAvailable);
+
+ if (state.mNoTimeStampCerts || state.mTimestampService) {
+ if (state.mTimestampService)
+ CFDictionarySetValue(defaultTSContext, kTSAContextKeyURL, state.mTimestampService);
+ if (state.mNoTimeStampCerts)
+ CFDictionarySetValue(defaultTSContext, kTSAContextKeyNoCerts, kCFBooleanTrue);
+ }
+
+ CmsMessageSetTSAContext(cms, defaultTSContext);
+ }
+
CFDataRef signature;
MacOSError::check(CMSEncoderCopyEncodedContent(cms, &signature));
+
return signature;
}
CodeDirectory::HashAlgorithm digestAlgorithm() const { return state.mDigestAlgorithm; }
std::string path() const { return cfString(rep->canonicalPath()); }
+ SecIdentityRef signingIdentity() const { return state.mSigner; }
+ std::string signingIdentifier() const { return identifier; }
protected:
void prepare(SecCSFlags flags); // set up signing parameters
- void signMachO(Universal *fat); // sign a Mach-O binary
- void signArchitectureAgnostic(); // sign anything else
+ void signMachO(Universal *fat, const Requirement::Context &context); // sign a Mach-O binary
+ void signArchitectureAgnostic(const Requirement::Context &context); // sign anything else
void populate(DiskRep::Writer &writer); // global
void populate(CodeDirectory::Builder &builder, DiskRep::Writer &writer,
#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>
}
+//
+// InternalRequirements
+//
+void InternalRequirements::operator () (const Requirements *given, const Requirements *defaulted, const Requirement::Context &context)
+{
+ // first add the default internal requirements
+ if (defaulted) {
+ this->add(defaulted);
+ ::free((void *)defaulted); // was malloc(3)ed by DiskRep
+ }
+
+ // now override them with any requirements explicitly given by the signer
+ if (given)
+ this->add(given);
+
+ // now add the Designated Requirement, if we can make it and it's not been provided
+ if (!this->contains(kSecDesignatedRequirementType)) {
+ DRMaker maker(context);
+ if (Requirement *dr = maker.make()) {
+ this->add(kSecDesignatedRequirementType, dr); // takes ownership of dr
+ }
+ }
+
+ // return the result
+ mReqs = this->make();
+}
+
+
+//
+// Pre-Signing contexts
+//
+PreSigningContext::PreSigningContext(const SecCodeSigner::Signer &signer)
+{
+ // construct a cert chain
+ 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;
+ }
+
+ // other stuff
+ this->identifier = signer.signingIdentifier();
+}
+
+
} // end namespace CodeSigning
} // end namespace Security
namespace CodeSigning {
+//
+// A helper to deal with the magic merger logic of internal requirements
+//
+class InternalRequirements : public Requirements::Maker {
+public:
+ InternalRequirements() : mReqs(NULL) { }
+ ~InternalRequirements() { ::free((void *)mReqs); }
+ void operator () (const Requirements *given, const Requirements *defaulted, const Requirement::Context &context);
+ operator const Requirements * () const { return mReqs; }
+
+private:
+ const Requirements *mReqs;
+};
+
+
//
// A DiskRep::Writer that assembles data in a SuperBlob (in memory)
//
};
+//
+// A Requirement::Context populated from a signing request.
+// We use this to help generate the explicit Designated Requirement
+// during signing ops, and thus this must be constructed BEFORE we
+// actually have a signed object.
+//
+class PreSigningContext : public Requirement::Context {
+public:
+ PreSigningContext(const SecCodeSigner::Signer &signer);
+
+private:
+ CFRef<CFArrayRef> mCerts; // hold cert chain
+};
+
+
} // end namespace CodeSigning
} // end namespace Security
--
--- Copyright (c) 2011 Apple Inc. All Rights Reserved.
+-- Copyright (c) 2011-2012 Apple Inc. All Rights Reserved.
--
-- @APPLE_LICENSE_HEADER_START@
--
-- The feature table hold configuration features and options
--
CREATE TABLE feature (
- id INTEGER PRIMARY KEY, -- canononical
+ id INTEGER PRIMARY KEY, -- canononical
name TEXT NOT NULL UNIQUE, -- name of option
value TEXT NULL, -- value of option, if any
- remarks TEXT NOT NULL -- optional remarks string
+ remarks TEXT NULL -- optional remarks string
);
disabled INTEGER NOT NULL DEFAULT (0) -- disable count (stacks; enabled if zero)
CHECK (disabled >= 0),
expires FLOAT NOT NULL DEFAULT (5000000), -- expiration of rule authority (Julian date)
- priority REAL NOT NULL DEFAULT (0), -- rule priority (full float)
+ priority REAL NOT NULL DEFAULT (0), -- rule priority (full float)
label TEXT NULL, -- text label for authority rule
- flags INTEGER NOT NULL DEFAULT (0), -- amalgamated binary flags
+ flags INTEGER NOT NULL DEFAULT (0), -- amalgamated binary flags
-- following fields are for documentation only
ctime FLOAT NOT NULL DEFAULT (JULIANDAY('now')), -- rule creation time (Julian)
mtime FLOAT NOT NULL DEFAULT (JULIANDAY('now')), -- time rule was last changed (Julian)
WHERE JULIANDAY('now') < expires AND (flags & 1) = 0;
+--
+-- A table to carry (potentially large-ish) filesystem data stored as a bookmark blob.
+--
+CREATE TABLE bookmarkhints (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ bookmark BLOB NOT NULL,
+ authority INTEGER NOT NULL
+ REFERENCES authority(id) ON DELETE CASCADE
+);
+
+
+--
+-- Upgradable features already contained in this baseline.
+-- See policydatabase.cpp for upgrade code.
+--
+INSERT INTO feature (name, value, remarks)
+ VALUES ('bookmarkhints', 'value', 'builtin');
+INSERT INTO feature (name, value, remarks)
+ VALUES ('codesignedpackages', 'value', 'builtin');
+
+
--
-- Initial canonical contents of a fresh database
--
insert into authority (type, allow, flags, label, requirement)
values (1, 1, 2, 'Developer ID', 'anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] exists and certificate leaf[field.1.2.840.113635.100.6.1.13] exists');
insert into authority (type, allow, flags, label, requirement)
- values (2, 1, 2, 'Developer ID', 'anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] exists and certificate leaf[field.1.2.840.113635.100.6.1.14] exists');
+ values (2, 1, 2, 'Developer ID', 'anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] exists and (certificate leaf[field.1.2.840.113635.100.6.1.14] or certificate leaf[field.1.2.840.113635.100.6.1.13])');
--
Xar::Xar(const char *path)
{
mXar = 0;
- mSig = 0;
+ mSigCMS = 0;
+ mSigClassic = 0;
if (path)
open(path);
}
void Xar::open(const char *path)
{
- if ((mXar = ::xar_open(path, READ)))
- mSig = xar_signature_first(mXar);
+ if ((mXar = ::xar_open(path, READ)) == NULL)
+ return;
+
+ xar_signature_t sig = ::xar_signature_first(mXar);
+ // read signatures until we find a CMS signature
+ while (sig && mSigCMS == NULL) {
+ const char *type = ::xar_signature_type(sig);
+ if (strcmp(type, "CMS") == 0) {
+ mSigCMS = sig;
+ } else if (strcmp(type, "RSA") == 0) {
+ mSigClassic = sig;
+ }
+ sig = ::xar_signature_next(sig);
+ }
}
Xar::~Xar()
::xar_close(mXar);
}
-
-CFArrayRef Xar::copyCertChain()
+static CFArrayRef copyCertChainFromSignature(xar_signature_t sig)
{
- if (!mSig)
- return NULL;
- unsigned count = xar_signature_get_x509certificate_count(mSig);
+ unsigned count = xar_signature_get_x509certificate_count(sig);
CFRef<CFMutableArrayRef> certs = makeCFMutableArray(0);
for (unsigned ix = 0; ix < count; ix++) {
const uint8_t *data;
uint32_t length;
- if (xar_signature_get_x509certificate_data(mSig, ix, &data, &length) == 0) {
+ if (xar_signature_get_x509certificate_data(sig, ix, &data, &length) == 0) {
CFTempData cdata(data, length);
CFRef<SecCertificateRef> cert = SecCertificateCreateWithData(NULL, cdata);
CFArrayAppendValue(certs, cert.get());
return certs.yield();
}
+CFArrayRef Xar::copyCertChain()
+{
+ if (mSigCMS)
+ return copyCertChainFromSignature(mSigCMS);
+ else if (mSigClassic)
+ return copyCertChainFromSignature(mSigClassic);
+ return NULL;
+}
+
} // end namespace CodeSigning
} // end namespace Security
void open(const char *path);
operator bool() const { return mXar != 0; }
- bool isSigned() const { return mSig != 0; }
+ bool isSigned() const { return mSigClassic != 0 || mSigCMS != 0; }
CFArrayRef copyCertChain();
private:
xar_t mXar;
- xar_signature_t mSig;
+ xar_signature_t mSigClassic;
+ xar_signature_t mSigCMS;
};
#include <syslog.h>
#include <CoreFoundation/CoreFoundation.h>
#include <security_utilities/cfutilities.h>
-#include <Security/CodeSigning.h>
+#include <Security/SecRequirement.h>
namespace Security {
}
-bool xpcEngineUpdate(CFTypeRef target, uint flags, CFDictionaryRef context)
+CFDictionaryRef xpcEngineUpdate(CFTypeRef target, uint flags, CFDictionaryRef context)
{
Message msg("update");
// target can be NULL, a CFURLRef, a SecRequirementRef, or a CFNumberRef
if (int64_t error = xpc_dictionary_get_int64(msg, "error"))
MacOSError::throwMe(error);
- return true;
+ size_t resultLength;
+ const void *resultData = xpc_dictionary_get_data(msg, "result", &resultLength);
+ return makeCFDictionaryFrom(resultData, resultLength);
}
void xpcEngineAssess(CFURLRef path, uint flags, CFDictionaryRef context, CFMutableDictionaryRef result);
-bool xpcEngineUpdate(CFTypeRef target, uint flags, CFDictionaryRef context);
+CFDictionaryRef xpcEngineUpdate(CFTypeRef target, uint flags, CFDictionaryRef context)
+ CF_RETURNS_RETAINED;
bool xpcEngineControl(const char *name);
-
} // end namespace CodeSigning
} // end namespace Security
C26AC0F0143BCF18001C98CE /* ShellScript */,
C26AC0F4143BD1C4001C98CE /* CopyFiles */,
C2F24DFE14BCBBF200309FCD /* ShellScript */,
+ C24826BD159911A20082B10B /* CopyFiles */,
);
dependencies = (
);
C22463610B86210100626F1B /* antlrplugin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2CC31130B85254F005FA59D /* antlrplugin.cpp */; };
C236E3D70AD59446000F5140 /* signer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C236E3D50AD59446000F5140 /* signer.cpp */; };
C236E3DB0AD595C2000F5140 /* signerutils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C236E3D90AD595C2000F5140 /* signerutils.cpp */; };
+ C24826C6159911F40082B10B /* gkclear in CopyFiles */ = {isa = PBXBuildFile; fileRef = C24826BF159911CF0082B10B /* gkclear */; };
+ C24826C7159911F40082B10B /* gkgenerate in CopyFiles */ = {isa = PBXBuildFile; fileRef = C24826C0159911CF0082B10B /* gkgenerate */; };
+ C24826C8159911F40082B10B /* gkhandmake in CopyFiles */ = {isa = PBXBuildFile; fileRef = C24826C1159911CF0082B10B /* gkhandmake */; };
+ C24826C9159911F40082B10B /* gklist in CopyFiles */ = {isa = PBXBuildFile; fileRef = C24826C2159911CF0082B10B /* gklist */; };
+ C24826CA159911F40082B10B /* gkmerge in CopyFiles */ = {isa = PBXBuildFile; fileRef = C24826C3159911CF0082B10B /* gkmerge */; };
+ C24826CB159911F40082B10B /* gkrecord in CopyFiles */ = {isa = PBXBuildFile; fileRef = C24826C4159911CF0082B10B /* gkrecord */; };
C24EABAB1421432800C16AA9 /* policydb.h in Headers */ = {isa = PBXBuildFile; fileRef = C24EABAA1421432800C16AA9 /* policydb.h */; };
C24EABAD1421433700C16AA9 /* policydb.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C24EABAC1421433700C16AA9 /* policydb.cpp */; };
C250F6C30B5EF1910076098F /* SecIntegrity.h in Headers */ = {isa = PBXBuildFile; fileRef = C250F6C20B5EF1910076098F /* SecIntegrity.h */; };
C2F4439B14C626D4000A01E6 /* quarantine++.h in Headers */ = {isa = PBXBuildFile; fileRef = C2F4439914C626D4000A01E6 /* quarantine++.h */; };
C2F6566E0BCBFB250078779E /* cserror.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2F6566C0BCBFB250078779E /* cserror.cpp */; };
C2F656930BCBFFF40078779E /* cserror.h in Headers */ = {isa = PBXBuildFile; fileRef = C2F6566D0BCBFB250078779E /* cserror.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ EB5B6856156E4FEE0067635E /* drmaker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EB5B684E156E492D0067635E /* drmaker.cpp */; };
+ EB5B6857156E4FEE0067635E /* drmaker.h in Headers */ = {isa = PBXBuildFile; fileRef = EB5B684F156E492D0067635E /* drmaker.h */; };
FEB30C9310DAC89D00557BA2 /* SecTask.c in Sources */ = {isa = PBXBuildFile; fileRef = FEB30C9210DAC89D00557BA2 /* SecTask.c */; };
FEB30C9E10DAC8FD00557BA2 /* SecTask.h in Headers */ = {isa = PBXBuildFile; fileRef = FEB30C9410DAC8A500557BA2 /* SecTask.h */; settings = {ATTRIBUTES = (Public, ); }; };
FEB30CA310DAC91800557BA2 /* SecTask.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = FEB30C9410DAC8A500557BA2 /* SecTask.h */; };
);
runOnlyForDeploymentPostprocessing = 0;
};
+ C24826BD159911A20082B10B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/local/bin;
+ dstSubfolderSpec = 0;
+ files = (
+ C24826C6159911F40082B10B /* gkclear in CopyFiles */,
+ C24826C7159911F40082B10B /* gkgenerate in CopyFiles */,
+ C24826C8159911F40082B10B /* gkhandmake in CopyFiles */,
+ C24826C9159911F40082B10B /* gklist in CopyFiles */,
+ C24826CA159911F40082B10B /* gkmerge in CopyFiles */,
+ C24826CB159911F40082B10B /* gkrecord in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
C26AC0F4143BD1C4001C98CE /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 8;
C236E3D60AD59446000F5140 /* signer.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = signer.h; sourceTree = "<group>"; };
C236E3D90AD595C2000F5140 /* signerutils.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = signerutils.cpp; sourceTree = "<group>"; };
C236E3DA0AD595C2000F5140 /* signerutils.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = signerutils.h; sourceTree = "<group>"; };
+ C24826BF159911CF0082B10B /* gkclear */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; name = gkclear; path = gke/gkclear; sourceTree = SOURCE_ROOT; };
+ C24826C0159911CF0082B10B /* gkgenerate */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; name = gkgenerate; path = gke/gkgenerate; sourceTree = SOURCE_ROOT; };
+ C24826C1159911CF0082B10B /* gkhandmake */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; name = gkhandmake; path = gke/gkhandmake; sourceTree = SOURCE_ROOT; };
+ C24826C2159911CF0082B10B /* gklist */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; name = gklist; path = gke/gklist; sourceTree = SOURCE_ROOT; };
+ C24826C3159911CF0082B10B /* gkmerge */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; name = gkmerge; path = gke/gkmerge; sourceTree = SOURCE_ROOT; };
+ C24826C4159911CF0082B10B /* gkrecord */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; name = gkrecord; path = gke/gkrecord; sourceTree = SOURCE_ROOT; };
C24EABAA1421432800C16AA9 /* policydb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = policydb.h; sourceTree = "<group>"; };
C24EABAC1421433700C16AA9 /* policydb.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = policydb.cpp; sourceTree = "<group>"; };
C250F6C20B5EF1910076098F /* SecIntegrity.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = SecIntegrity.h; sourceTree = "<group>"; };
C2F6071B107D575700A83618 /* codesign-watch.d */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.dtrace; name = "codesign-watch.d"; path = "dtrace/codesign-watch.d"; sourceTree = SOURCE_ROOT; };
C2F6566C0BCBFB250078779E /* cserror.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = cserror.cpp; sourceTree = "<group>"; };
C2F6566D0BCBFB250078779E /* cserror.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = cserror.h; sourceTree = "<group>"; };
+ EB5B684E156E492D0067635E /* drmaker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = drmaker.cpp; sourceTree = "<group>"; };
+ EB5B684F156E492D0067635E /* drmaker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = drmaker.h; sourceTree = "<group>"; };
FEB30C9210DAC89D00557BA2 /* SecTask.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecTask.c; sourceTree = "<group>"; };
FEB30C9410DAC8A500557BA2 /* SecTask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecTask.h; sourceTree = "<group>"; };
/* End PBXFileReference section */
C2CC31160B852554005FA59D /* Security Plugins */,
FEB30C9110DAC6C400557BA2 /* Entitlements */,
C24EABA914213FAF00C16AA9 /* System Policy */,
+ C24826C5159911D70082B10B /* GKE */,
);
path = lib;
sourceTree = "<group>";
name = "Signing Operations";
sourceTree = "<group>";
};
+ C24826C5159911D70082B10B /* GKE */ = {
+ isa = PBXGroup;
+ children = (
+ C24826BF159911CF0082B10B /* gkclear */,
+ C24826C0159911CF0082B10B /* gkgenerate */,
+ C24826C1159911CF0082B10B /* gkhandmake */,
+ C24826C2159911CF0082B10B /* gklist */,
+ C24826C3159911CF0082B10B /* gkmerge */,
+ C24826C4159911CF0082B10B /* gkrecord */,
+ );
+ name = GKE;
+ sourceTree = "<group>";
+ };
C24EABA914213FAF00C16AA9 /* System Policy */ = {
isa = PBXGroup;
children = (
C2C1DF620A2E45B600D1B02B /* Requirements */ = {
isa = PBXGroup;
children = (
+ EB5B684E156E492D0067635E /* drmaker.cpp */,
+ EB5B684F156E492D0067635E /* drmaker.h */,
C2C1DF8F0A2E4A2700D1B02B /* requirements.grammar */,
C2D383360A237F47005C63A2 /* requirement.h */,
C2D383350A237F47005C63A2 /* requirement.cpp */,
C2A436160F2133B2007A41A6 /* slcrep.h in Headers */,
C24EABAB1421432800C16AA9 /* policydb.h in Headers */,
C2F4439B14C626D4000A01E6 /* quarantine++.h in Headers */,
+ EB5B6857156E4FEE0067635E /* drmaker.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
C2DC2DCA145F594000AD2A3A /* xar++.cpp in Sources */,
C2DC2DCB145F5CD000AD2A3A /* policyengine.cpp in Sources */,
C2F4439A14C626D4000A01E6 /* quarantine++.cpp in Sources */,
+ EB5B6856156E4FEE0067635E /* drmaker.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
isa = XCBuildConfiguration;
buildSettings = {
BUILD_VARIANTS = debug;
- CURRENT_PROJECT_VERSION = 55037.4;
+ CURRENT_PROJECT_VERSION = 55037.15;
EXECUTABLE_PREFIX = "";
EXECUTABLE_SUFFIX = "";
FRAMEWORK_SEARCH_PATHS = (
"$(BUILT_PRODUCTS_DIR)/SecurityPieces/PrivateHeaders",
"$(TEMPDIR)",
"$(SYSTEM_LIBRARY_DIR)/Frameworks/System.framework/PrivateHeaders",
+ /usr/local/SecurityPieces/Headers,
+ /usr/local/SecurityPieces/PrivateHeaders,
);
LIBRARY_STYLE = "\U0001STATIC";
OPT_CFLAGS = "-DNDEBUG -Os $(OPT_INLINEFLAGS)";
normal,
debug,
);
- CURRENT_PROJECT_VERSION = 55037.4;
+ CURRENT_PROJECT_VERSION = 55037.15;
EXECUTABLE_PREFIX = "";
EXECUTABLE_SUFFIX = "";
FRAMEWORK_SEARCH_PATHS = (
"$(BUILT_PRODUCTS_DIR)/SecurityPieces/PrivateHeaders",
"$(TEMPDIR)",
"$(SYSTEM_LIBRARY_DIR)/Frameworks/System.framework/PrivateHeaders",
+ /usr/local/SecurityPieces/Headers,
+ /usr/local/SecurityPieces/PrivateHeaders,
);
LIBRARY_STYLE = STATIC;
OPT_CFLAGS = "-DNDEBUG -Os $(OPT_INLINEFLAGS)";
normal,
debug,
);
- CURRENT_PROJECT_VERSION = 55037.4;
+ CURRENT_PROJECT_VERSION = 55037.15;
EXECUTABLE_PREFIX = "";
EXECUTABLE_SUFFIX = "";
FRAMEWORK_SEARCH_PATHS = (
"$(BUILT_PRODUCTS_DIR)/SecurityPieces/PrivateHeaders",
"$(TEMPDIR)",
"$(SYSTEM_LIBRARY_DIR)/Frameworks/System.framework/PrivateHeaders",
+ /usr/local/SecurityPieces/Headers,
+ /usr/local/SecurityPieces/PrivateHeaders,
);
LIBRARY_STYLE = STATIC;
OPT_CFLAGS = "-DNDEBUG -Os $(OPT_INLINEFLAGS)";